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

@ -4,11 +4,11 @@
*
*
* Copyright (c) 2002 - 2006, PostgreSQL Global Development Group
*
*
* Author: Andreas Pflug <pgadmin@pse-consulting.de>
*
* IDENTIFICATION
* $PostgreSQL: pgsql/contrib/adminpack/adminpack.c,v 1.3 2006/07/11 16:35:30 momjian Exp $
* $PostgreSQL: pgsql/contrib/adminpack/adminpack.c,v 1.4 2006/10/04 00:29:44 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -35,7 +35,6 @@
#ifdef unlink
#undef unlink
#endif
#endif
extern DLLIMPORT char *DataDir;
@ -44,20 +43,20 @@ extern DLLIMPORT char *Log_filename;
PG_MODULE_MAGIC;
Datum pg_file_write(PG_FUNCTION_ARGS);
Datum pg_file_rename(PG_FUNCTION_ARGS);
Datum pg_file_unlink(PG_FUNCTION_ARGS);
Datum pg_logdir_ls(PG_FUNCTION_ARGS);
Datum pg_file_write(PG_FUNCTION_ARGS);
Datum pg_file_rename(PG_FUNCTION_ARGS);
Datum pg_file_unlink(PG_FUNCTION_ARGS);
Datum pg_logdir_ls(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(pg_file_write);
PG_FUNCTION_INFO_V1(pg_file_rename);
PG_FUNCTION_INFO_V1(pg_file_unlink);
PG_FUNCTION_INFO_V1(pg_logdir_ls);
typedef struct
typedef struct
{
char *location;
DIR *dirdesc;
char *location;
DIR *dirdesc;
} directory_fctx;
/*-----------------------
@ -65,30 +64,31 @@ typedef struct
*/
/*
* Return an absolute path. Argument may be absolute or
* Return an absolute path. Argument may be absolute or
* relative to the DataDir.
*/
static char *absClusterPath(text *arg, bool logAllowed)
static char *
absClusterPath(text *arg, bool logAllowed)
{
char *filename;
int len=VARSIZE(arg) - VARHDRSZ;
int dlen = strlen(DataDir);
char *filename;
int len = VARSIZE(arg) - VARHDRSZ;
int dlen = strlen(DataDir);
filename = palloc(len+1);
filename = palloc(len + 1);
memcpy(filename, VARDATA(arg), len);
filename[len] = 0;
if (strstr(filename, "..") != NULL)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("No .. allowed in filenames"))));
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("No .. allowed in filenames"))));
if (is_absolute_path(filename))
{
if (logAllowed && !strncmp(filename, Log_directory, strlen(Log_directory)))
return filename;
if (logAllowed && !strncmp(filename, Log_directory, strlen(Log_directory)))
return filename;
if (strncmp(filename, DataDir, dlen))
ereport(ERROR,
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("Absolute path not allowed"))));
@ -96,7 +96,8 @@ static char *absClusterPath(text *arg, bool logAllowed)
}
else
{
char *absname = palloc(dlen+len+2);
char *absname = palloc(dlen + len + 2);
sprintf(absname, "%s/%s", DataDir, filename);
pfree(filename);
return absname;
@ -111,9 +112,9 @@ static void
requireSuperuser(void)
{
if (!superuser())
ereport(ERROR,
ereport(ERROR,
(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
*/
Datum pg_file_write(PG_FUNCTION_ARGS)
Datum
pg_file_write(PG_FUNCTION_ARGS)
{
FILE *f;
char *filename;
text *data;
int64 count = 0;
FILE *f;
char *filename;
text *data;
int64 count = 0;
requireSuperuser();
@ -136,16 +138,17 @@ Datum pg_file_write(PG_FUNCTION_ARGS)
if (PG_ARGISNULL(2) || !PG_GETARG_BOOL(2))
{
struct stat fst;
struct stat fst;
if (stat(filename, &fst) >= 0)
ereport(ERROR,
ereport(ERROR,
(ERRCODE_DUPLICATE_FILE,
errmsg("file %s exists", filename)));
f = fopen(filename, "wb");
f = fopen(filename, "wb");
}
else
f = fopen(filename, "ab");
f = fopen(filename, "ab");
if (!f)
{
@ -159,7 +162,7 @@ Datum pg_file_write(PG_FUNCTION_ARGS)
count = fwrite(VARDATA(data), 1, VARSIZE(data) - VARHDRSZ, f);
if (count != VARSIZE(data) - VARHDRSZ)
ereport(ERROR,
ereport(ERROR,
(errcode_for_file_access(),
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;
int rc;
char *fn1,
*fn2,
*fn3;
int rc;
requireSuperuser();
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
PG_RETURN_NULL();
fn1=absClusterPath(PG_GETARG_TEXT_P(0), false);
fn2=absClusterPath(PG_GETARG_TEXT_P(1), false);
fn1 = absClusterPath(PG_GETARG_TEXT_P(0), false);
fn2 = absClusterPath(PG_GETARG_TEXT_P(1), false);
if (PG_ARGISNULL(2))
fn3=0;
fn3 = 0;
else
fn3=absClusterPath(PG_GETARG_TEXT_P(2), false);
fn3 = absClusterPath(PG_GETARG_TEXT_P(2), false);
if (access(fn1, W_OK) < 0)
{
@ -192,7 +198,7 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
(errcode_for_file_access(),
errmsg("file %s not accessible: %m", fn1)));
PG_RETURN_BOOL(false);
PG_RETURN_BOOL(false);
}
if (fn3 && access(fn2, W_OK) < 0)
@ -201,7 +207,7 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
(errcode_for_file_access(),
errmsg("file %s not accessible: %m", fn2)));
PG_RETURN_BOOL(false);
PG_RETURN_BOOL(false);
}
@ -212,10 +218,10 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
(ERRCODE_DUPLICATE_FILE,
errmsg("cannot rename to target file %s", fn3 ? fn3 : fn2)));
}
if (fn3)
{
if (rename(fn2, fn3) != 0)
if (rename(fn2, fn3) != 0)
{
ereport(ERROR,
(errcode_for_file_access(),
@ -231,7 +237,7 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
{
ereport(ERROR,
(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
{
@ -244,9 +250,9 @@ Datum pg_file_rename(PG_FUNCTION_ARGS)
}
else if (rename(fn1, fn2) != 0)
{
ereport(WARNING,
(errcode_for_file_access(),
errmsg("renaming %s to %s %m", fn1, fn2)));
ereport(WARNING,
(errcode_for_file_access(),
errmsg("renaming %s to %s %m", fn1, fn2)));
ereport(ERROR,
(errcode_for_file_access(),
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();
filename = absClusterPath(PG_GETARG_TEXT_P(0), false);
filename = absClusterPath(PG_GETARG_TEXT_P(0), false);
if (access(filename, W_OK) < 0)
{
if (errno == ENOENT)
PG_RETURN_BOOL(false);
if (errno == ENOENT)
PG_RETURN_BOOL(false);
else
ereport(ERROR,
ereport(ERROR,
(errcode_for_file_access(),
errmsg("file %s not accessible: %m", filename)));
@ -287,17 +294,18 @@ Datum pg_file_unlink(PG_FUNCTION_ARGS)
}
Datum pg_logdir_ls(PG_FUNCTION_ARGS)
Datum
pg_logdir_ls(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
struct dirent *de;
directory_fctx *fctx;
if (!superuser())
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
(errmsg("only superuser can list the log directory"))));
if (memcmp(Log_filename, "postgresql-%Y-%m-%d_%H%M%S.log", 30) != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
@ -306,17 +314,17 @@ Datum pg_logdir_ls(PG_FUNCTION_ARGS)
if (SRF_IS_FIRSTCALL())
{
MemoryContext oldcontext;
TupleDesc tupdesc;
TupleDesc tupdesc;
funcctx=SRF_FIRSTCALL_INIT();
funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
fctx = palloc(sizeof(directory_fctx));
if (is_absolute_path(Log_directory))
fctx->location = Log_directory;
fctx->location = Log_directory;
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);
}
tupdesc = CreateTemplateTupleDesc(2, false);
@ -326,11 +334,11 @@ Datum pg_logdir_ls(PG_FUNCTION_ARGS)
TEXTOID, -1, 0);
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
fctx->dirdesc = AllocateDir(fctx->location);
if (!fctx->dirdesc)
ereport(ERROR,
ereport(ERROR,
(errcode_for_file_access(),
errmsg("%s is not browsable: %m", fctx->location)));
@ -338,47 +346,47 @@ Datum pg_logdir_ls(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldcontext);
}
funcctx=SRF_PERCALL_SETUP();
fctx = (directory_fctx*) funcctx->user_fctx;
funcctx = SRF_PERCALL_SETUP();
fctx = (directory_fctx *) funcctx->user_fctx;
if (!fctx->dirdesc) /* not a readable directory */
if (!fctx->dirdesc) /* not a readable directory */
SRF_RETURN_DONE(funcctx);
while ((de = readdir(fctx->dirdesc)) != NULL)
{
char *values[2];
HeapTuple tuple;
char *field[MAXDATEFIELDS];
char *values[2];
HeapTuple tuple;
char *field[MAXDATEFIELDS];
char lowstr[MAXDATELEN + 1];
int dtype;
int nf, ftype[MAXDATEFIELDS];
int dtype;
int nf,
ftype[MAXDATEFIELDS];
fsec_t fsec;
int tz = 0;
struct pg_tm date;
int tz = 0;
struct pg_tm date;
/*
* Default format:
* postgresql-YYYY-MM-DD_HHMMSS.log
* Default format: postgresql-YYYY-MM-DD_HHMMSS.log
*/
if (strlen(de->d_name) != 32
|| memcmp(de->d_name, "postgresql-", 11)
|| memcmp(de->d_name, "postgresql-", 11)
|| de->d_name[21] != '_'
|| strcmp(de->d_name + 28, ".log"))
continue;
continue;
values[1] = palloc(strlen(fctx->location) + strlen(de->d_name) + 2);
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;
/* parse and decode expected timestamp */
/* parse and decode expected timestamp */
if (ParseDateTime(values[0], lowstr, MAXDATELEN, field, ftype, MAXDATEFIELDS, &nf))
continue;
continue;
if (DecodeDateTime(field, ftype, nf, &dtype, &date, &fsec, &tz))
continue;
continue;
/* 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
called by the backend in the process of processing queries. The calling
@ -159,7 +159,7 @@ Datum
cube_in(PG_FUNCTION_ARGS)
{
void *result;
char *str;
char *str;
str = PG_GETARG_CSTRING(0);
@ -170,7 +170,7 @@ cube_in(PG_FUNCTION_ARGS)
cube_scanner_finish();
PG_RETURN_POINTER (result);
PG_RETURN_POINTER(result);
}
/* Allow conversion from text to cube to allow input of computed strings */
@ -178,11 +178,11 @@ cube_in(PG_FUNCTION_ARGS)
Datum
cube(PG_FUNCTION_ARGS)
{
char *cstring;
char *cstring;
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
cube_a_f8_f8(PG_FUNCTION_ARGS)
{
int i;
int dim;
int size;
NDBOX *result;
ArrayType *ur, *ll;
double *dur, *dll;
int i;
int dim;
int size;
NDBOX *result;
ArrayType *ur,
*ll;
double *dur,
*dll;
ur = (ArrayType *) PG_GETARG_VARLENA_P(0);
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))
{
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("Cannot work with NULL arrays")));
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("Cannot work with NULL arrays")));
}
dim = ARRNELEMS(ur);
if (ARRNELEMS(ll) != dim)
{
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("UR and LL arrays must be of same length")));
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("UR and LL arrays must be of same length")));
}
dur = ARRPTR(ur);
dll = ARRPTR(ll);
size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim;
result = (NDBOX *) palloc (size);
memset (result, 0, size);
result = (NDBOX *) palloc(size);
memset(result, 0, size);
result->size = size;
result->dim = dim;
for (i=0; i<dim; i++)
for (i = 0; i < dim; i++)
{
result->x[i] = dur[i];
result->x[i+dim] = dll[i];
result->x[i + dim] = dll[i];
}
PG_RETURN_POINTER(result);
@ -241,20 +243,20 @@ cube_a_f8_f8(PG_FUNCTION_ARGS)
Datum
cube_a_f8(PG_FUNCTION_ARGS)
{
int i;
int dim;
int size;
NDBOX *result;
ArrayType *ur;
double *dur;
int i;
int dim;
int size;
NDBOX *result;
ArrayType *ur;
double *dur;
ur = (ArrayType *) PG_GETARG_VARLENA_P(0);
if (ARR_HASNULL(ur))
{
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("Cannot work with NULL arrays")));
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("Cannot work with NULL arrays")));
}
dim = ARRNELEMS(ur);
@ -262,15 +264,15 @@ cube_a_f8(PG_FUNCTION_ARGS)
dur = ARRPTR(ur);
size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim;
result = (NDBOX *) palloc (size);
memset (result, 0, size);
result = (NDBOX *) palloc(size);
memset(result, 0, size);
result->size = size;
result->dim = dim;
for (i=0; i<dim; i++)
for (i = 0; i < dim; i++)
{
result->x[i] = dur[i];
result->x[i+dim] = dur[i];
result->x[i + dim] = dur[i];
}
PG_RETURN_POINTER(result);
@ -279,10 +281,13 @@ cube_a_f8(PG_FUNCTION_ARGS)
Datum
cube_subset(PG_FUNCTION_ARGS)
{
NDBOX *c, *result;
ArrayType *idx;
int size, dim, i;
int *dx;
NDBOX *c,
*result;
ArrayType *idx;
int size,
dim,
i;
int *dx;
c = (NDBOX *) PG_GETARG_POINTER(0);
idx = (ArrayType *) PG_GETARG_VARLENA_P(1);
@ -290,30 +295,30 @@ cube_subset(PG_FUNCTION_ARGS)
if (ARR_HASNULL(idx))
{
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("Cannot work with NULL arrays")));
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("Cannot work with NULL arrays")));
}
dx = (int4 *) ARR_DATA_PTR (idx);
dx = (int4 *) ARR_DATA_PTR(idx);
dim = ARRNELEMS(idx);
size = offsetof(NDBOX, x[0]) + sizeof(double) * 2 * dim;
result = (NDBOX *) palloc (size);
memset (result, 0, size);
result = (NDBOX *) palloc(size);
memset(result, 0, size);
result->size = size;
result->dim = dim;
for (i=0; i<dim; i++)
for (i = 0; i < dim; i++)
{
if ((dx[i] <= 0) || (dx[i] > c->dim))
{
pfree (result);
pfree(result);
ereport(ERROR,
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("Index out of bounds")));
(errcode(ERRCODE_ARRAY_ELEMENT_ERROR),
errmsg("Index out of bounds")));
}
result->x[i] = c->x[dx[i]-1];
result->x[i+dim] = c->x[dx[i]+c->dim-1];
result->x[i] = c->x[dx[i] - 1];
result->x[i + dim] = c->x[dx[i] + c->dim - 1];
}
PG_RETURN_POINTER(result);
@ -327,11 +332,11 @@ cube_out(PG_FUNCTION_ARGS)
int dim;
int i;
int ndig;
NDBOX *cube;
NDBOX *cube;
initStringInfo(&buf);
cube = (NDBOX *) PG_GETARG_POINTER (0);
cube = (NDBOX *) PG_GETARG_POINTER(0);
dim = cube->dim;
@ -369,7 +374,7 @@ cube_out(PG_FUNCTION_ARGS)
appendStringInfoChar(&buf, ')');
}
PG_RETURN_CSTRING (buf.data);
PG_RETURN_CSTRING(buf.data);
}
@ -383,11 +388,11 @@ cube_out(PG_FUNCTION_ARGS)
** the predicate x op query == FALSE, where op is the oper
** corresponding to strategy in the pg_amop table.
*/
Datum
Datum
g_cube_consistent(PG_FUNCTION_ARGS)
{
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
NDBOX *query = (NDBOX *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
NDBOX *query = (NDBOX *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
/*
@ -414,7 +419,7 @@ g_cube_union(PG_FUNCTION_ARGS)
NDBOX *out = (NDBOX *) NULL;
NDBOX *tmp;
int *sizep;
GistEntryVector *entryvec;
GistEntryVector *entryvec;
entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
sizep = (int *) PG_GETARG_POINTER(1);
@ -446,15 +451,15 @@ g_cube_union(PG_FUNCTION_ARGS)
*/
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
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
*/
Datum
g_cube_penalty (PG_FUNCTION_ARGS)
g_cube_penalty(PG_FUNCTION_ARGS)
{
GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
float *result = (float *) PG_GETARG_POINTER(2);
GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
float *result = (float *) PG_GETARG_POINTER(2);
NDBOX *ud;
double tmp1,
tmp2;
ud = cube_union_v0((NDBOX *) DatumGetPointer(origentry->key),
(NDBOX *) DatumGetPointer(newentry->key));
(NDBOX *) DatumGetPointer(newentry->key));
rt_cube_size(ud, &tmp1);
rt_cube_size((NDBOX *) DatumGetPointer(origentry->key), &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);
*/
PG_RETURN_FLOAT8 (*result);
PG_RETURN_FLOAT8(*result);
}
@ -493,8 +498,8 @@ g_cube_penalty (PG_FUNCTION_ARGS)
Datum
g_cube_picksplit(PG_FUNCTION_ARGS)
{
GistEntryVector *entryvec;
GIST_SPLITVEC *v;
GistEntryVector *entryvec;
GIST_SPLITVEC *v;
OffsetNumber i,
j;
NDBOX *datum_alpha,
@ -546,9 +551,9 @@ g_cube_picksplit(PG_FUNCTION_ARGS)
/* size_waste = size_union - size_inter; */
union_d = cube_union_v0(datum_alpha, datum_beta);
rt_cube_size(union_d, &size_union);
inter_d = (NDBOX *) DatumGetPointer (DirectFunctionCall2
(cube_inter,
entryvec->vector[i].key, entryvec->vector[j].key));
inter_d = (NDBOX *) DatumGetPointer(DirectFunctionCall2
(cube_inter,
entryvec->vector[i].key, entryvec->vector[j].key));
rt_cube_size(inter_d, &size_inter);
size_waste = size_union - size_inter;
@ -649,12 +654,13 @@ g_cube_picksplit(PG_FUNCTION_ARGS)
Datum
g_cube_same(PG_FUNCTION_ARGS)
{
NDBOX *b1, *b2;
bool *result;
b1 = (NDBOX *) PG_GETARG_POINTER (0);
b2 = (NDBOX *) PG_GETARG_POINTER (1);
result = (bool *) PG_GETARG_POINTER (2);
NDBOX *b1,
*b2;
bool *result;
b1 = (NDBOX *) PG_GETARG_POINTER(0);
b2 = (NDBOX *) PG_GETARG_POINTER(1);
result = (bool *) PG_GETARG_POINTER(2);
if (cube_cmp_v0(b1, b2) == 0)
*result = TRUE;
@ -664,7 +670,7 @@ g_cube_same(PG_FUNCTION_ARGS)
/*
* 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
cube_union (PG_FUNCTION_ARGS)
cube_union(PG_FUNCTION_ARGS)
{
NDBOX *a, *b;
NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
PG_RETURN_POINTER(cube_union_v0(a,b));
PG_RETURN_POINTER(cube_union_v0(a, b));
}
/* cube_inter */
@ -818,7 +825,9 @@ Datum
cube_inter(PG_FUNCTION_ARGS)
{
int i;
NDBOX *result, *a, *b;
NDBOX *result,
*a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
@ -874,17 +883,17 @@ cube_inter(PG_FUNCTION_ARGS)
/*
* Is it OK to return a non-null intersection for non-overlapping boxes?
*/
PG_RETURN_POINTER (result);
PG_RETURN_POINTER(result);
}
/* cube_size */
Datum
cube_size(PG_FUNCTION_ARGS)
{
NDBOX *a;
NDBOX *a;
int i,
j;
double result;
double result;
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++)
result = result * Abs((a->x[j] - a->x[i]));
PG_RETURN_FLOAT8 (result);
PG_RETURN_FLOAT8(result);
}
void
@ -994,10 +1003,11 @@ cube_cmp_v0(NDBOX * a, NDBOX * b)
return 0;
}
Datum
Datum
cube_cmp(PG_FUNCTION_ARGS)
{
NDBOX *a, *b;
NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1009,7 +1019,8 @@ cube_cmp(PG_FUNCTION_ARGS)
Datum
cube_eq(PG_FUNCTION_ARGS)
{
NDBOX *a, *b;
NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1021,7 +1032,8 @@ cube_eq(PG_FUNCTION_ARGS)
Datum
cube_ne(PG_FUNCTION_ARGS)
{
NDBOX *a, *b;
NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1033,7 +1045,8 @@ cube_ne(PG_FUNCTION_ARGS)
Datum
cube_lt(PG_FUNCTION_ARGS)
{
NDBOX *a, *b;
NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1045,7 +1058,8 @@ cube_lt(PG_FUNCTION_ARGS)
Datum
cube_gt(PG_FUNCTION_ARGS)
{
NDBOX *a, *b;
NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1057,7 +1071,8 @@ cube_gt(PG_FUNCTION_ARGS)
Datum
cube_le(PG_FUNCTION_ARGS)
{
NDBOX *a, *b;
NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1069,7 +1084,8 @@ cube_le(PG_FUNCTION_ARGS)
Datum
cube_ge(PG_FUNCTION_ARGS)
{
NDBOX *a, *b;
NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1122,7 +1138,8 @@ cube_contains_v0(NDBOX * a, NDBOX * b)
Datum
cube_contains(PG_FUNCTION_ARGS)
{
NDBOX *a, *b;
NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1135,12 +1152,13 @@ cube_contains(PG_FUNCTION_ARGS)
Datum
cube_contained(PG_FUNCTION_ARGS)
{
NDBOX *a, *b;
NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
PG_RETURN_BOOL (cube_contains_v0(b, a));
PG_RETURN_BOOL(cube_contains_v0(b, a));
}
/* Overlap */
@ -1193,12 +1211,13 @@ cube_overlap_v0(NDBOX * a, NDBOX * b)
Datum
cube_overlap(PG_FUNCTION_ARGS)
{
NDBOX *a, *b;
NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
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;
double d,
distance;
NDBOX *a, *b;
NDBOX *a,
*b;
a = (NDBOX *) PG_GETARG_POINTER(0);
b = (NDBOX *) PG_GETARG_POINTER(1);
@ -1266,7 +1286,7 @@ cube_is_point(PG_FUNCTION_ARGS)
{
int i,
j;
NDBOX *a;
NDBOX *a;
a = (NDBOX *) PG_GETARG_POINTER(0);
@ -1283,7 +1303,7 @@ cube_is_point(PG_FUNCTION_ARGS)
Datum
cube_dim(PG_FUNCTION_ARGS)
{
NDBOX *c;
NDBOX *c;
c = (NDBOX *) PG_GETARG_POINTER(0);
@ -1397,8 +1417,8 @@ cube_f8(PG_FUNCTION_ARGS)
result->dim = 1;
result->x[0] = PG_GETARG_FLOAT8(0);
result->x[1] = result->x[0];
PG_RETURN_POINTER (result);
PG_RETURN_POINTER(result);
}
/* Create a one dimensional box */
@ -1416,7 +1436,7 @@ cube_f8_f8(PG_FUNCTION_ARGS)
result->x[0] = PG_GETARG_FLOAT8(0);
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
@ -1431,7 +1451,7 @@ cube_c_f8(PG_FUNCTION_ARGS)
int i;
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;
result = (NDBOX *) palloc(size);
@ -1446,7 +1466,7 @@ cube_c_f8(PG_FUNCTION_ARGS)
result->x[result->dim - 1] = x;
result->x[2 * result->dim - 1] = x;
PG_RETURN_POINTER(result);
PG_RETURN_POINTER(result);
}
/* Add a dimension to an existing cube */
@ -1455,13 +1475,14 @@ cube_c_f8_f8(PG_FUNCTION_ARGS)
{
NDBOX *c;
NDBOX *result;
double x1, x2;
double x1,
x2;
int size;
int i;
c = (NDBOX *) PG_GETARG_POINTER(0);
x1 = PG_GETARG_FLOAT8 (1);
x2 = PG_GETARG_FLOAT8 (2);
x1 = PG_GETARG_FLOAT8(1);
x2 = PG_GETARG_FLOAT8(2);
size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
result = (NDBOX *) palloc(size);
@ -1476,7 +1497,5 @@ cube_c_f8_f8(PG_FUNCTION_ARGS)
result->x[result->dim - 1] = x1;
result->x[2 * result->dim - 1] = x2;
PG_RETURN_POINTER(result);
PG_RETURN_POINTER(result);
}

View File

@ -8,7 +8,7 @@
* Darko Prenosil <Darko.Prenosil@finteh.hr>
* Shridhar Daithankar <shridhar_daithankar@persistent.co.in>
*
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.58 2006/09/02 21:11:15 joe Exp $
* $PostgreSQL: pgsql/contrib/dblink/dblink.c,v 1.59 2006/10/04 00:29:44 momjian Exp $
* Copyright (c) 2001-2006, PostgreSQL Global Development Group
* ALL RIGHTS RESERVED;
*
@ -362,11 +362,11 @@ dblink_open(PG_FUNCTION_ARGS)
DBLINK_RES_INTERNALERROR("begin error");
PQclear(res);
rconn->newXactForCursor = TRUE;
/*
* Since transaction state was IDLE, we force cursor count to
* initially be 0. This is needed as a previous ABORT might
* have wiped out our transaction without maintaining the
* cursor count for us.
* initially be 0. This is needed as a previous ABORT might have wiped
* out our transaction without maintaining the cursor count for us.
*/
rconn->openCursorCount = 0;
}
@ -621,8 +621,8 @@ dblink_fetch(PG_FUNCTION_ARGS)
if (PQnfields(res) != tupdesc->natts)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("remote query result rowtype does not match "
"the specified FROM clause rowtype")));
errmsg("remote query result rowtype does not match "
"the specified FROM clause rowtype")));
/* fast track when no results */
if (funcctx->max_calls < 1)
@ -827,7 +827,7 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
if (!res ||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
PQresultStatus(res) != PGRES_TUPLES_OK))
PQresultStatus(res) != PGRES_TUPLES_OK))
{
if (fail)
DBLINK_RES_ERROR("sql error");
@ -839,33 +839,33 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
SRF_RETURN_DONE(funcctx);
}
}
if (PQresultStatus(res) == PGRES_COMMAND_OK)
{
is_sql_cmd = true;
/* need a tuple descriptor representing one TEXT column */
tupdesc = CreateTemplateTupleDesc(1, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "status",
TEXTOID, -1, 0);
TEXTOID, -1, 0);
/*
* and save a copy of the command status string to return as our
* result tuple
*/
* and save a copy of the command status string to return as
* our result tuple
*/
sql_cmd_status = PQcmdStatus(res);
funcctx->max_calls = 1;
}
else
funcctx->max_calls = PQntuples(res);
/* got results, keep track of them */
funcctx->user_fctx = res;
/* if needed, close the connection to the database and cleanup */
if (freeconn)
PQfinish(conn);
if (!is_sql_cmd)
{
/* get a tuple descriptor for our result type */
@ -878,26 +878,29 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
/* failed to determine actual type of RECORD */
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("function returning record called in context "
"that cannot accept type record")));
errmsg("function returning record called in context "
"that cannot accept type record")));
break;
default:
/* result type isn't composite */
elog(ERROR, "return type must be a row type");
break;
}
/* make sure we have a persistent copy of the 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)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("remote query result rowtype does not match "
"the specified FROM clause rowtype")));
errmsg("remote query result rowtype does not match "
"the specified FROM clause rowtype")));
/* fast track when no results */
if (funcctx->max_calls < 1)
{
@ -905,11 +908,11 @@ dblink_record_internal(FunctionCallInfo fcinfo, bool is_async, bool do_get)
PQclear(res);
SRF_RETURN_DONE(funcctx);
}
/* store needed metadata for subsequent calls */
attinmeta = TupleDescGetAttInMetadata(tupdesc);
funcctx->attinmeta = attinmeta;
MemoryContextSwitchTo(oldcontext);
}
else
@ -991,9 +994,9 @@ PG_FUNCTION_INFO_V1(dblink_get_connections);
Datum
dblink_get_connections(PG_FUNCTION_ARGS)
{
HASH_SEQ_STATUS status;
remoteConnHashEnt *hentry;
ArrayBuildState *astate = NULL;
HASH_SEQ_STATUS status;
remoteConnHashEnt *hentry;
ArrayBuildState *astate = NULL;
if (remoteConnHash)
{
@ -1019,19 +1022,19 @@ dblink_get_connections(PG_FUNCTION_ARGS)
*
* Returns 1 if the connection is busy, 0 otherwise
* 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);
Datum
dblink_is_busy(PG_FUNCTION_ARGS)
{
char *msg;
PGconn *conn = NULL;
char *conname = NULL;
char *connstr = NULL;
remoteConn *rconn = NULL;
bool freeconn = false;
char *msg;
PGconn *conn = NULL;
char *conname = NULL;
char *connstr = NULL;
remoteConn *rconn = NULL;
bool freeconn = false;
DBLINK_INIT;
DBLINK_GET_CONN;
@ -1045,27 +1048,27 @@ dblink_is_busy(PG_FUNCTION_ARGS)
/*
* Cancels a running request on a connection
*
* Returns text:
* Returns text:
* "OK" if the cancel request has been sent correctly,
* an error message otherwise
*
* an error message otherwise
*
* 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);
Datum
dblink_cancel_query(PG_FUNCTION_ARGS)
{
char *msg;
int res = 0;
PGconn *conn = NULL;
char *conname = NULL;
char *connstr = NULL;
remoteConn *rconn = NULL;
bool freeconn = false;
PGcancel *cancel;
char errbuf[256];
char *msg;
int res = 0;
PGconn *conn = NULL;
char *conname = NULL;
char *connstr = NULL;
remoteConn *rconn = NULL;
bool freeconn = false;
PGcancel *cancel;
char errbuf[256];
DBLINK_INIT;
DBLINK_GET_CONN;
@ -1077,7 +1080,7 @@ dblink_cancel_query(PG_FUNCTION_ARGS)
PQfreeCancel(cancel);
if (res == 0)
PG_RETURN_TEXT_P(GET_TEXT("OK"));
PG_RETURN_TEXT_P(GET_TEXT("OK"));
else
PG_RETURN_TEXT_P(GET_TEXT(errbuf));
}
@ -1086,23 +1089,23 @@ dblink_cancel_query(PG_FUNCTION_ARGS)
/*
* Get error message from a connection
*
* Returns text:
* Returns text:
* "OK" if no error, an error message otherwise
*
*
* 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);
Datum
dblink_error_message(PG_FUNCTION_ARGS)
{
char *msg;
PGconn *conn = NULL;
char *conname = NULL;
char *connstr = NULL;
remoteConn *rconn = NULL;
bool freeconn = false;
char *msg;
PGconn *conn = NULL;
char *conname = NULL;
char *connstr = NULL;
remoteConn *rconn = NULL;
bool freeconn = false;
DBLINK_INIT;
DBLINK_GET_CONN;
@ -1859,7 +1862,7 @@ get_sql_delete(Oid relid, int2vector *pkattnums, int16 pknumatts, char **tgt_pka
char *relname;
TupleDesc tupdesc;
int natts;
StringInfoData buf;
StringInfoData buf;
int i;
initStringInfo(&buf);

View File

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

View File

@ -7,8 +7,8 @@
/* bigint defines */
#define BITBYTE 8
#define SIGLENINT 4 /* >122 => key will toast, so very slow!!! */
#define SIGLEN ( sizeof(int)*SIGLENINT )
#define SIGLENINT 4 /* >122 => key will toast, so very slow!!! */
#define SIGLEN ( sizeof(int)*SIGLENINT )
#define SIGLENBIT (SIGLEN*BITBYTE)
typedef char BITVEC[SIGLEN];
@ -36,22 +36,23 @@ typedef char *BITVECP;
#define HASHVAL(val) (((unsigned int)(val)) % SIGLENBIT)
#define HASH(sign, val) SETBIT((sign), HASHVAL(val))
typedef struct {
int4 len;
int4 flag;
char data[1];
} GISTTYPE;
typedef struct
{
int4 len;
int4 flag;
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 GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) )
#define SUMBIT(val) ( \
#define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) )
#define SUMBIT(val) ( \
GETBITBYTE((val),0) + \
GETBITBYTE((val),1) + \
GETBITBYTE((val),2) + \
@ -67,20 +68,22 @@ typedef struct {
#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
PG_FUNCTION_INFO_V1(ghstore_in);
Datum ghstore_in(PG_FUNCTION_ARGS);
Datum ghstore_in(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(ghstore_out);
Datum ghstore_out(PG_FUNCTION_ARGS);
Datum ghstore_out(PG_FUNCTION_ARGS);
Datum
ghstore_in(PG_FUNCTION_ARGS) {
ghstore_in(PG_FUNCTION_ARGS)
{
elog(ERROR, "Not implemented");
PG_RETURN_DATUM(0);
}
Datum
ghstore_out(PG_FUNCTION_ARGS) {
ghstore_out(PG_FUNCTION_ARGS)
{
elog(ERROR, "Not implemented");
PG_RETURN_DATUM(0);
}
@ -93,36 +96,41 @@ PG_FUNCTION_INFO_V1(ghstore_picksplit);
PG_FUNCTION_INFO_V1(ghstore_union);
PG_FUNCTION_INFO_V1(ghstore_same);
Datum ghstore_consistent(PG_FUNCTION_ARGS);
Datum ghstore_compress(PG_FUNCTION_ARGS);
Datum ghstore_decompress(PG_FUNCTION_ARGS);
Datum ghstore_penalty(PG_FUNCTION_ARGS);
Datum ghstore_picksplit(PG_FUNCTION_ARGS);
Datum ghstore_union(PG_FUNCTION_ARGS);
Datum ghstore_same(PG_FUNCTION_ARGS);
Datum ghstore_consistent(PG_FUNCTION_ARGS);
Datum ghstore_compress(PG_FUNCTION_ARGS);
Datum ghstore_decompress(PG_FUNCTION_ARGS);
Datum ghstore_penalty(PG_FUNCTION_ARGS);
Datum ghstore_picksplit(PG_FUNCTION_ARGS);
Datum ghstore_union(PG_FUNCTION_ARGS);
Datum ghstore_same(PG_FUNCTION_ARGS);
Datum
ghstore_compress(PG_FUNCTION_ARGS) {
ghstore_compress(PG_FUNCTION_ARGS)
{
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
GISTENTRY *retval = entry;
if (entry->leafkey) {
GISTTYPE *res = (GISTTYPE*)palloc(CALCGTSIZE(0));
HStore *toastedval = (HStore *) DatumGetPointer(entry->key);
HStore *val = (HStore *) DatumGetPointer(PG_DETOAST_DATUM(entry->key));
HEntry *ptr = ARRPTR(val);
char *words = STRPTR(val);
memset(res,0,CALCGTSIZE(0));
res->len=CALCGTSIZE(0);
while(ptr-ARRPTR(val) < val->size) {
int h;
h = crc32_sz((char*)(words+ptr->pos), ptr->keylen);
HASH( GETSIGN(res), h);
if ( !ptr->valisnull ) {
h = crc32_sz((char *)(words+ptr->pos+ptr->keylen), ptr->vallen);
HASH( GETSIGN(res), h);
if (entry->leafkey)
{
GISTTYPE *res = (GISTTYPE *) palloc(CALCGTSIZE(0));
HStore *toastedval = (HStore *) DatumGetPointer(entry->key);
HStore *val = (HStore *) DatumGetPointer(PG_DETOAST_DATUM(entry->key));
HEntry *ptr = ARRPTR(val);
char *words = STRPTR(val);
memset(res, 0, CALCGTSIZE(0));
res->len = CALCGTSIZE(0);
while (ptr - ARRPTR(val) < val->size)
{
int h;
h = crc32_sz((char *) (words + ptr->pos), ptr->keylen);
HASH(GETSIGN(res), h);
if (!ptr->valisnull)
{
h = crc32_sz((char *) (words + ptr->pos + ptr->keylen), ptr->vallen);
HASH(GETSIGN(res), h);
}
ptr++;
}
@ -135,14 +143,16 @@ ghstore_compress(PG_FUNCTION_ARGS) {
entry->rel, entry->page,
entry->offset,
FALSE);
} else if ( !ISALLTRUE(DatumGetPointer(entry->key)) ) {
int4 i;
}
else if (!ISALLTRUE(DatumGetPointer(entry->key)))
{
int4 i;
GISTTYPE *res;
BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
LOOPBYTE(
if ((sign[i] & 0xff) != 0xff)
PG_RETURN_POINTER(retval);
if ((sign[i] & 0xff) != 0xff)
PG_RETURN_POINTER(retval);
);
res = (GISTTYPE *) palloc(CALCGTSIZE(ALLISTRUE));
@ -152,7 +162,7 @@ ghstore_compress(PG_FUNCTION_ARGS) {
retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
gistentryinit(*retval, PointerGetDatum(res),
entry->rel, entry->page,
entry->offset,
entry->offset,
FALSE);
}
@ -160,15 +170,17 @@ ghstore_compress(PG_FUNCTION_ARGS) {
}
Datum
ghstore_decompress(PG_FUNCTION_ARGS) {
ghstore_decompress(PG_FUNCTION_ARGS)
{
PG_RETURN_DATUM(PG_GETARG_DATUM(0));
}
Datum
ghstore_same(PG_FUNCTION_ARGS) {
ghstore_same(PG_FUNCTION_ARGS)
{
GISTTYPE *a = (GISTTYPE *) PG_GETARG_POINTER(0);
GISTTYPE *b = (GISTTYPE *) PG_GETARG_POINTER(1);
bool *result = (bool *) PG_GETARG_POINTER(2);
bool *result = (bool *) PG_GETARG_POINTER(2);
if (ISALLTRUE(a) && ISALLTRUE(b))
*result = true;
@ -176,83 +188,97 @@ ghstore_same(PG_FUNCTION_ARGS) {
*result = false;
else if (ISALLTRUE(b))
*result = false;
else {
int4 i;
BITVECP sa = GETSIGN(a),
sb = GETSIGN(b);
else
{
int4 i;
BITVECP sa = GETSIGN(a),
sb = GETSIGN(b);
*result = true;
LOOPBYTE(
if (sa[i] != sb[i]) {
*result = false;
break;
}
if (sa[i] != sb[i])
{
*result = false;
break;
}
);
}
PG_RETURN_POINTER(result);
}
static int4
sizebitvec(BITVECP sign) {
int4 size = 0, i;
sizebitvec(BITVECP sign)
{
int4 size = 0,
i;
LOOPBYTE(
size += SUMBIT(sign);
sign = (BITVECP) (((char *) sign) + 1);
size += SUMBIT(sign);
sign = (BITVECP) (((char *) sign) + 1);
);
return size;
}
static int
hemdistsign(BITVECP a, BITVECP b) {
int i,dist=0;
hemdistsign(BITVECP a, BITVECP b)
{
int i,
dist = 0;
LOOPBIT(
if ( GETBIT(a,i) != GETBIT(b,i) )
if (GETBIT(a, i) != GETBIT(b, i))
dist++;
);
return dist;
}
static int
hemdist(GISTTYPE *a, GISTTYPE *b) {
if ( ISALLTRUE(a) ) {
hemdist(GISTTYPE * a, GISTTYPE * b)
{
if (ISALLTRUE(a))
{
if (ISALLTRUE(b))
return 0;
else
return SIGLENBIT-sizebitvec(GETSIGN(b));
} else if (ISALLTRUE(b))
return SIGLENBIT-sizebitvec(GETSIGN(a));
return SIGLENBIT - sizebitvec(GETSIGN(b));
}
else if (ISALLTRUE(b))
return SIGLENBIT - sizebitvec(GETSIGN(a));
return hemdistsign( GETSIGN(a), GETSIGN(b) );
return hemdistsign(GETSIGN(a), GETSIGN(b));
}
static int4
unionkey(BITVECP sbase, GISTTYPE * add)
{
int4 i;
BITVECP sadd = GETSIGN(add);
int4 i;
BITVECP sadd = GETSIGN(add);
if (ISALLTRUE(add))
return 1;
LOOPBYTE(
sbase[i] |= sadd[i];
sbase[i] |= sadd[i];
);
return 0;
}
Datum
ghstore_union(PG_FUNCTION_ARGS) {
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
int4 len = entryvec->n;
ghstore_union(PG_FUNCTION_ARGS)
{
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
int4 len = entryvec->n;
int *size = (int *) PG_GETARG_POINTER(1);
BITVEC base;
int4 i;
int4 flag = 0;
int *size = (int *) PG_GETARG_POINTER(1);
BITVEC base;
int4 i;
int4 flag = 0;
GISTTYPE *result;
MemSet((void *) base, 0, sizeof(BITVEC));
for (i = 0; i < len; i++) {
if (unionkey(base, GETENTRY(entryvec, i))) {
for (i = 0; i < len; i++)
{
if (unionkey(base, GETENTRY(entryvec, i)))
{
flag = ALLISTRUE;
break;
}
@ -269,64 +295,72 @@ ghstore_union(PG_FUNCTION_ARGS) {
}
Datum
ghstore_penalty(PG_FUNCTION_ARGS) {
ghstore_penalty(PG_FUNCTION_ARGS)
{
GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
float *penalty = (float *) PG_GETARG_POINTER(2);
float *penalty = (float *) PG_GETARG_POINTER(2);
GISTTYPE *origval = (GISTTYPE *) DatumGetPointer(origentry->key);
GISTTYPE *newval = (GISTTYPE *) DatumGetPointer(newentry->key);
*penalty=hemdist(origval,newval);
*penalty = hemdist(origval, newval);
PG_RETURN_POINTER(penalty);
}
typedef struct {
typedef struct
{
OffsetNumber pos;
int4 cost;
} SPLITCOST;
int4 cost;
} SPLITCOST;
static int
comparecost(const void *a, const void *b) {
comparecost(const void *a, const void *b)
{
return ((SPLITCOST *) a)->cost - ((SPLITCOST *) b)->cost;
}
Datum
ghstore_picksplit(PG_FUNCTION_ARGS) {
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
ghstore_picksplit(PG_FUNCTION_ARGS)
{
GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
OffsetNumber maxoff = entryvec->n - 2;
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
OffsetNumber k,
j;
GISTTYPE *datum_l,
GISTTYPE *datum_l,
*datum_r;
BITVECP union_l,
BITVECP union_l,
union_r;
int4 size_alpha, size_beta;
int4 size_waste,
int4 size_alpha,
size_beta;
int4 size_waste,
waste = -1;
int4 nbytes;
int4 nbytes;
OffsetNumber seed_1 = 0,
seed_2 = 0;
OffsetNumber *left,
*right;
BITVECP ptr;
int i;
BITVECP ptr;
int i;
SPLITCOST *costvector;
GISTTYPE *_k,
GISTTYPE *_k,
*_j;
nbytes = (maxoff + 2) * sizeof(OffsetNumber);
v->spl_left = (OffsetNumber *) palloc(nbytes);
v->spl_right = (OffsetNumber *) palloc(nbytes);
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k)) {
for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
{
_k = GETENTRY(entryvec, k);
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j)) {
size_waste=hemdist(_k, GETENTRY(entryvec, j));
if (size_waste > waste ) {
for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
{
size_waste = hemdist(_k, GETENTRY(entryvec, j));
if (size_waste > waste)
{
waste = size_waste;
seed_1 = k;
seed_2 = j;
@ -346,26 +380,32 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
}
/* form initial .. */
if (ISALLTRUE(GETENTRY(entryvec, seed_1))) {
if (ISALLTRUE(GETENTRY(entryvec, seed_1)))
{
datum_l = (GISTTYPE *) palloc(GTHDRSIZE);
datum_l->len = GTHDRSIZE;
datum_l->flag = ALLISTRUE;
} else {
}
else
{
datum_l = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
datum_l->len = GTHDRSIZE + SIGLEN;
datum_l->flag = 0;
memcpy((void *) GETSIGN(datum_l), (void *) GETSIGN(GETENTRY(entryvec, seed_1)), sizeof(BITVEC))
;
;
}
if (ISALLTRUE(GETENTRY(entryvec, seed_2))) {
if (ISALLTRUE(GETENTRY(entryvec, seed_2)))
{
datum_r = (GISTTYPE *) palloc(GTHDRSIZE);
datum_r->len = GTHDRSIZE;
datum_r->flag = ALLISTRUE;
} else {
}
else
{
datum_r = (GISTTYPE *) palloc(GTHDRSIZE + SIGLEN);
datum_r->len = GTHDRSIZE + SIGLEN;
datum_r->flag = 0;
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);
@ -375,50 +415,63 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
{
costvector[j - 1].pos = j;
_j = GETENTRY(entryvec, j);
size_alpha = hemdist(datum_l,_j);
size_beta = hemdist(datum_r,_j);
size_alpha = hemdist(datum_l, _j);
size_beta = hemdist(datum_r, _j);
costvector[j - 1].cost = abs(size_alpha - size_beta);
}
qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
union_l=GETSIGN(datum_l);
union_r=GETSIGN(datum_r);
union_l = GETSIGN(datum_l);
union_r = GETSIGN(datum_r);
for (k = 0; k < maxoff; k++) {
for (k = 0; k < maxoff; k++)
{
j = costvector[k].pos;
if (j == seed_1) {
if (j == seed_1)
{
*left++ = j;
v->spl_nleft++;
continue;
} else if (j == seed_2) {
}
else if (j == seed_2)
{
*right++ = j;
v->spl_nright++;
continue;
}
_j = GETENTRY(entryvec, j);
size_alpha = hemdist(datum_l,_j);
size_beta = hemdist(datum_r,_j);
size_alpha = hemdist(datum_l, _j);
size_beta = hemdist(datum_r, _j);
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.0001)) {
if (ISALLTRUE(datum_l) || ISALLTRUE(_j) ) {
if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.0001))
{
if (ISALLTRUE(datum_l) || ISALLTRUE(_j))
{
if (!ISALLTRUE(datum_l))
MemSet((void *) union_l, 0xff, sizeof(BITVEC));
} else {
ptr=GETSIGN(_j);
}
else
{
ptr = GETSIGN(_j);
LOOPBYTE(
union_l[i] |= ptr[i];
union_l[i] |= ptr[i];
);
}
*left++ = j;
v->spl_nleft++;
} else {
if (ISALLTRUE(datum_r) || ISALLTRUE(_j) ) {
}
else
{
if (ISALLTRUE(datum_r) || ISALLTRUE(_j))
{
if (!ISALLTRUE(datum_r))
MemSet((void *) union_r, 0xff, sizeof(BITVEC));
} else {
ptr=GETSIGN(_j);
}
else
{
ptr = GETSIGN(_j);
LOOPBYTE(
union_r[i] |= ptr[i];
union_r[i] |= ptr[i];
);
}
*right++ = j;
@ -436,36 +489,41 @@ ghstore_picksplit(PG_FUNCTION_ARGS) {
}
Datum
ghstore_consistent(PG_FUNCTION_ARGS) {
GISTTYPE *entry = (GISTTYPE*) DatumGetPointer( ((GISTENTRY *) PG_GETARG_POINTER(0))->key );
HStore *query=PG_GETARG_HS(1);
bool res=true;
HEntry *qe = ARRPTR(query);
char *qv = STRPTR(query);
BITVECP sign;
Datum
ghstore_consistent(PG_FUNCTION_ARGS)
{
GISTTYPE *entry = (GISTTYPE *) DatumGetPointer(((GISTENTRY *) PG_GETARG_POINTER(0))->key);
HStore *query = PG_GETARG_HS(1);
bool res = true;
HEntry *qe = ARRPTR(query);
char *qv = STRPTR(query);
BITVECP sign;
if ( ISALLTRUE(entry) ) {
PG_FREE_IF_COPY(query,1);
if (ISALLTRUE(entry))
{
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(true);
}
sign=GETSIGN(entry);
while(res && qe-ARRPTR(query) < query->size) {
int crc = crc32_sz((char *)(qv + qe->pos), qe->keylen);
if (GETBIT(sign,HASHVAL(crc))) {
if ( !qe->valisnull ) {
crc = crc32_sz((char *)(qv + qe->pos + qe->keylen), qe->vallen);
if ( !GETBIT(sign,HASHVAL(crc)) )
res=false;
sign = GETSIGN(entry);
while (res && qe - ARRPTR(query) < query->size)
{
int crc = crc32_sz((char *) (qv + qe->pos), qe->keylen);
if (GETBIT(sign, HASHVAL(crc)))
{
if (!qe->valisnull)
{
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++;
}
PG_FREE_IF_COPY(query,1);
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(res);
}

View File

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

View File

@ -7,20 +7,22 @@
static HEntry *
findkey(HStore *hs, char *key, int keylen) {
HEntry *StopLow = ARRPTR(hs);
HEntry *StopHigh = StopLow + hs->size;
HEntry *StopMiddle;
int difference;
char *base = STRPTR(hs);
findkey(HStore * hs, char *key, int keylen)
{
HEntry *StopLow = ARRPTR(hs);
HEntry *StopHigh = StopLow + hs->size;
HEntry *StopMiddle;
int difference;
char *base = STRPTR(hs);
while (StopLow < StopHigh) {
while (StopLow < StopHigh)
{
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
if ( StopMiddle->keylen == keylen )
difference=strncmp(base+StopMiddle->pos, key, StopMiddle->keylen);
if (StopMiddle->keylen == keylen)
difference = strncmp(base + StopMiddle->pos, key, StopMiddle->keylen);
else
difference=(StopMiddle->keylen > keylen) ? 1 : -1;
difference = (StopMiddle->keylen > keylen) ? 1 : -1;
if (difference == 0)
return StopMiddle;
@ -29,520 +31,583 @@ findkey(HStore *hs, char *key, int keylen) {
else
StopHigh = StopMiddle;
}
return NULL;
}
PG_FUNCTION_INFO_V1(fetchval);
Datum fetchval(PG_FUNCTION_ARGS);
Datum fetchval(PG_FUNCTION_ARGS);
Datum
fetchval(PG_FUNCTION_ARGS) {
HStore *hs = PG_GETARG_HS(0);
text *key = PG_GETARG_TEXT_P(1);
HEntry *entry;
text *out;
fetchval(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0);
text *key = PG_GETARG_TEXT_P(1);
HEntry *entry;
text *out;
if ((entry=findkey(hs,VARDATA(key), VARSIZE(key)-VARHDRSZ))==NULL || entry->valisnull) {
PG_FREE_IF_COPY(hs,0);
PG_FREE_IF_COPY(key,1);
if ((entry = findkey(hs, VARDATA(key), VARSIZE(key) - VARHDRSZ)) == NULL || entry->valisnull)
{
PG_FREE_IF_COPY(hs, 0);
PG_FREE_IF_COPY(key, 1);
PG_RETURN_NULL();
}
out=palloc(VARHDRSZ+entry->vallen);
memcpy(VARDATA(out),STRPTR(hs) + entry->pos + entry->keylen, entry->vallen);
VARATT_SIZEP(out) = VARHDRSZ+entry->vallen;
out = palloc(VARHDRSZ + entry->vallen);
memcpy(VARDATA(out), STRPTR(hs) + entry->pos + entry->keylen, entry->vallen);
VARATT_SIZEP(out) = VARHDRSZ + entry->vallen;
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_POINTER(out);
}
PG_FUNCTION_INFO_V1(exists);
Datum exists(PG_FUNCTION_ARGS);
Datum exists(PG_FUNCTION_ARGS);
Datum
exists(PG_FUNCTION_ARGS) {
HStore *hs = PG_GETARG_HS(0);
text *key = PG_GETARG_TEXT_P(1);
HEntry *entry;
exists(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0);
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(key,1);
PG_FREE_IF_COPY(hs, 0);
PG_FREE_IF_COPY(key, 1);
PG_RETURN_BOOL(entry);
}
PG_FUNCTION_INFO_V1(defined);
Datum defined(PG_FUNCTION_ARGS);
Datum defined(PG_FUNCTION_ARGS);
Datum
defined(PG_FUNCTION_ARGS) {
HStore *hs = PG_GETARG_HS(0);
text *key = PG_GETARG_TEXT_P(1);
HEntry *entry;
bool res;
defined(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0);
text *key = PG_GETARG_TEXT_P(1);
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(key,1);
PG_FREE_IF_COPY(hs, 0);
PG_FREE_IF_COPY(key, 1);
PG_RETURN_BOOL(res);
}
PG_FUNCTION_INFO_V1(delete);
Datum delete(PG_FUNCTION_ARGS);
Datum delete(PG_FUNCTION_ARGS);
Datum
delete(PG_FUNCTION_ARGS) {
HStore *hs = PG_GETARG_HS(0);
text *key = PG_GETARG_TEXT_P(1);
HStore *out = palloc(hs->len);
char *ptrs, *ptrd;
HEntry *es, *ed;
delete(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0);
text *key = PG_GETARG_TEXT_P(1);
HStore *out = palloc(hs->len);
char *ptrs,
*ptrd;
HEntry *es,
*ed;
out->len=hs->len;
out->size=hs->size; /* temprorary! */
out->len = hs->len;
out->size = hs->size; /* temprorary! */
ptrs=STRPTR(hs);
es =ARRPTR(hs);
ptrd=STRPTR(out);
ed =ARRPTR(out);
ptrs = STRPTR(hs);
es = ARRPTR(hs);
ptrd = STRPTR(out);
ed = ARRPTR(out);
while( es - ARRPTR(hs) < hs->size ) {
if ( !(es->keylen == VARSIZE(key) - VARHDRSZ && strncmp(ptrs, VARDATA(key), es->keylen)==0) ) {
memcpy( ed, es, sizeof(HEntry) );
memcpy( ptrd, ptrs, es->keylen + ( (es->valisnull) ? 0 : es->vallen ) );
while (es - ARRPTR(hs) < hs->size)
{
if (!(es->keylen == VARSIZE(key) - VARHDRSZ && strncmp(ptrs, VARDATA(key), es->keylen) == 0))
{
memcpy(ed, es, sizeof(HEntry));
memcpy(ptrd, ptrs, es->keylen + ((es->valisnull) ? 0 : es->vallen));
ed->pos = ptrd - STRPTR(out);
ptrd += es->keylen + ( (es->valisnull) ? 0 : es->vallen );
ptrd += es->keylen + ((es->valisnull) ? 0 : es->vallen);
ed++;
}
ptrs += es->keylen + ( (es->valisnull) ? 0 : es->vallen );
ptrs += es->keylen + ((es->valisnull) ? 0 : es->vallen);
es++;
}
if ( ed - ARRPTR(out) != out->size ) {
int buflen=ptrd-STRPTR(out);
if (ed - ARRPTR(out) != out->size)
{
int buflen = ptrd - STRPTR(out);
ptrd = STRPTR(out);
out->size = ed - ARRPTR(out);
memmove( STRPTR(out), ptrd, buflen);
memmove(STRPTR(out), ptrd, buflen);
out->len = CALCDATASIZE(out->size, buflen);
}
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_POINTER(out);
}
PG_FUNCTION_INFO_V1(hs_concat);
Datum hs_concat(PG_FUNCTION_ARGS);
Datum hs_concat(PG_FUNCTION_ARGS);
Datum
hs_concat(PG_FUNCTION_ARGS) {
HStore *s1 = PG_GETARG_HS(0);
HStore *s2 = PG_GETARG_HS(1);
HStore *out = palloc( s1->len + s2->len );
char *ps1, *ps2, *pd;
HEntry *es1, *es2, *ed;
hs_concat(PG_FUNCTION_ARGS)
{
HStore *s1 = PG_GETARG_HS(0);
HStore *s2 = PG_GETARG_HS(1);
HStore *out = palloc(s1->len + s2->len);
char *ps1,
*ps2,
*pd;
HEntry *es1,
*es2,
*ed;
out->len = s1->len + s2->len;
out->size = s1->size + s2->size;
ps1=STRPTR(s1);
ps2=STRPTR(s2);
pd=STRPTR(out);
es1=ARRPTR(s1);
es2=ARRPTR(s2);
ed=ARRPTR(out);
ps1 = STRPTR(s1);
ps2 = STRPTR(s2);
pd = STRPTR(out);
es1 = ARRPTR(s1);
es2 = ARRPTR(s2);
ed = ARRPTR(out);
while( es1 - ARRPTR(s1) < s1->size && es2 - ARRPTR(s2) < s2->size ) {
int difference;
if ( es1->keylen == es2->keylen )
difference=strncmp(ps1, ps2, es1->keylen);
while (es1 - ARRPTR(s1) < s1->size && es2 - ARRPTR(s2) < s2->size)
{
int difference;
if (es1->keylen == es2->keylen)
difference = strncmp(ps1, ps2, es1->keylen);
else
difference=(es1->keylen > es2->keylen) ? 1 : -1;
difference = (es1->keylen > es2->keylen) ? 1 : -1;
if ( difference == 0 ) {
memcpy( ed, es2, sizeof(HEntry) );
memcpy( pd, ps2, es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ) );
if (difference == 0)
{
memcpy(ed, es2, sizeof(HEntry));
memcpy(pd, ps2, es2->keylen + ((es2->valisnull) ? 0 : es2->vallen));
ed->pos = pd - STRPTR(out);
pd += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen );
pd += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
ed++;
ps1 += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen );
ps1 += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
es1++;
ps2 += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen );
ps2 += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
es2++;
} else if ( difference > 0 ) {
memcpy( ed, es2, sizeof(HEntry) );
memcpy( pd, ps2, es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ) );
}
else if (difference > 0)
{
memcpy(ed, es2, sizeof(HEntry));
memcpy(pd, ps2, es2->keylen + ((es2->valisnull) ? 0 : es2->vallen));
ed->pos = pd - STRPTR(out);
pd += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen );
pd += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
ed++;
ps2 += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen );
ps2 += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
es2++;
} else {
memcpy( ed, es1, sizeof(HEntry) );
memcpy( pd, ps1, es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen ) );
}
else
{
memcpy(ed, es1, sizeof(HEntry));
memcpy(pd, ps1, es1->keylen + ((es1->valisnull) ? 0 : es1->vallen));
ed->pos = pd - STRPTR(out);
pd += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen );
pd += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
ed++;
ps1 += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen );
ps1 += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
es1++;
}
}
while( es1 - ARRPTR(s1) < s1->size ) {
memcpy( ed, es1, sizeof(HEntry) );
memcpy( pd, ps1, es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen ) );
while (es1 - ARRPTR(s1) < s1->size)
{
memcpy(ed, es1, sizeof(HEntry));
memcpy(pd, ps1, es1->keylen + ((es1->valisnull) ? 0 : es1->vallen));
ed->pos = pd - STRPTR(out);
pd += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen );
pd += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
ed++;
ps1 += es1->keylen + ( (es1->valisnull) ? 0 : es1->vallen );
ps1 += es1->keylen + ((es1->valisnull) ? 0 : es1->vallen);
es1++;
}
while( es2 - ARRPTR(s2) < s2->size ) {
memcpy( ed, es2, sizeof(HEntry) );
memcpy( pd, ps2, es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen ) );
while (es2 - ARRPTR(s2) < s2->size)
{
memcpy(ed, es2, sizeof(HEntry));
memcpy(pd, ps2, es2->keylen + ((es2->valisnull) ? 0 : es2->vallen));
ed->pos = pd - STRPTR(out);
pd += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen );
pd += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
ed++;
ps2 += es2->keylen + ( (es2->valisnull) ? 0 : es2->vallen );
ps2 += es2->keylen + ((es2->valisnull) ? 0 : es2->vallen);
es2++;
}
if ( ed - ARRPTR(out) != out->size ) {
int buflen=pd-STRPTR(out);
if (ed - ARRPTR(out) != out->size)
{
int buflen = pd - STRPTR(out);
pd = STRPTR(out);
out->size = ed - ARRPTR(out);
memmove( STRPTR(out), pd, buflen);
memmove(STRPTR(out), pd, buflen);
out->len = CALCDATASIZE(out->size, buflen);
}
PG_FREE_IF_COPY(s1,0);
PG_FREE_IF_COPY(s2,1);
PG_FREE_IF_COPY(s1, 0);
PG_FREE_IF_COPY(s2, 1);
PG_RETURN_POINTER(out);
}
PG_FUNCTION_INFO_V1(tconvert);
Datum tconvert(PG_FUNCTION_ARGS);
Datum tconvert(PG_FUNCTION_ARGS);
Datum
tconvert(PG_FUNCTION_ARGS) {
text *key = PG_GETARG_TEXT_P(0);
text *val = PG_GETARG_TEXT_P(1);
int len;
HStore *out;
tconvert(PG_FUNCTION_ARGS)
{
text *key = PG_GETARG_TEXT_P(0);
text *val = PG_GETARG_TEXT_P(1);
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->len=len;
out->size=1;
out->len = len;
out->size = 1;
ARRPTR(out)->keylen = VARSIZE(key) - VARHDRSZ;
ARRPTR(out)->vallen = VARSIZE(val) - VARHDRSZ;
ARRPTR(out)->valisnull = false;
ARRPTR(out)->pos=0;
ARRPTR(out)->pos = 0;
memcpy( STRPTR(out), VARDATA(key), ARRPTR(out)->keylen );
memcpy( STRPTR(out) + ARRPTR(out)->keylen, VARDATA(val), ARRPTR(out)->vallen );
PG_FREE_IF_COPY(key,0);
PG_FREE_IF_COPY(val,1);
memcpy(STRPTR(out), VARDATA(key), ARRPTR(out)->keylen);
memcpy(STRPTR(out) + ARRPTR(out)->keylen, VARDATA(val), ARRPTR(out)->vallen);
PG_FREE_IF_COPY(key, 0);
PG_FREE_IF_COPY(val, 1);
PG_RETURN_POINTER(out);
}
PG_FUNCTION_INFO_V1(akeys);
Datum akeys(PG_FUNCTION_ARGS);
Datum akeys(PG_FUNCTION_ARGS);
Datum
akeys(PG_FUNCTION_ARGS) {
HStore *hs = PG_GETARG_HS(0);
Datum *d;
ArrayType *a;
HEntry *ptr=ARRPTR(hs);
char *base=STRPTR(hs);
akeys(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0);
Datum *d;
ArrayType *a;
HEntry *ptr = ARRPTR(hs);
char *base = STRPTR(hs);
d=(Datum*)palloc(sizeof(Datum)*(hs->size+1));
while( ptr-ARRPTR(hs) < hs->size ) {
text *item=(text*)palloc(VARHDRSZ + ptr->keylen);
VARATT_SIZEP(item) = VARHDRSZ+ptr->keylen;
d = (Datum *) palloc(sizeof(Datum) * (hs->size + 1));
while (ptr - ARRPTR(hs) < hs->size)
{
text *item = (text *) palloc(VARHDRSZ + ptr->keylen);
VARATT_SIZEP(item) = VARHDRSZ + ptr->keylen;
memcpy(VARDATA(item), base + ptr->pos, ptr->keylen);
d[ ptr-ARRPTR(hs) ] = PointerGetDatum(item);
d[ptr - ARRPTR(hs)] = PointerGetDatum(item);
ptr++;
}
a = construct_array(
d,
hs->size,
TEXTOID,
-1,
false,
'i'
);
ptr=ARRPTR(hs);
while( ptr-ARRPTR(hs) < hs->size ) {
pfree(DatumGetPointer(d[ ptr-ARRPTR(hs) ]));
a = construct_array(
d,
hs->size,
TEXTOID,
-1,
false,
'i'
);
ptr = ARRPTR(hs);
while (ptr - ARRPTR(hs) < hs->size)
{
pfree(DatumGetPointer(d[ptr - ARRPTR(hs)]));
ptr++;
}
pfree(d);
PG_FREE_IF_COPY(hs,0);
PG_FREE_IF_COPY(hs, 0);
PG_RETURN_POINTER(a);
}
PG_FUNCTION_INFO_V1(avals);
Datum avals(PG_FUNCTION_ARGS);
Datum avals(PG_FUNCTION_ARGS);
Datum
avals(PG_FUNCTION_ARGS) {
HStore *hs = PG_GETARG_HS(0);
Datum *d;
ArrayType *a;
HEntry *ptr=ARRPTR(hs);
char *base=STRPTR(hs);
avals(PG_FUNCTION_ARGS)
{
HStore *hs = PG_GETARG_HS(0);
Datum *d;
ArrayType *a;
HEntry *ptr = ARRPTR(hs);
char *base = STRPTR(hs);
d=(Datum*)palloc(sizeof(Datum)*(hs->size+1));
while( ptr-ARRPTR(hs) < hs->size ) {
int vallen = (ptr->valisnull) ? 0 : ptr->vallen;
text *item=(text*)palloc(VARHDRSZ + vallen);
VARATT_SIZEP(item) = VARHDRSZ+vallen;
d = (Datum *) palloc(sizeof(Datum) * (hs->size + 1));
while (ptr - ARRPTR(hs) < hs->size)
{
int vallen = (ptr->valisnull) ? 0 : ptr->vallen;
text *item = (text *) palloc(VARHDRSZ + vallen);
VARATT_SIZEP(item) = VARHDRSZ + vallen;
memcpy(VARDATA(item), base + ptr->pos + ptr->keylen, vallen);
d[ ptr-ARRPTR(hs) ] = PointerGetDatum(item);
d[ptr - ARRPTR(hs)] = PointerGetDatum(item);
ptr++;
}
a = construct_array(
d,
hs->size,
TEXTOID,
-1,
false,
'i'
);
ptr=ARRPTR(hs);
while( ptr-ARRPTR(hs) < hs->size ) {
pfree(DatumGetPointer(d[ ptr-ARRPTR(hs) ]));
a = construct_array(
d,
hs->size,
TEXTOID,
-1,
false,
'i'
);
ptr = ARRPTR(hs);
while (ptr - ARRPTR(hs) < hs->size)
{
pfree(DatumGetPointer(d[ptr - ARRPTR(hs)]));
ptr++;
}
pfree(d);
PG_FREE_IF_COPY(hs,0);
PG_FREE_IF_COPY(hs, 0);
PG_RETURN_POINTER(a);
}
typedef struct {
HStore *hs;
int i;
} AKStore;
typedef struct
{
HStore *hs;
int i;
} AKStore;
static void
setup_firstcall(FuncCallContext *funcctx, HStore *hs) {
MemoryContext oldcontext;
AKStore *st;
setup_firstcall(FuncCallContext *funcctx, HStore * hs)
{
MemoryContext oldcontext;
AKStore *st;
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
st=(AKStore*)palloc( sizeof(AKStore) );
st->i=0;
st->hs = (HStore*)palloc(hs->len);
memcpy( st->hs, hs, hs->len );
st = (AKStore *) palloc(sizeof(AKStore));
st->i = 0;
st->hs = (HStore *) palloc(hs->len);
memcpy(st->hs, hs, hs->len);
funcctx->user_fctx = (void*)st;
funcctx->user_fctx = (void *) st;
MemoryContextSwitchTo(oldcontext);
}
PG_FUNCTION_INFO_V1(skeys);
Datum skeys(PG_FUNCTION_ARGS);
Datum skeys(PG_FUNCTION_ARGS);
Datum
skeys(PG_FUNCTION_ARGS) {
FuncCallContext *funcctx;
AKStore *st;
skeys(PG_FUNCTION_ARGS)
{
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();
setup_firstcall(funcctx, hs);
PG_FREE_IF_COPY(hs,0);
PG_FREE_IF_COPY(hs, 0);
}
funcctx = SRF_PERCALL_SETUP();
st = (AKStore*)funcctx->user_fctx;
if ( st->i < st->hs->size ) {
HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
text *item=(text*)palloc(VARHDRSZ + ptr->keylen);
st = (AKStore *) funcctx->user_fctx;
VARATT_SIZEP(item) = VARHDRSZ+ptr->keylen;
if (st->i < st->hs->size)
{
HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
text *item = (text *) palloc(VARHDRSZ + ptr->keylen);
VARATT_SIZEP(item) = VARHDRSZ + ptr->keylen;
memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos, ptr->keylen);
st->i++;
SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
}
pfree( st->hs );
pfree( st );
SRF_RETURN_DONE(funcctx);
pfree(st->hs);
pfree(st);
SRF_RETURN_DONE(funcctx);
}
PG_FUNCTION_INFO_V1(svals);
Datum svals(PG_FUNCTION_ARGS);
Datum svals(PG_FUNCTION_ARGS);
Datum
svals(PG_FUNCTION_ARGS) {
FuncCallContext *funcctx;
AKStore *st;
svals(PG_FUNCTION_ARGS)
{
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();
setup_firstcall(funcctx, hs);
PG_FREE_IF_COPY(hs,0);
PG_FREE_IF_COPY(hs, 0);
}
funcctx = SRF_PERCALL_SETUP();
st = (AKStore*)funcctx->user_fctx;
if ( st->i < st->hs->size ) {
HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
st = (AKStore *) funcctx->user_fctx;
if ( ptr->valisnull ) {
ReturnSetInfo *rsi;
if (st->i < st->hs->size)
{
HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
if (ptr->valisnull)
{
ReturnSetInfo *rsi;
st->i++;
(funcctx)->call_cntr++;
rsi = (ReturnSetInfo *) fcinfo->resultinfo;
rsi->isDone = ExprMultipleResult;
PG_RETURN_NULL();
} else {
int vallen = ptr->vallen;
text *item=(text*)palloc(VARHDRSZ + vallen);
}
else
{
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);
st->i++;
SRF_RETURN_NEXT(funcctx, PointerGetDatum(item));
}
}
pfree( st->hs );
pfree( st );
SRF_RETURN_DONE(funcctx);
pfree(st->hs);
pfree(st);
SRF_RETURN_DONE(funcctx);
}
PG_FUNCTION_INFO_V1(hs_contains);
Datum hs_contains(PG_FUNCTION_ARGS);
Datum hs_contains(PG_FUNCTION_ARGS);
Datum
hs_contains(PG_FUNCTION_ARGS) {
HStore *val = PG_GETARG_HS(0);
HStore *tmpl = PG_GETARG_HS(1);
bool res = true;
HEntry *te = ARRPTR(tmpl);
char *vv = STRPTR(val);
char *tv = STRPTR(tmpl);
hs_contains(PG_FUNCTION_ARGS)
{
HStore *val = PG_GETARG_HS(0);
HStore *tmpl = PG_GETARG_HS(1);
bool res = true;
HEntry *te = ARRPTR(tmpl);
char *vv = STRPTR(val);
char *tv = STRPTR(tmpl);
while(res && te-ARRPTR(tmpl) < tmpl->size) {
HEntry *entry = findkey(val, tv + te->pos, te->keylen);
if ( entry ) {
if ( ! te->valisnull ) {
if ( entry->valisnull || !(
te->vallen==entry->vallen &&
strncmp(
vv + entry->pos + entry->keylen,
tv + te->pos + te->keylen,
te->vallen ) == 0
) )
res=false;
while (res && te - ARRPTR(tmpl) < tmpl->size)
{
HEntry *entry = findkey(val, tv + te->pos, te->keylen);
if (entry)
{
if (!te->valisnull)
{
if (entry->valisnull || !(
te->vallen == entry->vallen &&
strncmp(
vv + entry->pos + entry->keylen,
tv + te->pos + te->keylen,
te->vallen) == 0
))
res = false;
}
} else
}
else
res = false;
te++;
}
PG_FREE_IF_COPY(val,0);
PG_FREE_IF_COPY(tmpl,1);
PG_FREE_IF_COPY(val, 0);
PG_FREE_IF_COPY(tmpl, 1);
PG_RETURN_BOOL(res);
}
PG_FUNCTION_INFO_V1(hs_contained);
Datum hs_contained(PG_FUNCTION_ARGS);
Datum hs_contained(PG_FUNCTION_ARGS);
Datum
hs_contained(PG_FUNCTION_ARGS) {
PG_RETURN_DATUM( DirectFunctionCall2(
hs_contains,
PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0)
));
hs_contained(PG_FUNCTION_ARGS)
{
PG_RETURN_DATUM(DirectFunctionCall2(
hs_contains,
PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0)
));
}
PG_FUNCTION_INFO_V1(each);
Datum each(PG_FUNCTION_ARGS);
Datum each(PG_FUNCTION_ARGS);
Datum
each(PG_FUNCTION_ARGS) {
FuncCallContext *funcctx;
AKStore *st;
each(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
AKStore *st;
if (SRF_IS_FIRSTCALL()) {
TupleDesc tupdesc;
MemoryContext oldcontext;
HStore *hs = PG_GETARG_HS(0);
if (SRF_IS_FIRSTCALL())
{
TupleDesc tupdesc;
MemoryContext oldcontext;
HStore *hs = PG_GETARG_HS(0);
funcctx = SRF_FIRSTCALL_INIT();
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
st=(AKStore*)palloc( sizeof(AKStore) );
st->i=0;
st->hs = (HStore*)palloc(hs->len);
memcpy( st->hs, hs, hs->len );
funcctx->user_fctx = (void*)st;
st = (AKStore *) palloc(sizeof(AKStore));
st->i = 0;
st->hs = (HStore *) palloc(hs->len);
memcpy(st->hs, hs, hs->len);
funcctx->user_fctx = (void *) st;
tupdesc = RelationNameGetTupleDesc("hs_each");
funcctx->slot = TupleDescGetSlot(tupdesc);
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
MemoryContextSwitchTo(oldcontext);
PG_FREE_IF_COPY(hs,0);
PG_FREE_IF_COPY(hs, 0);
}
funcctx = SRF_PERCALL_SETUP();
st = (AKStore*)funcctx->user_fctx;
if ( st->i < st->hs->size ) {
HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
Datum res, dvalues[2];
char nulls[] = {' ', ' '};
text *item;
HeapTuple tuple;
st = (AKStore *) funcctx->user_fctx;
item=(text*)palloc(VARHDRSZ + ptr->keylen);
VARATT_SIZEP(item) = VARHDRSZ+ptr->keylen;
if (st->i < st->hs->size)
{
HEntry *ptr = &(ARRPTR(st->hs)[st->i]);
Datum res,
dvalues[2];
char nulls[] = {' ', ' '};
text *item;
HeapTuple tuple;
item = (text *) palloc(VARHDRSZ + ptr->keylen);
VARATT_SIZEP(item) = VARHDRSZ + ptr->keylen;
memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos, ptr->keylen);
dvalues[0] = PointerGetDatum(item);
if ( ptr->valisnull ) {
dvalues[1]=(Datum)0;
nulls[1]='n';
} else {
int vallen = ptr->vallen;
if (ptr->valisnull)
{
dvalues[1] = (Datum) 0;
nulls[1] = 'n';
}
else
{
int vallen = ptr->vallen;
item=(text*)palloc(VARHDRSZ + vallen);
VARATT_SIZEP(item) = VARHDRSZ+vallen;
item = (text *) palloc(VARHDRSZ + vallen);
VARATT_SIZEP(item) = VARHDRSZ + vallen;
memcpy(VARDATA(item), STRPTR(st->hs) + ptr->pos + ptr->keylen, vallen);
dvalues[1] = PointerGetDatum(item);
}
@ -551,17 +616,15 @@ each(PG_FUNCTION_ARGS) {
tuple = heap_formtuple(funcctx->attinmeta->tupdesc, dvalues, nulls);
res = TupleGetDatum(funcctx->slot, tuple);
pfree( DatumGetPointer(dvalues[0]) );
if ( nulls[1] != 'n' )
pfree( DatumGetPointer(dvalues[1]) );
pfree(DatumGetPointer(dvalues[0]));
if (nulls[1] != 'n')
pfree(DatumGetPointer(dvalues[1]));
SRF_RETURN_NEXT(funcctx, PointerGetDatum(res));
}
pfree( st->hs );
pfree( st );
SRF_RETURN_DONE(funcctx);
pfree(st->hs);
pfree(st);
SRF_RETURN_DONE(funcctx);
}

View File

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

View File

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

View File

@ -1,102 +1,118 @@
#include "_int.h"
PG_FUNCTION_INFO_V1(ginint4_queryextract);
Datum ginint4_queryextract(PG_FUNCTION_ARGS);
Datum ginint4_queryextract(PG_FUNCTION_ARGS);
Datum
ginint4_queryextract(PG_FUNCTION_ARGS) {
uint32 *nentries = (uint32*)PG_GETARG_POINTER(1);
StrategyNumber strategy = PG_GETARG_UINT16(2);
Datum *res = NULL;
ginint4_queryextract(PG_FUNCTION_ARGS)
{
uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
StrategyNumber strategy = PG_GETARG_UINT16(2);
Datum *res = NULL;
*nentries = 0;
if ( strategy == BooleanSearchStrategy ) {
QUERYTYPE *query = (QUERYTYPE*)PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0));
ITEM *items = GETQUERY(query);
int i;
if (strategy == BooleanSearchStrategy)
{
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_POINTER(0));
ITEM *items = GETQUERY(query);
int i;
if (query->size == 0)
PG_RETURN_POINTER(NULL);
if ( shorterquery(items, query->size) == 0 )
elog(ERROR,"Query requires full scan, GIN doesn't support it");
if (shorterquery(items, query->size) == 0)
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);
res = (Datum*)palloc(sizeof(Datum) * query->size);
res = (Datum *) palloc(sizeof(Datum) * query->size);
*nentries = 0;
for(i=0;i<query->size;i++)
if ( items[i].type == VAL ) {
res[*nentries] = Int32GetDatum( items[i].val );
for (i = 0; i < query->size; i++)
if (items[i].type == VAL)
{
res[*nentries] = Int32GetDatum(items[i].val);
(*nentries)++;
}
} else {
ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
int4 *arr;
uint32 i;
}
else
{
ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
int4 *arr;
uint32 i;
CHECKARRVALID(query);
*nentries=ARRNELEMS(query);
if ( *nentries > 0 ) {
res = (Datum*)palloc(sizeof(Datum) * (*nentries));
*nentries = ARRNELEMS(query);
if (*nentries > 0)
{
res = (Datum *) palloc(sizeof(Datum) * (*nentries));
arr=ARRPTR(query);
for(i=0;i<*nentries;i++)
res[i] = Int32GetDatum( arr[i] );
arr = ARRPTR(query);
for (i = 0; i < *nentries; i++)
res[i] = Int32GetDatum(arr[i]);
}
}
PG_RETURN_POINTER( res );
PG_RETURN_POINTER(res);
}
PG_FUNCTION_INFO_V1(ginint4_consistent);
Datum ginint4_consistent(PG_FUNCTION_ARGS);
Datum ginint4_consistent(PG_FUNCTION_ARGS);
Datum
ginint4_consistent(PG_FUNCTION_ARGS) {
bool *check = (bool*)PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1);
int res=FALSE;
ginint4_consistent(PG_FUNCTION_ARGS)
{
bool *check = (bool *) PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1);
int res = FALSE;
/* we can do not check array carefully, it's done by previous ginarrayextract call */
/*
* we can do not check array carefully, it's done by previous
* ginarrayextract call
*/
switch( strategy ) {
case RTOverlapStrategyNumber:
case RTContainedByStrategyNumber:
case RTOldContainedByStrategyNumber:
/* at least one element in check[] is true, so result = true */
switch (strategy)
{
case RTOverlapStrategyNumber:
case RTContainedByStrategyNumber:
case RTOldContainedByStrategyNumber:
/* at least one element in check[] is true, so result = 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);
res = TRUE;
break;
default:
elog(ERROR, "ginint4_consistent: unknown strategy number: %d", strategy);
}
case RTSameStrategyNumber:
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);
bool retval;
if (strategy == BooleanSearchStrategy) {
if (strategy == BooleanSearchStrategy)
{
retval = execconsistent((QUERYTYPE *) query,
(ArrayType *) DatumGetPointer(entry->key),
GIST_LEAF(entry));
(ArrayType *) DatumGetPointer(entry->key),
GIST_LEAF(entry));
pfree( query );
pfree(query);
PG_RETURN_BOOL(retval);
}
/* sort query for fast search, key is already sorted */
CHECKARRVALID(query);
if (ARRISVOID(query)) {
pfree( query );
if (ARRISVOID(query))
{
pfree(query);
PG_RETURN_BOOL(false);
}
PREPAREARR(query);
@ -88,7 +90,7 @@ g_int_consistent(PG_FUNCTION_ARGS)
default:
retval = FALSE;
}
pfree( query );
pfree(query);
PG_RETURN_BOOL(retval);
}
@ -156,7 +158,7 @@ g_int_compress(PG_FUNCTION_ARGS)
retval = palloc(sizeof(GISTENTRY));
gistentryinit(*retval, PointerGetDatum(r),
entry->rel, entry->page, entry->offset, FALSE);
entry->rel, entry->page, entry->offset, FALSE);
PG_RETURN_POINTER(retval);
}
@ -203,7 +205,7 @@ g_int_compress(PG_FUNCTION_ARGS)
r = resize_intArrayType(r, len);
retval = palloc(sizeof(GISTENTRY));
gistentryinit(*retval, PointerGetDatum(r),
entry->rel, entry->page, entry->offset, FALSE);
entry->rel, entry->page, entry->offset, FALSE);
PG_RETURN_POINTER(retval);
}
else
@ -240,7 +242,7 @@ g_int_decompress(PG_FUNCTION_ARGS)
{
retval = palloc(sizeof(GISTENTRY));
gistentryinit(*retval, PointerGetDatum(in),
entry->rel, entry->page, entry->offset, FALSE);
entry->rel, entry->page, entry->offset, FALSE);
PG_RETURN_POINTER(retval);
}
@ -331,7 +333,7 @@ typedef struct
{
OffsetNumber pos;
float cost;
} SPLITCOST;
} SPLITCOST;
static int
comparecost(const void *a, const void *b)

View File

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

View File

@ -214,7 +214,7 @@ sizebitvec(BITVECP sign)
i;
LOOPBYTE(
size += number_of_ones[(unsigned char) sign[i]];
size += number_of_ones[(unsigned char) sign[i]];
);
return size;
}
@ -227,8 +227,8 @@ hemdistsign(BITVECP a, BITVECP b)
dist = 0;
LOOPBYTE(
diff = (unsigned char) (a[i] ^ b[i]);
dist += number_of_ones[diff];
diff = (unsigned char) (a[i] ^ b[i]);
dist += number_of_ones[diff];
);
return dist;
}
@ -318,7 +318,7 @@ typedef struct
{
OffsetNumber pos;
int4 cost;
} SPLITCOST;
} SPLITCOST;
static int
comparecost(const void *a, const void *b)
@ -506,16 +506,17 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
if (strategy == BooleanSearchStrategy)
{
retval =signconsistent((QUERYTYPE *) query,
GETSIGN(DatumGetPointer(entry->key)),
false);
PG_FREE_IF_COPY( query, 1 );
retval = signconsistent((QUERYTYPE *) query,
GETSIGN(DatumGetPointer(entry->key)),
false);
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(retval);
}
CHECKARRVALID(query);
if (ARRISVOID(query)) {
PG_FREE_IF_COPY( query, 1 );
if (ARRISVOID(query))
{
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(FALSE);
}
@ -602,6 +603,6 @@ g_intbig_consistent(PG_FUNCTION_ARGS)
default:
retval = FALSE;
}
PG_FREE_IF_COPY( query, 1 );
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(retval);
}

View File

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

View File

@ -1,4 +1,4 @@
/*
/*
* ISBN.h
* PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC)
*
@ -7,39 +7,39 @@
* http://www.isbn.org/
*
* IDENTIFICATION
* $PostgreSQL: pgsql/contrib/isn/ISBN.h,v 1.1 2006/09/09 04:07:52 tgl Exp $
* $PostgreSQL: pgsql/contrib/isn/ISBN.h,v 1.2 2006/10/04 00:29:45 momjian Exp $
*
* 0-393-04002-X => 039304002(X) <=> 039304002 <=> (978)039304002 <=> 978039304002(9) <=> 978-0-393-04002-9
*
*
* ISBN 0 3 9 3 0 4 0 0 2
* Weight 10 9 8 7 6 5 4 3 2
* Product 0 + 27 + 72 + 21 + 0 + 20 + 0 + 0 + 4 = 144
* 144 / 11 = 13 remainder 1
* Check digit 11 - 1 = 10 = X
* ISBN 0 3 9 3 0 4 0 0 2
* Weight 10 9 8 7 6 5 4 3 2
* Product 0 + 27 + 72 + 21 + 0 + 20 + 0 + 0 + 4 = 144
* 144 / 11 = 13 remainder 1
* Check digit 11 - 1 = 10 = X
* => 0-393-04002-X
*
* 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
* Product 9 + 21 + 8 + 0 + 3 + 27 + 3 + 0 + 4 + 0 + 0 + 6 = 81
* 81 / 10 = 8 remainder 1
* Check digit 10 - 1 = 9
* 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
* Product 9 + 21 + 8 + 0 + 3 + 27 + 3 + 0 + 4 + 0 + 0 + 6 = 81
* 81 / 10 = 8 remainder 1
* Check digit 10 - 1 = 9
* => 978-0-393-04002-9
*
*/
/* where the digit set begins, and how many of them are in the table */
const unsigned ISBN_index[10][2] = {
{0, 6},
{6, 6},
{12, 8},
{20, 10},
{30, 6},
{36, 12},
{48, 0},
{48, 5},
{53, 59},
{112, 573},
{0, 6},
{6, 6},
{12, 8},
{20, 10},
{30, 6},
{36, 12},
{48, 0},
{48, 5},
{53, 59},
{112, 573},
};
const char *ISBN_range[][2] = {

View File

@ -1,4 +1,4 @@
/*
/*
* ISMN.h
* PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC)
*
@ -6,23 +6,23 @@
* http://www.ismn-international.org
*
* IDENTIFICATION
* $PostgreSQL: pgsql/contrib/isn/ISMN.h,v 1.1 2006/09/09 04:07:52 tgl Exp $
* $PostgreSQL: pgsql/contrib/isn/ISMN.h,v 1.2 2006/10/04 00:29:45 momjian Exp $
*
* M-3452-4680-5 <=> (0)-3452-4680-5 <=> 0345246805 <=> 9790345246805 <=> 979-0-3452-4680-5
*
* (M counts as 3)
* ISMN M 3 4 5 2 4 6 8 0
* Weight 3 1 3 1 3 1 3 1 3
* Product 9 + 3 + 12 + 5 + 6 + 4 + 18 + 8 + 0 = 65
* 65 / 10 = 6 remainder 5
* Check digit 10 - 5 = 5
* (M counts as 3)
* ISMN M 3 4 5 2 4 6 8 0
* Weight 3 1 3 1 3 1 3 1 3
* Product 9 + 3 + 12 + 5 + 6 + 4 + 18 + 8 + 0 = 65
* 65 / 10 = 6 remainder 5
* Check digit 10 - 5 = 5
* => M-3452-4680-5
*
* 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
* Product 9 + 21 + 9 + 0 + 3 + 12 + 5 + 6 + 4 + 18 + 8 + 0 = 95
* 95 / 10 = 9 remainder 5
* Check digit 10 - 5 = 5
* 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
* Product 9 + 21 + 9 + 0 + 3 + 12 + 5 + 6 + 4 + 18 + 8 + 0 = 95
* 95 / 10 = 9 remainder 5
* Check digit 10 - 5 = 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.
@ -31,16 +31,16 @@
/* where the digit set begins, and how many of them are in the table */
const unsigned ISMN_index[10][2] = {
{0, 5},
{5, 0},
{5, 0},
{5, 0},
{5, 0},
{5, 0},
{5, 0},
{5, 0},
{5, 0},
{5, 0},
{0, 5},
{5, 0},
{5, 0},
{5, 0},
{5, 0},
{5, 0},
{5, 0},
{5, 0},
{5, 0},
{5, 0},
};
const char *ISMN_range[][2] = {
{"0-000", "0-099"},

View File

@ -1,4 +1,4 @@
/*
/*
* ISSN.h
* PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC)
*
@ -6,25 +6,25 @@
* http://www.issn.org/
*
* IDENTIFICATION
* $PostgreSQL: pgsql/contrib/isn/ISSN.h,v 1.1 2006/09/09 04:07:52 tgl Exp $
* $PostgreSQL: pgsql/contrib/isn/ISSN.h,v 1.2 2006/10/04 00:29:45 momjian Exp $
*
* 1144-875X <=> 1144875(X) <=> 1144875 <=> (977)1144875 <=> 9771144875(00) <=> 977114487500(7) <=> 977-1144-875-00-7
*
*
* ISSN 1 1 4 4 8 7 5
* Weight 8 7 6 5 4 3 2
* Product 8 + 7 + 24 + 20 + 32 + 21 + 10 = 122
* 122 / 11 = 11 remainder 1
* Check digit 11 - 1 = 10 = X
*
* ISSN 1 1 4 4 8 7 5
* Weight 8 7 6 5 4 3 2
* Product 8 + 7 + 24 + 20 + 32 + 21 + 10 = 122
* 122 / 11 = 11 remainder 1
* Check digit 11 - 1 = 10 = X
* => 1144-875X
*
* 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
* Product 9 + 21 + 7 + 3 + 1 + 12 + 4 + 24 + 7 + 15 + 0 + 0 = 103
* 103 / 10 = 10 remainder 3
* Check digit 10 - 3 = 7
*
* 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
* Product 9 + 21 + 7 + 3 + 1 + 12 + 4 + 24 + 7 + 15 + 0 + 0 = 103
* 103 / 10 = 10 remainder 3
* Check digit 10 - 3 = 7
* => 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.
*
@ -32,16 +32,16 @@
/* where the digit set begins, and how many of them are in the table */
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] = {
{"0000-000", "9999-999"},

View File

@ -1,27 +1,27 @@
/*
/*
* ISSN.h
* PostgreSQL type definitions for ISNs (ISBN, ISMN, ISSN, EAN13, UPC)
*
* No information available for UPC prefixes
*
*
*
* 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 */
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] = {
{NULL, NULL}

File diff suppressed because it is too large Load Diff

View File

@ -219,7 +219,7 @@ sizebitvec(BITVECP sign)
i;
ALOOPBYTE(
size += number_of_ones[(unsigned char) sign[i]];
size += number_of_ones[(unsigned char) sign[i]];
);
return size;
}
@ -232,8 +232,8 @@ hemdistsign(BITVECP a, BITVECP b)
dist = 0;
ALOOPBYTE(
diff = (unsigned char) (a[i] ^ b[i]);
dist += number_of_ones[diff];
diff = (unsigned char) (a[i] ^ b[i]);
dist += number_of_ones[diff];
);
return dist;
}
@ -270,7 +270,7 @@ typedef struct
{
OffsetNumber pos;
int4 cost;
} SPLITCOST;
} SPLITCOST;
static int
comparecost(const void *a, const void *b)
@ -580,6 +580,6 @@ _ltree_consistent(PG_FUNCTION_ARGS)
/* internal error */
elog(ERROR, "unrecognized StrategyNumber: %d", strategy);
}
PG_FREE_IF_COPY(query,1);
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(res);
}

View File

@ -1,7 +1,7 @@
/*
* op function for ltree and lquery
* Teodor Sigaev <teodor@stack.net>
* $PostgreSQL: pgsql/contrib/ltree/lquery_op.c,v 1.10 2006/03/11 04:38:29 momjian Exp $
* $PostgreSQL: pgsql/contrib/ltree/lquery_op.c,v 1.11 2006/10/04 00:29:45 momjian Exp $
*/
#include "ltree.h"
@ -46,7 +46,7 @@ getlexeme(char *start, char *end, int *len)
}
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 *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__
#define __LTREE_H__
@ -163,7 +163,7 @@ bool compare_subnode(ltree_level * t, char *q, 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_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_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))))

View File

@ -1,7 +1,7 @@
/*
* GiST support for ltree
* Teodor Sigaev <teodor@stack.net>
* $PostgreSQL: pgsql/contrib/ltree/ltree_gist.c,v 1.18 2006/08/08 15:45:18 teodor Exp $
* $PostgreSQL: pgsql/contrib/ltree/ltree_gist.c,v 1.19 2006/10/04 00:29:45 momjian Exp $
*/
#include "ltree.h"
@ -457,8 +457,10 @@ gist_isparent(ltree_gist * key, ltree * query)
}
static ltree *
copy_ltree( ltree *src ) {
ltree *dst = (ltree*)palloc(src->len);
copy_ltree(ltree * src)
{
ltree *dst = (ltree *) palloc(src->len);
memcpy(dst, src, src->len);
return dst;
}
@ -466,9 +468,9 @@ copy_ltree( ltree *src ) {
static bool
gist_ischild(ltree_gist * key, ltree * query)
{
ltree *left = copy_ltree(LTG_GETLNODE(key));
ltree *right = copy_ltree(LTG_GETRNODE(key));
bool res = true;
ltree *left = copy_ltree(LTG_GETLNODE(key));
ltree *right = copy_ltree(LTG_GETRNODE(key));
bool res = true;
if (left->numlevel > query->numlevel)
left->numlevel = query->numlevel;
@ -711,6 +713,6 @@ ltree_consistent(PG_FUNCTION_ARGS)
elog(ERROR, "unrecognized StrategyNumber: %d", strategy);
}
PG_FREE_IF_COPY(query,1);
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(res);
}

View File

@ -1,7 +1,7 @@
/*
* op function for ltree
* Teodor Sigaev <teodor@stack.net>
* $PostgreSQL: pgsql/contrib/ltree/ltree_op.c,v 1.13 2006/09/20 19:50:21 tgl Exp $
* $PostgreSQL: pgsql/contrib/ltree/ltree_op.c,v 1.14 2006/10/04 00:29:45 momjian Exp $
*/
#include "ltree.h"
@ -620,8 +620,8 @@ ltreeparentsel(PG_FUNCTION_ARGS)
/*
* If the histogram is large enough, see what fraction of it the
* constant is "<@" to, and assume that's representative of the
* non-MCV population. Otherwise use the default selectivity for
* the non-MCV population.
* non-MCV population. Otherwise use the default selectivity for the
* non-MCV population.
*/
selec = histogram_selectivity(&vardata, &contproc,
constval, varonleft,

View File

@ -3,7 +3,7 @@
* pg_buffercache_pages.c
* display some contents of the buffer cache
*
* $PostgreSQL: pgsql/contrib/pg_buffercache/pg_buffercache_pages.c,v 1.8 2006/07/23 03:07:57 tgl Exp $
* $PostgreSQL: pgsql/contrib/pg_buffercache/pg_buffercache_pages.c,v 1.9 2006/10/04 00:29:45 momjian Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@ -74,7 +74,7 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
if (SRF_IS_FIRSTCALL())
{
int i;
int i;
volatile BufferDesc *bufHdr;
funcctx = SRF_FIRSTCALL_INIT();
@ -123,9 +123,9 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldcontext);
/*
* To get a consistent picture of the buffer state, we must lock
* all partitions of the buffer map. Needless to say, this is
* horrible for concurrency...
* To get a consistent picture of the buffer state, we must lock all
* partitions of the buffer map. Needless to say, this is horrible
* for concurrency...
*/
for (i = 0; i < NUM_BUFFER_PARTITIONS; i++)
LWLockAcquire(FirstBufMappingLock + i, LW_SHARED);

View File

@ -3,7 +3,7 @@
* pg_freespacemap.c
* display some contents of the free space relation and page maps.
*
* $PostgreSQL: pgsql/contrib/pg_freespacemap/pg_freespacemap.c,v 1.7 2006/09/21 20:31:21 tgl Exp $
* $PostgreSQL: pgsql/contrib/pg_freespacemap/pg_freespacemap.c,v 1.8 2006/10/04 00:29:45 momjian Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@ -14,13 +14,13 @@
#include "storage/freespace.h"
#define NUM_FREESPACE_PAGES_ELEM 5
#define NUM_FREESPACE_RELATIONS_ELEM 7
#define NUM_FREESPACE_PAGES_ELEM 5
#define NUM_FREESPACE_RELATIONS_ELEM 7
#if defined(WIN32) || defined(__CYGWIN__)
/* Need DLLIMPORT for some things that are not so marked in main headers */
extern DLLIMPORT int MaxFSMPages;
extern DLLIMPORT int MaxFSMRelations;
extern DLLIMPORT int MaxFSMPages;
extern DLLIMPORT int MaxFSMRelations;
extern DLLIMPORT volatile uint32 InterruptHoldoffCount;
#endif
@ -35,12 +35,12 @@ Datum pg_freespacemap_relations(PG_FUNCTION_ARGS);
*/
typedef struct
{
Oid reltablespace;
Oid reldatabase;
Oid relfilenode;
BlockNumber relblocknumber;
Size bytes;
bool isindex;
Oid reltablespace;
Oid reldatabase;
Oid relfilenode;
BlockNumber relblocknumber;
Size bytes;
bool isindex;
} FreeSpacePagesRec;
@ -49,14 +49,14 @@ typedef struct
*/
typedef struct
{
Oid reltablespace;
Oid reldatabase;
Oid relfilenode;
Size avgrequest;
BlockNumber interestingpages;
int storedpages;
int nextpage;
bool isindex;
Oid reltablespace;
Oid reldatabase;
Oid relfilenode;
Size avgrequest;
BlockNumber interestingpages;
int storedpages;
int nextpage;
bool isindex;
} FreeSpaceRelationsRec;
@ -66,8 +66,8 @@ typedef struct
*/
typedef struct
{
TupleDesc tupdesc;
FreeSpacePagesRec *record;
TupleDesc tupdesc;
FreeSpacePagesRec *record;
} FreeSpacePagesContext;
@ -76,8 +76,8 @@ typedef struct
*/
typedef struct
{
TupleDesc tupdesc;
FreeSpaceRelationsRec *record;
TupleDesc tupdesc;
FreeSpaceRelationsRec *record;
} FreeSpaceRelationsContext;
@ -89,21 +89,21 @@ PG_FUNCTION_INFO_V1(pg_freespacemap_pages);
Datum
pg_freespacemap_pages(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
Datum result;
MemoryContext oldcontext;
FreeSpacePagesContext *fctx; /* User function context. */
TupleDesc tupledesc;
HeapTuple tuple;
FSMHeader *FreeSpaceMap; /* FSM main structure. */
FSMRelation *fsmrel; /* Individual relation. */
FuncCallContext *funcctx;
Datum result;
MemoryContext oldcontext;
FreeSpacePagesContext *fctx; /* User function context. */
TupleDesc tupledesc;
HeapTuple tuple;
FSMHeader *FreeSpaceMap; /* FSM main structure. */
FSMRelation *fsmrel; /* Individual relation. */
if (SRF_IS_FIRSTCALL())
{
int i;
int numPages; /* Max possible no. of pages in map. */
int nPages; /* Mapped pages for a relation. */
int i;
int numPages; /* Max possible no. of pages in map. */
int nPages; /* Mapped pages for a relation. */
/*
* Get the free space map data structure.
*/
@ -138,8 +138,8 @@ pg_freespacemap_pages(PG_FUNCTION_ARGS)
fctx->tupdesc = BlessTupleDesc(tupledesc);
/*
* Allocate numPages worth of FreeSpacePagesRec records, this is
* an upper bound.
* Allocate numPages worth of FreeSpacePagesRec records, this is an
* upper bound.
*/
fctx->record = (FreeSpacePagesRec *) palloc(sizeof(FreeSpacePagesRec) * numPages);
@ -147,16 +147,16 @@ pg_freespacemap_pages(PG_FUNCTION_ARGS)
MemoryContextSwitchTo(oldcontext);
/*
* Lock free space map and scan though all the relations.
* For each relation, gets all its mapped pages.
* Lock free space map and scan though all the relations. For each
* relation, gets all its mapped pages.
*/
LWLockAcquire(FreeSpaceLock, LW_EXCLUSIVE);
i = 0;
for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = fsmrel->nextUsage)
for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = fsmrel->nextUsage)
{
if (fsmrel->isIndex)
if (fsmrel->isIndex)
{
/* Index relation. */
IndexFSMPageData *page;
@ -169,9 +169,9 @@ pg_freespacemap_pages(PG_FUNCTION_ARGS)
fctx->record[i].reltablespace = fsmrel->key.spcNode;
fctx->record[i].reldatabase = fsmrel->key.dbNode;
fctx->record[i].relfilenode = fsmrel->key.relNode;
fctx->record[i].relblocknumber = IndexFSMPageGetPageNum(page);
fctx->record[i].bytes = 0;
fctx->record[i].isindex = true;
fctx->record[i].relblocknumber = IndexFSMPageGetPageNum(page);
fctx->record[i].bytes = 0;
fctx->record[i].isindex = true;
page++;
i++;
@ -191,9 +191,9 @@ pg_freespacemap_pages(PG_FUNCTION_ARGS)
fctx->record[i].reldatabase = fsmrel->key.dbNode;
fctx->record[i].relfilenode = fsmrel->key.relNode;
fctx->record[i].relblocknumber = FSMPageGetPageNum(page);
fctx->record[i].bytes = FSMPageGetSpace(page);
fctx->record[i].isindex = false;
fctx->record[i].bytes = FSMPageGetSpace(page);
fctx->record[i].isindex = false;
page++;
i++;
}
@ -216,7 +216,7 @@ pg_freespacemap_pages(PG_FUNCTION_ARGS)
if (funcctx->call_cntr < funcctx->max_calls)
{
int i = funcctx->call_cntr;
FreeSpacePagesRec *record = &fctx->record[i];
FreeSpacePagesRec *record = &fctx->record[i];
Datum values[NUM_FREESPACE_PAGES_ELEM];
bool nulls[NUM_FREESPACE_PAGES_ELEM];
@ -261,20 +261,20 @@ PG_FUNCTION_INFO_V1(pg_freespacemap_relations);
Datum
pg_freespacemap_relations(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx;
Datum result;
MemoryContext oldcontext;
FreeSpaceRelationsContext *fctx; /* User function context. */
TupleDesc tupledesc;
HeapTuple tuple;
FSMHeader *FreeSpaceMap; /* FSM main structure. */
FSMRelation *fsmrel; /* Individual relation. */
FuncCallContext *funcctx;
Datum result;
MemoryContext oldcontext;
FreeSpaceRelationsContext *fctx; /* User function context. */
TupleDesc tupledesc;
HeapTuple tuple;
FSMHeader *FreeSpaceMap; /* FSM main structure. */
FSMRelation *fsmrel; /* Individual relation. */
if (SRF_IS_FIRSTCALL())
{
int i;
int numRelations; /* Max no. of Relations in map. */
int i;
int numRelations; /* Max no. of Relations in map. */
/*
* Get the free space map data structure.
*/
@ -313,8 +313,8 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
fctx->tupdesc = BlessTupleDesc(tupledesc);
/*
* Allocate numRelations worth of FreeSpaceRelationsRec records,
* this is also an upper bound.
* Allocate numRelations worth of FreeSpaceRelationsRec records, this
* is also an upper bound.
*/
fctx->record = (FreeSpaceRelationsRec *) palloc(sizeof(FreeSpaceRelationsRec) * numRelations);
@ -328,12 +328,12 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
i = 0;
for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = fsmrel->nextUsage)
for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = fsmrel->nextUsage)
{
fctx->record[i].reltablespace = fsmrel->key.spcNode;
fctx->record[i].reldatabase = fsmrel->key.dbNode;
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].storedpages = fsmrel->storedPages;
fctx->record[i].nextpage = fsmrel->nextPage;
@ -358,7 +358,7 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
if (funcctx->call_cntr < funcctx->max_calls)
{
int i = funcctx->call_cntr;
FreeSpaceRelationsRec *record = &fctx->record[i];
FreeSpaceRelationsRec *record = &fctx->record[i];
Datum values[NUM_FREESPACE_RELATIONS_ELEM];
bool nulls[NUM_FREESPACE_RELATIONS_ELEM];
@ -368,6 +368,7 @@ pg_freespacemap_relations(PG_FUNCTION_ARGS)
nulls[1] = false;
values[2] = ObjectIdGetDatum(record->relfilenode);
nulls[2] = false;
/*
* avgrequest isn't meaningful for an index
*/

View File

@ -307,7 +307,7 @@ sizebitvec(BITVECP sign)
i;
LOOPBYTE(
size += number_of_ones[(unsigned char) sign[i]];
size += number_of_ones[(unsigned char) sign[i]];
);
return size;
}
@ -320,8 +320,8 @@ hemdistsign(BITVECP a, BITVECP b)
dist = 0;
LOOPBYTE(
diff = (unsigned char) (a[i] ^ b[i]);
dist += number_of_ones[diff];
diff = (unsigned char) (a[i] ^ b[i]);
dist += number_of_ones[diff];
);
return dist;
}
@ -393,7 +393,7 @@ typedef struct
{
OffsetNumber pos;
int4 cost;
} SPLITCOST;
} SPLITCOST;
static int
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
* written by Tatsuo Ishii
@ -136,7 +136,7 @@ int num_files; /* its number */
static char *tpc_b = {
"\\set nbranches :scale\n"
"\\set ntellers 10 * :scale\n"
"\\set naccounts 100000 * :scale\n"
"\\set naccounts 100000 * :scale\n"
"\\setrandom aid 1 :naccounts\n"
"\\setrandom bid 1 :nbranches\n"
"\\setrandom tid 1 :ntellers\n"
@ -154,7 +154,7 @@ static char *tpc_b = {
static char *simple_update = {
"\\set nbranches :scale\n"
"\\set ntellers 10 * :scale\n"
"\\set naccounts 100000 * :scale\n"
"\\set naccounts 100000 * :scale\n"
"\\setrandom aid 1 :naccounts\n"
"\\setrandom bid 1 :nbranches\n"
"\\setrandom tid 1 :ntellers\n"
@ -168,7 +168,7 @@ static char *simple_update = {
/* -S case */
static char *select_only = {
"\\set naccounts 100000 * :scale\n"
"\\set naccounts 100000 * :scale\n"
"\\setrandom aid 1 :naccounts\n"
"SELECT abalance FROM accounts WHERE aid = :aid;\n"
};
@ -338,7 +338,7 @@ putVariable(CState * st, char *name, char *value)
}
else
{
char *val;
char *val;
if ((val = strdup(value)) == NULL)
return false;
@ -1009,14 +1009,16 @@ process_file(char *filename)
while (isspace((unsigned char) buf[i]))
i++;
if (buf[i] != '\0' && strncmp(&buf[i], "--", 2) != 0) {
if (buf[i] != '\0' && strncmp(&buf[i], "--", 2) != 0)
{
commands = process_commands(&buf[i]);
if (commands == NULL)
{
fclose(fd);
return false;
}
} else
}
else
continue;
my_commands[lineno] = commands;
@ -1530,7 +1532,7 @@ main(int argc, char **argv)
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);
remains--; /* I've aborted */
remains--; /* I've aborted */
PQfinish(state[i].con);
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)
{
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);
state[i].con = NULL;
}

View File

@ -2,7 +2,7 @@
* Written by Solar Designer and placed in the public domain.
* See crypt_blowfish.c for more information.
*
* $PostgreSQL: pgsql/contrib/pgcrypto/crypt-gensalt.c,v 1.9 2006/07/13 04:15:24 neilc Exp $
* $PostgreSQL: pgsql/contrib/pgcrypto/crypt-gensalt.c,v 1.10 2006/10/04 00:29:46 momjian Exp $
*
* This file contains salt generation functions for the traditional and
* other common crypt(3) algorithms, except for bcrypt which is defined
@ -64,9 +64,9 @@ _crypt_gensalt_extended_rn(unsigned long count,
output[2] = _crypt_itoa64[(count >> 6) & 0x3f];
output[3] = _crypt_itoa64[(count >> 12) & 0x3f];
output[4] = _crypt_itoa64[(count >> 18) & 0x3f];
value = (unsigned long)(unsigned char) input[0] |
((unsigned long)(unsigned char) input[1] << 8) |
((unsigned long)(unsigned char) input[2] << 16);
value = (unsigned long) (unsigned char) input[0] |
((unsigned long) (unsigned char) input[1] << 8) |
((unsigned long) (unsigned char) input[2] << 16);
output[5] = _crypt_itoa64[value & 0x3f];
output[6] = _crypt_itoa64[(value >> 6) & 0x3f];
output[7] = _crypt_itoa64[(value >> 12) & 0x3f];
@ -92,9 +92,9 @@ _crypt_gensalt_md5_rn(unsigned long count,
output[0] = '$';
output[1] = '1';
output[2] = '$';
value = (unsigned long)(unsigned char) input[0] |
((unsigned long)(unsigned char) input[1] << 8) |
((unsigned long)(unsigned char) input[2] << 16);
value = (unsigned long) (unsigned char) input[0] |
((unsigned long) (unsigned char) input[1] << 8) |
((unsigned long) (unsigned char) input[2] << 16);
output[3] = _crypt_itoa64[value & 0x3f];
output[4] = _crypt_itoa64[(value >> 6) & 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)
{
value = (unsigned long)(unsigned char) input[3] |
((unsigned long)(unsigned char) input[4] << 8) |
((unsigned long)(unsigned char) input[5] << 16);
value = (unsigned long) (unsigned char) input[3] |
((unsigned long) (unsigned char) input[4] << 8) |
((unsigned long) (unsigned char) input[5] << 16);
output[7] = _crypt_itoa64[value & 0x3f];
output[8] = _crypt_itoa64[(value >> 6) & 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 $
*
* $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"
@ -24,7 +24,7 @@ static const char _crypt_a64[] =
static void
_crypt_to64(char *s, unsigned long v, int n)
{
while (--n >= 0)
while (--n >= 0)
{
*s++ = _crypt_a64[v & 0x3f];
v >>= 6;

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.c,v 1.7 2006/07/13 04:15:24 neilc Exp $
* $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.c,v 1.8 2006/10/04 00:29:46 momjian Exp $
*/
#include "postgres.h"
@ -365,8 +365,8 @@ rekey(FState * st)
static void
startup_tricks(FState * st)
{
int i;
uint8 buf[BLOCK];
int i;
uint8 buf[BLOCK];
/* Use next block as 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
Purpose: Arbitrary precision integer arithmetic routines.
Author: M. J. Fromberger <http://www.dartmouth.edu/~sting/>
Info: Id: imath.h 21 2006-04-02 18:58:36Z sting
Name: imath.h
Purpose: Arbitrary precision integer arithmetic routines.
Author: M. J. Fromberger <http://www.dartmouth.edu/~sting/>
Info: Id: imath.h 21 2006-04-02 18:58:36Z sting
Copyright (C) 2002 Michael J. Fromberger, All Rights Reserved.
@ -20,13 +20,13 @@
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
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
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/* $PostgreSQL: pgsql/contrib/pgcrypto/imath.h,v 1.4 2006/07/19 17:05:50 neilc Exp $ */
/* $PostgreSQL: pgsql/contrib/pgcrypto/imath.h,v 1.5 2006/10/04 00:29:46 momjian Exp $ */
#ifndef IMATH_H_
#define IMATH_H_
@ -36,32 +36,36 @@
#include <limits.h>
typedef unsigned char mp_sign;
typedef unsigned int mp_size;
typedef int mp_result;
typedef unsigned char mp_sign;
typedef unsigned int mp_size;
typedef int mp_result;
#ifdef USE_LONG_LONG
typedef uint32 mp_digit;
typedef uint64 mp_word;
#define MP_DIGIT_MAX 0xFFFFFFFFULL
#define MP_WORD_MAX 0xFFFFFFFFFFFFFFFFULL
typedef uint32 mp_digit;
typedef uint64 mp_word;
#define MP_DIGIT_MAX 0xFFFFFFFFULL
#define MP_WORD_MAX 0xFFFFFFFFFFFFFFFFULL
#else
typedef uint16 mp_digit;
typedef uint32 mp_word;
#define MP_DIGIT_MAX 0xFFFFUL
#define MP_WORD_MAX 0xFFFFFFFFUL
typedef uint16 mp_digit;
typedef uint32 mp_word;
#define MP_DIGIT_MAX 0xFFFFUL
#define MP_WORD_MAX 0xFFFFFFFFUL
#endif
typedef struct mpz {
mp_digit *digits;
mp_size alloc;
mp_size used;
mp_sign sign;
} mpz_t, *mp_int;
typedef struct mpz
{
mp_digit *digits;
mp_size alloc;
mp_size used;
mp_sign sign;
} mpz_t, *mp_int;
#define MP_DIGITS(Z) ((Z)->digits)
#define MP_ALLOC(Z) ((Z)->alloc)
#define MP_USED(Z) ((Z)->used)
#define MP_SIGN(Z) ((Z)->sign)
#define MP_USED(Z) ((Z)->used)
#define MP_SIGN(Z) ((Z)->sign)
extern const mp_result MP_OK;
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_BADARG;
#define MP_DIGIT_BIT (sizeof(mp_digit) * CHAR_BIT)
#define MP_WORD_BIT (sizeof(mp_word) * CHAR_BIT)
#define MP_DIGIT_BIT (sizeof(mp_digit) * CHAR_BIT)
#define MP_WORD_BIT (sizeof(mp_word) * CHAR_BIT)
#define MP_MIN_RADIX 2
#define MP_MAX_RADIX 36
#define MP_MIN_RADIX 2
#define MP_MAX_RADIX 36
extern const mp_sign MP_NEG;
extern const mp_sign MP_ZPOS;
extern const mp_sign MP_NEG;
extern const mp_sign MP_ZPOS;
#define mp_int_is_odd(Z) ((Z)->digits[0] & 1)
#define mp_int_is_even(Z) !((Z)->digits[0] & 1)
mp_size mp_get_default_precision(void);
void mp_set_default_precision(mp_size s);
mp_size mp_get_multiply_threshold(void);
void mp_set_multiply_threshold(mp_size s);
mp_size mp_get_default_precision(void);
void mp_set_default_precision(mp_size s);
mp_size mp_get_multiply_threshold(void);
void mp_set_multiply_threshold(mp_size s);
mp_result mp_int_init(mp_int z);
mp_int mp_int_alloc(void);
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_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_free(mp_int z);
mp_result mp_int_init(mp_int z);
mp_int mp_int_alloc(void);
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_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_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))
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(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 */
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_zero(mp_int z); /* a <=> 0 */
int mp_int_compare_value(mp_int z, int value); /* a <=> v */
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_zero(mp_int z); /* a <=> 0 */
int mp_int_compare_value(mp_int z, int value); /* a <=> v */
/* 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 */
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_int c); /* c = a^b (mod m) */
mp_result mp_int_exptmod_evalue(mp_int a, int value,
mp_int m, mp_int c); /* c = a^v (mod m) */
mp_result mp_int_exptmod_bvalue(int value, mp_int b,
mp_int m, mp_int c); /* c = v^b (mod m) */
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_exptmod(mp_int a, mp_int b, mp_int m,
mp_int c); /* c = a^b (mod m) */
mp_result
mp_int_exptmod_evalue(mp_int a, int value,
mp_int m, mp_int c); /* c = a^v (mod m) */
mp_result
mp_int_exptmod_bvalue(int value, mp_int b,
mp_int m, mp_int c); /* c = v^b (mod m) */
mp_result
mp_int_exptmod_known(mp_int a, mp_int b,
mp_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_int x, mp_int y); /* c = ax + by */
mp_result
mp_int_egcd(mp_int a, mp_int b, mp_int c, /* c = gcd(a, b) */
mp_int x, mp_int y); /* c = ax + by */
mp_result mp_int_sqrt(mp_int a, mp_int c); /* c = floor(sqrt(q)) */
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). */
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
most limit characters including the nul terminator */
mp_result mp_int_to_string(mp_int z, mp_size radix,
char *str, int limit);
mp_result mp_int_to_string(mp_int z, mp_size radix,
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. */
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 */
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,
char **end);
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,
char **end);
/* 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 */
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 */
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. */
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 */
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 */
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 */
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 */
const char *mp_error_string(mp_result res);
#if 0
void s_print(char *tag, mp_int z);
void s_print_buf(char *tag, mp_digit *buf, mp_size num);
void s_print(char *tag, mp_int z);
void s_print_buf(char *tag, mp_digit * buf, mp_size num);
#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
* 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"
@ -36,10 +36,10 @@
#include "px.h"
#include "sha2.h"
void init_sha224(PX_MD * h);
void init_sha256(PX_MD * h);
void init_sha384(PX_MD * h);
void init_sha512(PX_MD * h);
void init_sha224(PX_MD * h);
void init_sha256(PX_MD * h);
void init_sha384(PX_MD * h);
void init_sha512(PX_MD * h);
/* SHA224 */
@ -314,4 +314,3 @@ init_sha512(PX_MD * md)
md->reset(md);
}

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $PostgreSQL: pgsql/contrib/pgcrypto/internal.c,v 1.24 2006/07/13 04:15:24 neilc Exp $
* $PostgreSQL: pgsql/contrib/pgcrypto/internal.c,v 1.25 2006/10/04 00:29:46 momjian Exp $
*/
#include "postgres.h"
@ -78,10 +78,10 @@
static void init_md5(PX_MD * h);
static void init_sha1(PX_MD * h);
void init_sha224(PX_MD * h);
void init_sha256(PX_MD * h);
void init_sha384(PX_MD * h);
void init_sha512(PX_MD * h);
void init_sha224(PX_MD * h);
void init_sha256(PX_MD * h);
void init_sha384(PX_MD * h);
void init_sha512(PX_MD * h);
struct int_digest
{

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $PostgreSQL: pgsql/contrib/pgcrypto/openssl.c,v 1.29 2006/09/05 23:02:28 tgl Exp $
* $PostgreSQL: pgsql/contrib/pgcrypto/openssl.c,v 1.30 2006/10/04 00:29:46 momjian Exp $
*/
#include "postgres.h"
@ -58,7 +58,6 @@
*/
#include <openssl/aes.h>
#else /* old OPENSSL */
/*
@ -121,29 +120,32 @@
* Emulate newer digest API.
*/
static void EVP_MD_CTX_init(EVP_MD_CTX *ctx)
static void
EVP_MD_CTX_init(EVP_MD_CTX *ctx)
{
memset(ctx, 0, sizeof(*ctx));
}
static int EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx)
static int
EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx)
{
memset(ctx, 0, sizeof(*ctx));
return 1;
}
static int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, void *engine)
static int
EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *md, void *engine)
{
EVP_DigestInit(ctx, md);
return 1;
}
static int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *res, unsigned int *len)
static int
EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *res, unsigned int *len)
{
EVP_DigestFinal(ctx, res, len);
return 1;
}
#endif /* old OpenSSL */
/*
@ -154,11 +156,12 @@ static int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *res, unsigned int
#include "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)
init = init_sha224;
@ -175,7 +178,6 @@ static int compat_find_digest(const char *name, PX_MD **res)
init(*res);
return 0;
}
#else
#define compat_find_digest(name, res) (PXE_NO_HASH)
#endif
@ -184,29 +186,32 @@ static int compat_find_digest(const char *name, PX_MD **res)
* Hashes
*/
typedef struct OSSLDigest {
typedef struct OSSLDigest
{
const EVP_MD *algo;
EVP_MD_CTX ctx;
} OSSLDigest;
EVP_MD_CTX ctx;
} OSSLDigest;
static unsigned
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);
}
static unsigned
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);
}
static void
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);
}
@ -214,7 +219,7 @@ digest_reset(PX_MD * h)
static void
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);
}
@ -222,7 +227,7 @@ digest_update(PX_MD * h, const uint8 *data, unsigned dlen)
static void
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);
}
@ -230,7 +235,7 @@ digest_finish(PX_MD * h, uint8 *dst)
static void
digest_free(PX_MD * h)
{
OSSLDigest *digest = (OSSLDigest *)h->p.ptr;
OSSLDigest *digest = (OSSLDigest *) h->p.ptr;
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;
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);
return 0;
}
@ -574,7 +579,7 @@ ossl_des3_ecb_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
ossldata *od = c->ptr;
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);
return 0;
}

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $PostgreSQL: pgsql/contrib/pgcrypto/pgcrypto.c,v 1.23 2006/09/05 21:26:48 tgl Exp $
* $PostgreSQL: pgsql/contrib/pgcrypto/pgcrypto.c,v 1.24 2006/10/04 00:29:46 momjian Exp $
*/
#include "postgres.h"
@ -491,9 +491,9 @@ PG_FUNCTION_INFO_V1(pg_random_bytes);
Datum
pg_random_bytes(PG_FUNCTION_ARGS)
{
int err;
int len = PG_GETARG_INT32(0);
bytea *res;
int err;
int len = PG_GETARG_INT32(0);
bytea *res;
if (len < 1 || len > 1024)
ereport(ERROR,
@ -504,7 +504,7 @@ pg_random_bytes(PG_FUNCTION_ARGS)
VARATT_SIZEP(res) = VARHDRSZ + len;
/* generate result */
err = px_get_random_bytes((uint8*)VARDATA(res), len);
err = px_get_random_bytes((uint8 *) VARDATA(res), len);
if (err < 0)
ereport(ERROR,
(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
* SUCH DAMAGE.
*
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi-internal.c,v 1.6 2006/07/13 04:52:51 neilc Exp $
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi-internal.c,v 1.7 2006/10/04 00:29:46 momjian Exp $
*/
#include "postgres.h"
@ -36,14 +36,17 @@
#include "mbuf.h"
#include "pgp.h"
static mpz_t *mp_new()
static mpz_t *
mp_new()
{
mpz_t *mp = mp_int_alloc();
mpz_t *mp = mp_int_alloc();
mp_int_init_size(mp, 256);
return mp;
}
static void mp_clear_free(mpz_t *a)
static void
mp_clear_free(mpz_t * a)
{
if (!a)
return;
@ -52,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;
unsigned bytes = (bits + 7) / 8;
int last_bits = bits & 7;
uint8 *buf;
int err;
unsigned bytes = (bits + 7) / 8;
int last_bits = bits & 7;
uint8 *buf;
buf = px_alloc(bytes);
err = px_get_random_bytes(buf, bytes);
if (err < 0) {
if (err < 0)
{
px_free(buf);
return err;
}
/* clear unnecessary bits and set last bit to one */
if (last_bits) {
if (last_bits)
{
buf[0] >>= 8 - last_bits;
buf[0] |= 1 << (last_bits - 1);
} else
}
else
buf[0] |= 1 << 7;
mp_int_read_unsigned(res, buf, bytes);
@ -80,9 +87,11 @@ static int mp_px_rand(uint32 bits, mpz_t *res)
return 0;
}
static void mp_modmul(mpz_t *a, mpz_t *b, mpz_t *p, mpz_t *res)
static void
mp_modmul(mpz_t * a, mpz_t * b, mpz_t * p, mpz_t * res)
{
mpz_t *tmp = mp_new();
mpz_t *tmp = mp_new();
mp_int_mul(a, b, tmp);
mp_int_mod(tmp, p, res);
mp_clear_free(tmp);
@ -92,6 +101,7 @@ static mpz_t *
mpi_to_bn(PGP_MPI * n)
{
mpz_t *bn = mp_new();
mp_int_read_unsigned(bn, n->data, n->bytes);
if (!bn)
@ -107,11 +117,11 @@ mpi_to_bn(PGP_MPI * n)
}
static PGP_MPI *
bn_to_mpi(mpz_t *bn)
bn_to_mpi(mpz_t * bn)
{
int res;
PGP_MPI *n;
int bytes;
int bytes;
res = pgp_mpi_alloc(mp_int_count_bits(bn), &n);
if (res < 0)

View File

@ -33,7 +33,7 @@
*
* $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $
*
* $PostgreSQL: pgsql/contrib/pgcrypto/sha2.c,v 1.7 2006/07/13 04:15:25 neilc Exp $
* $PostgreSQL: pgsql/contrib/pgcrypto/sha2.c,v 1.8 2006/10/04 00:29:46 momjian Exp $
*/
#include "postgres.h"
@ -534,7 +534,7 @@ SHA256_Update(SHA256_CTX * context, const uint8 *data, size_t len)
}
static void
SHA256_Last(SHA256_CTX *context)
SHA256_Last(SHA256_CTX * context)
{
unsigned int usedspace;
@ -1023,4 +1023,3 @@ SHA224_Final(uint8 digest[], SHA224_CTX * context)
/* Clean up state data: */
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
*
@ -63,11 +63,12 @@ extern Datum pgrowlocks(PG_FUNCTION_ARGS);
*/
#undef MAKERANGEVARFROMNAMELIST_HAS_TWO_ARGS
typedef struct {
typedef struct
{
Relation rel;
HeapScanDesc scan;
int ncolumns;
} MyData;
int ncolumns;
} MyData;
Datum
pgrowlocks(PG_FUNCTION_ARGS)
@ -78,7 +79,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
TupleDesc tupdesc;
AttInMetadata *attinmeta;
Datum result;
MyData *mydata;
MyData *mydata;
Relation rel;
if (SRF_IS_FIRSTCALL())
@ -96,8 +97,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
relname = PG_GETARG_TEXT_P(0);
#ifdef MAKERANGEVARFROMNAMELIST_HAS_TWO_ARGS
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname, "pgrowlocks"));
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname, "pgrowlocks"));
#else
relrv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
#endif
@ -114,7 +114,7 @@ pgrowlocks(PG_FUNCTION_ARGS)
funcctx = SRF_PERCALL_SETUP();
attinmeta = funcctx->attinmeta;
mydata = (MyData *)funcctx->user_fctx;
mydata = (MyData *) funcctx->user_fctx;
scan = mydata->scan;
/* scan the relation */
@ -124,16 +124,16 @@ pgrowlocks(PG_FUNCTION_ARGS)
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_SHARE);
if (HeapTupleSatisfiesUpdate(tuple->t_data, GetCurrentCommandId(), scan->rs_cbuf)
== HeapTupleBeingUpdated)
== HeapTupleBeingUpdated)
{
char **values;
int i;
char **values;
int i;
values = (char **) palloc(mydata->ncolumns * sizeof(char *));
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
if (tuple->t_data->t_infomask & HEAP_XMAX_SHARED_LOCK)
@ -143,15 +143,15 @@ pgrowlocks(PG_FUNCTION_ARGS)
#else
values[i++] = pstrdup("Exclusive");
#endif
values[i] = palloc(NCHARS*sizeof(char));
values[i] = palloc(NCHARS * sizeof(char));
snprintf(values[i++], NCHARS, "%d", HeapTupleHeaderGetXmax(tuple->t_data));
#ifdef HEAP_XMAX_SHARED_LOCK
if (tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI)
{
TransactionId *xids;
int nxids;
int j;
int isValidXid = 0; /* any valid xid ever exists? */
int nxids;
int j;
int isValidXid = 0; /* any valid xid ever exists? */
values[i++] = pstrdup("true");
nxids = GetMultiXactIdMembers(HeapTupleHeaderGetXmax(tuple->t_data), &xids);
@ -160,45 +160,44 @@ pgrowlocks(PG_FUNCTION_ARGS)
elog(ERROR, "GetMultiXactIdMembers returns error");
}
values[i] = palloc(NCHARS*nxids);
values[i+1] = palloc(NCHARS*nxids);
values[i] = palloc(NCHARS * nxids);
values[i + 1] = palloc(NCHARS * nxids);
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 (isValidXid)
{
strcat(values[i], ",");
strcat(values[i+1], ",");
strcat(values[i + 1], ",");
}
snprintf(buf, NCHARS, "%d", xids[j]);
strcat(values[i], buf);
snprintf(buf, NCHARS, "%d", BackendXidGetPid(xids[j]));
strcat(values[i+1], buf);
strcat(values[i + 1], buf);
isValidXid = 1;
}
}
strcat(values[i], "}");
strcat(values[i+1], "}");
strcat(values[i + 1], "}");
i++;
}
else
{
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));
values[i] = palloc(NCHARS*sizeof(char));
values[i] = palloc(NCHARS * sizeof(char));
snprintf(values[i++], NCHARS, "{%d}", BackendXidGetPid(HeapTupleHeaderGetXmax(tuple->t_data)));
}
#else
values[i++] = pstrdup("false");
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
*
@ -51,36 +51,36 @@ extern Datum pgstattuplebyid(PG_FUNCTION_ARGS);
*/
typedef struct pgstattuple_type
{
uint64 table_len;
uint64 tuple_count;
uint64 tuple_len;
uint64 dead_tuple_count;
uint64 dead_tuple_len;
uint64 free_space; /* free/reusable space in bytes */
} pgstattuple_type;
uint64 table_len;
uint64 tuple_count;
uint64 tuple_len;
uint64 dead_tuple_count;
uint64 dead_tuple_len;
uint64 free_space; /* free/reusable space in bytes */
} 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,
FunctionCallInfo fcinfo);
static Datum build_pgstattuple_type(pgstattuple_type * stat,
FunctionCallInfo fcinfo);
static Datum pgstat_relation(Relation rel, FunctionCallInfo fcinfo);
static Datum pgstat_heap(Relation rel, FunctionCallInfo fcinfo);
static void pgstat_btree_page(pgstattuple_type *stat,
Relation rel, BlockNumber blkno);
static void pgstat_hash_page(pgstattuple_type *stat,
Relation rel, BlockNumber blkno);
static void pgstat_gist_page(pgstattuple_type *stat,
Relation rel, BlockNumber blkno);
static void pgstat_btree_page(pgstattuple_type * stat,
Relation rel, BlockNumber blkno);
static void pgstat_hash_page(pgstattuple_type * stat,
Relation rel, BlockNumber blkno);
static void pgstat_gist_page(pgstattuple_type * stat,
Relation rel, BlockNumber blkno);
static Datum pgstat_index(Relation rel, BlockNumber start,
pgstat_page pagefn, FunctionCallInfo fcinfo);
static void pgstat_index_page(pgstattuple_type *stat, Page page,
OffsetNumber minoff, OffsetNumber maxoff);
pgstat_page pagefn, FunctionCallInfo fcinfo);
static void pgstat_index_page(pgstattuple_type * stat, Page page,
OffsetNumber minoff, OffsetNumber maxoff);
/*
* build_pgstattuple_type -- build a pgstattuple_type tuple
*/
static Datum
build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
build_pgstattuple_type(pgstattuple_type * stat, FunctionCallInfo fcinfo)
{
#define NCOLUMNS 9
#define NCHARS 32
@ -91,7 +91,7 @@ build_pgstattuple_type(pgstattuple_type *stat, FunctionCallInfo fcinfo)
int i;
double tuple_percent;
double dead_tuple_percent;
double free_percent; /* free/reusable space in % */
double free_percent; /* free/reusable space in % */
TupleDesc tupdesc;
AttInMetadata *attinmeta;
@ -190,49 +190,49 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
{
const char *err;
switch(rel->rd_rel->relkind)
switch (rel->rd_rel->relkind)
{
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_UNCATALOGED:
case RELKIND_SEQUENCE:
return pgstat_heap(rel, fcinfo);
case RELKIND_INDEX:
switch(rel->rd_rel->relam)
{
case BTREE_AM_OID:
return pgstat_index(rel, BTREE_METAPAGE + 1,
pgstat_btree_page, fcinfo);
case HASH_AM_OID:
return pgstat_index(rel, HASH_METAPAGE + 1,
pgstat_hash_page, fcinfo);
case GIST_AM_OID:
return pgstat_index(rel, GIST_ROOT_BLKNO + 1,
pgstat_gist_page, fcinfo);
case GIN_AM_OID:
err = "gin index";
case RELKIND_RELATION:
case RELKIND_TOASTVALUE:
case RELKIND_UNCATALOGED:
case RELKIND_SEQUENCE:
return pgstat_heap(rel, fcinfo);
case RELKIND_INDEX:
switch (rel->rd_rel->relam)
{
case BTREE_AM_OID:
return pgstat_index(rel, BTREE_METAPAGE + 1,
pgstat_btree_page, fcinfo);
case HASH_AM_OID:
return pgstat_index(rel, HASH_METAPAGE + 1,
pgstat_hash_page, fcinfo);
case GIST_AM_OID:
return pgstat_index(rel, GIST_ROOT_BLKNO + 1,
pgstat_gist_page, fcinfo);
case GIN_AM_OID:
err = "gin index";
break;
default:
err = "unknown index";
break;
}
break;
case RELKIND_VIEW:
err = "view";
break;
case RELKIND_COMPOSITE_TYPE:
err = "composite type";
break;
default:
err = "unknown index";
err = "unknown";
break;
}
break;
case RELKIND_VIEW:
err = "view";
break;
case RELKIND_COMPOSITE_TYPE:
err = "composite type";
break;
default:
err = "unknown";
break;
}
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("\"%s\" (%s) is not supported",
RelationGetRelationName(rel), err)));
return 0; /* should not happen */
RelationGetRelationName(rel), err)));
return 0; /* should not happen */
}
/*
@ -241,13 +241,13 @@ pgstat_relation(Relation rel, FunctionCallInfo fcinfo)
static Datum
pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
{
HeapScanDesc scan;
HeapTuple tuple;
BlockNumber nblocks;
BlockNumber block = 0; /* next block to count free space in */
BlockNumber tupblock;
Buffer buffer;
pgstattuple_type stat = { 0 };
HeapScanDesc scan;
HeapTuple tuple;
BlockNumber nblocks;
BlockNumber block = 0; /* next block to count free space in */
BlockNumber tupblock;
Buffer buffer;
pgstattuple_type stat = {0};
scan = heap_beginscan(rel, SnapshotAny, 0, NULL);
@ -302,7 +302,7 @@ pgstat_heap(Relation rel, FunctionCallInfo fcinfo)
relation_close(rel, AccessShareLock);
stat.table_len = (uint64) nblocks * BLCKSZ;
stat.table_len = (uint64) nblocks *BLCKSZ;
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
*/
static void
pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
pgstat_btree_page(pgstattuple_type * stat, Relation rel, BlockNumber blkno)
{
Buffer buf;
Page page;
Buffer buf;
Page page;
buf = ReadBuffer(rel, blkno);
LockBuffer(buf, BT_READ);
@ -328,7 +328,8 @@ pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
}
else
{
BTPageOpaque opaque;
BTPageOpaque opaque;
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
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))
{
pgstat_index_page(stat, page, P_FIRSTDATAKEY(opaque),
PageGetMaxOffsetNumber(page));
PageGetMaxOffsetNumber(page));
}
else
{
@ -353,10 +354,10 @@ pgstat_btree_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
* pgstat_hash_page -- check tuples in a hash page
*/
static void
pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
pgstat_hash_page(pgstattuple_type * stat, Relation rel, BlockNumber blkno)
{
Buffer buf;
Page page;
Buffer buf;
Page page;
_hash_getlock(rel, blkno, HASH_SHARE);
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)))
{
HashPageOpaque opaque;
HashPageOpaque opaque;
opaque = (HashPageOpaque) PageGetSpecialPointer(page);
switch (opaque->hasho_flag)
{
case LH_UNUSED_PAGE:
stat->free_space += BLCKSZ;
break;
case LH_BUCKET_PAGE:
case LH_OVERFLOW_PAGE:
pgstat_index_page(stat, page, FirstOffsetNumber,
PageGetMaxOffsetNumber(page));
break;
case LH_BITMAP_PAGE:
case LH_META_PAGE:
default:
break;
case LH_UNUSED_PAGE:
stat->free_space += BLCKSZ;
break;
case LH_BUCKET_PAGE:
case LH_OVERFLOW_PAGE:
pgstat_index_page(stat, page, FirstOffsetNumber,
PageGetMaxOffsetNumber(page));
break;
case LH_BITMAP_PAGE:
case LH_META_PAGE:
default:
break;
}
}
else
@ -395,10 +397,10 @@ pgstat_hash_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
* pgstat_gist_page -- check tuples in a gist page
*/
static void
pgstat_gist_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
pgstat_gist_page(pgstattuple_type * stat, Relation rel, BlockNumber blkno)
{
Buffer buf;
Page page;
Buffer buf;
Page page;
buf = ReadBuffer(rel, blkno);
LockBuffer(buf, GIST_SHARE);
@ -408,7 +410,7 @@ pgstat_gist_page(pgstattuple_type *stat, Relation rel, BlockNumber blkno)
if (GistPageIsLeaf(page))
{
pgstat_index_page(stat, page, FirstOffsetNumber,
PageGetMaxOffsetNumber(page));
PageGetMaxOffsetNumber(page));
}
else
{
@ -427,7 +429,7 @@ pgstat_index(Relation rel, BlockNumber start, pgstat_page pagefn,
{
BlockNumber nblocks;
BlockNumber blkno;
pgstattuple_type stat = { 0 };
pgstattuple_type stat = {0};
blkno = start;
for (;;)
@ -440,7 +442,8 @@ pgstat_index(Relation rel, BlockNumber start, pgstat_page pagefn,
/* Quit if we've scanned the whole relation */
if (blkno >= nblocks)
{
stat.table_len = (uint64) nblocks * BLCKSZ;
stat.table_len = (uint64) nblocks *BLCKSZ;
break;
}
@ -457,16 +460,16 @@ pgstat_index(Relation rel, BlockNumber start, pgstat_page pagefn,
* pgstat_index_page -- for generic index page
*/
static void
pgstat_index_page(pgstattuple_type *stat, Page page,
OffsetNumber minoff, OffsetNumber maxoff)
pgstat_index_page(pgstattuple_type * stat, Page page,
OffsetNumber minoff, OffsetNumber maxoff)
{
OffsetNumber i;
OffsetNumber i;
stat->free_space += PageGetFreeSpace(page);
for (i = minoff; i <= maxoff; i = OffsetNumberNext(i))
{
ItemId itemid = PageGetItemId(page, i);
ItemId itemid = PageGetItemId(page, i);
if (ItemIdDeleted(itemid))
{

View File

@ -4,7 +4,7 @@
* Written by Victor B. Wagner <vitus@cryptocom.ru>, Cryptocom LTD
* This file is distributed under BSD-style license.
*
* $PostgreSQL: pgsql/contrib/sslinfo/sslinfo.c,v 1.4 2006/09/30 18:44:37 tgl Exp $
* $PostgreSQL: pgsql/contrib/sslinfo/sslinfo.c,v 1.5 2006/10/04 00:29:46 momjian Exp $
*/
#include "postgres.h"
@ -22,28 +22,29 @@
PG_MODULE_MAGIC;
Datum ssl_is_used(PG_FUNCTION_ARGS);
Datum ssl_client_cert_present(PG_FUNCTION_ARGS);
Datum ssl_client_serial(PG_FUNCTION_ARGS);
Datum ssl_client_dn_field(PG_FUNCTION_ARGS);
Datum ssl_issuer_field(PG_FUNCTION_ARGS);
Datum ssl_client_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_to_text(X509_NAME *name);
Datum ASN1_STRING_to_text(ASN1_STRING *str);
Datum ssl_is_used(PG_FUNCTION_ARGS);
Datum ssl_client_cert_present(PG_FUNCTION_ARGS);
Datum ssl_client_serial(PG_FUNCTION_ARGS);
Datum ssl_client_dn_field(PG_FUNCTION_ARGS);
Datum ssl_issuer_field(PG_FUNCTION_ARGS);
Datum ssl_client_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_to_text(X509_NAME *name);
Datum ASN1_STRING_to_text(ASN1_STRING *str);
/*
/*
* Indicates whether current session uses SSL
*
* Function has no arguments. Returns bool. True if current session
* is SSL session and false if it is local or non-ssl session.
*/
PG_FUNCTION_INFO_V1(ssl_is_used);
Datum ssl_is_used(PG_FUNCTION_ARGS)
Datum
ssl_is_used(PG_FUNCTION_ARGS)
{
PG_RETURN_BOOL(MyProcPort->ssl !=NULL);
PG_RETURN_BOOL(MyProcPort->ssl != NULL);
}
@ -54,7 +55,8 @@ Datum ssl_is_used(PG_FUNCTION_ARGS)
* is SSL session and client certificate is verified, otherwise false.
*/
PG_FUNCTION_INFO_V1(ssl_client_cert_present);
Datum ssl_client_cert_present(PG_FUNCTION_ARGS)
Datum
ssl_client_cert_present(PG_FUNCTION_ARGS)
{
PG_RETURN_BOOL(MyProcPort->peer != NULL);
}
@ -69,20 +71,22 @@ Datum ssl_client_cert_present(PG_FUNCTION_ARGS)
* SSL connection is established without sending client certificate.
*/
PG_FUNCTION_INFO_V1(ssl_client_serial);
Datum ssl_client_serial(PG_FUNCTION_ARGS)
Datum
ssl_client_serial(PG_FUNCTION_ARGS)
{
Datum result;
Port *port = MyProcPort;
X509 *peer = port->peer;
Datum result;
Port *port = MyProcPort;
X509 *peer = port->peer;
ASN1_INTEGER *serial = NULL;
BIGNUM *b;
char *decimal;
BIGNUM *b;
char *decimal;
if (!peer)
PG_RETURN_NULL();
serial = X509_get_serialNumber(peer);
b = ASN1_INTEGER_to_BN(serial, NULL);
decimal = BN_bn2dec(b);
BN_free(b);
result = DirectFunctionCall3(numeric_in,
CStringGetDatum(decimal),
@ -100,23 +104,25 @@ Datum ssl_client_serial(PG_FUNCTION_ARGS)
* current database encoding if possible. Any invalid characters are
* 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.
*
* Returns Datum, which can be directly returned from a C language SQL
* function.
*/
Datum ASN1_STRING_to_text(ASN1_STRING *str)
Datum
ASN1_STRING_to_text(ASN1_STRING *str)
{
BIO *membuf = NULL;
size_t size, outlen;
char *sp;
char *dp;
text *result;
BIO *membuf = NULL;
size_t size,
outlen;
char *sp;
char *dp;
text *result;
membuf = BIO_new(BIO_s_mem());
(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_UTF8_CONVERT));
@ -124,7 +130,7 @@ Datum ASN1_STRING_to_text(ASN1_STRING *str)
BIO_write(membuf, &outlen, 1);
size = BIO_get_mem_data(membuf, &sp);
dp = (char *) pg_do_encoding_conversion((unsigned char *) sp,
size-1,
size - 1,
PG_UTF8,
GetDatabaseEncoding());
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: 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
* part of name
*/
Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
Datum
X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
{
char *sp;
char *string_fieldname;
char *dp;
size_t name_len = VARSIZE(fieldName) - VARHDRSZ;
int nid, index, i;
char *sp;
char *string_fieldname;
char *dp;
size_t name_len = VARSIZE(fieldName) - VARHDRSZ;
int nid,
index,
i;
ASN1_STRING *data;
string_fieldname = palloc(name_len + 1);
@ -175,7 +184,7 @@ Datum X509_NAME_field_to_text(X509_NAME *name, text *fieldName)
pfree(string_fieldname);
index = X509_NAME_get_index_by_NID(name, nid, -1);
if (index < 0)
return (Datum)0;
return (Datum) 0;
data = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name, index));
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.
*/
PG_FUNCTION_INFO_V1(ssl_client_dn_field);
Datum ssl_client_dn_field(PG_FUNCTION_ARGS)
Datum
ssl_client_dn_field(PG_FUNCTION_ARGS)
{
text *fieldname = PG_GETARG_TEXT_P(0);
Datum result;
text *fieldname = PG_GETARG_TEXT_P(0);
Datum result;
if (!(MyProcPort->peer))
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.
*/
PG_FUNCTION_INFO_V1(ssl_issuer_field);
Datum ssl_issuer_field(PG_FUNCTION_ARGS)
Datum
ssl_issuer_field(PG_FUNCTION_ARGS)
{
text *fieldname = PG_GETARG_TEXT_P(0);
Datum result;
text *fieldname = PG_GETARG_TEXT_P(0);
Datum result;
if (!(MyProcPort->peer))
PG_RETURN_NULL();
@ -260,21 +271,25 @@ Datum ssl_issuer_field(PG_FUNCTION_ARGS)
* Returns: text datum which contains string representation of
* X509_NAME
*/
Datum X509_NAME_to_text(X509_NAME *name)
Datum
X509_NAME_to_text(X509_NAME *name)
{
BIO *membuf = BIO_new(BIO_s_mem());
int i,nid,count = X509_NAME_entry_count(name);
BIO *membuf = BIO_new(BIO_s_mem());
int i,
nid,
count = X509_NAME_entry_count(name);
X509_NAME_ENTRY *e;
ASN1_STRING *v;
const char *field_name;
size_t size,outlen;
char *sp;
char *dp;
text *result;
size_t size,
outlen;
char *sp;
char *dp;
text *result;
(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);
nid = OBJ_obj2nid(X509_NAME_ENTRY_get_object(e));
@ -283,17 +298,17 @@ Datum X509_NAME_to_text(X509_NAME *name)
if (!field_name)
field_name = OBJ_nid2ln(nid);
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_UTF8_CONVERT));
}
i=0;
i = 0;
BIO_write(membuf, &i, 1);
size = BIO_get_mem_data(membuf, &sp);
dp = (char *) pg_do_encoding_conversion((unsigned char *) sp,
size-1,
size - 1,
PG_UTF8,
GetDatabaseEncoding());
BIO_free(membuf);
@ -301,8 +316,10 @@ Datum X509_NAME_to_text(X509_NAME *name)
result = palloc(VARHDRSZ + outlen);
memcpy(VARDATA(result), dp, outlen);
/* pg_do_encoding_conversion has annoying habit of returning
* source pointer */
/*
* pg_do_encoding_conversion has annoying habit of returning source
* pointer
*/
if (dp != sp)
pfree(dp);
VARATT_SIZEP(result) = outlen + VARHDRSZ;
@ -320,7 +337,8 @@ Datum X509_NAME_to_text(X509_NAME *name)
* Returns text datum.
*/
PG_FUNCTION_INFO_V1(ssl_client_dn);
Datum ssl_client_dn(PG_FUNCTION_ARGS)
Datum
ssl_client_dn(PG_FUNCTION_ARGS)
{
if (!(MyProcPort->peer))
PG_RETURN_NULL();
@ -338,7 +356,8 @@ Datum ssl_client_dn(PG_FUNCTION_ARGS)
* Returns text datum.
*/
PG_FUNCTION_INFO_V1(ssl_issuer_dn);
Datum ssl_issuer_dn(PG_FUNCTION_ARGS)
Datum
ssl_issuer_dn(PG_FUNCTION_ARGS)
{
if (!(MyProcPort->peer))
PG_RETURN_NULL();

View File

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

View File

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

View File

@ -14,7 +14,7 @@ text *mtextdup(text *in);
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 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
@ -102,7 +102,8 @@ comparedict(const void *a, const void *b)
}
static void
insertdict(Oid id) {
insertdict(Oid id)
{
DictInfo newdict;
if (DList.len == DList.reallen)
@ -143,7 +144,7 @@ finddict(Oid id)
return DList.last_dict;
}
/* insert new dictionary */
/* insert new dictionary */
insertdict(id);
return finddict(id); /* qsort changed order!! */ ;
}
@ -201,30 +202,31 @@ lexize(PG_FUNCTION_ARGS)
*ptr;
Datum *da;
ArrayType *a;
DictSubState dstate = { false, false, NULL };
DictSubState dstate = {false, false, NULL};
SET_FUNCOID();
dict = finddict(PG_GETARG_OID(0));
ptr = res = (TSLexeme *) DatumGetPointer(
FunctionCall4(&(dict->lexize_info),
PointerGetDatum(dict->dictionary),
PointerGetDatum(VARDATA(in)),
Int32GetDatum(VARSIZE(in) - VARHDRSZ),
PointerGetDatum(&dstate)
FunctionCall4(&(dict->lexize_info),
PointerGetDatum(dict->dictionary),
PointerGetDatum(VARDATA(in)),
Int32GetDatum(VARSIZE(in) - VARHDRSZ),
PointerGetDatum(&dstate)
)
);
if (dstate.getnext) {
dstate.isend = true;
if (dstate.getnext)
{
dstate.isend = true;
ptr = res = (TSLexeme *) DatumGetPointer(
FunctionCall4(&(dict->lexize_info),
FunctionCall4(&(dict->lexize_info),
PointerGetDatum(dict->dictionary),
PointerGetDatum(VARDATA(in)),
Int32GetDatum(VARSIZE(in) - VARHDRSZ),
PointerGetDatum(&dstate)
Int32GetDatum(VARSIZE(in) - VARHDRSZ),
PointerGetDatum(&dstate)
)
);
);
}
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__
#define __DICT_H__
@ -30,11 +30,14 @@ DictInfo *finddict(Oid id);
Oid name2id_dict(text *name);
void reset_dict(void);
typedef struct {
bool isend; /* in: marks for lexize_info about text end is reached */
bool getnext; /* out: dict wants next lexeme */
void *private; /* internal dict state between calls with getnext == true */
} DictSubState;
typedef struct
{
bool isend; /* in: marks for lexize_info about text end is
* reached */
bool getnext; /* out: dict wants next lexeme */
void *private; /* internal dict state between calls with
* getnext == true */
} DictSubState;
/* simple parser of cfg string */
typedef struct
@ -51,13 +54,8 @@ typedef struct
/*
* number of variant of split word , for example Word 'fotballklubber'
* (norwegian) has two varian to split: ( fotball, klubb ) and ( fot,
* ball, klubb ). So, dictionary should return:
* nvariant lexeme
* 1 fotball
* 1 klubb
* 2 fot
* 2 ball
* 2 klubb
* ball, klubb ). So, dictionary should return: nvariant lexeme 1
* fotball 1 klubb 2 fot 2 ball 2 klubb
*/
uint16 nvariant;
@ -74,38 +72,43 @@ typedef struct
* Lexize subsystem
*/
typedef struct ParsedLex {
int type;
char *lemm;
int lenlemm;
typedef struct ParsedLex
{
int type;
char *lemm;
int lenlemm;
bool resfollow;
struct ParsedLex *next;
} ParsedLex;
struct ParsedLex *next;
} ParsedLex;
typedef struct ListParsedLex {
ParsedLex *head;
ParsedLex *tail;
} ListParsedLex;
typedef struct ListParsedLex
{
ParsedLex *head;
ParsedLex *tail;
} ListParsedLex;
typedef struct {
TSCfgInfo *cfg;
Oid curDictId;
int posDict;
DictSubState dictState;
ParsedLex *curSub;
ListParsedLex towork; /* current list to work */
ListParsedLex waste; /* list of lexemes that already lexized */
typedef struct
{
TSCfgInfo *cfg;
Oid curDictId;
int posDict;
DictSubState dictState;
ParsedLex *curSub;
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 */
ParsedLex *lastRes;
TSLexeme *tmpRes;
} LexizeData;
/*
* fields to store last variant to lexize (basically, thesaurus or similar
* to, which wants several lexemes
*/
ParsedLex *lastRes;
TSLexeme *tmpRes;
} LexizeData;
void LexizeInit(LexizeData *ld, TSCfgInfo *cfg);
void LexizeAddLemm(LexizeData *ld, int type, char *lemm, int lenlemm);
TSLexeme* LexizeExec(LexizeData *ld, ParsedLex **correspondLexem);
void LexizeInit(LexizeData * ld, TSCfgInfo * cfg);
void LexizeAddLemm(LexizeData * ld, int type, char *lemm, int lenlemm);
TSLexeme *LexizeExec(LexizeData * ld, ParsedLex ** correspondLexem);
#endif

File diff suppressed because it is too large Load Diff

View File

@ -15,29 +15,32 @@
#include "query_cleanup.h"
PG_FUNCTION_INFO_V1(gin_extract_tsvector);
Datum gin_extract_tsvector(PG_FUNCTION_ARGS);
Datum gin_extract_tsvector(PG_FUNCTION_ARGS);
Datum
gin_extract_tsvector(PG_FUNCTION_ARGS) {
tsvector *vector = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
uint32 *nentries = (uint32*)PG_GETARG_POINTER(1);
Datum *entries = NULL;
gin_extract_tsvector(PG_FUNCTION_ARGS)
{
tsvector *vector = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL;
*nentries = 0;
if ( vector->size > 0 ) {
int i;
WordEntry *we = ARRPTR( vector );
if (vector->size > 0)
{
int i;
WordEntry *we = ARRPTR(vector);
*nentries = (uint32)vector->size;
entries = (Datum*)palloc( sizeof(Datum) * vector->size );
*nentries = (uint32) vector->size;
entries = (Datum *) palloc(sizeof(Datum) * vector->size);
for(i=0;i<vector->size;i++) {
text *txt = (text*)palloc( VARHDRSZ + we->len );
for (i = 0; i < vector->size; i++)
{
text *txt = (text *) palloc(VARHDRSZ + we->len);
VARATT_SIZEP(txt) = VARHDRSZ + we->len;
memcpy( VARDATA(txt), STRPTR( vector ) + we->pos, we->len );
VARATT_SIZEP(txt) = VARHDRSZ + we->len;
memcpy(VARDATA(txt), STRPTR(vector) + we->pos, we->len);
entries[i] = PointerGetDatum( txt );
entries[i] = PointerGetDatum(txt);
we++;
}
@ -49,45 +52,50 @@ gin_extract_tsvector(PG_FUNCTION_ARGS) {
PG_FUNCTION_INFO_V1(gin_extract_tsquery);
Datum gin_extract_tsquery(PG_FUNCTION_ARGS);
Datum gin_extract_tsquery(PG_FUNCTION_ARGS);
Datum
gin_extract_tsquery(PG_FUNCTION_ARGS) {
QUERYTYPE *query = (QUERYTYPE*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
uint32 *nentries = (uint32*)PG_GETARG_POINTER(1);
StrategyNumber strategy = DatumGetUInt16( PG_GETARG_DATUM(2) );
Datum *entries = NULL;
gin_extract_tsquery(PG_FUNCTION_ARGS)
{
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
StrategyNumber strategy = DatumGetUInt16(PG_GETARG_DATUM(2));
Datum *entries = NULL;
*nentries = 0;
if ( query->size > 0 ) {
int4 i, j=0, len;
ITEM *item;
if (query->size > 0)
{
int4 i,
j = 0,
len;
ITEM *item;
item = clean_NOT_v2(GETQUERY(query), &len);
if ( !item )
elog(ERROR,"Query requires full scan, GIN doesn't support it");
if (!item)
elog(ERROR, "Query requires full scan, GIN doesn't support it");
item = GETQUERY(query);
for(i=0; i<query->size; i++)
if ( item[i].type == VAL )
for (i = 0; i < query->size; i++)
if (item[i].type == VAL)
(*nentries)++;
entries = (Datum*)palloc( sizeof(Datum) * (*nentries) );
entries = (Datum *) palloc(sizeof(Datum) * (*nentries));
for(i=0; i<query->size; i++)
if ( item[i].type == VAL ) {
text *txt;
for (i = 0; i < query->size; i++)
if (item[i].type == VAL)
{
text *txt;
txt = (text*)palloc( VARHDRSZ + item[i].length );
txt = (text *) palloc(VARHDRSZ + item[i].length);
VARATT_SIZEP(txt) = VARHDRSZ + item[i].length;
memcpy( VARDATA(txt), GETOPERAND( query ) + item[i].distance, item[i].length );
VARATT_SIZEP(txt) = VARHDRSZ + 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 )
elog(ERROR,"With class of lexeme restrictions use @@@ operation");
if (strategy == 1 && item[i].weight != 0)
elog(ERROR, "With class of lexeme restrictions use @@@ operation");
}
}
@ -96,51 +104,54 @@ gin_extract_tsquery(PG_FUNCTION_ARGS) {
PG_RETURN_POINTER(entries);
}
typedef struct {
ITEM *frst;
bool *mapped_check;
} GinChkVal;
typedef struct
{
ITEM *frst;
bool *mapped_check;
} GinChkVal;
static bool
checkcondition_gin(void *checkval, ITEM * val) {
GinChkVal *gcv = (GinChkVal*)checkval;
checkcondition_gin(void *checkval, ITEM * val)
{
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);
Datum gin_ts_consistent(PG_FUNCTION_ARGS);
Datum gin_ts_consistent(PG_FUNCTION_ARGS);
Datum
gin_ts_consistent(PG_FUNCTION_ARGS) {
bool *check = (bool*)PG_GETARG_POINTER(0);
QUERYTYPE *query = (QUERYTYPE*) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
bool res = FALSE;
gin_ts_consistent(PG_FUNCTION_ARGS)
{
bool *check = (bool *) PG_GETARG_POINTER(0);
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
bool res = FALSE;
if ( query->size > 0 ) {
int4 i, j=0;
ITEM *item;
if (query->size > 0)
{
int4 i,
j = 0;
ITEM *item;
GinChkVal gcv;
gcv.frst = item = GETQUERY(query);
gcv.mapped_check= (bool*)palloc( sizeof(bool) * query->size );
gcv.frst = item = GETQUERY(query);
gcv.mapped_check = (bool *) palloc(sizeof(bool) * query->size);
for(i=0; i<query->size; i++)
if ( item[i].type == VAL )
gcv.mapped_check[ i ] = check[ j++ ];
for (i = 0; i < query->size; i++)
if (item[i].type == VAL)
gcv.mapped_check[i] = check[j++];
res = TS_execute(
GETQUERY(query),
&gcv,
true,
checkcondition_gin
);
GETQUERY(query),
&gcv,
true,
checkcondition_gin
);
}
PG_FREE_IF_COPY(query, 2);
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"
@ -447,7 +447,7 @@ sizebitvec(BITVECP sign)
i;
LOOPBYTE(
size += number_of_ones[(unsigned char) sign[i]];
size += number_of_ones[(unsigned char) sign[i]];
);
return size;
}
@ -460,8 +460,8 @@ hemdistsign(BITVECP a, BITVECP b)
dist = 0;
LOOPBYTE(
diff = (unsigned char) (a[i] ^ b[i]);
dist += number_of_ones[diff];
diff = (unsigned char) (a[i] ^ b[i]);
dist += number_of_ones[diff];
);
return dist;
}
@ -533,7 +533,7 @@ typedef struct
{
OffsetNumber pos;
int4 cost;
} SPLITCOST;
} SPLITCOST;
static int
comparecost(const void *a, const void *b)

View File

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

View File

@ -27,12 +27,12 @@ typedef struct Regis
unused:15;
} 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);
/*returns true if matches */
bool RS_execute(Regis * r, char *str);
bool RS_execute(Regis * r, char *str);
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -29,7 +29,7 @@ makesign(QUERYTYPE * a)
for (i = 0; i < a->size; i++)
{
if (ptr->type == VAL)
sign |= ((TPQTGist)1) << (ptr->val % SIGLEN);
sign |= ((TPQTGist) 1) << (ptr->val % SIGLEN);
ptr++;
}
@ -104,7 +104,7 @@ tsq_mcontained(PG_FUNCTION_ARGS)
PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0)
)
);
);
}
PG_FUNCTION_INFO_V1(gtsq_in);
@ -272,7 +272,7 @@ typedef struct
{
OffsetNumber pos;
int4 cost;
} SPLITCOST;
} SPLITCOST;
static int
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 RANK_NO_NORM 0x00
#define RANK_NORM_LOGLENGTH 0x01
#define RANK_NORM_LENGTH 0x02
#define RANK_NORM_EXTDIST 0x04
#define RANK_NO_NORM 0x00
#define RANK_NORM_LOGLENGTH 0x01
#define RANK_NORM_LENGTH 0x02
#define RANK_NORM_EXTDIST 0x04
#define RANK_NORM_UNIQ 0x08
#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_and(float *w, tsvector * t, QUERYTYPE * q);
@ -334,19 +334,20 @@ calc_rank(float *w, tsvector * t, QUERYTYPE * q, int4 method)
if (res < 0)
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);
if ( method & RANK_NORM_LENGTH ) {
if (method & RANK_NORM_LENGTH)
{
len = cnt_length(t);
if ( len>0 )
if (len > 0)
res /= (float) len;
}
if ( (method & RANK_NORM_UNIQ) && t->size > 0 )
res /= (float)( t->size );
if ((method & RANK_NORM_UNIQ) && t->size > 0)
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);
return res;
@ -457,17 +458,18 @@ reset_istrue_flag(QUERYTYPE * query)
}
}
typedef struct {
int pos;
int p;
int q;
DocRepresentation *begin;
DocRepresentation *end;
} Extention;
typedef struct
{
int pos;
int p;
int q;
DocRepresentation *begin;
DocRepresentation *end;
} Extention;
static bool
Cover(DocRepresentation * doc, int len, QUERYTYPE * query, Extention *ext)
Cover(DocRepresentation * doc, int len, QUERYTYPE * query, Extention * ext)
{
DocRepresentation *ptr;
int lastpos = ext->pos;
@ -513,7 +515,8 @@ Cover(DocRepresentation * doc, int len, QUERYTYPE * query, Extention *ext)
ptr->item[i]->istrue = 1;
if (TS_execute(GETQUERY(query), NULL, true, checkcondition_ITEM))
{
if (ptr->pos < ext->p) {
if (ptr->pos < ext->p)
{
ext->begin = ptr;
ext->p = ptr->pos;
}
@ -629,69 +632,77 @@ get_docrep(tsvector * txt, QUERYTYPE * query, int *doclen)
}
static float4
calc_rank_cd(float4 *arrdata, tsvector *txt, QUERYTYPE *query, int method) {
calc_rank_cd(float4 *arrdata, tsvector * txt, QUERYTYPE * query, int method)
{
DocRepresentation *doc;
int len,
int len,
i,
doclen = 0;
Extention ext;
double Wdoc = 0.0;
double invws[lengthof(weights)];
double SumDist=0.0, PrevExtPos=0.0, CurExtPos=0.0;
int NExtent=0;
double SumDist = 0.0,
PrevExtPos = 0.0,
CurExtPos = 0.0;
int NExtent = 0;
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)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("weight out of range")));
invws[i] = 1.0/invws[i];
invws[i] = 1.0 / invws[i];
}
doc = get_docrep(txt, query, &doclen);
if (!doc)
if (!doc)
return 0.0;
MemSet( &ext, 0, sizeof(Extention) );
while (Cover(doc, doclen, query, &ext)) {
double Cpos = 0.0;
double InvSum = 0.0;
MemSet(&ext, 0, sizeof(Extention));
while (Cover(doc, doclen, query, &ext))
{
double Cpos = 0.0;
double InvSum = 0.0;
DocRepresentation *ptr = ext.begin;
while ( ptr<=ext.end ) {
InvSum += invws[ ptr->wclass ];
while (ptr <= ext.end)
{
InvSum += invws[ptr->wclass];
ptr++;
}
Cpos = ((double)( ext.end-ext.begin+1 )) / InvSum;
Wdoc += Cpos / ( (double)(( 1 + (ext.q - ext.p) - (ext.end - ext.begin) )) );
Cpos = ((double) (ext.end - ext.begin + 1)) / InvSum;
Wdoc += Cpos / ((double) ((1 + (ext.q - ext.p) - (ext.end - ext.begin))));
CurExtPos = ((double)(ext.q + ext.p))/2.0;
if ( NExtent>0 && CurExtPos > PrevExtPos /* prevent devision by zero in a case of multiple lexize */ )
SumDist += 1.0/( CurExtPos - PrevExtPos );
CurExtPos = ((double) (ext.q + ext.p)) / 2.0;
if (NExtent > 0 && CurExtPos > PrevExtPos /* prevent devision by
* zero in a case of
multiple lexize */ )
SumDist += 1.0 / (CurExtPos - PrevExtPos);
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));
if ( method & RANK_NORM_LENGTH ) {
if (method & RANK_NORM_LENGTH)
{
len = cnt_length(txt);
if ( len>0 )
if (len > 0)
Wdoc /= (double) len;
}
if ( (method & RANK_NORM_EXTDIST) && SumDist > 0 )
Wdoc /= ((double)NExtent) / SumDist;
if ((method & RANK_NORM_EXTDIST) && SumDist > 0)
Wdoc /= ((double) NExtent) / SumDist;
if ( (method & RANK_NORM_UNIQ) && txt->size > 0 )
Wdoc /= (double)( txt->size );
if ((method & RANK_NORM_UNIQ) && txt->size > 0)
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);
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);
return (float4)Wdoc;
}
return (float4) Wdoc;
}
Datum
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));
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(2));
int method = DEF_NORM_METHOD;
@ -729,7 +740,7 @@ rank_cd(PG_FUNCTION_ARGS)
if (PG_NARGS() == 4)
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(txt, 1);
@ -744,10 +755,10 @@ rank_cd_def(PG_FUNCTION_ARGS)
{
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
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(query, 1);
@ -791,7 +802,7 @@ get_covers(PG_FUNCTION_ARGS)
text *out;
char *cptr;
DocRepresentation *doc;
int olddwpos = 0;
int olddwpos = 0;
int ncover = 1;
Extention ext;
@ -833,7 +844,7 @@ get_covers(PG_FUNCTION_ARGS)
}
qsort((void *) dw, dlen, sizeof(DocWord), compareDocWord);
MemSet( &ext, 0, sizeof(Extention) );
MemSet(&ext, 0, sizeof(Extention));
while (Cover(doc, rlen, query, &ext))
{
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 */
#ifdef __cplusplus
extern "C" {
extern "C"
{
#endif
extern struct SN_env * russian_UTF_8_create_env(void);
extern void russian_UTF_8_close_env(struct SN_env * z);
extern struct SN_env *russian_UTF_8_create_env(void);
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
}
#endif
#endif

View File

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

View File

@ -301,14 +301,15 @@ parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
LexizeInit(&ldata, cfg);
do {
do
{
type = DatumGetInt32(FunctionCall3(
&(prsobj->getlexeme_info),
PointerGetDatum(prsobj->prs),
PointerGetDatum(&lemm),
&(prsobj->getlexeme_info),
PointerGetDatum(prsobj->prs),
PointerGetDatum(&lemm),
PointerGetDatum(&lenlemm)));
if (type>0 && lenlemm >= MAXSTRLEN)
if (type > 0 && lenlemm >= MAXSTRLEN)
{
#ifdef IGNORE_LONGLEXEME
ereport(NOTICE,
@ -324,9 +325,9 @@ parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
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 */
@ -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));
}
if ( ptr->flags & TSL_ADDPOS )
if (ptr->flags & TSL_ADDPOS)
prs->pos++;
prs->words[prs->curwords].len = strlen(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++;
}
pfree(norms);
}
} while(type>0);
}
} while (type > 0);
FunctionCall1(
&(prsobj->end_info),
@ -407,30 +408,35 @@ hlfinditem(HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int buflen)
}
static void
addHLParsedLex(HLPRSTEXT *prs, QUERYTYPE * query, ParsedLex *lexs, TSLexeme *norms) {
ParsedLex *tmplexs;
TSLexeme *ptr;
addHLParsedLex(HLPRSTEXT * prs, QUERYTYPE * query, ParsedLex * lexs, TSLexeme * norms)
{
ParsedLex *tmplexs;
TSLexeme *ptr;
while( lexs ) {
if ( lexs->type > 0 )
while (lexs)
{
if (lexs->type > 0)
hladdword(prs, lexs->lemm, lexs->lenlemm, lexs->type);
ptr = norms;
while( ptr && ptr->lexeme ) {
while (ptr && ptr->lexeme)
{
hlfinditem(prs, query, ptr->lexeme, strlen(ptr->lexeme));
ptr++;
}
tmplexs = lexs->next;
pfree( lexs );
pfree(lexs);
lexs = tmplexs;
}
if ( norms ) {
if (norms)
{
ptr = norms;
while( ptr->lexeme ) {
pfree( ptr->lexeme );
while (ptr->lexeme)
{
pfree(ptr->lexeme);
ptr++;
}
pfree(norms);
@ -445,8 +451,8 @@ hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4
char *lemm = NULL;
WParserInfo *prsobj = findprs(cfg->prs_id);
LexizeData ldata;
TSLexeme *norms;
ParsedLex *lexs;
TSLexeme *norms;
ParsedLex *lexs;
prsobj->prs = (void *) DatumGetPointer(
FunctionCall2(
@ -458,14 +464,15 @@ hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4
LexizeInit(&ldata, cfg);
do {
do
{
type = DatumGetInt32(FunctionCall3(
&(prsobj->getlexeme_info),
PointerGetDatum(prsobj->prs),
PointerGetDatum(&lemm),
PointerGetDatum(&lenlemm)));
&(prsobj->getlexeme_info),
PointerGetDatum(prsobj->prs),
PointerGetDatum(&lemm),
PointerGetDatum(&lenlemm)));
if (type>0 && lenlemm >= MAXSTRLEN)
if (type > 0 && lenlemm >= MAXSTRLEN)
{
#ifdef IGNORE_LONGLEXEME
ereport(NOTICE,
@ -481,14 +488,15 @@ hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4
LexizeAddLemm(&ldata, type, lemm, lenlemm);
do {
if ( (norms = LexizeExec(&ldata,&lexs)) != NULL )
do
{
if ((norms = LexizeExec(&ldata, &lexs)) != NULL)
addHLParsedLex(prs, query, lexs, norms);
else
else
addHLParsedLex(prs, query, lexs, NULL);
} while( norms );
} while (norms);
} while( type>0 );
} while (type > 0);
FunctionCall1(
&(prsobj->end_info),

View File

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

View File

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

View File

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

View File

@ -477,7 +477,8 @@ ts_stat_sql(text *txt, text *ws)
buf = VARDATA(ws);
while (buf - VARDATA(ws) < VARSIZE(ws) - VARHDRSZ)
{
if ( pg_mblen(buf) == 1 ) {
if (pg_mblen(buf) == 1)
{
switch (*buf)
{
case 'A':
@ -500,7 +501,7 @@ ts_stat_sql(text *txt, text *ws)
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 WAITENDWORD 2
#define WAITENDWORD 2
#define WAITNEXTCHAR 3
#define WAITENDCMPLX 4
#define WAITPOSINFO 5
#define WAITPOSINFO 5
#define INPOSINFO 6
#define WAITPOSDELIM 7
#define WAITCHARCMPLX 8
#define WAITCHARCMPLX 8
#define RESIZEPRSBUF \
do { \
@ -200,9 +200,9 @@ gettoken_tsvector(TI_IN_STATE * state)
{
if (*(state->prsbuf) == '\0')
return 0;
else if ( t_iseq(state->prsbuf, '\'') )
else if (t_iseq(state->prsbuf, '\''))
state->state = WAITENDCMPLX;
else if ( t_iseq(state->prsbuf, '\\') )
else if (t_iseq(state->prsbuf, '\\'))
{
state->state = WAITNEXTCHAR;
oldstate = WAITENDWORD;
@ -214,7 +214,7 @@ gettoken_tsvector(TI_IN_STATE * state)
else if (!t_isspace(state->prsbuf))
{
COPYCHAR(state->curpos, state->prsbuf);
state->curpos+=pg_mblen(state->prsbuf);
state->curpos += pg_mblen(state->prsbuf);
state->state = WAITENDWORD;
}
}
@ -228,18 +228,18 @@ gettoken_tsvector(TI_IN_STATE * state)
{
RESIZEPRSBUF;
COPYCHAR(state->curpos, state->prsbuf);
state->curpos+=pg_mblen(state->prsbuf);
state->curpos += pg_mblen(state->prsbuf);
state->state = oldstate;
}
}
else if (state->state == WAITENDWORD)
{
if ( t_iseq(state->prsbuf, '\\') )
if (t_iseq(state->prsbuf, '\\'))
{
state->state = WAITNEXTCHAR;
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)))
{
RESIZEPRSBUF;
@ -250,7 +250,7 @@ gettoken_tsvector(TI_IN_STATE * state)
*(state->curpos) = '\0';
return 1;
}
else if ( t_iseq(state->prsbuf,':') )
else if (t_iseq(state->prsbuf, ':'))
{
if (state->curpos == state->word)
ereport(ERROR,
@ -266,15 +266,16 @@ gettoken_tsvector(TI_IN_STATE * state)
{
RESIZEPRSBUF;
COPYCHAR(state->curpos, state->prsbuf);
state->curpos+=pg_mblen(state->prsbuf);
state->curpos += pg_mblen(state->prsbuf);
}
}
else if (state->state == WAITENDCMPLX)
{
if ( t_iseq(state->prsbuf, '\'') ) {
state->state = WAITCHARCMPLX;
if (t_iseq(state->prsbuf, '\''))
{
state->state = WAITCHARCMPLX;
}
else if ( t_iseq(state->prsbuf, '\\') )
else if (t_iseq(state->prsbuf, '\\'))
{
state->state = WAITNEXTCHAR;
oldstate = WAITENDCMPLX;
@ -287,18 +288,20 @@ gettoken_tsvector(TI_IN_STATE * state)
{
RESIZEPRSBUF;
COPYCHAR(state->curpos, state->prsbuf);
state->curpos+=pg_mblen(state->prsbuf);
state->curpos += pg_mblen(state->prsbuf);
}
}
else if (state->state == WAITCHARCMPLX)
{
if ( t_iseq(state->prsbuf, '\'') )
if (t_iseq(state->prsbuf, '\''))
{
RESIZEPRSBUF;
COPYCHAR(state->curpos, state->prsbuf);
state->curpos+=pg_mblen(state->prsbuf);
state->curpos += pg_mblen(state->prsbuf);
state->state = WAITENDCMPLX;
} else {
}
else
{
RESIZEPRSBUF;
*(state->curpos) = '\0';
if (state->curpos == state->word)
@ -312,12 +315,12 @@ gettoken_tsvector(TI_IN_STATE * state)
}
else
state->state = WAITPOSINFO;
continue; /* recheck current character */
continue; /* recheck current character */
}
}
else if (state->state == WAITPOSINFO)
{
if ( t_iseq(state->prsbuf, ':') )
if (t_iseq(state->prsbuf, ':'))
state->state = INPOSINFO;
else
return 1;
@ -353,9 +356,9 @@ gettoken_tsvector(TI_IN_STATE * state)
}
else if (state->state == WAITPOSDELIM)
{
if ( t_iseq(state->prsbuf, ',') )
if (t_iseq(state->prsbuf, ','))
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)]))
ereport(ERROR,
@ -363,7 +366,7 @@ gettoken_tsvector(TI_IN_STATE * state)
errmsg("syntax error")));
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)]))
ereport(ERROR,
@ -371,7 +374,7 @@ gettoken_tsvector(TI_IN_STATE * state)
errmsg("syntax error")));
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)]))
ereport(ERROR,
@ -379,7 +382,7 @@ gettoken_tsvector(TI_IN_STATE * state)
errmsg("syntax error")));
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)]))
ereport(ERROR,
@ -400,7 +403,7 @@ gettoken_tsvector(TI_IN_STATE * state)
elog(ERROR, "internal error");
/* get next char */
state->prsbuf+=pg_mblen(state->prsbuf);
state->prsbuf += pg_mblen(state->prsbuf);
}
return 0;
@ -423,7 +426,7 @@ tsvector_in(PG_FUNCTION_ARGS)
SET_FUNCOID();
pg_verifymbstr( buf, strlen(buf), false );
pg_verifymbstr(buf, strlen(buf), false);
state.prsbuf = buf;
state.len = 32;
state.word = (char *) palloc(state.len);
@ -517,13 +520,14 @@ tsvector_out(PG_FUNCTION_ARGS)
lenbuf = 0,
pp;
WordEntry *ptr = ARRPTR(out);
char *curbegin, *curin,
char *curbegin,
*curin,
*curout;
lenbuf = out->size * 2 /* '' */ + out->size - 1 /* space */ + 2 /* \0 */ ;
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)
lenbuf += 7 * POSDATALEN(out, &(ptr[i]));
}
@ -535,10 +539,11 @@ tsvector_out(PG_FUNCTION_ARGS)
if (i != 0)
*curout++ = ' ';
*curout++ = '\'';
while ( curin-curbegin < ptr->len )
while (curin - curbegin < ptr->len)
{
int len = pg_mblen(curin);
if ( t_iseq(curin, '\'') )
int len = pg_mblen(curin);
if (t_iseq(curin, '\''))
{
int4 pos = curout - outbuf;
@ -546,7 +551,7 @@ tsvector_out(PG_FUNCTION_ARGS)
curout = outbuf + pos;
*curout++ = '\'';
}
while(len--)
while (len--)
*curout++ = *curin++;
}
*curout++ = '\'';
@ -983,36 +988,49 @@ silly_cmp_tsvector(const tsvector * a, const tsvector * b)
{
WordEntry *aptr = ARRPTR(a);
WordEntry *bptr = ARRPTR(b);
int i = 0;
int res;
int i = 0;
int res;
for(i=0;i<a->size;i++) {
if ( aptr->haspos != bptr->haspos ) {
return ( aptr->haspos > bptr->haspos ) ? -1 : 1;
} else if ( aptr->len != bptr->len ) {
return ( aptr->len > bptr->len ) ? -1 : 1;
} else if ( (res=strncmp(STRPTR(a) + aptr->pos, STRPTR(b) + bptr->pos, bptr->len))!= 0 ) {
for (i = 0; i < a->size; i++)
{
if (aptr->haspos != bptr->haspos)
{
return (aptr->haspos > bptr->haspos) ? -1 : 1;
}
else if (aptr->len != bptr->len)
{
return (aptr->len > bptr->len) ? -1 : 1;
}
else if ((res = strncmp(STRPTR(a) + aptr->pos, STRPTR(b) + bptr->pos, bptr->len)) != 0)
{
return res;
} else if ( aptr->haspos ) {
WordEntryPos *ap = POSDATAPTR(a, aptr);
WordEntryPos *bp = POSDATAPTR(b, bptr);
int j;
}
else if (aptr->haspos)
{
WordEntryPos *ap = POSDATAPTR(a, aptr);
WordEntryPos *bp = POSDATAPTR(b, bptr);
int j;
if ( POSDATALEN(a, aptr) != POSDATALEN(b, bptr) )
return ( POSDATALEN(a, aptr) > POSDATALEN(b, bptr) ) ? -1 : 1;
if (POSDATALEN(a, aptr) != POSDATALEN(b, bptr))
return (POSDATALEN(a, aptr) > POSDATALEN(b, bptr)) ? -1 : 1;
for(j=0;j<POSDATALEN(a, aptr);j++) {
if ( WEP_GETPOS(*ap) != WEP_GETPOS(*bp) ) {
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;
for (j = 0; j < POSDATALEN(a, aptr); j++)
{
if (WEP_GETPOS(*ap) != WEP_GETPOS(*bp))
{
return (WEP_GETPOS(*ap) > WEP_GETPOS(*bp)) ? -1 : 1;
}
else if (WEP_GETWEIGHT(*ap) != WEP_GETWEIGHT(*bp))
{
return (WEP_GETWEIGHT(*ap) > WEP_GETWEIGHT(*bp)) ? -1 : 1;
}
ap++, bp++;
}
}
aptr++; bptr++;
aptr++;
bptr++;
}
}

View File

@ -49,17 +49,17 @@ typedef uint16 WordEntryPos;
/*
* 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
* 3) Array of WordEntry - sorted array, comparison based on word's length
* and strncmp(). WordEntry->pos points number of
* bytes from end of WordEntry array to start of
* corresponding lexeme.
* 4) Lexeme's storage:
* SHORTALIGNED(lexeme) and position information if it exists
* Position information: first int2 - is a number of positions and it
* follows array of WordEntryPos
*/
* SHORTALIGNED(lexeme) and position information if it exists
* Position information: first int2 - is a number of positions and it
* follows array of WordEntryPos
*/
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"
@ -458,7 +458,7 @@ static TParserStateActionItem actionTPS_InVerVersion[] = {
static TParserStateActionItem actionTPS_InSVerVersion[] = {
{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}
};
@ -613,7 +613,7 @@ static TParserStateActionItem actionTPS_InTagEnd[] = {
static TParserStateActionItem actionTPS_InCommentFirst[] = {
{p_isEOF, 0, A_POP, TPS_Null, 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},
{NULL, 0, A_POP, TPS_Null, 0, NULL}
@ -753,10 +753,10 @@ static TParserStateActionItem actionTPS_InPathFirstFirst[] = {
};
static TParserStateActionItem actionTPS_InPathSecond[] = {
{p_isEOF, 0, A_BINGO|A_CLEAR, TPS_Base, FILEPATH, NULL},
{p_iseqC, '/', A_NEXT|A_PUSH, TPS_InFileFirst, 0, NULL},
{p_iseqC, '/', A_BINGO|A_CLEAR, TPS_Base, FILEPATH, NULL},
{p_isspace, 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_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}
};

View File

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

View File

@ -671,7 +671,7 @@ xpath_table(PG_FUNCTION_ARGS)
* document */
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 */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))

View File

@ -16,7 +16,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.110 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.111 2006/10/04 00:29:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -1294,7 +1294,7 @@ slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
{
if (tuple == NULL) /* internal error */
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");
return heap_getsysattr(tuple, attnum, tupleDesc, isnull);
}
@ -1480,7 +1480,7 @@ slot_attisnull(TupleTableSlot *slot, int attnum)
{
if (tuple == NULL) /* internal error */
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");
return heap_attisnull(tuple, attnum);
}

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.98 2006/08/12 02:52:03 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.99 2006/10/04 00:29:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -127,8 +127,8 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
}
/*
* If we are supposed to emit row descriptions,
* then send the tuple descriptor of the tuples.
* If we are supposed to emit row descriptions, then send the tuple
* descriptor of the tuples.
*/
if (myState->sendDescrip)
SendRowDescriptionMessage(typeinfo,

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.1 2006/07/03 22:45:36 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/common/reloptions.c,v 1.2 2006/10/04 00:29:47 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -59,7 +59,7 @@ transformRelOptions(Datum oldOptions, List *defList,
/* Copy any oldOptions that aren't to be replaced */
if (oldOptions != (Datum) 0)
{
ArrayType *array = DatumGetArrayTypeP(oldOptions);
ArrayType *array = DatumGetArrayTypeP(oldOptions);
Datum *oldoptions;
int noldoptions;
int i;
@ -71,15 +71,15 @@ transformRelOptions(Datum oldOptions, List *defList,
for (i = 0; i < noldoptions; i++)
{
text *oldoption = DatumGetTextP(oldoptions[i]);
char *text_str = (char *) VARATT_DATA(oldoption);
int text_len = VARATT_SIZE(oldoption) - VARHDRSZ;
text *oldoption = DatumGetTextP(oldoptions[i]);
char *text_str = (char *) VARATT_DATA(oldoption);
int text_len = VARATT_SIZE(oldoption) - VARHDRSZ;
/* Search for a match in defList */
foreach(cell, defList)
{
DefElem *def = lfirst(cell);
int kw_len = strlen(def->defname);
DefElem *def = lfirst(cell);
int kw_len = strlen(def->defname);
if (text_len > kw_len && text_str[kw_len] == '=' &&
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
* the user didn't say RESET (option=val). (Must do this because the
* grammar doesn't enforce it.)
* If CREATE/SET, add new options to array; if RESET, just check that the
* user didn't say RESET (option=val). (Must do this because the grammar
* doesn't enforce it.)
*/
foreach(cell, defList)
{
DefElem *def = lfirst(cell);
DefElem *def = lfirst(cell);
if (isReset)
{
if (def->arg != NULL)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("RESET must not include values for parameters")));
errmsg("RESET must not include values for parameters")));
}
else
{
text *t;
text *t;
const char *value;
Size len;
Size len;
if (ignoreOids && pg_strcasecmp(def->defname, "oids") == 0)
continue;
/*
* Flatten the DefElem into a text string like "name=arg".
* If we have just "name", assume "name=true" is meant.
* Flatten the DefElem into a text string like "name=arg". If we
* have just "name", assume "name=true" is meant.
*/
if (def->arg != NULL)
value = defGetString(def);
@ -163,10 +163,10 @@ transformRelOptions(Datum oldOptions, List *defList,
* containing the corresponding value, or NULL if the keyword does not appear.
*/
void
parseRelOptions(Datum options, int numkeywords, const char * const *keywords,
parseRelOptions(Datum options, int numkeywords, const char *const * keywords,
char **values, bool validate)
{
ArrayType *array;
ArrayType *array;
Datum *optiondatums;
int noptions;
int i;
@ -187,21 +187,21 @@ parseRelOptions(Datum options, int numkeywords, const char * const *keywords,
for (i = 0; i < noptions; i++)
{
text *optiontext = DatumGetTextP(optiondatums[i]);
char *text_str = (char *) VARATT_DATA(optiontext);
int text_len = VARATT_SIZE(optiontext) - VARHDRSZ;
int j;
text *optiontext = DatumGetTextP(optiondatums[i]);
char *text_str = (char *) VARATT_DATA(optiontext);
int text_len = VARATT_SIZE(optiontext) - VARHDRSZ;
int j;
/* Search for a match in keywords */
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] == '=' &&
pg_strncasecmp(text_str, keywords[j], kw_len) == 0)
{
char *value;
int value_len;
char *value;
int value_len;
if (values[j] && validate)
ereport(ERROR,
@ -218,8 +218,8 @@ parseRelOptions(Datum options, int numkeywords, const char * const *keywords,
}
if (j >= numkeywords && validate)
{
char *s;
char *p;
char *s;
char *p;
s = DatumGetCString(DirectFunctionCall1(textout, optiondatums[i]));
p = strchr(s, '=');
@ -240,17 +240,17 @@ bytea *
default_reloptions(Datum reloptions, bool validate,
int minFillfactor, int defaultFillfactor)
{
static const char * const default_keywords[1] = { "fillfactor" };
char *values[1];
int32 fillfactor;
static const char *const default_keywords[1] = {"fillfactor"};
char *values[1];
int32 fillfactor;
StdRdOptions *result;
parseRelOptions(reloptions, 1, default_keywords, values, validate);
/*
* If no options, we can just return NULL rather than doing anything.
* (defaultFillfactor is thus not used, but we require callers to pass
* it anyway since we would need it if more options were added.)
* (defaultFillfactor is thus not used, but we require callers to pass it
* anyway since we would need it if more options were added.)
*/
if (values[0] == NULL)
return NULL;

View File

@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* 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) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginarrayproc.c,v 1.5 2006/09/10 20:14:20 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginarrayproc.c,v 1.6 2006/10/04 00:29:47 momjian Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@ -23,64 +23,73 @@
#define GinContainedStrategy 3
#define GinEqualStrategy 4
#define ARRAYCHECK(x) do { \
#define ARRAYCHECK(x) do { \
if ( ARR_HASNULL(x) ) \
ereport(ERROR, \
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \
errmsg("array must not contain nulls"))); \
} while(0)
ereport(ERROR, \
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \
errmsg("array must not contain nulls"))); \
} while(0)
/*
* Function used as extractValue and extractQuery both
*/
Datum
ginarrayextract(PG_FUNCTION_ARGS) {
ArrayType *array;
uint32 *nentries = (uint32*)PG_GETARG_POINTER(1);
Datum *entries = NULL;
int16 elmlen;
bool elmbyval;
char elmalign;
ginarrayextract(PG_FUNCTION_ARGS)
{
ArrayType *array;
uint32 *nentries = (uint32 *) PG_GETARG_POINTER(1);
Datum *entries = NULL;
int16 elmlen;
bool elmbyval;
char elmalign;
/* we should guarantee that array will not be destroyed during all operation */
/*
* we should guarantee that array will not be destroyed during all
* operation
*/
array = PG_GETARG_ARRAYTYPE_P_COPY(0);
ARRAYCHECK(array);
get_typlenbyvalalign(ARR_ELEMTYPE(array),
&elmlen, &elmbyval, &elmalign);
&elmlen, &elmbyval, &elmalign);
deconstruct_array(array,
ARR_ELEMTYPE(array),
elmlen, elmbyval, elmalign,
&entries, NULL, (int*)nentries);
ARR_ELEMTYPE(array),
elmlen, elmbyval, elmalign,
&entries, NULL, (int *) nentries);
/* we should not free array, entries[i] points into it */
PG_RETURN_POINTER(entries);
}
Datum
ginarrayconsistent(PG_FUNCTION_ARGS) {
bool *check = (bool*)PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1);
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
int res, i, nentries;
ginarrayconsistent(PG_FUNCTION_ARGS)
{
bool *check = (bool *) PG_GETARG_POINTER(0);
StrategyNumber strategy = PG_GETARG_UINT16(1);
ArrayType *query = PG_GETARG_ARRAYTYPE_P(2);
int res,
i,
nentries;
/* ARRAYCHECK was already done by previous ginarrayextract call */
switch( strategy ) {
switch (strategy)
{
case GinOverlapStrategy:
case GinContainedStrategy:
/* at least one element in check[] is true, so result = true */
/* at least one element in check[] is true, so result = true */
res = TRUE;
break;
case GinContainsStrategy:
case GinEqualStrategy:
nentries=ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query));
nentries = ArrayGetNItems(ARR_NDIM(query), ARR_DIMS(query));
res = TRUE;
for(i=0;i<nentries;i++)
if ( !check[i] ) {
for (i = 0; i < nentries; i++)
if (!check[i])
{
res = FALSE;
break;
}

View File

@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* 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) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginbtree.c,v 1.4 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginbtree.c,v 1.5 2006/10/04 00:29:47 momjian Exp $
*-------------------------------------------------------------------------
*/
@ -20,24 +20,29 @@
* Locks buffer by needed method for search.
*/
static int
ginTraverseLock(Buffer buffer, bool searchMode) {
Page page;
int access=GIN_SHARE;
ginTraverseLock(Buffer buffer, bool searchMode)
{
Page page;
int access = GIN_SHARE;
LockBuffer(buffer, GIN_SHARE);
page = BufferGetPage( buffer );
if ( GinPageIsLeaf(page) ) {
if ( searchMode == FALSE ) {
page = BufferGetPage(buffer);
if (GinPageIsLeaf(page))
{
if (searchMode == FALSE)
{
/* we should relock our page */
LockBuffer(buffer, GIN_UNLOCK);
LockBuffer(buffer, GIN_EXCLUSIVE);
/* But root can become non-leaf during relock */
if ( !GinPageIsLeaf(page) ) {
/* resore old lock type (very rare) */
if (!GinPageIsLeaf(page))
{
/* resore old lock type (very rare) */
LockBuffer(buffer, GIN_UNLOCK);
LockBuffer(buffer, GIN_SHARE);
} else
}
else
access = GIN_EXCLUSIVE;
}
}
@ -45,9 +50,10 @@ ginTraverseLock(Buffer buffer, bool searchMode) {
return access;
}
GinBtreeStack*
ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno) {
GinBtreeStack *stack = (GinBtreeStack*)palloc(sizeof(GinBtreeStack));
GinBtreeStack *
ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno)
{
GinBtreeStack *stack = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
stack->blkno = blkno;
stack->buffer = ReadBuffer(btree->index, stack->blkno);
@ -62,63 +68,73 @@ ginPrepareFindLeafPage(GinBtree btree, BlockNumber blkno) {
/*
* Locates leaf page contained tuple
*/
GinBtreeStack*
ginFindLeafPage(GinBtree btree, GinBtreeStack *stack) {
bool isfirst=TRUE;
GinBtreeStack *
ginFindLeafPage(GinBtree btree, GinBtreeStack *stack)
{
bool isfirst = TRUE;
BlockNumber rootBlkno;
if ( !stack )
if (!stack)
stack = ginPrepareFindLeafPage(btree, GIN_ROOT_BLKNO);
rootBlkno = stack->blkno;
for(;;) {
Page page;
for (;;)
{
Page page;
BlockNumber child;
int access=GIN_SHARE;
int access = GIN_SHARE;
stack->off = InvalidOffsetNumber;
page = BufferGetPage( stack->buffer );
if ( isfirst ) {
if ( GinPageIsLeaf(page) && !btree->searchMode )
page = BufferGetPage(stack->buffer);
if (isfirst)
{
if (GinPageIsLeaf(page) && !btree->searchMode)
access = GIN_EXCLUSIVE;
isfirst = FALSE;
} else
}
else
access = ginTraverseLock(stack->buffer, btree->searchMode);
/* ok, page is correctly locked, we should check to move right ..,
root never has a right link, so small optimization */
while( btree->fullScan==FALSE && stack->blkno != rootBlkno && btree->isMoveRight(btree, page) ) {
/*
* ok, page is correctly locked, we should check to move right ..,
* root never has a right link, so small optimization
*/
while (btree->fullScan == FALSE && stack->blkno != rootBlkno && btree->isMoveRight(btree, page))
{
BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
if ( rightlink==InvalidBlockNumber )
if (rightlink == InvalidBlockNumber)
/* rightmost page */
break;
stack->blkno = rightlink;
LockBuffer(stack->buffer, GIN_UNLOCK);
stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno);
LockBuffer(stack->buffer, access);
page = BufferGetPage( stack->buffer );
LockBuffer(stack->buffer, access);
page = BufferGetPage(stack->buffer);
}
if ( GinPageIsLeaf(page) ) /* we found, return locked page */
if (GinPageIsLeaf(page)) /* we found, return locked page */
return stack;
/* now we have correct buffer, try to find child */
child = btree->findChildPage(btree, stack);
LockBuffer(stack->buffer, GIN_UNLOCK);
Assert( child != InvalidBlockNumber );
Assert( stack->blkno != child );
Assert(child != InvalidBlockNumber);
Assert(stack->blkno != child);
if ( btree->searchMode ) {
if (btree->searchMode)
{
/* in search mode we may forget path to leaf */
stack->blkno = child;
stack->buffer = ReleaseAndReadBuffer( stack->buffer, btree->index, stack->blkno );
} else {
GinBtreeStack *ptr = (GinBtreeStack*)palloc(sizeof(GinBtreeStack));
stack->buffer = ReleaseAndReadBuffer(stack->buffer, btree->index, stack->blkno);
}
else
{
GinBtreeStack *ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
ptr->parent = stack;
stack = ptr;
@ -133,93 +149,110 @@ ginFindLeafPage(GinBtree btree, GinBtreeStack *stack) {
}
void
freeGinBtreeStack( GinBtreeStack *stack ) {
while(stack) {
GinBtreeStack *tmp = stack->parent;
if ( stack->buffer != InvalidBuffer )
freeGinBtreeStack(GinBtreeStack *stack)
{
while (stack)
{
GinBtreeStack *tmp = stack->parent;
if (stack->buffer != InvalidBuffer)
ReleaseBuffer(stack->buffer);
pfree( stack );
pfree(stack);
stack = tmp;
}
}
/*
* Try to find parent for current stack position, returns correct
* Try to find parent for current stack position, returns correct
* parent and child's offset in stack->parent.
* Function should never release root page to prevent conflicts
* with vacuum process
*/
void
findParents( GinBtree btree, GinBtreeStack *stack,
BlockNumber rootBlkno) {
findParents(GinBtree btree, GinBtreeStack *stack,
BlockNumber rootBlkno)
{
Page page;
Buffer buffer;
BlockNumber blkno, leftmostBlkno;
Page page;
Buffer buffer;
BlockNumber blkno,
leftmostBlkno;
OffsetNumber offset;
GinBtreeStack *root = stack->parent;
GinBtreeStack *ptr;
GinBtreeStack *root = stack->parent;
GinBtreeStack *ptr;
if ( !root ) {
if (!root)
{
/* XLog mode... */
root = (GinBtreeStack*)palloc(sizeof(GinBtreeStack));
root = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
root->blkno = rootBlkno;
root->buffer = ReadBuffer(btree->index, rootBlkno);
LockBuffer(root->buffer, GIN_EXCLUSIVE);
root->parent = NULL;
} else {
/* find root, we should not release root page until update is finished!! */
while( root->parent ) {
ReleaseBuffer( root->buffer );
}
else
{
/*
* find root, we should not release root page until update is
* finished!!
*/
while (root->parent)
{
ReleaseBuffer(root->buffer);
root = root->parent;
}
Assert( root->blkno == rootBlkno );
Assert( BufferGetBlockNumber(root->buffer) == rootBlkno );
Assert(root->blkno == rootBlkno);
Assert(BufferGetBlockNumber(root->buffer) == rootBlkno);
LockBuffer(root->buffer, GIN_EXCLUSIVE);
}
root->off = InvalidOffsetNumber;
page = BufferGetPage(root->buffer);
Assert( !GinPageIsLeaf(page) );
Assert(!GinPageIsLeaf(page));
/* check trivial case */
if ( (root->off = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) != InvalidOffsetNumber ) {
if ((root->off = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) != InvalidOffsetNumber)
{
stack->parent = root;
return;
}
leftmostBlkno = blkno = btree->getLeftMostPage(btree, page);
LockBuffer(root->buffer, GIN_UNLOCK );
Assert( blkno!=InvalidBlockNumber );
LockBuffer(root->buffer, GIN_UNLOCK);
Assert(blkno != InvalidBlockNumber);
for(;;) {
for (;;)
{
buffer = ReadBuffer(btree->index, blkno);
LockBuffer(buffer, GIN_EXCLUSIVE);
page = BufferGetPage(buffer);
if ( GinPageIsLeaf(page) )
if (GinPageIsLeaf(page))
elog(ERROR, "Lost path");
leftmostBlkno = btree->getLeftMostPage(btree, page);
while( (offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber))==InvalidOffsetNumber ) {
while ((offset = btree->findChildPtr(btree, page, stack->blkno, InvalidOffsetNumber)) == InvalidOffsetNumber)
{
blkno = GinPageGetOpaque(page)->rightlink;
LockBuffer(buffer,GIN_UNLOCK);
LockBuffer(buffer, GIN_UNLOCK);
ReleaseBuffer(buffer);
if ( blkno == InvalidBlockNumber )
if (blkno == InvalidBlockNumber)
break;
buffer = ReadBuffer(btree->index, blkno);
LockBuffer(buffer, GIN_EXCLUSIVE);
page = BufferGetPage(buffer);
}
if ( blkno != InvalidBlockNumber ) {
ptr = (GinBtreeStack*)palloc(sizeof(GinBtreeStack));
if (blkno != InvalidBlockNumber)
{
ptr = (GinBtreeStack *) palloc(sizeof(GinBtreeStack));
ptr->blkno = blkno;
ptr->buffer = buffer;
ptr->parent = root; /* it's may be wrong, but in next call we will correct */
ptr->parent = root; /* it's may be wrong, but in next call we will
* correct */
ptr->off = offset;
stack->parent = ptr;
return;
@ -233,79 +266,94 @@ findParents( GinBtree btree, GinBtreeStack *stack,
* Insert value (stored in GinBtree) to tree descibed by stack
*/
void
ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
GinBtreeStack *parent = stack;
BlockNumber rootBlkno = InvalidBuffer;
Page page, rpage, lpage;
ginInsertValue(GinBtree btree, GinBtreeStack *stack)
{
GinBtreeStack *parent = stack;
BlockNumber rootBlkno = InvalidBuffer;
Page page,
rpage,
lpage;
/* remember root BlockNumber */
while( parent ) {
while (parent)
{
rootBlkno = parent->blkno;
parent = parent->parent;
}
while( stack ) {
while (stack)
{
XLogRecData *rdata;
BlockNumber savedRightLink;
BlockNumber savedRightLink;
page = BufferGetPage( stack->buffer );
page = BufferGetPage(stack->buffer);
savedRightLink = GinPageGetOpaque(page)->rightlink;
if ( btree->isEnoughSpace( btree, stack->buffer, stack->off ) ) {
if (btree->isEnoughSpace(btree, stack->buffer, stack->off))
{
START_CRIT_SECTION();
btree->placeToPage( btree, stack->buffer, stack->off, &rdata );
btree->placeToPage(btree, stack->buffer, stack->off, &rdata);
if (!btree->index->rd_istemp) {
XLogRecPtr recptr;
if (!btree->index->rd_istemp)
{
XLogRecPtr recptr;
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_INSERT, rdata);
PageSetLSN(page, recptr);
PageSetTLI(page, ThisTimeLineID);
}
}
MarkBufferDirty( stack->buffer );
MarkBufferDirty(stack->buffer);
UnlockReleaseBuffer(stack->buffer);
END_CRIT_SECTION();
freeGinBtreeStack(stack->parent);
return;
} else {
Buffer rbuffer = GinNewBuffer(btree->index);
Page newlpage;
}
else
{
Buffer rbuffer = GinNewBuffer(btree->index);
Page newlpage;
/* newlpage is a pointer to memory page, it does'nt assosiates with buffer,
stack->buffer shoud be untouched */
newlpage = btree->splitPage( btree, stack->buffer, rbuffer, stack->off, &rdata );
/*
* newlpage is a pointer to memory page, it does'nt assosiates
* with buffer, stack->buffer shoud be untouched
*/
newlpage = btree->splitPage(btree, stack->buffer, rbuffer, stack->off, &rdata);
((ginxlogSplit*)(rdata->data))->rootBlkno = rootBlkno;
((ginxlogSplit *) (rdata->data))->rootBlkno = rootBlkno;
parent = stack->parent;
if ( parent == NULL ) {
/* split root, so we need to allocate new left page and
place pointer on root to left and right page */
Buffer lbuffer = GinNewBuffer(btree->index);
if (parent == NULL)
{
/*
* split root, so we need to allocate new left page and place
* pointer on root to left and right page
*/
Buffer lbuffer = GinNewBuffer(btree->index);
((ginxlogSplit*)(rdata->data))->isRootSplit = TRUE;
((ginxlogSplit*)(rdata->data))->rrlink = InvalidBlockNumber;
((ginxlogSplit *) (rdata->data))->isRootSplit = TRUE;
((ginxlogSplit *) (rdata->data))->rrlink = InvalidBlockNumber;
page = BufferGetPage( stack->buffer );
lpage = BufferGetPage( lbuffer );
rpage = BufferGetPage( rbuffer );
page = BufferGetPage(stack->buffer);
lpage = BufferGetPage(lbuffer);
rpage = BufferGetPage(rbuffer);
GinPageGetOpaque(rpage)->rightlink = InvalidBlockNumber;
GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
((ginxlogSplit*)(rdata->data))->lblkno = BufferGetBlockNumber(lbuffer);
((ginxlogSplit *) (rdata->data))->lblkno = BufferGetBlockNumber(lbuffer);
START_CRIT_SECTION();
GinInitBuffer( stack->buffer, GinPageGetOpaque(newlpage)->flags & ~GIN_LEAF );
PageRestoreTempPage( newlpage, lpage );
btree->fillRoot( btree, stack->buffer, lbuffer, rbuffer );
if (!btree->index->rd_istemp) {
XLogRecPtr recptr;
GinInitBuffer(stack->buffer, GinPageGetOpaque(newlpage)->flags & ~GIN_LEAF);
PageRestoreTempPage(newlpage, lpage);
btree->fillRoot(btree, stack->buffer, lbuffer, rbuffer);
if (!btree->index->rd_istemp)
{
XLogRecPtr recptr;
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata);
PageSetLSN(page, recptr);
@ -324,23 +372,26 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
UnlockReleaseBuffer(stack->buffer);
END_CRIT_SECTION();
return;
} else {
/* split non-root page */
((ginxlogSplit*)(rdata->data))->isRootSplit = FALSE;
((ginxlogSplit*)(rdata->data))->rrlink = savedRightLink;
lpage = BufferGetPage( stack->buffer );
rpage = BufferGetPage( rbuffer );
return;
}
else
{
/* split non-root page */
((ginxlogSplit *) (rdata->data))->isRootSplit = FALSE;
((ginxlogSplit *) (rdata->data))->rrlink = savedRightLink;
lpage = BufferGetPage(stack->buffer);
rpage = BufferGetPage(rbuffer);
GinPageGetOpaque(rpage)->rightlink = savedRightLink;
GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
START_CRIT_SECTION();
PageRestoreTempPage( newlpage, lpage );
if (!btree->index->rd_istemp) {
XLogRecPtr recptr;
PageRestoreTempPage(newlpage, lpage);
if (!btree->index->rd_istemp)
{
XLogRecPtr recptr;
recptr = XLogInsert(RM_GIN_ID, XLOG_GIN_SPLIT, rdata);
PageSetLSN(lpage, recptr);
@ -350,7 +401,7 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
}
MarkBufferDirty(rbuffer);
UnlockReleaseBuffer(rbuffer);
MarkBufferDirty( stack->buffer );
MarkBufferDirty(stack->buffer);
END_CRIT_SECTION();
}
}
@ -361,31 +412,33 @@ ginInsertValue(GinBtree btree, GinBtreeStack *stack) {
LockBuffer(parent->buffer, GIN_EXCLUSIVE);
/* move right if it's needed */
page = BufferGetPage( parent->buffer );
while( (parent->off=btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber ) {
page = BufferGetPage(parent->buffer);
while ((parent->off = btree->findChildPtr(btree, page, stack->blkno, parent->off)) == InvalidOffsetNumber)
{
BlockNumber rightlink = GinPageGetOpaque(page)->rightlink;
LockBuffer(parent->buffer, GIN_UNLOCK);
if ( rightlink==InvalidBlockNumber ) {
/* rightmost page, but we don't find parent, we should
use plain search... */
if (rightlink == InvalidBlockNumber)
{
/*
* rightmost page, but we don't find parent, we should use
* plain search...
*/
findParents(btree, stack, rootBlkno);
parent=stack->parent;
page = BufferGetPage( parent->buffer );
parent = stack->parent;
page = BufferGetPage(parent->buffer);
break;
}
parent->blkno = rightlink;
parent->buffer = ReleaseAndReadBuffer(parent->buffer, btree->index, parent->blkno);
LockBuffer(parent->buffer, GIN_EXCLUSIVE);
page = BufferGetPage( parent->buffer );
LockBuffer(parent->buffer, GIN_EXCLUSIVE);
page = BufferGetPage(parent->buffer);
}
UnlockReleaseBuffer(stack->buffer);
pfree( stack );
pfree(stack);
stack = parent;
}
}

View File

@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* 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) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.5 2006/08/29 14:05:44 teodor Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginbulk.c,v 1.6 2006/10/04 00:29:47 momjian Exp $
*-------------------------------------------------------------------------
*/
@ -22,7 +22,8 @@
#define DEF_NPTR 4
void
ginInitBA(BuildAccumulator *accum) {
ginInitBA(BuildAccumulator *accum)
{
accum->maxdepth = 1;
accum->stackpos = 0;
accum->entries = NULL;
@ -31,11 +32,13 @@ ginInitBA(BuildAccumulator *accum) {
accum->entryallocator = NULL;
}
static EntryAccumulator*
EAAllocate( BuildAccumulator *accum ) {
if ( accum->entryallocator == NULL || accum->length>=DEF_NENTRY ) {
accum->entryallocator = palloc(sizeof(EntryAccumulator)*DEF_NENTRY);
accum->allocatedMemory += sizeof(EntryAccumulator)*DEF_NENTRY;
static EntryAccumulator *
EAAllocate(BuildAccumulator *accum)
{
if (accum->entryallocator == NULL || accum->length >= DEF_NENTRY)
{
accum->entryallocator = palloc(sizeof(EntryAccumulator) * DEF_NENTRY);
accum->allocatedMemory += sizeof(EntryAccumulator) * DEF_NENTRY;
accum->length = 0;
}
@ -48,24 +51,27 @@ EAAllocate( BuildAccumulator *accum ) {
* item pointer are ordered
*/
static void
ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heapptr) {
if ( entry->number >= entry->length ) {
ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heapptr)
{
if (entry->number >= entry->length)
{
accum->allocatedMemory += sizeof(ItemPointerData) * entry->length;
entry->length *= 2;
entry->list = (ItemPointerData*)repalloc(entry->list,
sizeof(ItemPointerData)*entry->length);
entry->list = (ItemPointerData *) repalloc(entry->list,
sizeof(ItemPointerData) * entry->length);
}
if ( entry->shouldSort==FALSE ) {
int res = compareItemPointers( entry->list + entry->number - 1, heapptr );
if (entry->shouldSort == FALSE)
{
int res = compareItemPointers(entry->list + entry->number - 1, heapptr);
Assert( res != 0 );
Assert(res != 0);
if ( res > 0 )
entry->shouldSort=TRUE;
if (res > 0)
entry->shouldSort = TRUE;
}
entry->list[ entry->number ] = *heapptr;
entry->list[entry->number] = *heapptr;
entry->number++;
}
@ -74,7 +80,8 @@ ginInsertData(BuildAccumulator *accum, EntryAccumulator *entry, ItemPointer heap
* to avoid computing the datum size twice.
*/
static Datum
getDatumCopy(BuildAccumulator *accum, Datum value) {
getDatumCopy(BuildAccumulator *accum, Datum value)
{
Form_pg_attribute *att = accum->ginstate->tupdesc->attrs;
Datum res;
@ -100,51 +107,58 @@ getDatumCopy(BuildAccumulator *accum, Datum value) {
* Find/store one entry from indexed value.
*/
static void
ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) {
EntryAccumulator *ea = accum->entries, *pea = NULL;
int res = 0;
uint32 depth = 1;
ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry)
{
EntryAccumulator *ea = accum->entries,
*pea = NULL;
int res = 0;
uint32 depth = 1;
while( ea ) {
while (ea)
{
res = compareEntries(accum->ginstate, entry, ea->value);
if ( res == 0 )
break; /* found */
else {
if (res == 0)
break; /* found */
else
{
pea = ea;
if ( res < 0 )
if (res < 0)
ea = ea->left;
else
ea = ea->right;
}
depth++;
}
if ( depth > accum->maxdepth )
if (depth > accum->maxdepth)
accum->maxdepth = depth;
if ( ea == NULL ) {
if (ea == NULL)
{
ea = EAAllocate(accum);
ea->left = ea->right = NULL;
ea->value = getDatumCopy(accum, entry);
ea->value = getDatumCopy(accum, entry);
ea->length = DEF_NPTR;
ea->number = 1;
ea->shouldSort = FALSE;
ea->list = (ItemPointerData*)palloc(sizeof(ItemPointerData)*DEF_NPTR);
ea->list = (ItemPointerData *) palloc(sizeof(ItemPointerData) * DEF_NPTR);
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;
else {
Assert( res != 0 );
if ( res < 0 )
else
{
Assert(res != 0);
if (res < 0)
pea->left = ea;
else
pea->right = ea;
}
} else
ginInsertData( accum, ea, heapptr );
}
else
ginInsertData(accum, ea, heapptr);
}
/*
@ -152,22 +166,23 @@ ginInsertEntry(BuildAccumulator *accum, ItemPointer heapptr, Datum entry) {
* then calls itself for each parts
*/
static void
ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry,
uint32 low, uint32 high, uint32 offset) {
uint32 pos;
uint32 middle = (low+high)>>1;
ginChooseElem(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry,
uint32 low, uint32 high, uint32 offset)
{
uint32 pos;
uint32 middle = (low + high) >> 1;
pos = (low+middle)>>1;
if ( low!=middle && pos>=offset && pos-offset < nentry )
ginInsertEntry( accum, heapptr, entries[ pos-offset ]);
pos = (high+middle+1)>>1;
if ( middle+1 != high && pos>=offset && pos-offset < nentry )
ginInsertEntry( accum, heapptr, entries[ pos-offset ]);
pos = (low + middle) >> 1;
if (low != middle && pos >= offset && pos - offset < nentry)
ginInsertEntry(accum, heapptr, entries[pos - offset]);
pos = (high + middle + 1) >> 1;
if (middle + 1 != high && pos >= offset && pos - offset < nentry)
ginInsertEntry(accum, heapptr, entries[pos - offset]);
if ( low!=middle )
ginChooseElem(accum, heapptr, entries, nentry, low, middle, offset );
if ( high!=middle+1 )
ginChooseElem(accum, heapptr, entries, nentry, middle+1, high, offset );
if (low != middle)
ginChooseElem(accum, heapptr, entries, nentry, low, middle, offset);
if (high != middle + 1)
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.
*/
void
ginInsertRecordBA( BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry ) {
uint32 i, nbit=0, offset;
ginInsertRecordBA(BuildAccumulator *accum, ItemPointer heapptr, Datum *entries, uint32 nentry)
{
uint32 i,
nbit = 0,
offset;
if (nentry==0)
if (nentry == 0)
return;
i=nentry-1;
for(;i>0;i>>=1) nbit++;
i = nentry - 1;
for (; i > 0; i >>= 1)
nbit++;
nbit = 1<<nbit;
offset = (nbit-nentry)/2;
nbit = 1 << nbit;
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);
}
static int
qsortCompareItemPointers( const void *a, const void *b ) {
int res = compareItemPointers( (ItemPointer)a, (ItemPointer)b );
Assert( res!=0 );
static int
qsortCompareItemPointers(const void *a, const void *b)
{
int res = compareItemPointers((ItemPointer) a, (ItemPointer) b);
Assert(res != 0);
return res;
}
/*
* walk on binary tree and returns ordered nodes
*/
static EntryAccumulator*
walkTree( BuildAccumulator *accum ) {
EntryAccumulator *entry = accum->stack[ accum->stackpos ];
* walk on binary tree and returns ordered nodes
*/
static EntryAccumulator *
walkTree(BuildAccumulator *accum)
{
EntryAccumulator *entry = accum->stack[accum->stackpos];
if ( entry->list != NULL ) {
if (entry->list != NULL)
{
/* return entry itself: we already was at left sublink */
return entry;
} else if ( entry->right && entry->right != accum->stack[ accum->stackpos+1 ] ) {
}
else if (entry->right && entry->right != accum->stack[accum->stackpos + 1])
{
/* go on right sublink */
accum->stackpos++;
entry = entry->right;
/* find most-left value */
for(;;) {
accum->stack[ accum->stackpos ] = entry;
if ( entry->left ) {
for (;;)
{
accum->stack[accum->stackpos] = entry;
if (entry->left)
{
accum->stackpos++;
entry = entry->left;
} else
}
else
break;
}
} else {
}
else
{
/* we already return all left subtree, itself and right subtree */
if ( accum->stackpos == 0 )
if (accum->stackpos == 0)
return 0;
accum->stackpos--;
return walkTree(accum);
@ -234,47 +264,53 @@ walkTree( BuildAccumulator *accum ) {
return entry;
}
ItemPointerData*
ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n) {
EntryAccumulator *entry;
ItemPointerData *
ginGetEntry(BuildAccumulator *accum, Datum *value, uint32 *n)
{
EntryAccumulator *entry;
ItemPointerData *list;
if ( accum->stack == NULL ) {
if (accum->stack == NULL)
{
/* first call */
accum->stack = palloc0(sizeof(EntryAccumulator*)*(accum->maxdepth+1));
accum->stack = palloc0(sizeof(EntryAccumulator *) * (accum->maxdepth + 1));
entry = accum->entries;
if ( entry == NULL )
if (entry == NULL)
return NULL;
/* find most-left value */
for(;;) {
accum->stack[ accum->stackpos ] = entry;
if ( entry->left ) {
for (;;)
{
accum->stack[accum->stackpos] = entry;
if (entry->left)
{
accum->stackpos++;
entry = entry->left;
} else
}
else
break;
}
} else {
pfree( accum->stack[ accum->stackpos ]->list );
accum->stack[ accum->stackpos ]->list = NULL;
entry = walkTree( accum );
}
else
{
pfree(accum->stack[accum->stackpos]->list);
accum->stack[accum->stackpos]->list = NULL;
entry = walkTree(accum);
}
if ( entry == NULL )
if (entry == NULL)
return NULL;
*n = entry->number;
*value = entry->value;
list = entry->list;
*n = entry->number;
*value = entry->value;
list = entry->list;
Assert(list != NULL);
if ( entry->shouldSort && entry->number > 1 )
if (entry->shouldSort && entry->number > 1)
qsort(list, *n, sizeof(ItemPointerData), qsortCompareItemPointers);
return list;
}

View File

@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* 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) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/gindatapage.c,v 1.3 2006/07/16 00:52:05 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/gindatapage.c,v 1.4 2006/10/04 00:29:47 momjian Exp $
*-------------------------------------------------------------------------
*/
@ -16,50 +16,56 @@
#include "access/gin.h"
int
compareItemPointers( ItemPointer a, ItemPointer b ) {
if ( GinItemPointerGetBlockNumber(a) == GinItemPointerGetBlockNumber(b) ) {
if ( GinItemPointerGetOffsetNumber(a) == GinItemPointerGetOffsetNumber(b) )
compareItemPointers(ItemPointer a, ItemPointer b)
{
if (GinItemPointerGetBlockNumber(a) == GinItemPointerGetBlockNumber(b))
{
if (GinItemPointerGetOffsetNumber(a) == GinItemPointerGetOffsetNumber(b))
return 0;
return ( GinItemPointerGetOffsetNumber(a) > GinItemPointerGetOffsetNumber(b) ) ? 1 : -1;
}
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
*/
void
MergeItemPointers(ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb) {
void
MergeItemPointers(ItemPointerData *dst, ItemPointerData *a, uint32 na, ItemPointerData *b, uint32 nb)
{
ItemPointerData *dptr = dst;
ItemPointerData *aptr = a, *bptr = b;
ItemPointerData *aptr = a,
*bptr = b;
while( aptr - a < na && bptr - b < nb ) {
if ( compareItemPointers(aptr, bptr) > 0 )
while (aptr - a < na && bptr - b < nb)
{
if (compareItemPointers(aptr, bptr) > 0)
*dptr++ = *bptr++;
else
*dptr++ = *aptr++;
}
while( aptr - a < na )
while (aptr - a < na)
*dptr++ = *aptr++;
while( bptr - b < nb )
while (bptr - b < nb)
*dptr++ = *bptr++;
}
/*
* Checks, should we move to right link...
* Checks, should we move to right link...
* Compares inserting itemp pointer with right bound of current page
*/
static bool
dataIsMoveRight(GinBtree btree, Page page) {
ItemPointer iptr = GinDataPageGetRightBound(page);
dataIsMoveRight(GinBtree btree, Page page)
{
ItemPointer iptr = GinDataPageGetRightBound(page);
if ( GinPageRightMost(page) )
return FALSE;
if (GinPageRightMost(page))
return FALSE;
return ( compareItemPointers( btree->items + btree->curitem, iptr ) > 0 ) ? TRUE : FALSE;
return (compareItemPointers(btree->items + btree->curitem, iptr) > 0) ? TRUE : FALSE;
}
/*
@ -67,94 +73,113 @@ dataIsMoveRight(GinBtree btree, Page page) {
* page correctly choosen and searching value SHOULD be on page
*/
static BlockNumber
dataLocateItem(GinBtree btree, GinBtreeStack *stack) {
OffsetNumber low, high, maxoff;
PostingItem *pitem=NULL;
int result;
Page page = BufferGetPage( stack->buffer );
dataLocateItem(GinBtree btree, GinBtreeStack *stack)
{
OffsetNumber low,
high,
maxoff;
PostingItem *pitem = NULL;
int result;
Page page = BufferGetPage(stack->buffer);
Assert( !GinPageIsLeaf(page) );
Assert( GinPageIsData(page) );
Assert(!GinPageIsLeaf(page));
Assert(GinPageIsData(page));
if ( btree->fullScan ) {
if (btree->fullScan)
{
stack->off = FirstOffsetNumber;
stack->predictNumber *= GinPageGetOpaque(page)->maxoff;
return btree->getLeftMostPage(btree, page);
}
low = FirstOffsetNumber;
maxoff = high = GinPageGetOpaque(page)->maxoff;
Assert( high >= low );
maxoff = high = GinPageGetOpaque(page)->maxoff;
Assert(high >= low);
high++;
while (high > low) {
while (high > low)
{
OffsetNumber mid = low + ((high - low) / 2);
pitem = (PostingItem*)GinDataPageGetItem(page,mid);
if ( mid == maxoff )
/* Right infinity, page already correctly choosen
with a help of dataIsMoveRight */
pitem = (PostingItem *) GinDataPageGetItem(page, mid);
if (mid == maxoff)
/*
* Right infinity, page already correctly choosen with a help of
* dataIsMoveRight
*/
result = -1;
else {
pitem = (PostingItem*)GinDataPageGetItem(page,mid);
result = compareItemPointers( btree->items + btree->curitem, &( pitem->key ) );
else
{
pitem = (PostingItem *) GinDataPageGetItem(page, mid);
result = compareItemPointers(btree->items + btree->curitem, &(pitem->key));
}
if ( result == 0 ) {
if (result == 0)
{
stack->off = mid;
return PostingItemGetBlockNumber(pitem);
} else if ( result > 0 )
}
else if (result > 0)
low = mid + 1;
else
high = mid;
}
Assert( high>=FirstOffsetNumber && high <= maxoff );
Assert(high >= FirstOffsetNumber && high <= maxoff);
stack->off = high;
pitem = (PostingItem*)GinDataPageGetItem(page,high);
pitem = (PostingItem *) GinDataPageGetItem(page, high);
return PostingItemGetBlockNumber(pitem);
}
/*
/*
* Searches correct position for value on leaf page.
* Page should be corrrectly choosen.
* Page should be corrrectly choosen.
* Returns true if value found on page.
*/
static bool
dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack) {
Page page = BufferGetPage( stack->buffer );
OffsetNumber low, high;
int result;
dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack)
{
Page page = BufferGetPage(stack->buffer);
OffsetNumber low,
high;
int result;
Assert( GinPageIsLeaf(page) );
Assert( GinPageIsData(page) );
Assert(GinPageIsLeaf(page));
Assert(GinPageIsData(page));
if ( btree->fullScan ) {
if (btree->fullScan)
{
stack->off = FirstOffsetNumber;
return TRUE;
}
low=FirstOffsetNumber;
low = FirstOffsetNumber;
high = GinPageGetOpaque(page)->maxoff;
if ( high < low ) {
if (high < low)
{
stack->off = FirstOffsetNumber;
return false;
}
high++;
while (high > low) {
while (high > low)
{
OffsetNumber mid = low + ((high - low) / 2);
result = compareItemPointers( btree->items + btree->curitem, (ItemPointer)GinDataPageGetItem(page,mid) );
result = compareItemPointers(btree->items + btree->curitem, (ItemPointer) GinDataPageGetItem(page, mid));
if ( result == 0 ) {
if (result == 0)
{
stack->off = mid;
return true;
} else if ( result > 0 )
}
else if (result > 0)
low = mid + 1;
else
high = mid;
@ -169,34 +194,41 @@ dataLocateLeafItem(GinBtree btree, GinBtreeStack *stack) {
* offset of PostingItem
*/
static OffsetNumber
dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff) {
OffsetNumber i, maxoff = GinPageGetOpaque(page)->maxoff;
dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber storedOff)
{
OffsetNumber i,
maxoff = GinPageGetOpaque(page)->maxoff;
PostingItem *pitem;
Assert( !GinPageIsLeaf(page) );
Assert( GinPageIsData(page) );
Assert(!GinPageIsLeaf(page));
Assert(GinPageIsData(page));
/* if page isn't changed, we returns storedOff */
if ( storedOff>= FirstOffsetNumber && storedOff<=maxoff) {
pitem = (PostingItem*)GinDataPageGetItem(page, storedOff);
if ( PostingItemGetBlockNumber(pitem) == blkno )
if (storedOff >= FirstOffsetNumber && storedOff <= maxoff)
{
pitem = (PostingItem *) GinDataPageGetItem(page, storedOff);
if (PostingItemGetBlockNumber(pitem) == blkno)
return storedOff;
/* we hope, that needed pointer goes to right. It's true
if there wasn't a deletion */
for( i=storedOff+1 ; i <= maxoff ; i++ ) {
pitem = (PostingItem*)GinDataPageGetItem(page, i);
if ( PostingItemGetBlockNumber(pitem) == blkno )
/*
* we hope, that needed pointer goes to right. It's true if there
* wasn't a deletion
*/
for (i = storedOff + 1; i <= maxoff; i++)
{
pitem = (PostingItem *) GinDataPageGetItem(page, i);
if (PostingItemGetBlockNumber(pitem) == blkno)
return i;
}
maxoff = storedOff-1;
maxoff = storedOff - 1;
}
/* last chance */
for( i=FirstOffsetNumber; i <= maxoff ; i++ ) {
pitem = (PostingItem*)GinDataPageGetItem(page, i);
if ( PostingItemGetBlockNumber(pitem) == blkno )
for (i = FirstOffsetNumber; i <= maxoff; i++)
{
pitem = (PostingItem *) GinDataPageGetItem(page, i);
if (PostingItemGetBlockNumber(pitem) == blkno)
return i;
}
@ -207,14 +239,15 @@ dataFindChildPtr(GinBtree btree, Page page, BlockNumber blkno, OffsetNumber stor
* retunrs blkno of lefmost child
*/
static BlockNumber
dataGetLeftMostPage(GinBtree btree, Page page) {
dataGetLeftMostPage(GinBtree btree, Page page)
{
PostingItem *pitem;
Assert( !GinPageIsLeaf(page) );
Assert( GinPageIsData(page) );
Assert( GinPageGetOpaque(page)->maxoff >= FirstOffsetNumber );
Assert(!GinPageIsLeaf(page));
Assert(GinPageIsData(page));
Assert(GinPageGetOpaque(page)->maxoff >= FirstOffsetNumber);
pitem = (PostingItem*)GinDataPageGetItem(page, FirstOffsetNumber);
pitem = (PostingItem *) GinDataPageGetItem(page, FirstOffsetNumber);
return PostingItemGetBlockNumber(pitem);
}
@ -223,18 +256,22 @@ dataGetLeftMostPage(GinBtree btree, Page page) {
* correct value! depending on leaf or non-leaf page
*/
void
GinDataPageAddItem( Page page, void *data, OffsetNumber offset ) {
GinDataPageAddItem(Page page, void *data, OffsetNumber offset)
{
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
char *ptr;
char *ptr;
if ( offset == InvalidOffsetNumber ) {
ptr = GinDataPageGetItem(page,maxoff+1);
} else {
ptr = GinDataPageGetItem(page,offset);
if ( maxoff+1-offset != 0 )
memmove( ptr+GinSizeOfItem(page), ptr, (maxoff-offset+1) * GinSizeOfItem(page) );
if (offset == InvalidOffsetNumber)
{
ptr = GinDataPageGetItem(page, maxoff + 1);
}
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++;
}
@ -243,15 +280,16 @@ GinDataPageAddItem( Page page, void *data, OffsetNumber offset ) {
* Deletes posting item from non-leaf page
*/
void
PageDeletePostingItem(Page page, OffsetNumber offset) {
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
PageDeletePostingItem(Page page, OffsetNumber offset)
{
OffsetNumber maxoff = GinPageGetOpaque(page)->maxoff;
Assert( !GinPageIsLeaf(page) );
Assert( offset>=FirstOffsetNumber && offset <= maxoff );
Assert(!GinPageIsLeaf(page));
Assert(offset >= FirstOffsetNumber && offset <= maxoff);
if ( offset != maxoff )
memmove( GinDataPageGetItem(page,offset), GinDataPageGetItem(page,offset+1),
sizeof(PostingItem) * (maxoff-offset) );
if (offset != maxoff)
memmove(GinDataPageGetItem(page, offset), GinDataPageGetItem(page, offset + 1),
sizeof(PostingItem) * (maxoff - offset));
GinPageGetOpaque(page)->maxoff--;
}
@ -261,19 +299,24 @@ PageDeletePostingItem(Page page, OffsetNumber offset) {
* item pointer never deletes!
*/
static bool
dataIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) {
Page page = BufferGetPage(buf);
dataIsEnoughSpace(GinBtree btree, Buffer buf, OffsetNumber off)
{
Page page = BufferGetPage(buf);
Assert( GinPageIsData(page) );
Assert( !btree->isDelete );
Assert(GinPageIsData(page));
Assert(!btree->isDelete);
if ( GinPageIsLeaf(page) ) {
if ( GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff ) {
if ( (btree->nitem - btree->curitem) * sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page) )
if (GinPageIsLeaf(page))
{
if (GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff)
{
if ((btree->nitem - btree->curitem) * sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page))
return true;
} else if ( sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page) )
}
else if (sizeof(ItemPointerData) <= GinDataPageGetFreeSpace(page))
return true;
} else if ( sizeof(PostingItem) <= GinDataPageGetFreeSpace(page) )
}
else if (sizeof(PostingItem) <= GinDataPageGetFreeSpace(page))
return true;
return false;
@ -285,14 +328,17 @@ dataIsEnoughSpace( GinBtree btree, Buffer buf, OffsetNumber off ) {
* item pointer never deletes!
*/
static BlockNumber
dataPrepareData( GinBtree btree, Page page, OffsetNumber off) {
dataPrepareData(GinBtree btree, Page page, OffsetNumber off)
{
BlockNumber ret = InvalidBlockNumber;
Assert( GinPageIsData(page) );
Assert(GinPageIsData(page));
if ( !GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber ) {
PostingItem *pitem = (PostingItem*)GinDataPageGetItem(page,off);
PostingItemSetBlockNumber( pitem, btree->rightblkno );
if (!GinPageIsLeaf(page) && btree->rightblkno != InvalidBlockNumber)
{
PostingItem *pitem = (PostingItem *) GinDataPageGetItem(page, off);
PostingItemSetBlockNumber(pitem, btree->rightblkno);
ret = btree->rightblkno;
}
@ -301,24 +347,25 @@ dataPrepareData( GinBtree btree, Page page, OffsetNumber off) {
return ret;
}
/*
/*
* Places keys to page and fills WAL record. In case leaf page and
* build mode puts all ItemPointers to page.
*/
static void
dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata) {
Page page = BufferGetPage(buf);
dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prdata)
{
Page page = BufferGetPage(buf);
static XLogRecData rdata[3];
int sizeofitem = GinSizeOfItem(page);
static ginxlogInsert data;
int sizeofitem = GinSizeOfItem(page);
static ginxlogInsert data;
*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.blkno = BufferGetBlockNumber( buf );
data.blkno = BufferGetBlockNumber(buf);
data.offset = off;
data.nitem = 1;
data.isDelete = FALSE;
@ -337,109 +384,124 @@ dataPlaceToPage(GinBtree btree, Buffer buf, OffsetNumber off, XLogRecData **prda
rdata[1].next = &rdata[2];
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].next = NULL;
if ( GinPageIsLeaf(page) ) {
if ( GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff ) {
if (GinPageIsLeaf(page))
{
if (GinPageRightMost(page) && off > GinPageGetOpaque(page)->maxoff)
{
/* usually, create index... */
uint32 savedPos = btree->curitem;
uint32 savedPos = btree->curitem;
while( btree->curitem < btree->nitem ) {
GinDataPageAddItem(page, btree->items+btree->curitem, off);
while (btree->curitem < btree->nitem)
{
GinDataPageAddItem(page, btree->items + btree->curitem, off);
off++;
btree->curitem++;
}
data.nitem = btree->curitem-savedPos;
data.nitem = btree->curitem - savedPos;
rdata[2].len = sizeofitem * data.nitem;
} else {
GinDataPageAddItem(page, btree->items+btree->curitem, off);
}
else
{
GinDataPageAddItem(page, btree->items + btree->curitem, off);
btree->curitem++;
}
} else
GinDataPageAddItem(page, &(btree->pitem), off);
}
else
GinDataPageAddItem(page, &(btree->pitem), off);
}
/*
* split page and fills WAL record. original buffer(lbuf) leaves untouched,
* returns shadow page of lbuf filled new data. In leaf page and build mode puts all
* returns shadow page of lbuf filled new data. In leaf page and build mode puts all
* ItemPointers to pages. Also, in build mode splits data by way to full fulled
* left page
*/
static Page
dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRecData **prdata) {
dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRecData **prdata)
{
static ginxlogSplit data;
static XLogRecData rdata[4];
static char vector[2*BLCKSZ];
char *ptr;
static char vector[2 * BLCKSZ];
char *ptr;
OffsetNumber separator;
ItemPointer bound;
Page lpage = GinPageGetCopyPage( BufferGetPage( lbuf ) );
ItemPointerData oldbound = *GinDataPageGetRightBound(lpage);
int sizeofitem = GinSizeOfItem(lpage);
ItemPointer bound;
Page lpage = GinPageGetCopyPage(BufferGetPage(lbuf));
ItemPointerData oldbound = *GinDataPageGetRightBound(lpage);
int sizeofitem = GinSizeOfItem(lpage);
OffsetNumber maxoff = GinPageGetOpaque(lpage)->maxoff;
Page rpage = BufferGetPage( rbuf );
Size pageSize = PageGetPageSize( lpage );
Size freeSpace;
uint32 nCopied = 1;
Page rpage = BufferGetPage(rbuf);
Size pageSize = PageGetPageSize(lpage);
Size freeSpace;
uint32 nCopied = 1;
GinInitPage( rpage, GinPageGetOpaque(lpage)->flags, pageSize );
GinInitPage(rpage, GinPageGetOpaque(lpage)->flags, pageSize);
freeSpace = GinDataPageGetFreeSpace(rpage);
*prdata = rdata;
data.leftChildBlkno = ( GinPageIsLeaf(lpage) ) ?
InvalidOffsetNumber : PostingItemGetBlockNumber( &(btree->pitem) );
data.updateBlkno = dataPrepareData( btree, lpage, off );
data.leftChildBlkno = (GinPageIsLeaf(lpage)) ?
InvalidOffsetNumber : PostingItemGetBlockNumber(&(btree->pitem));
data.updateBlkno = dataPrepareData(btree, lpage, off);
memcpy(vector, GinDataPageGetItem(lpage, FirstOffsetNumber),
maxoff*sizeofitem);
memcpy(vector, GinDataPageGetItem(lpage, FirstOffsetNumber),
maxoff * sizeofitem);
if ( GinPageIsLeaf(lpage) && GinPageRightMost(lpage) && off > GinPageGetOpaque(lpage)->maxoff ) {
if (GinPageIsLeaf(lpage) && GinPageRightMost(lpage) && off > GinPageGetOpaque(lpage)->maxoff)
{
nCopied = 0;
while( btree->curitem < btree->nitem && maxoff*sizeof(ItemPointerData) < 2*(freeSpace - sizeof(ItemPointerData)) ) {
memcpy( vector + maxoff*sizeof(ItemPointerData), btree->items+btree->curitem,
sizeof(ItemPointerData) );
while (btree->curitem < btree->nitem && maxoff * sizeof(ItemPointerData) < 2 * (freeSpace - sizeof(ItemPointerData)))
{
memcpy(vector + maxoff * sizeof(ItemPointerData), btree->items + btree->curitem,
sizeof(ItemPointerData));
maxoff++;
nCopied++;
btree->curitem++;
}
} else {
ptr = vector + (off-1)*sizeofitem;
if ( maxoff+1-off != 0 )
memmove( ptr+sizeofitem, ptr, (maxoff-off+1) * sizeofitem );
if ( GinPageIsLeaf(lpage) ) {
memcpy(ptr, btree->items+btree->curitem, sizeofitem );
}
else
{
ptr = vector + (off - 1) * sizeofitem;
if (maxoff + 1 - off != 0)
memmove(ptr + sizeofitem, ptr, (maxoff - off + 1) * sizeofitem);
if (GinPageIsLeaf(lpage))
{
memcpy(ptr, btree->items + btree->curitem, sizeofitem);
btree->curitem++;
} else
memcpy(ptr, &(btree->pitem), sizeofitem );
}
else
memcpy(ptr, &(btree->pitem), sizeofitem);
maxoff++;
}
/* we suppose that during index creation table scaned from
begin to end, so ItemPointers are monotonically increased.. */
if ( btree->isBuild && GinPageRightMost(lpage) )
separator=freeSpace/sizeofitem;
/*
* we suppose that during index creation table scaned from begin to end,
* so ItemPointers are monotonically increased..
*/
if (btree->isBuild && GinPageRightMost(lpage))
separator = freeSpace / sizeofitem;
else
separator=maxoff/2;
separator = maxoff / 2;
GinInitPage( rpage, GinPageGetOpaque(lpage)->flags, pageSize );
GinInitPage( lpage, GinPageGetOpaque(rpage)->flags, pageSize );
GinInitPage(rpage, GinPageGetOpaque(lpage)->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;
memcpy( GinDataPageGetItem(rpage, FirstOffsetNumber),
vector + separator * sizeofitem, (maxoff-separator) * sizeofitem );
GinPageGetOpaque(rpage)->maxoff = maxoff-separator;
memcpy(GinDataPageGetItem(rpage, FirstOffsetNumber),
vector + separator * sizeofitem, (maxoff - separator) * sizeofitem);
GinPageGetOpaque(rpage)->maxoff = maxoff - separator;
PostingItemSetBlockNumber( &(btree->pitem), BufferGetBlockNumber(lbuf) );
if ( GinPageIsLeaf(lpage) )
btree->pitem.key = *(ItemPointerData*)GinDataPageGetItem(lpage,
GinPageGetOpaque(lpage)->maxoff);
else
btree->pitem.key = ((PostingItem*)GinDataPageGetItem(lpage,
GinPageGetOpaque(lpage)->maxoff))->key;
PostingItemSetBlockNumber(&(btree->pitem), BufferGetBlockNumber(lbuf));
if (GinPageIsLeaf(lpage))
btree->pitem.key = *(ItemPointerData *) GinDataPageGetItem(lpage,
GinPageGetOpaque(lpage)->maxoff);
else
btree->pitem.key = ((PostingItem *) GinDataPageGetItem(lpage,
GinPageGetOpaque(lpage)->maxoff))->key;
btree->rightblkno = BufferGetBlockNumber(rbuf);
/* 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.rootBlkno = InvalidBlockNumber;
data.lblkno = BufferGetBlockNumber( lbuf );
data.rblkno = BufferGetBlockNumber( rbuf );
data.lblkno = BufferGetBlockNumber(lbuf);
data.rblkno = BufferGetBlockNumber(rbuf);
data.separator = separator;
data.nitem = maxoff;
data.isData = TRUE;
@ -468,34 +530,37 @@ dataSplitPage(GinBtree btree, Buffer lbuf, Buffer rbuf, OffsetNumber off, XLogRe
rdata[1].buffer = InvalidBuffer;
rdata[1].data = vector;
rdata[1].len = MAXALIGN( maxoff * sizeofitem );
rdata[1].len = MAXALIGN(maxoff * sizeofitem);
rdata[1].next = NULL;
return lpage;
}
/*
* Fills new root by right bound values from child.
* Fills new root by right bound values from child.
* Also called from ginxlog, should not use btree
*/
void
dataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf) {
Page page = BufferGetPage(root),
lpage = BufferGetPage(lbuf),
rpage = BufferGetPage(rbuf);
PostingItem li, ri;
dataFillRoot(GinBtree btree, Buffer root, Buffer lbuf, Buffer rbuf)
{
Page page = BufferGetPage(root),
lpage = BufferGetPage(lbuf),
rpage = BufferGetPage(rbuf);
PostingItem li,
ri;
li.key = *GinDataPageGetRightBound(lpage);
PostingItemSetBlockNumber( &li, BufferGetBlockNumber(lbuf) );
GinDataPageAddItem(page, &li, InvalidOffsetNumber );
PostingItemSetBlockNumber(&li, BufferGetBlockNumber(lbuf));
GinDataPageAddItem(page, &li, InvalidOffsetNumber);
ri.key = *GinDataPageGetRightBound(rpage);
PostingItemSetBlockNumber( &ri, BufferGetBlockNumber(rbuf) );
GinDataPageAddItem(page, &ri, InvalidOffsetNumber );
PostingItemSetBlockNumber(&ri, BufferGetBlockNumber(rbuf));
GinDataPageAddItem(page, &ri, InvalidOffsetNumber);
}
void
prepareDataScan( GinBtree btree, Relation index) {
prepareDataScan(GinBtree btree, Relation index)
{
memset(btree, 0, sizeof(GinBtreeData));
btree->index = index;
btree->isMoveRight = dataIsMoveRight;
@ -509,21 +574,22 @@ prepareDataScan( GinBtree btree, Relation index) {
btree->fillRoot = dataFillRoot;
btree->searchMode = FALSE;
btree->isDelete = FALSE;
btree->isDelete = FALSE;
btree->fullScan = FALSE;
btree->isBuild= FALSE;
btree->isBuild = FALSE;
}
GinPostingTreeScan*
prepareScanPostingTree( Relation index, BlockNumber rootBlkno, bool searchMode) {
GinPostingTreeScan *gdi = (GinPostingTreeScan*)palloc0( sizeof(GinPostingTreeScan) );
GinPostingTreeScan *
prepareScanPostingTree(Relation index, BlockNumber rootBlkno, bool searchMode)
{
GinPostingTreeScan *gdi = (GinPostingTreeScan *) palloc0(sizeof(GinPostingTreeScan));
prepareDataScan(&gdi->btree, index);
prepareDataScan( &gdi->btree, index );
gdi->btree.searchMode = searchMode;
gdi->btree.fullScan = searchMode;
gdi->stack = ginPrepareFindLeafPage( &gdi->btree, rootBlkno );
gdi->stack = ginPrepareFindLeafPage(&gdi->btree, rootBlkno);
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)
*/
void
insertItemPointer(GinPostingTreeScan *gdi, ItemPointerData *items, uint32 nitem) {
insertItemPointer(GinPostingTreeScan *gdi, ItemPointerData *items, uint32 nitem)
{
BlockNumber rootBlkno = gdi->stack->blkno;
gdi->btree.items = items;
gdi->btree.nitem = nitem;
gdi->btree.curitem = 0;
while( gdi->btree.curitem < gdi->btree.nitem ) {
while (gdi->btree.curitem < gdi->btree.nitem)
{
if (!gdi->stack)
gdi->stack = ginPrepareFindLeafPage( &gdi->btree, rootBlkno );
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 ) )
elog(ERROR,"item pointer (%u,%d) already exists",
ItemPointerGetBlockNumber(gdi->btree.items + gdi->btree.curitem),
ItemPointerGetOffsetNumber(gdi->btree.items + gdi->btree.curitem));
if (gdi->btree.findItem(&(gdi->btree), gdi->stack))
elog(ERROR, "item pointer (%u,%d) already exists",
ItemPointerGetBlockNumber(gdi->btree.items + gdi->btree.curitem),
ItemPointerGetOffsetNumber(gdi->btree.items + gdi->btree.curitem));
ginInsertValue(&(gdi->btree), gdi->stack);
gdi->stack=NULL;
gdi->stack = NULL;
}
}
Buffer
scanBeginPostingTree( GinPostingTreeScan *gdi ) {
gdi->stack = ginFindLeafPage( &gdi->btree, gdi->stack );
scanBeginPostingTree(GinPostingTreeScan *gdi)
{
gdi->stack = ginFindLeafPage(&gdi->btree, gdi->stack);
return gdi->stack->buffer;
}

View File

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

View File

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

View File

@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* 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) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.4 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/gininsert.c,v 1.5 2006/10/04 00:29:47 momjian Exp $
*-------------------------------------------------------------------------
*/
@ -19,12 +19,13 @@
#include "miscadmin.h"
#include "utils/memutils.h"
typedef struct {
GinState ginstate;
double indtuples;
MemoryContext tmpCtx;
MemoryContext funcCtx;
BuildAccumulator accum;
typedef struct
{
GinState ginstate;
double indtuples;
MemoryContext tmpCtx;
MemoryContext funcCtx;
BuildAccumulator accum;
} GinBuildState;
/*
@ -32,24 +33,26 @@ typedef struct {
* suppose that items[] fits to page
*/
static BlockNumber
createPostingTree( Relation index, ItemPointerData *items, uint32 nitems ) {
createPostingTree(Relation index, ItemPointerData *items, uint32 nitems)
{
BlockNumber blkno;
Buffer buffer = GinNewBuffer(index);
Page page;
Buffer buffer = GinNewBuffer(index);
Page page;
START_CRIT_SECTION();
GinInitBuffer( buffer, GIN_DATA|GIN_LEAF );
GinInitBuffer(buffer, GIN_DATA | GIN_LEAF);
page = BufferGetPage(buffer);
blkno = BufferGetBlockNumber(buffer);
memcpy( GinDataPageGetData(page), items, sizeof(ItemPointerData) * nitems );
memcpy(GinDataPageGetData(page), items, sizeof(ItemPointerData) * nitems);
GinPageGetOpaque(page)->maxoff = nitems;
if (!index->rd_istemp) {
XLogRecPtr recptr;
if (!index->rd_istemp)
{
XLogRecPtr recptr;
XLogRecData rdata[2];
ginxlogCreatePostingTree data;
ginxlogCreatePostingTree data;
data.node = index->rd_node;
data.blkno = blkno;
@ -71,7 +74,7 @@ createPostingTree( Relation index, ItemPointerData *items, uint32 nitems ) {
PageSetLSN(page, recptr);
PageSetTLI(page, ThisTimeLineID);
}
}
MarkBufferDirty(buffer);
UnlockReleaseBuffer(buffer);
@ -89,21 +92,25 @@ createPostingTree( Relation index, ItemPointerData *items, uint32 nitems ) {
* GinFormTuple().
*/
static IndexTuple
addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
IndexTuple old, ItemPointerData *items, uint32 nitem, bool isBuild) {
bool isnull;
Datum key = index_getattr(old, FirstOffsetNumber, ginstate->tupdesc, &isnull);
IndexTuple res = GinFormTuple(ginstate, key, NULL, nitem + GinGetNPosting(old));
addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
IndexTuple old, ItemPointerData *items, uint32 nitem, bool isBuild)
{
bool isnull;
Datum key = index_getattr(old, FirstOffsetNumber, ginstate->tupdesc, &isnull);
IndexTuple res = GinFormTuple(ginstate, key, NULL, nitem + GinGetNPosting(old));
if ( res ) {
if (res)
{
/* good, small enough */
MergeItemPointers( GinGetPosting(res),
GinGetPosting(old), GinGetNPosting(old),
items, nitem
);
MergeItemPointers(GinGetPosting(res),
GinGetPosting(old), GinGetNPosting(old),
items, nitem
);
GinSetNPosting(res, nitem + GinGetNPosting(old));
} else {
}
else
{
BlockNumber postingRoot;
GinPostingTreeScan *gdi;
@ -112,7 +119,7 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
postingRoot = createPostingTree(index, GinGetPosting(old), GinGetNPosting(old));
GinSetPostingTree(res, postingRoot);
gdi = prepareScanPostingTree(index, postingRoot, FALSE);
gdi = prepareScanPostingTree(index, postingRoot, FALSE);
gdi->btree.isBuild = isBuild;
insertItemPointer(gdi, items, nitem);
@ -124,36 +131,39 @@ addItemPointersToTuple(Relation index, GinState *ginstate, GinBtreeStack *stack,
}
/*
* Inserts only one entry to the index, but it can adds more that 1
* ItemPointer.
* Inserts only one entry to the index, but it can adds more that 1
* ItemPointer.
*/
static void
ginEntryInsert( Relation index, GinState *ginstate, Datum value, ItemPointerData *items, uint32 nitem, bool isBuild) {
GinBtreeData btree;
ginEntryInsert(Relation index, GinState *ginstate, Datum value, ItemPointerData *items, uint32 nitem, bool isBuild)
{
GinBtreeData btree;
GinBtreeStack *stack;
IndexTuple itup;
Page page;
IndexTuple itup;
Page page;
prepareEntryScan( &btree, index, value, ginstate );
prepareEntryScan(&btree, index, value, ginstate);
stack = ginFindLeafPage(&btree, NULL);
page = BufferGetPage( stack->buffer );
page = BufferGetPage(stack->buffer);
if ( btree.findItem( &btree, stack ) ) {
if (btree.findItem(&btree, stack))
{
/* found entry */
itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stack->off));
if ( GinIsPostingTree(itup) ) {
if (GinIsPostingTree(itup))
{
/* lock root of posting tree */
GinPostingTreeScan *gdi;
BlockNumber rootPostingTree = GinGetPostingTree(itup);
BlockNumber rootPostingTree = GinGetPostingTree(itup);
/* release all stack */
LockBuffer(stack->buffer, GIN_UNLOCK);
freeGinBtreeStack( stack );
freeGinBtreeStack(stack);
/* insert into posting tree */
gdi = prepareScanPostingTree( index, rootPostingTree, FALSE );
gdi = prepareScanPostingTree(index, rootPostingTree, FALSE);
gdi->btree.isBuild = isBuild;
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);
btree.isDelete = TRUE;
} else {
}
else
{
/* We suppose, that tuple can store at list one itempointer */
itup = GinFormTuple( ginstate, value, items, 1);
if ( itup==NULL || IndexTupleSize(itup) >= GinMaxItemSize )
itup = GinFormTuple(ginstate, value, items, 1);
if (itup == NULL || IndexTupleSize(itup) >= GinMaxItemSize)
elog(ERROR, "huge tuple");
if ( nitem>1 ) {
if (nitem > 1)
{
IndexTuple previtup = itup;
itup = addItemPointersToTuple(index, ginstate, stack, previtup, items+1, nitem-1, isBuild);
itup = addItemPointersToTuple(index, ginstate, stack, previtup, items + 1, nitem - 1, isBuild);
pfree(previtup);
}
}
btree.entry = itup;
ginInsertValue(&btree, stack);
pfree( itup );
pfree(itup);
}
/*
@ -187,48 +200,53 @@ ginEntryInsert( Relation index, GinState *ginstate, Datum value, ItemPointerData
* Function isnt use during normal insert
*/
static uint32
ginHeapTupleBulkInsert(GinBuildState *buildstate, Datum value, ItemPointer heapptr) {
Datum *entries;
uint32 nentries;
ginHeapTupleBulkInsert(GinBuildState *buildstate, Datum value, ItemPointer heapptr)
{
Datum *entries;
uint32 nentries;
MemoryContext oldCtx;
oldCtx = MemoryContextSwitchTo(buildstate->funcCtx);
entries = extractEntriesSU( buildstate->accum.ginstate, value, &nentries);
entries = extractEntriesSU(buildstate->accum.ginstate, value, &nentries);
MemoryContextSwitchTo(oldCtx);
if ( nentries==0 )
if (nentries == 0)
/* nothing to insert */
return 0;
ginInsertRecordBA( &buildstate->accum, heapptr, entries, nentries);
ginInsertRecordBA(&buildstate->accum, heapptr, entries, nentries);
MemoryContextReset(buildstate->funcCtx);
return nentries;
}
static void
static void
ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
bool *isnull, bool tupleIsAlive, void *state) {
bool *isnull, bool tupleIsAlive, void *state)
{
GinBuildState *buildstate = (GinBuildState*)state;
GinBuildState *buildstate = (GinBuildState *) state;
MemoryContext oldCtx;
if ( *isnull )
if (*isnull)
return;
oldCtx = MemoryContextSwitchTo(buildstate->tmpCtx);
buildstate->indtuples += ginHeapTupleBulkInsert(buildstate, *values, &htup->t_self);
/* we use only half maintenance_work_mem, because there is some leaks
during insertion and extract values */
if ( buildstate->accum.allocatedMemory >= maintenance_work_mem*1024L/2L ) {
ItemPointerData *list;
Datum entry;
uint32 nlist;
/*
* we use only half maintenance_work_mem, because there is some leaks
* during insertion and extract values
*/
if (buildstate->accum.allocatedMemory >= maintenance_work_mem * 1024L / 2L)
{
ItemPointerData *list;
Datum entry;
uint32 nlist;
while( (list=ginGetEntry(&buildstate->accum, &entry, &nlist)) != NULL )
while ((list = ginGetEntry(&buildstate->accum, &entry, &nlist)) != NULL)
ginEntryInsert(index, &buildstate->ginstate, entry, list, nlist, TRUE);
MemoryContextReset(buildstate->tmpCtx);
@ -239,22 +257,23 @@ ginBuildCallback(Relation index, HeapTuple htup, Datum *values,
}
Datum
ginbuild(PG_FUNCTION_ARGS) {
Relation heap = (Relation) PG_GETARG_POINTER(0);
Relation index = (Relation) PG_GETARG_POINTER(1);
ginbuild(PG_FUNCTION_ARGS)
{
Relation heap = (Relation) PG_GETARG_POINTER(0);
Relation index = (Relation) PG_GETARG_POINTER(1);
IndexInfo *indexInfo = (IndexInfo *) PG_GETARG_POINTER(2);
IndexBuildResult *result;
double reltuples;
GinBuildState buildstate;
double reltuples;
GinBuildState buildstate;
Buffer buffer;
ItemPointerData *list;
Datum entry;
uint32 nlist;
ItemPointerData *list;
Datum entry;
uint32 nlist;
MemoryContext oldCtx;
if (RelationGetNumberOfBlocks(index) != 0)
elog(ERROR, "index \"%s\" already contains data",
RelationGetRelationName(index));
RelationGetRelationName(index));
initGinState(&buildstate.ginstate, index);
@ -262,10 +281,11 @@ ginbuild(PG_FUNCTION_ARGS) {
buffer = GinNewBuffer(index);
START_CRIT_SECTION();
GinInitBuffer(buffer, GIN_LEAF);
if (!index->rd_istemp) {
XLogRecPtr recptr;
if (!index->rd_istemp)
{
XLogRecPtr recptr;
XLogRecData rdata;
Page page;
Page page;
rdata.buffer = InvalidBuffer;
rdata.data = (char *) &(index->rd_node);
@ -279,7 +299,7 @@ ginbuild(PG_FUNCTION_ARGS) {
PageSetLSN(page, recptr);
PageSetTLI(page, ThisTimeLineID);
}
}
MarkBufferDirty(buffer);
UnlockReleaseBuffer(buffer);
@ -293,26 +313,26 @@ ginbuild(PG_FUNCTION_ARGS) {
* inserted into the index
*/
buildstate.tmpCtx = AllocSetContextCreate(CurrentMemoryContext,
"Gin build temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
"Gin build temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
buildstate.funcCtx = AllocSetContextCreate(buildstate.tmpCtx,
"Gin build temporary context for user-defined function",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
"Gin build temporary context for user-defined function",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
buildstate.accum.ginstate = &buildstate.ginstate;
ginInitBA( &buildstate.accum );
ginInitBA(&buildstate.accum);
/* do the heap scan */
reltuples = IndexBuildHeapScan(heap, index, indexInfo,
ginBuildCallback, (void *) &buildstate);
ginBuildCallback, (void *) &buildstate);
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);
MemoryContextSwitchTo(oldCtx);
@ -333,55 +353,58 @@ ginbuild(PG_FUNCTION_ARGS) {
* Inserts value during normal insertion
*/
static uint32
ginHeapTupleInsert( Relation index, GinState *ginstate, Datum value, ItemPointer item) {
Datum *entries;
uint32 i,nentries;
ginHeapTupleInsert(Relation index, GinState *ginstate, Datum value, ItemPointer item)
{
Datum *entries;
uint32 i,
nentries;
entries = extractEntriesSU( ginstate, value, &nentries);
entries = extractEntriesSU(ginstate, value, &nentries);
if ( nentries==0 )
if (nentries == 0)
/* nothing to insert */
return 0;
for(i=0;i<nentries;i++)
for (i = 0; i < nentries; i++)
ginEntryInsert(index, ginstate, entries[i], item, 1, FALSE);
return nentries;
}
Datum
gininsert(PG_FUNCTION_ARGS) {
Relation index = (Relation) PG_GETARG_POINTER(0);
Datum *values = (Datum *) PG_GETARG_POINTER(1);
bool *isnull = (bool *) PG_GETARG_POINTER(2);
gininsert(PG_FUNCTION_ARGS)
{
Relation index = (Relation) PG_GETARG_POINTER(0);
Datum *values = (Datum *) PG_GETARG_POINTER(1);
bool *isnull = (bool *) PG_GETARG_POINTER(2);
ItemPointer ht_ctid = (ItemPointer) PG_GETARG_POINTER(3);
#ifdef NOT_USED
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
bool checkUnique = PG_GETARG_BOOL(5);
Relation heapRel = (Relation) PG_GETARG_POINTER(4);
bool checkUnique = PG_GETARG_BOOL(5);
#endif
GinState ginstate;
GinState ginstate;
MemoryContext oldCtx;
MemoryContext insertCtx;
uint32 res;
uint32 res;
if ( *isnull )
if (*isnull)
PG_RETURN_BOOL(false);
insertCtx = AllocSetContextCreate(CurrentMemoryContext,
"Gin insert temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
"Gin insert temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
oldCtx = MemoryContextSwitchTo(insertCtx);
initGinState(&ginstate, index);
res = ginHeapTupleInsert(index, &ginstate, *values, ht_ctid);
res = ginHeapTupleInsert(index, &ginstate, *values, ht_ctid);
MemoryContextSwitchTo(oldCtx);
MemoryContextDelete(insertCtx);
PG_RETURN_BOOL(res>0);
PG_RETURN_BOOL(res > 0);
}

View File

@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* 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) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginscan.c,v 1.5 2006/09/14 11:26:49 teodor Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginscan.c,v 1.6 2006/10/04 00:29:48 momjian Exp $
*-------------------------------------------------------------------------
*/
@ -19,11 +19,12 @@
#include "utils/memutils.h"
Datum
ginbeginscan(PG_FUNCTION_ARGS) {
Relation rel = (Relation) PG_GETARG_POINTER(0);
int keysz = PG_GETARG_INT32(1);
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
Datum
ginbeginscan(PG_FUNCTION_ARGS)
{
Relation rel = (Relation) PG_GETARG_POINTER(0);
int keysz = PG_GETARG_INT32(1);
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(2);
IndexScanDesc scan;
scan = RelationGetIndexScan(rel, keysz, scankey);
@ -32,22 +33,25 @@ ginbeginscan(PG_FUNCTION_ARGS) {
}
static void
fillScanKey( GinState *ginstate, GinScanKey key, Datum query,
Datum *entryValues, uint32 nEntryValues, StrategyNumber strategy ) {
uint32 i,j;
fillScanKey(GinState *ginstate, GinScanKey key, Datum query,
Datum *entryValues, uint32 nEntryValues, StrategyNumber strategy)
{
uint32 i,
j;
key->nentries = nEntryValues;
key->entryRes = (bool*)palloc0( sizeof(bool) * nEntryValues );
key->scanEntry = (GinScanEntry) palloc( sizeof(GinScanEntryData) * nEntryValues );
key->entryRes = (bool *) palloc0(sizeof(bool) * nEntryValues);
key->scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData) * nEntryValues);
key->strategy = strategy;
key->query = query;
key->firstCall= TRUE;
ItemPointerSet( &(key->curItem), InvalidBlockNumber, InvalidOffsetNumber );
key->firstCall = TRUE;
ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
for(i=0; i<nEntryValues; i++) {
for (i = 0; i < nEntryValues; i++)
{
key->scanEntry[i].pval = key->entryRes + i;
key->scanEntry[i].entry = entryValues[i];
ItemPointerSet( &(key->scanEntry[i].curItem), InvalidBlockNumber, InvalidOffsetNumber );
ItemPointerSet(&(key->scanEntry[i].curItem), InvalidBlockNumber, InvalidOffsetNumber);
key->scanEntry[i].offset = InvalidOffsetNumber;
key->scanEntry[i].buffer = InvalidBuffer;
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 */
key->scanEntry[i].master = NULL;
for( j=0; j<i; j++)
if ( compareEntries( ginstate, entryValues[i], entryValues[j] ) == 0 ) {
for (j = 0; j < i; j++)
if (compareEntries(ginstate, entryValues[i], entryValues[j]) == 0)
{
key->scanEntry[i].master = key->scanEntry + j;
break;
}
@ -66,23 +71,27 @@ fillScanKey( GinState *ginstate, GinScanKey key, Datum query,
#ifdef NOT_USED
static void
resetScanKeys(GinScanKey keys, uint32 nkeys) {
uint32 i, j;
resetScanKeys(GinScanKey keys, uint32 nkeys)
{
uint32 i,
j;
if ( keys == NULL )
if (keys == NULL)
return;
for(i=0;i<nkeys;i++) {
GinScanKey key = keys + i;
for (i = 0; i < nkeys; i++)
{
GinScanKey key = keys + i;
key->firstCall = TRUE;
ItemPointerSet( &(key->curItem), InvalidBlockNumber, InvalidOffsetNumber );
ItemPointerSet(&(key->curItem), InvalidBlockNumber, InvalidOffsetNumber);
for(j=0;j<key->nentries;j++) {
if ( key->scanEntry[j].buffer != InvalidBuffer )
ReleaseBuffer( key->scanEntry[i].buffer );
for (j = 0; j < key->nentries; j++)
{
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].buffer = InvalidBuffer;
key->scanEntry[j].list = NULL;
@ -90,111 +99,121 @@ resetScanKeys(GinScanKey keys, uint32 nkeys) {
}
}
}
#endif
static void
freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes) {
uint32 i, j;
freeScanKeys(GinScanKey keys, uint32 nkeys, bool removeRes)
{
uint32 i,
j;
if ( keys == NULL )
if (keys == NULL)
return;
for(i=0;i<nkeys;i++) {
GinScanKey key = keys + i;
for (i = 0; i < nkeys; i++)
{
GinScanKey key = keys + i;
for(j=0;j<key->nentries;j++) {
if ( key->scanEntry[j].buffer != InvalidBuffer )
ReleaseBuffer( key->scanEntry[j].buffer );
if ( removeRes && key->scanEntry[j].list )
for (j = 0; j < key->nentries; j++)
{
if (key->scanEntry[j].buffer != InvalidBuffer)
ReleaseBuffer(key->scanEntry[j].buffer);
if (removeRes && key->scanEntry[j].list)
pfree(key->scanEntry[j].list);
}
if ( removeRes )
if (removeRes)
pfree(key->entryRes);
pfree(key->scanEntry);
}
pfree(keys);
}
void
newScanKey( IndexScanDesc scan ) {
ScanKey scankey = scan->keyData;
newScanKey(IndexScanDesc scan)
{
ScanKey scankey = scan->keyData;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
int i;
uint32 nkeys = 0;
int i;
uint32 nkeys = 0;
so->keys = (GinScanKey) palloc( scan->numberOfKeys * sizeof(GinScanKeyData) );
so->keys = (GinScanKey) palloc(scan->numberOfKeys * sizeof(GinScanKeyData));
if (scan->numberOfKeys < 1)
ereport(ERROR,
(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++) {
Datum* entryValues;
uint32 nEntryValues;
for (i = 0; i < scan->numberOfKeys; i++)
{
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");
Assert( scankey[i].sk_attno == 1 );
Assert(scankey[i].sk_attno == 1);
entryValues = (Datum*)DatumGetPointer(
FunctionCall3(
&so->ginstate.extractQueryFn,
scankey[i].sk_argument,
PointerGetDatum( &nEntryValues ),
UInt16GetDatum(scankey[i].sk_strategy)
)
);
if ( entryValues==NULL || nEntryValues == 0 )
entryValues = (Datum *) DatumGetPointer(
FunctionCall3(
&so->ginstate.extractQueryFn,
scankey[i].sk_argument,
PointerGetDatum(&nEntryValues),
UInt16GetDatum(scankey[i].sk_strategy)
)
);
if (entryValues == NULL || nEntryValues == 0)
/* full scan... */
continue;
fillScanKey( &so->ginstate, &(so->keys[nkeys]), scankey[i].sk_argument,
entryValues, nEntryValues, scankey[i].sk_strategy );
fillScanKey(&so->ginstate, &(so->keys[nkeys]), scankey[i].sk_argument,
entryValues, nEntryValues, scankey[i].sk_strategy);
nkeys++;
}
so->nkeys = nkeys;
if ( so->nkeys == 0 )
if (so->nkeys == 0)
ereport(ERROR,
(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);
}
Datum
ginrescan(PG_FUNCTION_ARGS) {
ginrescan(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
GinScanOpaque so;
ScanKey scankey = (ScanKey) PG_GETARG_POINTER(1);
GinScanOpaque so;
so = (GinScanOpaque) scan->opaque;
if ( so == NULL ) {
if (so == NULL)
{
/* if called from ginbeginscan */
so = (GinScanOpaque)palloc( sizeof(GinScanOpaqueData) );
so = (GinScanOpaque) palloc(sizeof(GinScanOpaqueData));
so->tempCtx = AllocSetContextCreate(CurrentMemoryContext,
"Gin scan temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
"Gin scan temporary context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
initGinState(&so->ginstate, scan->indexRelation);
scan->opaque = so;
} else {
}
else
{
freeScanKeys(so->keys, so->nkeys, TRUE);
freeScanKeys(so->markPos, so->nkeys, FALSE);
}
so->markPos=so->keys=NULL;
so->markPos = so->keys = NULL;
if ( scankey && scan->numberOfKeys > 0 ) {
if (scankey && scan->numberOfKeys > 0)
{
memmove(scan->keyData, scankey,
scan->numberOfKeys * sizeof(ScanKeyData));
scan->numberOfKeys * sizeof(ScanKeyData));
}
PG_RETURN_VOID();
@ -202,13 +221,15 @@ ginrescan(PG_FUNCTION_ARGS) {
Datum
ginendscan(PG_FUNCTION_ARGS) {
ginendscan(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
GinScanOpaque so = (GinScanOpaque) scan->opaque;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
if ( so != NULL ) {
freeScanKeys(so->keys, so->nkeys, TRUE);
freeScanKeys(so->markPos, so->nkeys, FALSE);
if (so != NULL)
{
freeScanKeys(so->keys, so->nkeys, TRUE);
freeScanKeys(so->markPos, so->nkeys, FALSE);
MemoryContextDelete(so->tempCtx);
@ -219,22 +240,28 @@ ginendscan(PG_FUNCTION_ARGS) {
}
static GinScanKey
copyScanKeys( GinScanKey keys, uint32 nkeys ) {
copyScanKeys(GinScanKey keys, uint32 nkeys)
{
GinScanKey newkeys;
uint32 i, j;
uint32 i,
j;
newkeys = (GinScanKey)palloc( sizeof(GinScanKeyData) * nkeys );
memcpy( newkeys, keys, sizeof(GinScanKeyData) * nkeys );
newkeys = (GinScanKey) palloc(sizeof(GinScanKeyData) * nkeys);
memcpy(newkeys, keys, sizeof(GinScanKeyData) * nkeys);
for(i=0;i<nkeys;i++) {
newkeys[i].scanEntry = (GinScanEntry)palloc(sizeof(GinScanEntryData) * keys[i].nentries );
memcpy( newkeys[i].scanEntry, keys[i].scanEntry, sizeof(GinScanEntryData) * keys[i].nentries );
for (i = 0; i < nkeys; i++)
{
newkeys[i].scanEntry = (GinScanEntry) palloc(sizeof(GinScanEntryData) * keys[i].nentries);
memcpy(newkeys[i].scanEntry, keys[i].scanEntry, sizeof(GinScanEntryData) * keys[i].nentries);
for (j = 0; j < keys[i].nentries; j++)
{
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;
}
}
@ -243,24 +270,26 @@ copyScanKeys( GinScanKey keys, uint32 nkeys ) {
return newkeys;
}
Datum
ginmarkpos(PG_FUNCTION_ARGS) {
Datum
ginmarkpos(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
GinScanOpaque so = (GinScanOpaque) scan->opaque;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
freeScanKeys(so->markPos, so->nkeys, FALSE);
so->markPos = copyScanKeys( so->keys, so->nkeys );
so->markPos = copyScanKeys(so->keys, so->nkeys);
PG_RETURN_VOID();
}
Datum
ginrestrpos(PG_FUNCTION_ARGS) {
Datum
ginrestrpos(PG_FUNCTION_ARGS)
{
IndexScanDesc scan = (IndexScanDesc) PG_GETARG_POINTER(0);
GinScanOpaque so = (GinScanOpaque) scan->opaque;
GinScanOpaque so = (GinScanOpaque) scan->opaque;
freeScanKeys(so->keys, so->nkeys, FALSE);
so->keys = copyScanKeys( so->markPos, so->nkeys );
so->keys = copyScanKeys(so->markPos, so->nkeys);
PG_RETURN_VOID();
}

View File

@ -1,14 +1,14 @@
/*-------------------------------------------------------------------------
*
* 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) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.6 2006/09/05 18:25:10 teodor Exp $
* $PostgreSQL: pgsql/src/backend/access/gin/ginutil.c,v 1.7 2006/10/04 00:29:48 momjian Exp $
*-------------------------------------------------------------------------
*/
@ -19,26 +19,27 @@
#include "access/reloptions.h"
#include "storage/freespace.h"
void
initGinState( GinState *state, Relation index ) {
if ( index->rd_att->natts != 1 )
elog(ERROR, "numberOfAttributes %d != 1",
index->rd_att->natts);
void
initGinState(GinState *state, Relation index)
{
if (index->rd_att->natts != 1)
elog(ERROR, "numberOfAttributes %d != 1",
index->rd_att->natts);
state->tupdesc = index->rd_att;
fmgr_info_copy(&(state->compareFn),
index_getprocinfo(index, 1, GIN_COMPARE_PROC),
CurrentMemoryContext);
index_getprocinfo(index, 1, GIN_COMPARE_PROC),
CurrentMemoryContext);
fmgr_info_copy(&(state->extractValueFn),
index_getprocinfo(index, 1, GIN_EXTRACTVALUE_PROC),
CurrentMemoryContext);
index_getprocinfo(index, 1, GIN_EXTRACTVALUE_PROC),
CurrentMemoryContext);
fmgr_info_copy(&(state->extractQueryFn),
index_getprocinfo(index, 1, GIN_EXTRACTQUERY_PROC),
CurrentMemoryContext);
index_getprocinfo(index, 1, GIN_EXTRACTQUERY_PROC),
CurrentMemoryContext);
fmgr_info_copy(&(state->consistentFn),
index_getprocinfo(index, 1, GIN_CONSISTENT_PROC),
CurrentMemoryContext);
index_getprocinfo(index, 1, GIN_CONSISTENT_PROC),
CurrentMemoryContext);
}
/*
@ -48,13 +49,16 @@ initGinState( GinState *state, Relation index ) {
*/
Buffer
GinNewBuffer(Relation index) {
Buffer buffer;
bool needLock;
GinNewBuffer(Relation index)
{
Buffer buffer;
bool needLock;
/* First, try to get a page from FSM */
for(;;) {
for (;;)
{
BlockNumber blkno = GetFreeIndexPage(&index->rd_node);
if (blkno == InvalidBlockNumber)
break;
@ -64,14 +68,15 @@ GinNewBuffer(Relation index) {
* We have to guard against the possibility that someone else already
* recycled this page; the buffer may be locked if so.
*/
if (ConditionalLockBuffer(buffer)) {
Page page = BufferGetPage(buffer);
if (ConditionalLockBuffer(buffer))
{
Page page = BufferGetPage(buffer);
if (PageIsNew(page))
return buffer; /* OK to use, if never initialized */
return buffer; /* OK to use, if never initialized */
if (GinPageIsDeleted(page))
return buffer; /* OK to use */
return buffer; /* OK to use */
LockBuffer(buffer, GIN_UNLOCK);
}
@ -95,36 +100,39 @@ GinNewBuffer(Relation index) {
}
void
GinInitPage(Page page, uint32 f, Size pageSize) {
GinInitPage(Page page, uint32 f, Size pageSize)
{
GinPageOpaque opaque;
PageInit(page, pageSize, sizeof(GinPageOpaqueData));
opaque = GinPageGetOpaque(page);
memset( opaque, 0, sizeof(GinPageOpaqueData) );
opaque->flags = f;
memset(opaque, 0, sizeof(GinPageOpaqueData));
opaque->flags = f;
opaque->rightlink = InvalidBlockNumber;
}
void
GinInitBuffer(Buffer b, uint32 f) {
GinInitPage( BufferGetPage(b), f, BufferGetPageSize(b) );
GinInitBuffer(Buffer b, uint32 f)
{
GinInitPage(BufferGetPage(b), f, BufferGetPageSize(b));
}
int
compareEntries(GinState *ginstate, Datum a, Datum b) {
compareEntries(GinState *ginstate, Datum a, Datum b)
{
return DatumGetInt32(
FunctionCall2(
&ginstate->compareFn,
a, b
)
FunctionCall2(
&ginstate->compareFn,
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))
/*
* Intel Compiler on Intel Itanium with -O2 has a bug around
* change static variable by user function called from
* libc func: it doesn't change. So mark it as volatile.
@ -132,7 +140,7 @@ static FmgrInfo* cmpDatumPtr=NULL;
* It's a pity, but it's impossible to define optimization
* level here.
*/
#define VOLATILE volatile
#define VOLATILE volatile
#else
#define VOLATILE
#endif
@ -140,57 +148,64 @@ static FmgrInfo* cmpDatumPtr=NULL;
static bool VOLATILE needUnique = FALSE;
static int
cmpEntries(const void * a, const void * b) {
int res = DatumGetInt32(
FunctionCall2(
cmpDatumPtr,
*(Datum*)a,
*(Datum*)b
)
cmpEntries(const void *a, const void *b)
{
int res = DatumGetInt32(
FunctionCall2(
cmpDatumPtr,
*(Datum *) a,
*(Datum *) b
)
);
if ( res == 0 )
if (res == 0)
needUnique = TRUE;
return res;
}
Datum*
extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries) {
Datum *entries;
Datum *
extractEntriesS(GinState *ginstate, Datum value, uint32 *nentries)
{
Datum *entries;
entries = (Datum*)DatumGetPointer(
FunctionCall2(
&ginstate->extractValueFn,
value,
PointerGetDatum( nentries )
)
);
entries = (Datum *) DatumGetPointer(
FunctionCall2(
&ginstate->extractValueFn,
value,
PointerGetDatum(nentries)
)
);
if ( entries == NULL )
if (entries == NULL)
*nentries = 0;
if ( *nentries > 1 ) {
if (*nentries > 1)
{
cmpDatumPtr = &ginstate->compareFn;
needUnique = FALSE;
qsort(entries, *nentries, sizeof(Datum), cmpEntries);
qsort(entries, *nentries, sizeof(Datum), cmpEntries);
}
return entries;
}
Datum*
extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries) {
Datum *entries = extractEntriesS(ginstate, value, nentries);
Datum *
extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries)
{
Datum *entries = extractEntriesS(ginstate, value, nentries);
if ( *nentries>1 && needUnique ) {
Datum *ptr, *res;
if (*nentries > 1 && needUnique)
{
Datum *ptr,
*res;
ptr = res = entries;
while( ptr - entries < *nentries ) {
if ( compareEntries(ginstate, *ptr, *res ) != 0 )
while (ptr - entries < *nentries)
{
if (compareEntries(ginstate, *ptr, *res) != 0)
*(++res) = *ptr++;
else
ptr++;
@ -206,13 +221,14 @@ extractEntriesSU(GinState *ginstate, Datum value, uint32 *nentries) {
* It's analog of PageGetTempPage(), but copies whole page
*/
Page
GinPageGetCopyPage( Page page ) {
Size pageSize = PageGetPageSize( page );
Page tmppage;
GinPageGetCopyPage(Page page)
{
Size pageSize = PageGetPageSize(page);
Page tmppage;
tmppage = (Page) palloc(pageSize);
memcpy(tmppage, page, pageSize);
tmppage=(Page)palloc( pageSize );
memcpy( tmppage, page, pageSize );
return tmppage;
}

View File

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

View File

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

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.142 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gist.c,v 1.143 2006/10/04 00:29:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -185,7 +185,7 @@ gistbuildCallback(Relation index,
/* form an index tuple and point it at the heap tuple */
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;
/*
@ -199,7 +199,7 @@ gistbuildCallback(Relation index,
* after initial build do not.
*/
gistdoinsert(index, itup,
RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR),
RelationGetTargetPageFreeSpace(index, GIST_DEFAULT_FILLFACTOR),
&buildstate->giststate);
buildstate->indtuples += 1;
@ -236,7 +236,7 @@ gistinsert(PG_FUNCTION_ARGS)
initGISTstate(&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;
gistdoinsert(r, itup, 0, &giststate);
@ -285,18 +285,17 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
bool is_leaf = (GistPageIsLeaf(state->stack->page)) ? true : false;
/*
* if (!is_leaf) remove old key:
* This node's key has been modified, either because a child split
* occurred or because we needed to adjust our key for an insert in a
* child node. Therefore, remove the old version of this node's key.
* if (!is_leaf) remove old key: This node's key has been modified, either
* because a child split occurred or because we needed to adjust our key
* for an insert in a child node. Therefore, remove the old version of
* this node's key.
*
* for WAL replay, in the non-split case we handle this by
* setting up a one-element todelete array; in the split case, it's
* handled implicitly because the tuple vector passed to gistSplit
* won't include this tuple.
* for WAL replay, in the non-split case we handle this by setting up a
* one-element todelete array; in the split case, it's handled implicitly
* because the tuple vector passed to gistSplit won't include this tuple.
*
* XXX: If we want to change fillfactors between node and leaf,
* fillfactor = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
* XXX: If we want to change fillfactors between node and leaf, fillfactor
* = (is_leaf ? state->leaf_fillfactor : state->node_fillfactor)
*/
if (gistnospace(state->stack->page, state->itup, state->ituplen,
is_leaf ? InvalidOffsetNumber : state->stack->childoffnum,
@ -307,80 +306,88 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
int tlen;
SplitedPageLayout *dist = NULL,
*ptr;
BlockNumber rrlink = InvalidBlockNumber;
BlockNumber rrlink = InvalidBlockNumber;
GistNSN oldnsn;
is_splitted = true;
/*
* Form index tuples vector to split:
* remove old tuple if t's needed and add new tuples to vector
* Form index tuples vector to split: remove old tuple if t's needed
* and add new tuples to vector
*/
itvec = gistextractpage(state->stack->page, &tlen);
if ( !is_leaf ) {
if (!is_leaf)
{
/* on inner page we should remove old tuple */
int pos = state->stack->childoffnum - FirstOffsetNumber;
int pos = state->stack->childoffnum - FirstOffsetNumber;
tlen--;
if ( pos != tlen )
memmove( itvec+pos, itvec + pos + 1, sizeof( IndexTuple ) * (tlen-pos) );
tlen--;
if (pos != tlen)
memmove(itvec + pos, itvec + pos + 1, sizeof(IndexTuple) * (tlen - pos));
}
itvec = gistjoinvector(itvec, &tlen, state->itup, state->ituplen);
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;
if (state->stack->blkno != GIST_ROOT_BLKNO) {
/* if non-root split then we should not allocate new buffer,
but we must create temporary page to operate */
if (state->stack->blkno != GIST_ROOT_BLKNO)
{
/*
* if non-root split then we should not allocate new buffer, but
* we must create temporary page to operate
*/
dist->buffer = state->stack->buffer;
dist->page = PageGetTempPage( BufferGetPage(dist->buffer), sizeof(GISTPageOpaqueData) );
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;
}
/* make new pages and fills them */
for (ptr = dist; ptr; ptr = ptr->next) {
int i;
char *data;
for (ptr = dist; ptr; ptr = ptr->next)
{
int i;
char *data;
/* get new page */
if ( ptr->buffer == InvalidBuffer ) {
ptr->buffer = gistNewBuffer( state->r );
GISTInitBuffer( ptr->buffer, (is_leaf) ? F_LEAF : 0 );
if (ptr->buffer == InvalidBuffer)
{
ptr->buffer = gistNewBuffer(state->r);
GISTInitBuffer(ptr->buffer, (is_leaf) ? F_LEAF : 0);
ptr->page = BufferGetPage(ptr->buffer);
}
ptr->block.blkno = BufferGetBlockNumber( ptr->buffer );
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 */
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 )
/*
* fill page, we can do it becouse all this pages are new (ie not
* linked in tree or masked by temp page
*/
data = (char *) (ptr->list);
for (i = 0; i < ptr->block.num; i++)
{
if (PageAddItem(ptr->page, (Item) data, IndexTupleSize((IndexTuple) data), i + FirstOffsetNumber, LP_USED) == InvalidOffsetNumber)
elog(ERROR, "failed to add item to index page in \"%s\"", RelationGetRelationName(state->r));
data += IndexTupleSize((IndexTuple)data);
data += IndexTupleSize((IndexTuple) data);
}
/* set up ItemPointer and remmeber it for parent */
ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);
state->itup[ state->ituplen ] = ptr->itup;
state->itup[state->ituplen] = ptr->itup;
state->ituplen++;
}
/* saves old rightlink */
if ( state->stack->blkno != GIST_ROOT_BLKNO )
rrlink = GistPageGetOpaque(dist->page)->rightlink;
if (state->stack->blkno != GIST_ROOT_BLKNO)
rrlink = GistPageGetOpaque(dist->page)->rightlink;
START_CRIT_SECTION();
/*
* must mark buffers dirty before XLogInsert, even though we'll
* still be changing their opaque fields below.
* set up right links.
* must mark buffers dirty before XLogInsert, even though we'll still
* be changing their opaque fields below. set up right links.
*/
for (ptr = dist; ptr; ptr = ptr->next)
for (ptr = dist; ptr; ptr = ptr->next)
{
MarkBufferDirty(ptr->buffer);
GistPageGetOpaque(ptr->page)->rightlink = (ptr->next) ?
@ -388,9 +395,10 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
}
/* restore splitted non-root page */
if ( state->stack->blkno != GIST_ROOT_BLKNO ) {
PageRestoreTempPage( dist->page, BufferGetPage( dist->buffer ) );
dist->page = BufferGetPage( dist->buffer );
if (state->stack->blkno != GIST_ROOT_BLKNO)
{
PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));
dist->page = BufferGetPage(dist->buffer);
}
if (!state->r->rd_istemp)
@ -419,25 +427,27 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
/* set up 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 */
oldnsn = PageGetLSN(dist->page);
for (ptr = dist; ptr; ptr = ptr->next) {
for (ptr = dist; ptr; ptr = ptr->next)
{
/* only for last set oldnsn */
GistPageGetOpaque(ptr->page)->nsn = (ptr->next) ?
PageGetLSN(ptr->page) : oldnsn;
}
/*
* release buffers, if it was a root split then
* release all buffers because we create all buffers
/*
* release buffers, if it was a root split then release all buffers
* because we create all buffers
*/
ptr = ( state->stack->blkno == GIST_ROOT_BLKNO ) ? dist : dist->next;
for(; ptr; ptr = ptr->next)
ptr = (state->stack->blkno == GIST_ROOT_BLKNO) ? dist : dist->next;
for (; ptr; ptr = ptr->next)
UnlockReleaseBuffer(ptr->buffer);
if (state->stack->blkno == GIST_ROOT_BLKNO) {
if (state->stack->blkno == GIST_ROOT_BLKNO)
{
gistnewroot(state->r, state->stack->buffer, state->itup, state->ituplen, &(state->key));
state->needInsertComplete = false;
}
@ -470,7 +480,7 @@ gistplacetopage(GISTInsertState *state, GISTSTATE *giststate)
}
rdata = formUpdateRdata(state->r->rd_node, state->stack->buffer,
offs, noffs,
offs, noffs,
state->itup, state->ituplen,
&(state->key));
@ -922,16 +932,16 @@ gistSplit(Relation r,
GistSplitVector v;
GistEntryVector *entryvec;
int i;
SplitedPageLayout *res = NULL;
SplitedPageLayout *res = NULL;
/* generate the item array */
entryvec = palloc(GEVHDRSZ + (len + 1) * sizeof(GISTENTRY));
entryvec->n = len + 1;
memset( v.spl_lisnull, TRUE, sizeof(bool) * giststate->tupdesc->natts );
memset( v.spl_risnull, TRUE, sizeof(bool) * giststate->tupdesc->natts );
gistSplitByKey(r, page, itup, len, giststate,
&v, entryvec, 0);
memset(v.spl_lisnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);
memset(v.spl_risnull, TRUE, sizeof(bool) * giststate->tupdesc->natts);
gistSplitByKey(r, page, itup, len, giststate,
&v, entryvec, 0);
/* form left and right vector */
lvectup = (IndexTuple *) palloc(sizeof(IndexTuple) * (len + 1));
@ -952,19 +962,20 @@ gistSplit(Relation r,
{
ROTATEDIST(res);
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)
: gist_form_invalid_tuple(GIST_ROOT_BLKNO);
}
if (!gistfitpage(lvectup, v.splitVector.spl_nleft))
{
SplitedPageLayout *resptr, *subres;
SplitedPageLayout *resptr,
*subres;
resptr = subres = gistSplit(r, page, lvectup, v.splitVector.spl_nleft, giststate);
/* install on list's tail */
while( resptr->next )
/* install on list's tail */
while (resptr->next)
resptr = resptr->next;
resptr->next = res;
@ -974,7 +985,7 @@ gistSplit(Relation r,
{
ROTATEDIST(res);
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)
: gist_form_invalid_tuple(GIST_ROOT_BLKNO);
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.60 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistget.c,v 1.61 2006/10/04 00:29:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -360,8 +360,7 @@ gistindex_keytest(IndexTuple tuple,
IncrIndexProcessed();
/*
* Tuple doesn't restore after crash recovery because of incomplete
* insert
* Tuple doesn't restore after crash recovery because of incomplete insert
*/
if (!GistPageIsLeaf(p) && GistTupleIsInvalid(tuple))
return true;
@ -378,14 +377,18 @@ gistindex_keytest(IndexTuple tuple,
giststate->tupdesc,
&isNull);
if ( key->sk_flags & SK_ISNULL ) {
/* is the compared-to datum NULL? on non-leaf page it's possible
to have nulls in childs :( */
if (key->sk_flags & SK_ISNULL)
{
/*
* is the compared-to datum NULL? on non-leaf page it's possible
* to have nulls in childs :(
*/
if ( isNull || !GistPageIsLeaf(p) )
if (isNull || !GistPageIsLeaf(p))
return true;
return false;
} else if ( isNull )
}
else if (isNull)
return false;
gistdentryinit(giststate, key->sk_attno - 1, &de,

View File

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

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.64 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistscan.c,v 1.65 2006/10/04 00:29:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -228,12 +228,12 @@ gistendscan(PG_FUNCTION_ARGS)
static void
gistfreestack(GISTSearchStack *s)
{
{
while (s != NULL)
{
GISTSearchStack *p = s->next;
pfree(s);
s = p;
}
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistsplit.c,v 1.2 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistsplit.c,v 1.3 2006/10/04 00:29:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -16,12 +16,13 @@
#include "access/gist_private.h"
typedef struct {
Datum *attr;
int len;
typedef struct
{
Datum *attr;
int len;
OffsetNumber *entries;
bool *isnull;
bool *equiv;
bool *isnull;
bool *equiv;
} GistSplitUnion;
@ -29,25 +30,28 @@ typedef struct {
* Forms unions of subkeys after page split, but
* uses only tuples aren't in groups of equalent tuples
*/
static void
gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
GistSplitUnion *gsvp, int startkey) {
IndexTuple *cleanedItVec;
int i, cleanedLen=0;
static void
gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
GistSplitUnion *gsvp, int startkey)
{
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++) {
if ( gsvp->equiv && gsvp->equiv[gsvp->entries[i]])
for (i = 0; i < gsvp->len; i++)
{
if (gsvp->equiv && gsvp->equiv[gsvp->entries[i]])
continue;
cleanedItVec[cleanedLen++] = itvec[gsvp->entries[i] - 1];
}
gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, startkey,
gsvp->attr, gsvp->isnull);
gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen, startkey,
gsvp->attr, gsvp->isnull);
pfree( cleanedItVec );
pfree(cleanedItVec);
}
/*
@ -56,7 +60,7 @@ gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
static void
gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl, int attno)
{
GistSplitUnion gsvp;
GistSplitUnion gsvp;
gsvp.equiv = spl->spl_equiv;
@ -76,34 +80,40 @@ gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl, i
}
/*
* find group in vector with equivalent value
* find group in vector with equivalent value
*/
static int
gistfindgroup(Relation r, GISTSTATE *giststate, GISTENTRY *valvec, GistSplitVector *spl, int attno)
{
int i;
GISTENTRY entry;
int len=0;
int len = 0;
/*
* attno key is always not null (see gistSplitByKey), so we may not check for
* nulls
* attno key is always not null (see gistSplitByKey), so we may not check
* for nulls
*/
gistentryinit(entry, spl->splitVector.spl_rdatum, r, NULL, (OffsetNumber) 0, FALSE);
for (i = 0; i < spl->splitVector.spl_nleft; i++) {
float penalty = gistpenalty(giststate, attno, &entry, false,
&valvec[spl->splitVector.spl_left[i]], false);
if ( penalty == 0.0 ) {
for (i = 0; i < spl->splitVector.spl_nleft; i++)
{
float penalty = gistpenalty(giststate, attno, &entry, false,
&valvec[spl->splitVector.spl_left[i]], false);
if (penalty == 0.0)
{
spl->spl_equiv[spl->splitVector.spl_left[i]] = true;
len++;
}
}
gistentryinit(entry, spl->splitVector.spl_ldatum, r, NULL, (OffsetNumber) 0, FALSE);
for (i = 0; i < spl->splitVector.spl_nright; i++) {
float penalty = gistpenalty(giststate, attno, &entry, false,
&valvec[spl->splitVector.spl_right[i]], false);
if ( penalty == 0.0 ) {
for (i = 0; i < spl->splitVector.spl_nright; i++)
{
float penalty = gistpenalty(giststate, attno, &entry, false,
&valvec[spl->splitVector.spl_right[i]], false);
if (penalty == 0.0)
{
spl->spl_equiv[spl->splitVector.spl_right[i]] = true;
len++;
}
@ -113,24 +123,32 @@ gistfindgroup(Relation r, GISTSTATE *giststate, GISTENTRY *valvec, GistSplitVect
}
static void
cleanupOffsets( OffsetNumber *a, int *len, bool *equiv, int *LenEquiv ) {
int curlen,i;
OffsetNumber *curwpos;
cleanupOffsets(OffsetNumber *a, int *len, bool *equiv, int *LenEquiv)
{
int curlen,
i;
OffsetNumber *curwpos;
curlen = *len;
curwpos = a;
for (i = 0; i < *len; i++) {
if ( equiv[ a[i] ] == FALSE ) {
for (i = 0; i < *len; i++)
{
if (equiv[a[i]] == FALSE)
{
*curwpos = a[i];
curwpos++;
} else {
}
else
{
/* corner case: we shouldn't make void array */
if ( curlen==1 ) {
equiv[ a[i] ] = FALSE; /* mark item as non-equivalent */
i--; /* redo the same */
if (curlen == 1)
{
equiv[a[i]] = FALSE; /* mark item as non-equivalent */
i--; /* redo the same */
*LenEquiv -= 1;
continue;
} else
}
else
curlen--;
}
}
@ -139,33 +157,37 @@ cleanupOffsets( OffsetNumber *a, int *len, bool *equiv, int *LenEquiv ) {
}
static void
placeOne( Relation r, GISTSTATE *giststate, GistSplitVector *v, IndexTuple itup, OffsetNumber off, int attno ) {
placeOne(Relation r, GISTSTATE *giststate, GistSplitVector *v, IndexTuple itup, OffsetNumber off, int attno)
{
GISTENTRY identry[INDEX_MAX_KEYS];
bool isnull[INDEX_MAX_KEYS];
bool toLeft = true;
bool toLeft = true;
gistDeCompressAtt(giststate, r, itup, NULL, (OffsetNumber) 0, identry, isnull);
for(;attno<giststate->tupdesc->natts;attno++) {
float lpenalty, rpenalty;
for (; attno < giststate->tupdesc->natts; attno++)
{
float lpenalty,
rpenalty;
GISTENTRY entry;
gistentryinit(entry, v->spl_lattr[attno], r, NULL, 0, FALSE);
lpenalty = gistpenalty(giststate, attno, &entry, v->spl_lisnull[attno], identry+attno, isnull[ attno ]);
gistentryinit(entry, v->spl_rattr[attno], r, NULL, 0, FALSE);
rpenalty = gistpenalty(giststate, attno, &entry, v->spl_risnull[attno], identry+attno, isnull[ attno ]);
gistentryinit(entry, v->spl_lattr[attno], r, NULL, 0, FALSE);
lpenalty = gistpenalty(giststate, attno, &entry, v->spl_lisnull[attno], identry + attno, isnull[attno]);
gistentryinit(entry, v->spl_rattr[attno], r, NULL, 0, FALSE);
rpenalty = gistpenalty(giststate, attno, &entry, v->spl_risnull[attno], identry + attno, isnull[attno]);
if ( lpenalty != rpenalty ) {
if ( lpenalty > rpenalty )
if (lpenalty != rpenalty)
{
if (lpenalty > rpenalty)
toLeft = false;
break;
}
}
if ( toLeft )
v->splitVector.spl_left[ v->splitVector.spl_nleft++ ] = off;
if (toLeft)
v->splitVector.spl_left[v->splitVector.spl_nleft++] = off;
else
v->splitVector.spl_right[ v->splitVector.spl_nright++ ] = off;
v->splitVector.spl_right[v->splitVector.spl_nright++] = off;
}
#define SWAPVAR( s, d, t ) \
@ -176,71 +198,83 @@ do { \
} while(0)
/*
* adjust left and right unions according to splits by previous
* split by firsts columns. This function is called only in case
* adjust left and right unions according to splits by previous
* split by firsts columns. This function is called only in case
* when pickSplit doesn't support subspplit.
*/
static void
supportSecondarySplit( Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVEC *sv, Datum oldL, Datum oldR ) {
bool leaveOnLeft = true, tmpBool;
GISTENTRY entryL, entryR, entrySL, entrySR;
gistentryinit(entryL, oldL, r, NULL, 0, FALSE);
gistentryinit(entryR, oldR, r, NULL, 0, FALSE);
gistentryinit(entrySL, sv->spl_ldatum , r, NULL, 0, FALSE);
gistentryinit(entrySR, sv->spl_rdatum , r, NULL, 0, FALSE);
supportSecondarySplit(Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVEC *sv, Datum oldL, Datum oldR)
{
bool leaveOnLeft = true,
tmpBool;
GISTENTRY entryL,
entryR,
entrySL,
entrySR;
if ( sv->spl_ldatum_exists && sv->spl_rdatum_exists ) {
float penalty1, penalty2;
gistentryinit(entryL, oldL, r, NULL, 0, FALSE);
gistentryinit(entryR, oldR, r, NULL, 0, FALSE);
gistentryinit(entrySL, sv->spl_ldatum, r, NULL, 0, FALSE);
gistentryinit(entrySR, sv->spl_rdatum, r, NULL, 0, FALSE);
if (sv->spl_ldatum_exists && sv->spl_rdatum_exists)
{
float penalty1,
penalty2;
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) +
gistpenalty(giststate, attno, &entryR, false, &entrySL, false);
gistpenalty(giststate, attno, &entryR, false, &entrySL, false);
if ( penalty1 > penalty2 )
if (penalty1 > penalty2)
leaveOnLeft = false;
} else {
GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR;
float penalty1, penalty2;
}
else
{
GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR;
float penalty1,
penalty2;
/*
* there is only one previously defined union,
* so we just choose swap or not by lowest penalty
* there is only one previously defined union, so we just choose swap
* or not by lowest penalty
*/
penalty1 = gistpenalty(giststate, attno, entry1, false, &entrySL, false);
penalty2 = gistpenalty(giststate, attno, entry1, false, &entrySR, false);
if ( penalty1 < penalty2 )
leaveOnLeft = ( sv->spl_ldatum_exists ) ? true : false;
if (penalty1 < penalty2)
leaveOnLeft = (sv->spl_ldatum_exists) ? true : false;
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;
Datum datum;
OffsetNumber *off,
noff;
Datum datum;
SWAPVAR( sv->spl_left, sv->spl_right, off );
SWAPVAR( sv->spl_nleft, sv->spl_nright, noff );
SWAPVAR( sv->spl_ldatum, sv->spl_rdatum, datum );
gistentryinit(entrySL, sv->spl_ldatum , r, NULL, 0, FALSE);
gistentryinit(entrySR, sv->spl_rdatum , r, NULL, 0, FALSE);
SWAPVAR(sv->spl_left, sv->spl_right, off);
SWAPVAR(sv->spl_nleft, sv->spl_nright, noff);
SWAPVAR(sv->spl_ldatum, sv->spl_rdatum, datum);
gistentryinit(entrySL, sv->spl_ldatum, 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,
&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,
&sv->spl_rdatum, &tmpBool);
&sv->spl_rdatum, &tmpBool);
sv->spl_ldatum_exists = sv->spl_rdatum_exists = false;
}
@ -251,20 +285,21 @@ supportSecondarySplit( Relation r, GISTSTATE *giststate, int attno, GIST_SPLITVE
* get better split.
* Returns TRUE and v->spl_equiv = NULL if left and right unions of attno columns are the same,
* so caller may find better split
* Returns TRUE and v->spl_equiv != NULL if there is tuples which may be freely moved
* Returns TRUE and v->spl_equiv != NULL if there is tuples which may be freely moved
*/
static bool
gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVector *v,
IndexTuple *itup, int len, GISTSTATE *giststate)
{
GIST_SPLITVEC *sv = &v->splitVector;
/*
* now let the user-defined picksplit function set up the split vector; in
* entryvec have no null value!!
*/
sv->spl_ldatum_exists = ( v->spl_lisnull[ attno ] ) ? false : true;
sv->spl_rdatum_exists = ( v->spl_risnull[ 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_ldatum = v->spl_lattr[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)
sv->spl_right[sv->spl_nright - 1] = (OffsetNumber) (entryvec->n - 1);
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) );
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));
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;
@ -296,53 +332,64 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
*/
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
* we can get better split by following columns. Note,
* unions for attno columns are already done.
* Left and right key's unions are equial, so we can get better
* split by following columns. Note, unions for attno columns are
* already done.
*/
return true;
} else {
}
else
{
int LenEquiv;
v->spl_equiv = (bool *) palloc0(sizeof(bool) * (entryvec->n+1));
v->spl_equiv = (bool *) palloc0(sizeof(bool) * (entryvec->n + 1));
LenEquiv = gistfindgroup(r, giststate, entryvec->vector, v, attno);
/*
* if possible, we should distribute equivalent tuples
*/
if (LenEquiv == 0 ) {
* if possible, we should distribute equivalent tuples
*/
if (LenEquiv == 0)
{
gistunionsubkey(giststate, itup, v, attno + 1);
} else {
cleanupOffsets( sv->spl_left, &sv->spl_nleft, v->spl_equiv, &LenEquiv );
cleanupOffsets( sv->spl_right, &sv->spl_nright, v->spl_equiv, &LenEquiv );
}
else
{
cleanupOffsets(sv->spl_left, &sv->spl_nleft, v->spl_equiv, &LenEquiv);
cleanupOffsets(sv->spl_right, &sv->spl_nright, v->spl_equiv, &LenEquiv);
gistunionsubkey(giststate, itup, v, attno + 1);
if (LenEquiv == 1 ) {
if (LenEquiv == 1)
{
/*
* In case with one tuple we just choose left-right
* by penalty. It's simplify user-defined pickSplit
* In case with one tuple we just choose left-right by
* penalty. It's simplify user-defined pickSplit
*/
OffsetNumber toMove = InvalidOffsetNumber;
for(toMove=FirstOffsetNumber;toMove<entryvec->n;toMove++)
if ( v->spl_equiv[ toMove ] )
for (toMove = FirstOffsetNumber; toMove < entryvec->n; toMove++)
if (v->spl_equiv[toMove])
break;
Assert( toMove < entryvec->n );
placeOne( r, giststate, v, itup[ toMove-1 ], toMove, attno+1 );
/* redo gistunionsubkey(): it will not degradate performance,
* because it's very rarely */
Assert(toMove < entryvec->n);
placeOne(r, giststate, v, itup[toMove - 1], toMove, attno + 1);
/*
* redo gistunionsubkey(): it will not degradate
* performance, because it's very rarely
*/
v->spl_equiv = NULL;
gistunionsubkey(giststate, itup, v, attno + 1);
return false;
} else if ( LenEquiv > 1 )
}
else if (LenEquiv > 1)
return true;
}
}
@ -352,60 +399,65 @@ gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVec
}
/*
* simple split page
* simple split page
*/
static void
gistSplitHalf(GIST_SPLITVEC *v, int len) {
int i;
gistSplitHalf(GIST_SPLITVEC *v, int len)
{
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_right= (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
for(i = 1; i <= len; i++)
if ( i<len/2 )
v->spl_right[ v->spl_nright++ ] = i;
v->spl_right = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
for (i = 1; i <= len; i++)
if (i < len / 2)
v->spl_right[v->spl_nright++] = i;
else
v->spl_left[ v->spl_nleft++ ] = i;
v->spl_left[v->spl_nleft++] = i;
}
/*
* if it was invalid tuple then we need special processing.
* We move all invalid tuples on right page.
* We move all invalid tuples on right page.
*
* if there is no place on left page, gistSplit will be called one more
* if there is no place on left page, gistSplit will be called one more
* time for left page.
*
* Normally, we never exec this code, but after crash replay it's possible
* to get 'invalid' tuples (probability is low enough)
*/
static void
gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, int len) {
int i;
static OffsetNumber offInvTuples[ MaxOffsetNumber ];
int nOffInvTuples = 0;
gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, int len)
{
int i;
static OffsetNumber offInvTuples[MaxOffsetNumber];
int nOffInvTuples = 0;
for (i = 1; i <= len; i++)
if ( GistTupleIsInvalid(itup[i - 1]) )
offInvTuples[ nOffInvTuples++ ] = i;
if (GistTupleIsInvalid(itup[i - 1]))
offInvTuples[nOffInvTuples++] = i;
if ( nOffInvTuples == len ) {
if (nOffInvTuples == len)
{
/* corner case, all tuples are invalid */
v->spl_rightvalid= v->spl_leftvalid = false;
gistSplitHalf( &v->splitVector, len );
} else {
GistSplitUnion gsvp;
v->spl_rightvalid = v->spl_leftvalid = false;
gistSplitHalf(&v->splitVector, len);
}
else
{
GistSplitUnion gsvp;
v->splitVector.spl_right = offInvTuples;
v->splitVector.spl_nright = nOffInvTuples;
v->spl_rightvalid = false;
v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
v->splitVector.spl_nleft = 0;
for(i = 1; i <= len; i++)
if ( !GistTupleIsInvalid(itup[i - 1]) )
v->splitVector.spl_left[ v->splitVector.spl_nleft++ ] = i;
for (i = 1; i <= len; i++)
if (!GistTupleIsInvalid(itup[i - 1]))
v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
v->spl_leftvalid = true;
gsvp.equiv = NULL;
gsvp.attr = v->spl_lattr;
gsvp.len = v->splitVector.spl_nleft;
@ -418,52 +470,58 @@ gistSplitByInvalid(GISTSTATE *giststate, GistSplitVector *v, IndexTuple *itup, i
/*
* trys to split page by attno key, in a case of null
* values move its to separate page.
* values move its to separate page.
*/
void
gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate,
GistSplitVector *v, GistEntryVector *entryvec, int attno) {
int i;
static OffsetNumber offNullTuples[ MaxOffsetNumber ];
int nOffNullTuples = 0;
gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *giststate,
GistSplitVector *v, GistEntryVector *entryvec, int attno)
{
int i;
static OffsetNumber offNullTuples[MaxOffsetNumber];
int nOffNullTuples = 0;
for (i = 1; i <= len; i++) {
Datum datum;
bool IsNull;
for (i = 1; i <= len; i++)
{
Datum datum;
bool IsNull;
if (!GistPageIsLeaf(page) && GistTupleIsInvalid(itup[i - 1])) {
if (!GistPageIsLeaf(page) && GistTupleIsInvalid(itup[i - 1]))
{
gistSplitByInvalid(giststate, v, itup, len);
return;
}
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]),
datum, r, page, i,
FALSE, IsNull);
if ( IsNull )
offNullTuples[ nOffNullTuples++ ] = i;
if (IsNull)
offNullTuples[nOffNullTuples++] = i;
}
v->spl_leftvalid = v->spl_rightvalid = true;
if ( nOffNullTuples == len ) {
/*
if (nOffNullTuples == len)
{
/*
* Corner case: All keys in attno column are null, we should try to
* split by keys in next column. It all keys in all columns
* are NULL just split page half by half
* split by keys in next column. It all keys in all columns are NULL
* just split page half by half
*/
v->spl_risnull[attno] = v->spl_lisnull[attno] = TRUE;
if ( attno+1 == r->rd_att->natts )
gistSplitHalf( &v->splitVector, len );
else
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno+1);
} else if ( nOffNullTuples > 0 ) {
int j=0;
/*
* We don't want to mix NULLs and not-NULLs keys
* on one page, so move nulls to right page
if (attno + 1 == r->rd_att->natts)
gistSplitHalf(&v->splitVector, len);
else
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno + 1);
}
else if (nOffNullTuples > 0)
{
int j = 0;
/*
* We don't want to mix NULLs and not-NULLs keys on one page, so move
* nulls to right page
*/
v->splitVector.spl_right = offNullTuples;
v->splitVector.spl_nright = nOffNullTuples;
@ -471,61 +529,71 @@ gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len, GISTSTATE *gist
v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
v->splitVector.spl_nleft = 0;
for(i = 1; i <= len; i++)
if ( j<v->splitVector.spl_nright && offNullTuples[j] == i )
for (i = 1; i <= len; i++)
if (j < v->splitVector.spl_nright && offNullTuples[j] == i)
j++;
else
v->splitVector.spl_left[ v->splitVector.spl_nleft++ ] = i;
v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
v->spl_equiv = NULL;
gistunionsubkey(giststate, itup, v, attno);
} else {
}
else
{
/*
* 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
* left or right page, we will try to split page by
* following columns
* Splitting on attno column is not optimized: there is a tuples
* which can be freely left or right page, we will try to split
* page by following columns
*/
if ( v->spl_equiv == NULL ) {
/* simple case: left and right keys for attno column are equial */
gistSplitByKey(r, page, itup, len, giststate, v, entryvec, attno+1);
} else {
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
{
/* we should clean up vector from already distributed tuples */
IndexTuple *newitup = (IndexTuple*)palloc((len + 1) * sizeof(IndexTuple));
OffsetNumber *map = (OffsetNumber*)palloc((len + 1) * sizeof(IndexTuple));
int newlen = 0;
IndexTuple *newitup = (IndexTuple *) palloc((len + 1) * sizeof(IndexTuple));
OffsetNumber *map = (OffsetNumber *) palloc((len + 1) * sizeof(IndexTuple));
int newlen = 0;
GIST_SPLITVEC backupSplit = v->splitVector;
for(i=0; i<len; i++)
if ( v->spl_equiv[i+1] ) {
map[ newlen ] = i+1;
newitup[ newlen++ ] = itup[i];
for (i = 0; i < len; i++)
if (v->spl_equiv[i + 1])
{
map[newlen] = i + 1;
newitup[newlen++] = itup[i];
}
Assert( newlen>0 );
Assert(newlen > 0);
backupSplit.spl_left = (OffsetNumber*)palloc(sizeof(OffsetNumber)*len);
memcpy( backupSplit.spl_left, v->splitVector.spl_left, sizeof(OffsetNumber)*v->splitVector.spl_nleft);
backupSplit.spl_right = (OffsetNumber*)palloc(sizeof(OffsetNumber)*len);
memcpy( backupSplit.spl_right, v->splitVector.spl_right, sizeof(OffsetNumber)*v->splitVector.spl_nright);
backupSplit.spl_left = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
memcpy(backupSplit.spl_left, v->splitVector.spl_left, sizeof(OffsetNumber) * v->splitVector.spl_nleft);
backupSplit.spl_right = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
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 */
for(i=0;i<v->splitVector.spl_nleft;i++)
backupSplit.spl_left[ backupSplit.spl_nleft++ ] = map[ v->splitVector.spl_left[i]-1 ];
for(i=0;i<v->splitVector.spl_nright;i++)
backupSplit.spl_right[ backupSplit.spl_nright++ ] = map[ v->splitVector.spl_right[i]-1 ];
for (i = 0; i < v->splitVector.spl_nleft; i++)
backupSplit.spl_left[backupSplit.spl_nleft++] = map[v->splitVector.spl_left[i] - 1];
for (i = 0; i < v->splitVector.spl_nright; i++)
backupSplit.spl_right[backupSplit.spl_nright++] = map[v->splitVector.spl_right[i] - 1];
v->splitVector = backupSplit;
/* reunion left and right datums */
gistunionsubkey(giststate, itup, v, attno);
}
}
}
}
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.19 2006/07/14 14:52:16 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistutil.c,v 1.20 2006/10/04 00:29:48 momjian Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@ -22,8 +22,8 @@
* static *S used for temrorary storage (saves stack and palloc() call)
*/
static Datum attrS[INDEX_MAX_KEYS];
static bool isnullS[INDEX_MAX_KEYS];
static Datum attrS[INDEX_MAX_KEYS];
static bool isnullS[INDEX_MAX_KEYS];
/*
* Write itup vector to page, has no control of free space
@ -57,14 +57,17 @@ gistfillbuffer(Relation r, Page page, IndexTuple *itup,
bool
gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size freespace)
{
unsigned int size = freespace, deleted = 0;
unsigned int size = freespace,
deleted = 0;
int i;
for (i = 0; i < len; i++)
size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
if ( todelete != InvalidOffsetNumber ) {
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, todelete));
if (todelete != InvalidOffsetNumber)
{
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, todelete));
deleted = IndexTupleSize(itup) + sizeof(ItemIdData);
}
@ -72,11 +75,12 @@ gistnospace(Page page, IndexTuple *itvec, int len, OffsetNumber todelete, Size f
}
bool
gistfitpage(IndexTuple *itvec, int len) {
int i;
Size size=0;
gistfitpage(IndexTuple *itvec, int len)
{
int i;
Size size = 0;
for(i=0;i<len;i++)
for (i = 0; i < len; i++)
size += IndexTupleSize(itvec[i]) + sizeof(ItemIdData);
/* TODO: Consider fillfactor */
@ -119,56 +123,64 @@ gistjoinvector(IndexTuple *itvec, int *len, IndexTuple *additvec, int addlen)
*/
IndexTupleData *
gistfillitupvec(IndexTuple *vec, int veclen, int *memlen) {
char *ptr, *ret;
int i;
gistfillitupvec(IndexTuple *vec, int veclen, int *memlen)
{
char *ptr,
*ret;
int i;
*memlen = 0;
*memlen=0;
for (i = 0; i < veclen; i++)
*memlen += IndexTupleSize(vec[i]);
ptr = ret = palloc(*memlen);
for (i = 0; i < veclen; i++) {
for (i = 0; i < veclen; i++)
{
memcpy(ptr, vec[i], IndexTupleSize(vec[i]));
ptr += IndexTupleSize(vec[i]);
}
return (IndexTupleData*)ret;
return (IndexTupleData *) ret;
}
/*
* Make unions of keys in IndexTuple vector, return FALSE if itvec contains
* Make unions of keys in IndexTuple vector, return FALSE if itvec contains
* invalid tuple. Resulting Datums aren't compressed.
*/
bool
gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey,
Datum *attr, bool *isnull ) {
bool
gistMakeUnionItVec(GISTSTATE *giststate, IndexTuple *itvec, int len, int startkey,
Datum *attr, bool *isnull)
{
int i;
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++) {
int j;
for (i = startkey; i < giststate->tupdesc->natts; i++)
{
int j;
evec->n = 0;
if ( !isnull[i] ) {
gistentryinit( evec->vector[evec->n], attr[i],
NULL, NULL, (OffsetNumber) 0,
FALSE);
if (!isnull[i])
{
gistentryinit(evec->vector[evec->n], attr[i],
NULL, NULL, (OffsetNumber) 0,
FALSE);
evec->n++;
}
for (j = 0; j < len; j++) {
Datum datum;
bool IsNull;
for (j = 0; j < len; j++)
{
Datum datum;
bool IsNull;
if (GistTupleIsInvalid(itvec[j]))
return FALSE; /* signals that union with invalid tuple => result is invalid */
if (GistTupleIsInvalid(itvec[j]))
return FALSE; /* signals that union with invalid tuple =>
* result is invalid */
datum = index_getattr(itvec[j], i + 1, giststate->tupdesc, &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 ( evec->n == 0 ) {
if (evec->n == 0)
{
attr[i] = (Datum) 0;
isnull[i] = TRUE;
} else {
if (evec->n == 1) {
}
else
{
if (evec->n == 1)
{
evec->n = 2;
evec->vector[1] = evec->vector[0];
}
}
/* Make union and store in attr array */
attr[i] = FunctionCall2(&giststate->unionFn[i],
PointerGetDatum(evec),
PointerGetDatum(&attrsize));
PointerGetDatum(evec),
PointerGetDatum(&attrsize));
isnull[i] = FALSE;
}
@ -213,57 +229,67 @@ gistunion(Relation r, IndexTuple *itvec, int len, GISTSTATE *giststate)
{
memset(isnullS, TRUE, sizeof(bool) * giststate->tupdesc->natts);
if ( !gistMakeUnionItVec(giststate, itvec, len, 0, attrS, isnullS ) )
return gist_form_invalid_tuple(InvalidBlockNumber);
if (!gistMakeUnionItVec(giststate, itvec, len, 0, attrS, isnullS))
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
*/
void
gistMakeUnionKey( GISTSTATE *giststate, int attno,
GISTENTRY *entry1, bool isnull1,
GISTENTRY *entry2, bool isnull2,
Datum *dst, bool *dstisnull ) {
gistMakeUnionKey(GISTSTATE *giststate, int attno,
GISTENTRY *entry1, bool isnull1,
GISTENTRY *entry2, bool isnull2,
Datum *dst, bool *dstisnull)
{
int dstsize;
int dstsize;
static char storage[ 2 * sizeof(GISTENTRY) + GEVHDRSZ ];
GistEntryVector *evec = (GistEntryVector*)storage;
static char storage[2 * sizeof(GISTENTRY) + GEVHDRSZ];
GistEntryVector *evec = (GistEntryVector *) storage;
evec->n = 2;
if ( isnull1 && isnull2 ) {
if (isnull1 && isnull2)
{
*dstisnull = TRUE;
*dst = (Datum)0;
} else {
if ( isnull1 == FALSE && isnull2 == FALSE ) {
*dst = (Datum) 0;
}
else
{
if (isnull1 == FALSE && isnull2 == FALSE)
{
evec->vector[0] = *entry1;
evec->vector[1] = *entry2;
} else if ( isnull1 == FALSE ) {
}
else if (isnull1 == FALSE)
{
evec->vector[0] = *entry1;
evec->vector[1] = *entry1;
} else {
}
else
{
evec->vector[0] = *entry2;
evec->vector[1] = *entry2;
}
*dstisnull = FALSE;
*dst = FunctionCall2(&giststate->unionFn[attno],
PointerGetDatum(evec),
PointerGetDatum(&dstsize));
PointerGetDatum(evec),
PointerGetDatum(&dstsize));
}
}
bool
gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b) {
bool result;
gistKeyIsEQ(GISTSTATE *giststate, int attno, Datum a, Datum b)
{
bool result;
FunctionCall3(&giststate->equalFn[attno],
a, b,
PointerGetDatum(&result));
a, b,
PointerGetDatum(&result));
return result;
}
@ -309,22 +335,24 @@ gistgetadjusted(Relation r, IndexTuple oldtup, IndexTuple addtup, GISTSTATE *gis
gistDeCompressAtt(giststate, r, addtup, NULL,
(OffsetNumber) 0, addentries, addisnull);
for(i = 0; i < r->rd_att->natts; i++) {
gistMakeUnionKey( giststate, i,
oldentries + i, oldisnull[i],
addentries + i, addisnull[i],
attrS + i, isnullS + i );
for (i = 0; i < r->rd_att->natts; i++)
{
gistMakeUnionKey(giststate, i,
oldentries + i, oldisnull[i],
addentries + i, addisnull[i],
attrS + i, isnullS + i);
if ( neednew )
if (neednew)
/* we already need new key, so we can skip check */
continue;
if ( isnullS[i] )
if (isnullS[i])
/* union of key may be NULL if and only if both keys are NULL */
continue;
if ( !addisnull[i] ) {
if ( oldisnull[i] || gistKeyIsEQ(giststate, i, oldentries[i].key, attrS[i])==false )
if (!addisnull[i])
{
if (oldisnull[i] || gistKeyIsEQ(giststate, i, oldentries[i].key, attrS[i]) == false)
neednew = true;
}
}
@ -363,8 +391,8 @@ gistchoose(Relation r, Page p, IndexTuple it, /* it has compressed entry */
it, NULL, (OffsetNumber) 0,
identry, isnull);
Assert( maxoff >= FirstOffsetNumber );
Assert( !GistPageIsLeaf(p) );
Assert(maxoff >= FirstOffsetNumber);
Assert(!GistPageIsLeaf(p));
for (i = FirstOffsetNumber; i <= maxoff && sum_grow; i = OffsetNumberNext(i))
{
@ -484,7 +512,7 @@ gistFormTuple(GISTSTATE *giststate, Relation r,
{
gistcentryinit(giststate, i, &centry[i], attdata[i],
r, NULL, (OffsetNumber) 0,
newValues,
newValues,
FALSE);
compatt[i] = centry[i].key;
}
@ -500,18 +528,19 @@ gistpenalty(GISTSTATE *giststate, int attno,
GISTENTRY *orig, bool isNullOrig,
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],
PointerGetDatum(orig),
PointerGetDatum(add),
PointerGetDatum(&penalty));
else if ( isNullOrig && isNullAdd )
else if (isNullOrig && isNullAdd)
penalty = 0.0;
else
penalty = 1e10; /* try to prevent to mix null and non-null value */
penalty = 1e10; /* try to prevent to mix null and non-null
* value */
return penalty;
}

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.27 2006/09/21 20:31:21 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistvacuum.c,v 1.28 2006/10/04 00:29:48 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@ -45,19 +45,24 @@ typedef struct
} ArrayTuple;
/*
* Make union of keys on page
* Make union of keys on page
*/
static IndexTuple
PageMakeUnionKey(GistVacuum *gv, Buffer buffer) {
Page page = BufferGetPage( buffer );
PageMakeUnionKey(GistVacuum *gv, Buffer buffer)
{
Page page = BufferGetPage(buffer);
IndexTuple *vec,
tmp, res;
tmp,
res;
int veclen = 0;
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
vec = gistextractpage(page, &veclen);
/* we call gistunion() in temprorary context because user-defined functions called in gistunion()
may do not free all memory */
/*
* we call gistunion() in temprorary context because user-defined
* functions called in gistunion() may do not free all memory
*/
tmp = gistunion(gv->index, vec, veclen, &(gv->giststate));
MemoryContextSwitchTo(oldCtx);
@ -73,21 +78,25 @@ PageMakeUnionKey(GistVacuum *gv, Buffer buffer) {
}
static void
gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
Buffer buffer;
Page page;
gistDeleteSubtree(GistVacuum *gv, BlockNumber blkno)
{
Buffer buffer;
Page page;
buffer = ReadBuffer(gv->index, blkno);
LockBuffer(buffer, GIST_EXCLUSIVE);
page = (Page) BufferGetPage(buffer);
if ( !GistPageIsLeaf(page) ) {
int i;
if (!GistPageIsLeaf(page))
{
int i;
for (i = FirstOffsetNumber; i <= PageGetMaxOffsetNumber(page); i = OffsetNumberNext(i)) {
ItemId iid = PageGetItemId(page, i);
IndexTuple idxtuple = (IndexTuple) PageGetItem(page, iid);
gistDeleteSubtree(gv, ItemPointerGetBlockNumber(&(idxtuple->t_tid)));
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)));
}
}
@ -103,7 +112,7 @@ gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
{
XLogRecData rdata[2];
XLogRecPtr recptr;
gistxlogPageDelete xlrec;
gistxlogPageDelete xlrec;
xlrec.node = gv->index->rd_node;
xlrec.blkno = blkno;
@ -125,31 +134,34 @@ gistDeleteSubtree( GistVacuum *gv, BlockNumber blkno ) {
}
else
PageSetLSN(page, XLogRecPtrForTemp);
END_CRIT_SECTION();
UnlockReleaseBuffer(buffer);
}
static Page
GistPageGetCopyPage( Page page ) {
Size pageSize = PageGetPageSize( page );
Page tmppage;
static Page
GistPageGetCopyPage(Page page)
{
Size pageSize = PageGetPageSize(page);
Page tmppage;
tmppage=(Page)palloc( pageSize );
memcpy( tmppage, page, pageSize );
tmppage = (Page) palloc(pageSize);
memcpy(tmppage, page, pageSize);
return tmppage;
}
static ArrayTuple
vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon, int curlenaddon) {
vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon, int curlenaddon)
{
ArrayTuple res = {NULL, 0, false};
IndexTuple *vec;
SplitedPageLayout *dist = NULL,
*ptr;
int i, veclen=0;
BlockNumber blkno = BufferGetBlockNumber(buffer);
*ptr;
int i,
veclen = 0;
BlockNumber blkno = BufferGetBlockNumber(buffer);
MemoryContext oldCtx = MemoryContextSwitchTo(gv->opCtx);
vec = gistextractpage(tempPage, &veclen);
@ -158,67 +170,73 @@ vacuumSplitPage(GistVacuum *gv, Page tempPage, Buffer buffer, IndexTuple *addon,
MemoryContextSwitchTo(oldCtx);
if (blkno != GIST_ROOT_BLKNO) {
if (blkno != GIST_ROOT_BLKNO)
{
/* if non-root split then we should not allocate new buffer */
dist->buffer = buffer;
dist->page = tempPage;
/* during vacuum we never split leaf page */
GistPageGetOpaque(dist->page)->flags = 0;
} else
}
else
pfree(tempPage);
res.itup = (IndexTuple *) palloc(sizeof(IndexTuple) * veclen);
res.ituplen = 0;
/* make new pages and fills them */
for (ptr = dist; ptr; ptr = ptr->next) {
char *data;
for (ptr = dist; ptr; ptr = ptr->next)
{
char *data;
if ( ptr->buffer == InvalidBuffer ) {
ptr->buffer = gistNewBuffer( gv->index );
GISTInitBuffer( ptr->buffer, 0 );
if (ptr->buffer == InvalidBuffer)
{
ptr->buffer = gistNewBuffer(gv->index);
GISTInitBuffer(ptr->buffer, 0);
ptr->page = BufferGetPage(ptr->buffer);
}
ptr->block.blkno = BufferGetBlockNumber( ptr->buffer );
ptr->block.blkno = BufferGetBlockNumber(ptr->buffer);
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 )
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(gv->index));
data += IndexTupleSize((IndexTuple)data);
data += IndexTupleSize((IndexTuple) data);
}
ItemPointerSetBlockNumber(&(ptr->itup->t_tid), ptr->block.blkno);
res.itup[ res.ituplen ] = (IndexTuple)palloc(IndexTupleSize(ptr->itup));
memcpy( res.itup[ res.ituplen ], ptr->itup, IndexTupleSize(ptr->itup) );
res.itup[res.ituplen] = (IndexTuple) palloc(IndexTupleSize(ptr->itup));
memcpy(res.itup[res.ituplen], ptr->itup, IndexTupleSize(ptr->itup));
res.ituplen++;
}
START_CRIT_SECTION();
for (ptr = dist; ptr; ptr = ptr->next) {
for (ptr = dist; ptr; ptr = ptr->next)
{
MarkBufferDirty(ptr->buffer);
GistPageGetOpaque(ptr->page)->rightlink = InvalidBlockNumber;
}
/* restore splitted non-root page */
if (blkno != GIST_ROOT_BLKNO) {
PageRestoreTempPage( dist->page, BufferGetPage( dist->buffer ) );
dist->page = BufferGetPage( dist->buffer );
if (blkno != GIST_ROOT_BLKNO)
{
PageRestoreTempPage(dist->page, BufferGetPage(dist->buffer));
dist->page = BufferGetPage(dist->buffer);
}
if (!gv->index->rd_istemp)
{
XLogRecPtr recptr;
XLogRecData *rdata;
ItemPointerData key; /* set key for incomplete
* insert */
ItemPointerData key; /* set key for incomplete insert */
char *xlinfo;
ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
rdata = formSplitRdata(gv->index->rd_node, blkno,
false, &key, dist);
false, &key, dist);
xlinfo = rdata->data;
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 */
if (BufferGetBlockNumber(ptr->buffer) != blkno)
UnlockReleaseBuffer( ptr->buffer );
UnlockReleaseBuffer(ptr->buffer);
}
if (blkno == GIST_ROOT_BLKNO)
{
ItemPointerData key; /* set key for incomplete
* insert */
ItemPointerData key; /* set key for incomplete insert */
ItemPointerSet(&key, blkno, TUPLE_IS_VALID);
@ -266,7 +283,8 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
{
ArrayTuple res = {NULL, 0, false};
Buffer buffer;
Page page, tempPage = NULL;
Page page,
tempPage = NULL;
OffsetNumber i,
maxoff;
ItemId iid;
@ -278,7 +296,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
*addon = NULL;
bool needwrite = false;
OffsetNumber offToDelete[MaxOffsetNumber];
BlockNumber blkToDelete[MaxOffsetNumber];
BlockNumber blkToDelete[MaxOffsetNumber];
ItemPointerData *completed = NULL;
int ncompleted = 0,
lencompleted = 16;
@ -322,7 +340,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
if (chldtuple.ituplen || chldtuple.emptypage)
{
/* update tuple or/and inserts new */
if ( chldtuple.emptypage )
if (chldtuple.emptypage)
blkToDelete[nBlkToDelete++] = ItemPointerGetBlockNumber(&(idxtuple->t_tid));
offToDelete[nOffToDelete++] = i;
PageIndexTupleDelete(tempPage, i);
@ -333,7 +351,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
if (chldtuple.ituplen)
{
Assert( chldtuple.emptypage == false );
Assert(chldtuple.emptypage == false);
while (curlenaddon + chldtuple.ituplen >= lenaddon)
{
lenaddon *= 2;
@ -367,56 +385,63 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
}
}
}
Assert( maxoff == PageGetMaxOffsetNumber(tempPage) );
Assert(maxoff == PageGetMaxOffsetNumber(tempPage));
if (curlenaddon)
{
/* insert updated tuples */
if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber, 0)) {
if (gistnospace(tempPage, addon, curlenaddon, InvalidOffsetNumber, 0))
{
/* there is no space on page to insert tuples */
res = vacuumSplitPage(gv, tempPage, buffer, addon, curlenaddon);
tempPage=NULL; /* vacuumSplitPage() free tempPage */
needwrite = needunion = false; /* gistSplit already forms unions and writes pages */
} else
tempPage = NULL; /* vacuumSplitPage() free tempPage */
needwrite = needunion = false; /* gistSplit already forms
* unions and writes pages */
}
else
/* enough free space */
gistfillbuffer(gv->index, tempPage, addon, curlenaddon, InvalidOffsetNumber);
}
}
/*
* If page is empty, we should remove pointer to it before
* deleting page (except root)
/*
* If page is empty, we should remove pointer to it before deleting page
* (except root)
*/
if ( blkno != GIST_ROOT_BLKNO && ( PageIsEmpty(page) || (tempPage && PageIsEmpty(tempPage)) ) ) {
if (blkno != GIST_ROOT_BLKNO && (PageIsEmpty(page) || (tempPage && PageIsEmpty(tempPage))))
{
/*
* New version of page is empty, so leave it unchanged,
* upper call will mark our page as deleted.
* In case of page split we never will be here...
* New version of page is empty, so leave it unchanged, upper call
* will mark our page as deleted. In case of page split we never will
* be here...
*
* If page was empty it can't become non-empty during processing
* If page was empty it can't become non-empty during processing
*/
res.emptypage = true;
UnlockReleaseBuffer(buffer);
} else {
}
else
{
/* write page and remove its childs if it need */
START_CRIT_SECTION();
if ( tempPage && needwrite ) {
if (tempPage && needwrite)
{
PageRestoreTempPage(tempPage, page);
tempPage = NULL;
}
/* Empty index */
if (PageIsEmpty(page) && blkno == GIST_ROOT_BLKNO )
/* Empty index */
if (PageIsEmpty(page) && blkno == GIST_ROOT_BLKNO)
{
needwrite = true;
GistPageSetLeaf(page);
}
if (needwrite)
{
MarkBufferDirty(buffer);
@ -446,7 +471,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
END_CRIT_SECTION();
if ( needunion && !PageIsEmpty(page) )
if (needunion && !PageIsEmpty(page))
{
res.itup = (IndexTuple *) palloc(sizeof(IndexTuple));
res.ituplen = 1;
@ -456,7 +481,7 @@ gistVacuumUpdate(GistVacuum *gv, BlockNumber blkno, bool needunion)
UnlockReleaseBuffer(buffer);
/* 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]);
if (ncompleted && !gv->index->rd_istemp)
@ -506,9 +531,10 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
/* use heap's tuple count */
Assert(info->num_heap_tuples >= 0);
stats->std.num_index_tuples = info->num_heap_tuples;
/*
* XXX the above is wrong if index is partial. Would it be OK to
* just return NULL, or is there work we must do below?
* XXX the above is wrong if index is partial. Would it be OK to just
* return NULL, or is there work we must do below?
*/
}
@ -545,8 +571,8 @@ gistvacuumcleanup(PG_FUNCTION_ARGS)
RelationGetRelationName(rel))));
/*
* If vacuum full, we already have exclusive lock on the index.
* Otherwise, need lock unless it's local to this backend.
* If vacuum full, we already have exclusive lock on the index. Otherwise,
* need lock unless it's local to this backend.
*/
if (info->vacuum_full)
needLock = false;
@ -725,7 +751,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
if (callback(&(idxtuple->t_tid), callback_state))
{
todelete[ntodelete] = i-ntodelete;
todelete[ntodelete] = i - ntodelete;
ntodelete++;
stats->std.tuples_removed += 1;
}
@ -739,7 +765,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
MarkBufferDirty(buffer);
for(i=0;i<ntodelete;i++)
for (i = 0; i < ntodelete; i++)
PageIndexTupleDelete(page, todelete[i]);
GistMarkTuplesDeleted(page);
@ -750,7 +776,7 @@ gistbulkdelete(PG_FUNCTION_ARGS)
gistxlogPageUpdate *xlinfo;
rdata = formUpdateRdata(rel->rd_node, buffer,
todelete, ntodelete,
todelete, ntodelete,
NULL, 0,
NULL);
xlinfo = (gistxlogPageUpdate *) rdata->next->data;

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.23 2006/08/07 16:57:56 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/gist/gistxlog.c,v 1.24 2006/10/04 00:29:48 momjian Exp $
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@ -55,11 +55,11 @@ typedef struct gistIncompleteInsert
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;
#define ItemPointerEQ(a, b) \
#define ItemPointerEQ(a, b) \
( ItemPointerGetOffsetNumber(a) == ItemPointerGetOffsetNumber(b) && \
ItemPointerGetBlockNumber (a) == ItemPointerGetBlockNumber(b) )
@ -72,8 +72,9 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
MemoryContext oldCxt;
gistIncompleteInsert *ninsert;
if ( !ItemPointerIsValid(&key) )
/*
if (!ItemPointerIsValid(&key))
/*
* if key is null then we should not store insertion as incomplete,
* because it's a vacuum operation..
*/
@ -108,8 +109,8 @@ pushIncompleteInsert(RelFileNode node, XLogRecPtr lsn, ItemPointerData key,
/*
* Stick the new incomplete insert onto the front of the list, not the
* back. This is so that gist_xlog_cleanup will process incompletions
* in last-in-first-out order.
* back. This is so that gist_xlog_cleanup will process incompletions in
* last-in-first-out order.
*/
incomplete_inserts = lcons(ninsert, incomplete_inserts);
@ -121,10 +122,10 @@ forgetIncompleteInsert(RelFileNode node, ItemPointerData key)
{
ListCell *l;
if ( !ItemPointerIsValid(&key) )
if (!ItemPointerIsValid(&key))
return;
if (incomplete_inserts==NIL)
if (incomplete_inserts == NIL)
return;
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)
GistClearTuplesDeleted(page);
if ( !GistPageIsLeaf(page) && PageGetMaxOffsetNumber(page) == InvalidOffsetNumber && xldata->blkno == GIST_ROOT_BLKNO )
/* all links on non-leaf root page was deleted by vacuum full,
so root page becomes a leaf */
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
*/
GistPageSetLeaf(page);
GistPageGetOpaque(page)->rightlink = InvalidBlockNumber;
@ -432,11 +436,11 @@ static void
out_target(StringInfo buf, RelFileNode node, ItemPointerData key)
{
appendStringInfo(buf, "rel %u/%u/%u",
node.spcNode, node.dbNode, node.relNode);
if ( ItemPointerIsValid( &key ) )
node.spcNode, node.dbNode, node.relNode);
if (ItemPointerIsValid(&key))
appendStringInfo(buf, "; tid %u/%u",
ItemPointerGetBlockNumber(&key),
ItemPointerGetOffsetNumber(&key));
ItemPointerGetBlockNumber(&key),
ItemPointerGetOffsetNumber(&key));
}
static void
@ -450,8 +454,8 @@ static void
out_gistxlogPageDelete(StringInfo buf, gistxlogPageDelete *xlrec)
{
appendStringInfo(buf, "page_delete: rel %u/%u/%u; blkno %u",
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
xlrec->blkno);
xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode,
xlrec->blkno);
}
static void
@ -460,7 +464,7 @@ out_gistxlogPageSplit(StringInfo buf, gistxlogPageSplit *xlrec)
appendStringInfo(buf, "page_split: ");
out_target(buf, xlrec->node, xlrec->key);
appendStringInfo(buf, "; block number %u splits to %d pages",
xlrec->origblkno, xlrec->npage);
xlrec->origblkno, xlrec->npage);
}
void
@ -486,15 +490,15 @@ gist_desc(StringInfo buf, uint8 xl_info, char *rec)
break;
case XLOG_GIST_CREATE_INDEX:
appendStringInfo(buf, "create_index: rel %u/%u/%u",
((RelFileNode *) rec)->spcNode,
((RelFileNode *) rec)->dbNode,
((RelFileNode *) rec)->relNode);
((RelFileNode *) rec)->spcNode,
((RelFileNode *) rec)->dbNode,
((RelFileNode *) rec)->relNode);
break;
case XLOG_GIST_INSERT_COMPLETE:
appendStringInfo(buf, "complete_insert: rel %u/%u/%u",
((gistxlogInsertComplete *) rec)->node.spcNode,
((gistxlogInsertComplete *) rec)->node.dbNode,
((gistxlogInsertComplete *) rec)->node.relNode);
((gistxlogInsertComplete *) rec)->node.spcNode,
((gistxlogInsertComplete *) rec)->node.dbNode,
((gistxlogInsertComplete *) rec)->node.relNode);
break;
default:
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);
}
static SplitedPageLayout*
gistMakePageLayout(Buffer *buffers, int nbuffers) {
SplitedPageLayout *res=NULL, *resptr;
static SplitedPageLayout *
gistMakePageLayout(Buffer *buffers, int nbuffers)
{
SplitedPageLayout *res = NULL,
*resptr;
while( nbuffers-- > 0 ) {
Page page = BufferGetPage( buffers[ nbuffers ] );
IndexTuple* vec;
int veclen;
while (nbuffers-- > 0)
{
Page page = BufferGetPage(buffers[nbuffers]);
IndexTuple *vec;
int veclen;
resptr = (SplitedPageLayout*)palloc0( sizeof(SplitedPageLayout) );
resptr = (SplitedPageLayout *) palloc0(sizeof(SplitedPageLayout));
resptr->block.blkno = BufferGetBlockNumber( buffers[ nbuffers ] );
resptr->block.num = PageGetMaxOffsetNumber( page );
resptr->block.blkno = BufferGetBlockNumber(buffers[nbuffers]);
resptr->block.num = PageGetMaxOffsetNumber(page);
vec = gistextractpage( page, &veclen );
resptr->list = gistfillitupvec( vec, veclen, &(resptr->lenlist) );
vec = gistextractpage(page, &veclen);
resptr->list = gistfillitupvec(vec, veclen, &(resptr->lenlist));
resptr->next = res;
res = resptr;
@ -580,7 +587,7 @@ gistMakePageLayout(Buffer *buffers, int nbuffers) {
* Note that we assume the index is now in a valid state, except for the
* unfinished insertion. In particular it's safe to invoke gistFindPath();
* there shouldn't be any garbage pages for it to run into.
*
*
* To complete insert we can't use basic insertion algorithm because
* during insertion we can't call user-defined support functions of opclass.
* So, we insert 'invalid' tuples without real key and do it by separate algorithm.
@ -607,7 +614,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
itup[i] = gist_form_invalid_tuple(insert->blkno[i]);
/*
* any insertion of itup[] should make LOG message about
* any insertion of itup[] should make LOG message about
*/
if (insert->origblkno == GIST_ROOT_BLKNO)
@ -626,7 +633,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
Buffer *buffers;
Page *pages;
int numbuffer;
OffsetNumber *todelete;
OffsetNumber *todelete;
/* construct path */
gistxlogFindPath(index, insert);
@ -642,21 +649,22 @@ gistContinueInsert(gistIncompleteInsert *insert)
int j,
k,
pituplen = 0;
XLogRecData *rdata;
XLogRecPtr recptr;
Buffer tempbuffer = InvalidBuffer;
int ntodelete = 0;
XLogRecData *rdata;
XLogRecPtr recptr;
Buffer tempbuffer = InvalidBuffer;
int ntodelete = 0;
numbuffer = 1;
buffers[0] = ReadBuffer(index, insert->path[i]);
LockBuffer(buffers[0], GIST_EXCLUSIVE);
/*
* we check buffer, because we restored page earlier
*/
gistcheckpage(index, buffers[0]);
pages[0] = BufferGetPage(buffers[0]);
Assert( !GistPageIsLeaf(pages[0]) );
Assert(!GistPageIsLeaf(pages[0]));
pituplen = PageGetMaxOffsetNumber(pages[0]);
@ -678,12 +686,12 @@ gistContinueInsert(gistIncompleteInsert *insert)
}
}
if ( ntodelete == 0 )
elog(PANIC,"gistContinueInsert: can't find pointer to page(s)");
if (ntodelete == 0)
elog(PANIC, "gistContinueInsert: can't find pointer to page(s)");
/*
* we check space with subtraction only first tuple to delete, hope,
* that wiil be enough space....
* we check space with subtraction only first tuple to delete,
* hope, that wiil be enough space....
*/
if (gistnospace(pages[0], itup, lenitup, *todelete, 0))
@ -699,7 +707,7 @@ gistContinueInsert(gistIncompleteInsert *insert)
if (BufferGetBlockNumber(buffers[0]) == GIST_ROOT_BLKNO)
{
Buffer tmp;
Buffer tmp;
/*
* 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 */
tempbuffer = ReadBuffer(index, P_NEW);
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 */
tmp = buffers[0];
buffers[0] = tempbuffer;
tempbuffer = tmp; /* now in tempbuffer GIST_ROOT_BLKNO, it is still unchanged */
tempbuffer = tmp; /* now in tempbuffer GIST_ROOT_BLKNO,
* it is still unchanged */
pages[0] = BufferGetPage(buffers[0]);
}
START_CRIT_SECTION();
for(j=0;j<ntodelete;j++)
for (j = 0; j < ntodelete; j++)
PageIndexTupleDelete(pages[0], todelete[j]);
rdata = formSplitRdata(index->rd_node, insert->path[i],
false, &(insert->key),
gistMakePageLayout( buffers, numbuffer ) );
false, &(insert->key),
gistMakePageLayout(buffers, numbuffer));
} else {
}
else
{
START_CRIT_SECTION();
for(j=0;j<ntodelete;j++)
for (j = 0; j < ntodelete; j++)
PageIndexTupleDelete(pages[0], todelete[j]);
gistfillbuffer(index, pages[0], itup, lenitup, InvalidOffsetNumber);
rdata = formUpdateRdata(index->rd_node, buffers[0],
todelete, ntodelete,
itup, lenitup, &(insert->key));
rdata = formUpdateRdata(index->rd_node, buffers[0],
todelete, ntodelete,
itup, lenitup, &(insert->key));
}
/*
* use insert->key as mark for completion of insert (form*Rdata() above)
* for following possible replays
/*
* use insert->key as mark for completion of insert (form*Rdata()
* above) for following possible replays
*/
/* write pages, we should mark it dirty befor XLogInsert() */
for (j = 0; j < numbuffer; j++) {
for (j = 0; j < numbuffer; j++)
{
GistPageGetOpaque(pages[j])->rightlink = InvalidBlockNumber;
MarkBufferDirty(buffers[j]);
}
@ -764,12 +776,14 @@ gistContinueInsert(gistIncompleteInsert *insert)
END_CRIT_SECTION();
lenitup = numbuffer;
for (j = 0; j < numbuffer; j++) {
for (j = 0; j < numbuffer; j++)
{
itup[j] = gist_form_invalid_tuple(BufferGetBlockNumber(buffers[j]));
UnlockReleaseBuffer(buffers[j]);
}
if ( tempbuffer != InvalidBuffer ) {
if (tempbuffer != InvalidBuffer)
{
/*
* it was a root split, so fill it by new values
*/
@ -780,9 +794,9 @@ gistContinueInsert(gistIncompleteInsert *insert)
}
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),
errdetail("Incomplete insertion detected during crash replay.")));
errdetail("Incomplete insertion detected during crash replay.")));
}
void

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.47 2006/03/05 15:58:20 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.48 2006/10/04 00:29:48 momjian Exp $
*
* NOTES
* These functions are stored in pg_amproc. For each operator class
@ -138,9 +138,9 @@ hashtext(PG_FUNCTION_ARGS)
Datum result;
/*
* Note: this is currently identical in behavior to hashvarlena, but
* keep it as a separate function in case we someday want to do something
* different in non-C locales. (See also hashbpchar, if so.)
* Note: this is currently identical in behavior to hashvarlena, but keep
* it as a separate function in case we someday want to do something
* different in non-C locales. (See also hashbpchar, if so.)
*/
result = hash_any((unsigned char *) VARDATA(key),
VARSIZE(key) - VARHDRSZ);

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.59 2006/07/03 22:45:36 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.60 2006/10/04 00:29:48 momjian Exp $
*
* NOTES
* Postgres hash pages look like ordinary relation pages. The opaque
@ -224,7 +224,7 @@ _hash_metapinit(Relation rel)
/*
* 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
* 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
* some guessing involved.
*/

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.219 2006/08/18 16:09:08 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.220 2006/10/04 00:29:48 momjian Exp $
*
*
* INTERFACE ROUTINES
@ -133,9 +133,9 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
snapshot = scan->rs_snapshot;
/*
* We must hold share lock on the buffer content while examining
* tuple visibility. Afterwards, however, the tuples we have found
* to be visible are guaranteed good as long as we hold the buffer pin.
* We must hold share lock on the buffer content while examining tuple
* visibility. Afterwards, however, the tuples we have found to be
* visible are guaranteed good as long as we hold the buffer pin.
*/
LockBuffer(buffer, BUFFER_LOCK_SHARE);
@ -223,7 +223,7 @@ heapgettup(HeapScanDesc scan,
tuple->t_data = NULL;
return;
}
page = 0; /* first page */
page = 0; /* first page */
heapgetpage(scan, page);
lineoff = FirstOffsetNumber; /* first offnum */
scan->rs_inited = true;
@ -231,8 +231,8 @@ heapgettup(HeapScanDesc scan,
else
{
/* continue from previously returned page/tuple */
page = scan->rs_cblock; /* current page */
lineoff = /* next offnum */
page = scan->rs_cblock; /* current page */
lineoff = /* next offnum */
OffsetNumberNext(ItemPointerGetOffsetNumber(&(tuple->t_self)));
}
@ -263,7 +263,7 @@ heapgettup(HeapScanDesc scan,
else
{
/* 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);
@ -273,12 +273,12 @@ heapgettup(HeapScanDesc scan,
if (!scan->rs_inited)
{
lineoff = lines; /* final offnum */
lineoff = lines; /* final offnum */
scan->rs_inited = true;
}
else
{
lineoff = /* previous offnum */
lineoff = /* previous offnum */
OffsetNumberPrev(ItemPointerGetOffsetNumber(&(tuple->t_self)));
}
/* page and lineoff now reference the physically previous tid */
@ -450,7 +450,7 @@ heapgettup_pagemode(HeapScanDesc scan,
tuple->t_data = NULL;
return;
}
page = 0; /* first page */
page = 0; /* first page */
heapgetpage(scan, page);
lineindex = 0;
scan->rs_inited = true;
@ -458,7 +458,7 @@ heapgettup_pagemode(HeapScanDesc scan,
else
{
/* continue from previously returned page/tuple */
page = scan->rs_cblock; /* current page */
page = scan->rs_cblock; /* current page */
lineindex = scan->rs_cindex + 1;
}
@ -487,7 +487,7 @@ heapgettup_pagemode(HeapScanDesc scan,
else
{
/* continue from previously returned page/tuple */
page = scan->rs_cblock; /* current page */
page = scan->rs_cblock; /* current page */
}
dp = (Page) BufferGetPage(scan->rs_cbuf);
@ -721,8 +721,8 @@ try_relation_open(Oid relationId, LOCKMODE lockmode)
LockRelationOid(relationId, lockmode);
/*
* Now that we have the lock, probe to see if the relation really
* exists or not.
* Now that we have the lock, probe to see if the relation really exists
* or not.
*/
if (!SearchSysCacheExists(RELOID,
ObjectIdGetDatum(relationId),
@ -764,7 +764,7 @@ relation_open_nowait(Oid relationId, LOCKMODE lockmode)
if (!ConditionalLockRelationOid(relationId, lockmode))
{
/* try to throw error by name; relation could be deleted... */
char *relname = get_rel_name(relationId);
char *relname = get_rel_name(relationId);
if (relname)
ereport(ERROR,
@ -774,8 +774,8 @@ relation_open_nowait(Oid relationId, LOCKMODE lockmode)
else
ereport(ERROR,
(errcode(ERRCODE_LOCK_NOT_AVAILABLE),
errmsg("could not obtain lock on relation with OID %u",
relationId)));
errmsg("could not obtain lock on relation with OID %u",
relationId)));
}
}
@ -801,8 +801,8 @@ relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
/*
* Check for shared-cache-inval messages before trying to open the
* relation. This is needed to cover the case where the name identifies
* a rel that has been dropped and recreated since the start of our
* relation. This is needed to cover the case where the name identifies a
* rel that has been dropped and recreated since the start of our
* transaction: if we don't flush the old syscache entry then we'll latch
* onto that entry and suffer an error when we do RelationIdGetRelation.
* Note that relation_open does not need to do this, since a relation's
@ -2723,7 +2723,7 @@ l3:
* heap_inplace_update - update a tuple "in place" (ie, overwrite it)
*
* 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.
*
* 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))
{
scan->rs_ctup.t_data = NULL;
/*
* unpin scan buffers
*/
@ -2852,7 +2853,7 @@ heap_restrpos(HeapScanDesc scan)
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.
*/
scan->rs_inited = true;
@ -2862,13 +2863,13 @@ heap_restrpos(HeapScanDesc scan)
scan->rs_cindex = scan->rs_mindex;
heapgettup_pagemode(scan,
NoMovementScanDirection,
0, /* needn't recheck scan keys */
0, /* needn't recheck scan keys */
NULL);
}
else
heapgettup(scan,
NoMovementScanDirection,
0, /* needn't recheck scan keys */
0, /* needn't recheck scan keys */
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.
*/
static XLogRecPtr
@ -3173,8 +3174,8 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
if (record->xl_info & XLOG_HEAP_INIT_PAGE)
{
buffer = XLogReadBuffer(reln,
ItemPointerGetBlockNumber(&(xlrec->target.tid)),
true);
ItemPointerGetBlockNumber(&(xlrec->target.tid)),
true);
Assert(BufferIsValid(buffer));
page = (Page) BufferGetPage(buffer);
@ -3183,13 +3184,13 @@ heap_xlog_insert(XLogRecPtr lsn, XLogRecord *record)
else
{
buffer = XLogReadBuffer(reln,
ItemPointerGetBlockNumber(&(xlrec->target.tid)),
false);
ItemPointerGetBlockNumber(&(xlrec->target.tid)),
false);
if (!BufferIsValid(buffer))
return;
page = (Page) BufferGetPage(buffer);
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
{
UnlockReleaseBuffer(buffer);
return;
@ -3308,6 +3309,7 @@ heap_xlog_update(XLogRecPtr lsn, XLogRecord *record, bool move)
/* Set forward chain link in t_ctid */
htup->t_ctid = xlrec->newtid;
}
/*
* this test is ugly, but necessary to avoid thinking that insert change
* is already applied
@ -3345,7 +3347,7 @@ newt:;
return;
page = (Page) BufferGetPage(buffer);
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
if (XLByteLE(lsn, PageGetLSN(page))) /* changes are applied */
{
UnlockReleaseBuffer(buffer);
return;
@ -3548,9 +3550,9 @@ static void
out_target(StringInfo buf, xl_heaptid *target)
{
appendStringInfo(buf, "rel %u/%u/%u; tid %u/%u",
target->node.spcNode, target->node.dbNode, target->node.relNode,
ItemPointerGetBlockNumber(&(target->tid)),
ItemPointerGetOffsetNumber(&(target->tid)));
target->node.spcNode, target->node.dbNode, target->node.relNode,
ItemPointerGetBlockNumber(&(target->tid)),
ItemPointerGetOffsetNumber(&(target->tid)));
}
void
@ -3586,8 +3588,8 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
appendStringInfo(buf, "update: ");
out_target(buf, &(xlrec->target));
appendStringInfo(buf, "; new %u/%u",
ItemPointerGetBlockNumber(&(xlrec->newtid)),
ItemPointerGetOffsetNumber(&(xlrec->newtid)));
ItemPointerGetBlockNumber(&(xlrec->newtid)),
ItemPointerGetOffsetNumber(&(xlrec->newtid)));
}
else if (info == XLOG_HEAP_MOVE)
{
@ -3599,24 +3601,24 @@ heap_desc(StringInfo buf, uint8 xl_info, char *rec)
appendStringInfo(buf, "move: ");
out_target(buf, &(xlrec->target));
appendStringInfo(buf, "; new %u/%u",
ItemPointerGetBlockNumber(&(xlrec->newtid)),
ItemPointerGetOffsetNumber(&(xlrec->newtid)));
ItemPointerGetBlockNumber(&(xlrec->newtid)),
ItemPointerGetOffsetNumber(&(xlrec->newtid)));
}
else if (info == XLOG_HEAP_CLEAN)
{
xl_heap_clean *xlrec = (xl_heap_clean *) rec;
appendStringInfo(buf, "clean: rel %u/%u/%u; blk %u",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block);
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block);
}
else if (info == XLOG_HEAP_NEWPAGE)
{
xl_heap_newpage *xlrec = (xl_heap_newpage *) rec;
appendStringInfo(buf, "newpage: rel %u/%u/%u; blk %u",
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->blkno);
xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->blkno);
}
else if (info == XLOG_HEAP_LOCK)
{

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.64 2006/09/10 23:33:22 momjian Exp $
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.65 2006/10/04 00:29:48 momjian Exp $
*
*
* INTERFACE ROUTINES
@ -1331,7 +1331,7 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length)
VARATT_SIZEP(result) |= VARATT_FLAG_COMPRESSED;
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;
endchunk = (sliceoffset + length - 1) / TOAST_MAX_CHUNK_SIZE;

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.58 2006/07/31 20:08:59 tgl Exp $
* $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.59 2006/10/04 00:29:48 momjian Exp $
*
* NOTES
* many of the old access method routines have been turned into
@ -86,7 +86,7 @@ RelationGetIndexScan(Relation indexRelation,
else
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->ignore_killed_tuples = true; /* default setting */

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