mirror of
https://github.com/postgres/postgres.git
synced 2025-04-20 00:42:27 +03:00
pgindent run.
This commit is contained in:
parent
63354a0228
commit
089003fb46
@ -23,4 +23,3 @@ typedef struct rix
|
|||||||
|
|
||||||
extern GIST_SPLITVEC *btree_picksplit(bytea *entryvec, GIST_SPLITVEC *v,
|
extern GIST_SPLITVEC *btree_picksplit(bytea *entryvec, GIST_SPLITVEC *v,
|
||||||
BINARY_UNION bu, CMPFUNC cmp);
|
BINARY_UNION bu, CMPFUNC cmp);
|
||||||
|
|
||||||
|
@ -131,7 +131,8 @@ cube_out(NDBOX * cube)
|
|||||||
* Get the number of digits to display.
|
* Get the number of digits to display.
|
||||||
*/
|
*/
|
||||||
ndig = DBL_DIG + extra_float_digits;
|
ndig = DBL_DIG + extra_float_digits;
|
||||||
if (ndig < 1) ndig = 1;
|
if (ndig < 1)
|
||||||
|
ndig = 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* while printing the first (LL) corner, check if it is equal to the
|
* while printing the first (LL) corner, check if it is equal to the
|
||||||
@ -1192,7 +1193,8 @@ cube_enlarge(NDBOX * a, double *r, int4 n)
|
|||||||
j,
|
j,
|
||||||
k;
|
k;
|
||||||
|
|
||||||
if (n > CUBE_MAX_DIM) n = CUBE_MAX_DIM;
|
if (n > CUBE_MAX_DIM)
|
||||||
|
n = CUBE_MAX_DIM;
|
||||||
if (*r > 0 && n > 0)
|
if (*r > 0 && n > 0)
|
||||||
dim = n;
|
dim = n;
|
||||||
if (a->dim > dim)
|
if (a->dim > dim)
|
||||||
@ -1235,6 +1237,7 @@ cube_f8(double *x1)
|
|||||||
{
|
{
|
||||||
NDBOX *result;
|
NDBOX *result;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
size = offsetof(NDBOX, x[0]) + sizeof(double) * 2;
|
size = offsetof(NDBOX, x[0]) + sizeof(double) * 2;
|
||||||
result = (NDBOX *) palloc(size);
|
result = (NDBOX *) palloc(size);
|
||||||
memset(result, 0, size);
|
memset(result, 0, size);
|
||||||
@ -1251,6 +1254,7 @@ cube_f8_f8(double *x1, double *x2)
|
|||||||
{
|
{
|
||||||
NDBOX *result;
|
NDBOX *result;
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
size = offsetof(NDBOX, x[0]) + sizeof(double) * 2;
|
size = offsetof(NDBOX, x[0]) + sizeof(double) * 2;
|
||||||
result = (NDBOX *) palloc(size);
|
result = (NDBOX *) palloc(size);
|
||||||
memset(result, 0, size);
|
memset(result, 0, size);
|
||||||
@ -1269,12 +1273,14 @@ cube_c_f8(NDBOX *c, double *x1)
|
|||||||
NDBOX *result;
|
NDBOX *result;
|
||||||
int size;
|
int size;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
|
size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
|
||||||
result = (NDBOX *) palloc(size);
|
result = (NDBOX *) palloc(size);
|
||||||
memset(result, 0, size);
|
memset(result, 0, size);
|
||||||
result->size = size;
|
result->size = size;
|
||||||
result->dim = c->dim + 1;
|
result->dim = c->dim + 1;
|
||||||
for (i = 0; i < c->dim; i++) {
|
for (i = 0; i < c->dim; i++)
|
||||||
|
{
|
||||||
result->x[i] = c->x[i];
|
result->x[i] = c->x[i];
|
||||||
result->x[result->dim + i] = c->x[c->dim + i];
|
result->x[result->dim + i] = c->x[c->dim + i];
|
||||||
}
|
}
|
||||||
@ -1290,12 +1296,14 @@ cube_c_f8_f8(NDBOX *c, double *x1, double *x2)
|
|||||||
NDBOX *result;
|
NDBOX *result;
|
||||||
int size;
|
int size;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
|
size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
|
||||||
result = (NDBOX *) palloc(size);
|
result = (NDBOX *) palloc(size);
|
||||||
memset(result, 0, size);
|
memset(result, 0, size);
|
||||||
result->size = size;
|
result->size = size;
|
||||||
result->dim = c->dim + 1;
|
result->dim = c->dim + 1;
|
||||||
for (i = 0; i < c->dim; i++) {
|
for (i = 0; i < c->dim; i++)
|
||||||
|
{
|
||||||
result->x[i] = c->x[i];
|
result->x[i] = c->x[i];
|
||||||
result->x[result->dim + i] = c->x[c->dim + i];
|
result->x[result->dim + i] = c->x[c->dim + i];
|
||||||
}
|
}
|
||||||
|
@ -446,14 +446,12 @@ do_inserts(PGconn *conn, char *table, dbhead * dbh)
|
|||||||
j = 0; /* counter for fields in the output */
|
j = 0; /* counter for fields in the output */
|
||||||
for (h = 0; h < dbh->db_nfields; h++)
|
for (h = 0; h < dbh->db_nfields; h++)
|
||||||
{
|
{
|
||||||
if (!strlen(fields[h].db_name)) /* When the new fieldname is empty, the field is skipped */
|
if (!strlen(fields[h].db_name)) /* When the new fieldname
|
||||||
{
|
* is empty, the field is
|
||||||
|
* skipped */
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
j++;
|
j++;
|
||||||
}
|
|
||||||
|
|
||||||
if (j > 1) /* not for the first field! */
|
if (j > 1) /* not for the first field! */
|
||||||
strcat(query, "\t"); /* COPY statement field
|
strcat(query, "\t"); /* COPY statement field
|
||||||
|
@ -429,9 +429,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
|
|||||||
if (!res ||
|
if (!res ||
|
||||||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
|
(PQresultStatus(res) != PGRES_COMMAND_OK &&
|
||||||
PQresultStatus(res) != PGRES_TUPLES_OK))
|
PQresultStatus(res) != PGRES_TUPLES_OK))
|
||||||
{
|
|
||||||
DBLINK_RES_ERROR("sql error");
|
DBLINK_RES_ERROR("sql error");
|
||||||
}
|
|
||||||
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
||||||
{
|
{
|
||||||
/* cursor does not exist - closed already or bad name */
|
/* cursor does not exist - closed already or bad name */
|
||||||
@ -591,8 +589,8 @@ dblink_record(PG_FUNCTION_ARGS)
|
|||||||
TEXTOID, -1, 0, false);
|
TEXTOID, -1, 0, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* and save a copy of the command status string to return
|
* and save a copy of the command status string to return as
|
||||||
* as our result tuple
|
* our result tuple
|
||||||
*/
|
*/
|
||||||
sql_cmd_status = PQcmdStatus(res);
|
sql_cmd_status = PQcmdStatus(res);
|
||||||
funcctx->max_calls = 1;
|
funcctx->max_calls = 1;
|
||||||
@ -741,8 +739,8 @@ dblink_exec(PG_FUNCTION_ARGS)
|
|||||||
TEXTOID, -1, 0, false);
|
TEXTOID, -1, 0, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* and save a copy of the command status string to return as
|
* and save a copy of the command status string to return as our
|
||||||
* our result tuple
|
* result tuple
|
||||||
*/
|
*/
|
||||||
sql_cmd_status = GET_TEXT(PQcmdStatus(res));
|
sql_cmd_status = GET_TEXT(PQcmdStatus(res));
|
||||||
}
|
}
|
||||||
@ -802,6 +800,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
|
|||||||
(errcode(ERRCODE_UNDEFINED_TABLE),
|
(errcode(ERRCODE_UNDEFINED_TABLE),
|
||||||
errmsg("relation \"%s\" does not exist",
|
errmsg("relation \"%s\" does not exist",
|
||||||
GET_STR(PG_GETARG_TEXT_P(0)))));
|
GET_STR(PG_GETARG_TEXT_P(0)))));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* need a tuple descriptor representing one INT and one TEXT
|
* need a tuple descriptor representing one INT and one TEXT
|
||||||
* column
|
* column
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* pending.c
|
* pending.c
|
||||||
* $Id: pending.c,v 1.12 2003/07/24 17:52:20 tgl Exp $
|
* $Id: pending.c,v 1.13 2003/08/04 00:43:10 momjian Exp $
|
||||||
*
|
*
|
||||||
* This file contains a trigger for Postgresql-7.x to record changes to tables
|
* This file contains a trigger for Postgresql-7.x to record changes to tables
|
||||||
* to a pending table for mirroring.
|
* to a pending table for mirroring.
|
||||||
@ -81,6 +81,7 @@ recordchange(PG_FUNCTION_ARGS)
|
|||||||
char op = 0;
|
char op = 0;
|
||||||
char *schemaname;
|
char *schemaname;
|
||||||
char *fullyqualtblname;
|
char *fullyqualtblname;
|
||||||
|
|
||||||
if (fcinfo->context != NULL)
|
if (fcinfo->context != NULL)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -166,7 +167,7 @@ storePending(char *cpTableName, HeapTuple tBeforeTuple,
|
|||||||
int iResult = 0;
|
int iResult = 0;
|
||||||
HeapTuple tCurTuple;
|
HeapTuple tCurTuple;
|
||||||
|
|
||||||
//Points the current tuple(before or after)
|
/* Points the current tuple(before or after) */
|
||||||
Datum saPlanData[4];
|
Datum saPlanData[4];
|
||||||
Oid taPlanArgTypes[3] = {NAMEOID, CHAROID, INT4OID};
|
Oid taPlanArgTypes[3] = {NAMEOID, CHAROID, INT4OID};
|
||||||
void *vpPlan;
|
void *vpPlan;
|
||||||
|
@ -68,7 +68,8 @@ geo_distance(Point *pt1, Point *pt2)
|
|||||||
|
|
||||||
sino = sqrt(sin(fabs(lat1 - lat2) / 2.) * sin(fabs(lat1 - lat2) / 2.) +
|
sino = sqrt(sin(fabs(lat1 - lat2) / 2.) * sin(fabs(lat1 - lat2) / 2.) +
|
||||||
cos(lat1) * cos(lat2) * sin(longdiff / 2.) * sin(longdiff / 2.));
|
cos(lat1) * cos(lat2) * sin(longdiff / 2.) * sin(longdiff / 2.));
|
||||||
if (sino > 1.) sino = 1.;
|
if (sino > 1.)
|
||||||
|
sino = 1.;
|
||||||
*resultp = 2. * EARTH_RADIUS * asin(sino);
|
*resultp = 2. * EARTH_RADIUS * asin(sino);
|
||||||
|
|
||||||
return resultp;
|
return resultp;
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright 2002 by PostgreSQL Global Development Group
|
* Copyright 2002 by PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/contrib/findoidjoins/Attic/findoidjoins.c,v 1.20 2003/05/14 03:25:56 tgl Exp $
|
* $Header: /cvsroot/pgsql/contrib/findoidjoins/Attic/findoidjoins.c,v 1.21 2003/08/04 00:43:10 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
@ -24,7 +24,8 @@ main(int argc, char **argv)
|
|||||||
char *fk_attname;
|
char *fk_attname;
|
||||||
char *pk_relname;
|
char *pk_relname;
|
||||||
char *pk_nspname;
|
char *pk_nspname;
|
||||||
int fk, pk; /* loop counters */
|
int fk,
|
||||||
|
pk; /* loop counters */
|
||||||
|
|
||||||
if (argc != 2)
|
if (argc != 2)
|
||||||
{
|
{
|
||||||
@ -95,8 +96,8 @@ main(int argc, char **argv)
|
|||||||
fkrel_res = res;
|
fkrel_res = res;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For each column and each relation-having-OIDs, look to see if
|
* For each column and each relation-having-OIDs, look to see if the
|
||||||
* the column contains any values matching entries in the relation.
|
* column contains any values matching entries in the relation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (fk = 0; fk < PQntuples(fkrel_res); fk++)
|
for (fk = 0; fk < PQntuples(fkrel_res); fk++)
|
||||||
|
@ -132,9 +132,9 @@ ShrinkPGArray(PGARRAY * p)
|
|||||||
|
|
||||||
/* use current transaction context */
|
/* use current transaction context */
|
||||||
pnew = palloc(cb);
|
pnew = palloc(cb);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fix up the fields in the new structure, so Postgres
|
* Fix up the fields in the new structure, so Postgres understands
|
||||||
* understands
|
|
||||||
*/
|
*/
|
||||||
memcpy(pnew, p, cb);
|
memcpy(pnew, p, cb);
|
||||||
pnew->a.size = cb;
|
pnew->a.size = cb;
|
||||||
|
@ -173,5 +173,3 @@ int compDESC(const void *a, const void *b);
|
|||||||
if (ARRNELEMS(a) > 1) \
|
if (ARRNELEMS(a) > 1) \
|
||||||
qsort((void*)ARRPTR(a), ARRNELEMS(a),sizeof(int4), \
|
qsort((void*)ARRPTR(a), ARRNELEMS(a),sizeof(int4), \
|
||||||
(direction) ? compASC : compDESC )
|
(direction) ? compASC : compDESC )
|
||||||
|
|
||||||
|
|
||||||
|
@ -743,4 +743,3 @@ querytree(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
PG_RETURN_POINTER(res);
|
PG_RETURN_POINTER(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,12 +85,15 @@ g_int_consistent(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
g_int_union(PG_FUNCTION_ARGS) {
|
g_int_union(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0);
|
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0);
|
||||||
int *size = (int *) PG_GETARG_POINTER(1);
|
int *size = (int *) PG_GETARG_POINTER(1);
|
||||||
int4 i,len = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
|
int4 i,
|
||||||
|
len = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
|
||||||
ArrayType *res;
|
ArrayType *res;
|
||||||
int totlen=0,*ptr;
|
int totlen = 0,
|
||||||
|
*ptr;
|
||||||
|
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
totlen += ARRNELEMS(GETENTRY(entryvec, i));
|
totlen += ARRNELEMS(GETENTRY(entryvec, i));
|
||||||
@ -98,7 +101,8 @@ g_int_union(PG_FUNCTION_ARGS) {
|
|||||||
res = new_intArrayType(totlen);
|
res = new_intArrayType(totlen);
|
||||||
ptr = ARRPTR(res);
|
ptr = ARRPTR(res);
|
||||||
|
|
||||||
for (i = 0; i < len; i++) {
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
memcpy(ptr, ARRPTR(GETENTRY(entryvec, i)), ARRNELEMS(GETENTRY(entryvec, i)) * sizeof(int4));
|
memcpy(ptr, ARRPTR(GETENTRY(entryvec, i)), ARRNELEMS(GETENTRY(entryvec, i)) * sizeof(int4));
|
||||||
ptr += ARRNELEMS(GETENTRY(entryvec, i));
|
ptr += ARRNELEMS(GETENTRY(entryvec, i));
|
||||||
}
|
}
|
||||||
@ -239,7 +243,8 @@ g_int_decompress(PG_FUNCTION_ARGS)
|
|||||||
** The GiST Penalty method for _intments
|
** The GiST Penalty method for _intments
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
g_int_penalty(PG_FUNCTION_ARGS) {
|
g_int_penalty(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||||
GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
|
GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
|
||||||
float *result = (float *) PG_GETARG_POINTER(2);
|
float *result = (float *) PG_GETARG_POINTER(2);
|
||||||
@ -311,7 +316,8 @@ comparecost(const void *a, const void *b)
|
|||||||
** We use Guttman's poly time split algorithm
|
** We use Guttman's poly time split algorithm
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
g_int_picksplit(PG_FUNCTION_ARGS) {
|
g_int_picksplit(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0);
|
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0);
|
||||||
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
|
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
|
||||||
OffsetNumber i,
|
OffsetNumber i,
|
||||||
@ -501,4 +507,3 @@ g_int_picksplit(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
PG_RETURN_POINTER(v);
|
PG_RETURN_POINTER(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,4 +367,3 @@ compDESC(const void *a, const void *b)
|
|||||||
return 0;
|
return 0;
|
||||||
return (*(int4 *) a < *(int4 *) b) ? 1 : -1;
|
return (*(int4 *) a < *(int4 *) b) ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,8 +144,10 @@ _lt_q_regex(PG_FUNCTION_ARGS)
|
|||||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||||
errmsg("array must be one-dimensional")));
|
errmsg("array must be one-dimensional")));
|
||||||
|
|
||||||
while (num > 0) {
|
while (num > 0)
|
||||||
if ( array_iterator(_tree, ltq_regex, (void*)query, NULL) ) {
|
{
|
||||||
|
if (array_iterator(_tree, ltq_regex, (void *) query, NULL))
|
||||||
|
{
|
||||||
res = true;
|
res = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -123,10 +123,15 @@ printFieldNot(FieldNot *fn ) {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static struct {
|
static struct
|
||||||
|
{
|
||||||
bool muse;
|
bool muse;
|
||||||
uint32 high_pos;
|
uint32 high_pos;
|
||||||
} SomeStack = {false,0,};
|
} SomeStack =
|
||||||
|
|
||||||
|
{
|
||||||
|
false, 0,
|
||||||
|
};
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_numlevel, FieldNot * ptr)
|
checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_numlevel, FieldNot * ptr)
|
||||||
@ -140,7 +145,8 @@ checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_
|
|||||||
lquery_level *prevq = NULL;
|
lquery_level *prevq = NULL;
|
||||||
ltree_level *prevt = NULL;
|
ltree_level *prevt = NULL;
|
||||||
|
|
||||||
if ( SomeStack.muse ) {
|
if (SomeStack.muse)
|
||||||
|
{
|
||||||
high_pos = SomeStack.high_pos;
|
high_pos = SomeStack.high_pos;
|
||||||
qlen--;
|
qlen--;
|
||||||
prevq = curq;
|
prevq = curq;
|
||||||
@ -200,8 +206,10 @@ checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_
|
|||||||
curt = LEVEL_NEXT(curt);
|
curt = LEVEL_NEXT(curt);
|
||||||
tlen--;
|
tlen--;
|
||||||
cur_tpos++;
|
cur_tpos++;
|
||||||
if ( isok && prevq && prevq->numvar==0 && tlen>0 && cur_tpos <= high_pos ) {
|
if (isok && prevq && prevq->numvar == 0 && tlen > 0 && cur_tpos <= high_pos)
|
||||||
|
{
|
||||||
FieldNot tmpptr;
|
FieldNot tmpptr;
|
||||||
|
|
||||||
if (ptr)
|
if (ptr)
|
||||||
memcpy(&tmpptr, ptr, sizeof(FieldNot));
|
memcpy(&tmpptr, ptr, sizeof(FieldNot));
|
||||||
SomeStack.high_pos = high_pos - cur_tpos;
|
SomeStack.high_pos = high_pos - cur_tpos;
|
||||||
@ -321,9 +329,11 @@ lt_q_regex(PG_FUNCTION_ARGS)
|
|||||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||||
errmsg("array must be one-dimensional")));
|
errmsg("array must be one-dimensional")));
|
||||||
|
|
||||||
while (num > 0) {
|
while (num > 0)
|
||||||
|
{
|
||||||
if (DatumGetBool(DirectFunctionCall2(ltq_regex,
|
if (DatumGetBool(DirectFunctionCall2(ltq_regex,
|
||||||
PointerGetDatum(tree), PointerGetDatum(query)))) {
|
PointerGetDatum(tree), PointerGetDatum(query))))
|
||||||
|
{
|
||||||
|
|
||||||
res = true;
|
res = true;
|
||||||
break;
|
break;
|
||||||
@ -345,5 +355,3 @@ lt_q_rregex(PG_FUNCTION_ARGS)
|
|||||||
PG_GETARG_DATUM(0)
|
PG_GETARG_DATUM(0)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -332,36 +332,45 @@ ltree_index(PG_FUNCTION_ARGS)
|
|||||||
ltree *a = PG_GETARG_LTREE(0);
|
ltree *a = PG_GETARG_LTREE(0);
|
||||||
ltree *b = PG_GETARG_LTREE(1);
|
ltree *b = PG_GETARG_LTREE(1);
|
||||||
int start = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
|
int start = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
|
||||||
int i,j;
|
int i,
|
||||||
ltree_level *startptr, *aptr, *bptr;
|
j;
|
||||||
|
ltree_level *startptr,
|
||||||
|
*aptr,
|
||||||
|
*bptr;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
if ( start < 0 ) {
|
if (start < 0)
|
||||||
|
{
|
||||||
if (-start >= a->numlevel)
|
if (-start >= a->numlevel)
|
||||||
start = 0;
|
start = 0;
|
||||||
else
|
else
|
||||||
start = (int) (a->numlevel) + start;
|
start = (int) (a->numlevel) + start;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( a->numlevel - start < b->numlevel || a->numlevel==0 || b->numlevel==0 ) {
|
if (a->numlevel - start < b->numlevel || a->numlevel == 0 || b->numlevel == 0)
|
||||||
|
{
|
||||||
PG_FREE_IF_COPY(a, 0);
|
PG_FREE_IF_COPY(a, 0);
|
||||||
PG_FREE_IF_COPY(b, 1);
|
PG_FREE_IF_COPY(b, 1);
|
||||||
PG_RETURN_INT32(-1);
|
PG_RETURN_INT32(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
startptr = LTREE_FIRST(a);
|
startptr = LTREE_FIRST(a);
|
||||||
for(i=0; i<=a->numlevel-b->numlevel; i++) {
|
for (i = 0; i <= a->numlevel - b->numlevel; i++)
|
||||||
if ( i>=start ) {
|
{
|
||||||
|
if (i >= start)
|
||||||
|
{
|
||||||
aptr = startptr;
|
aptr = startptr;
|
||||||
bptr = LTREE_FIRST(b);
|
bptr = LTREE_FIRST(b);
|
||||||
for(j=0;j<b->numlevel;j++) {
|
for (j = 0; j < b->numlevel; j++)
|
||||||
|
{
|
||||||
if (!(aptr->len == bptr->len && strncmp(aptr->name, bptr->name, aptr->len) == 0))
|
if (!(aptr->len == bptr->len && strncmp(aptr->name, bptr->name, aptr->len) == 0))
|
||||||
break;
|
break;
|
||||||
aptr = LEVEL_NEXT(aptr);
|
aptr = LEVEL_NEXT(aptr);
|
||||||
bptr = LEVEL_NEXT(bptr);
|
bptr = LEVEL_NEXT(bptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( j==b->numlevel ) {
|
if (j == b->numlevel)
|
||||||
|
{
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -524,8 +533,10 @@ ltree2text(PG_FUNCTION_ARGS)
|
|||||||
out = (text *) palloc(in->len + VARHDRSZ);
|
out = (text *) palloc(in->len + VARHDRSZ);
|
||||||
ptr = VARDATA(out);
|
ptr = VARDATA(out);
|
||||||
curlevel = LTREE_FIRST(in);
|
curlevel = LTREE_FIRST(in);
|
||||||
for (i = 0; i < in->numlevel; i++) {
|
for (i = 0; i < in->numlevel; i++)
|
||||||
if (i != 0) {
|
{
|
||||||
|
if (i != 0)
|
||||||
|
{
|
||||||
*ptr = '.';
|
*ptr = '.';
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
@ -539,7 +550,3 @@ ltree2text(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
PG_RETURN_POINTER(out);
|
PG_RETURN_POINTER(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -15,16 +15,19 @@ log_entry (const char *logentry)
|
|||||||
{
|
{
|
||||||
time_t curtime;
|
time_t curtime;
|
||||||
struct tm *loctime;
|
struct tm *loctime;
|
||||||
|
|
||||||
curtime = time(NULL);
|
curtime = time(NULL);
|
||||||
loctime = localtime(&curtime);
|
loctime = localtime(&curtime);
|
||||||
strftime (timebuffer, TIMEBUFF, "%Y-%m-%d %r", loctime); /* cbb - %F is not always available */
|
strftime(timebuffer, TIMEBUFF, "%Y-%m-%d %r", loctime); /* cbb - %F is not
|
||||||
|
* always available */
|
||||||
fprintf(LOGOUTPUT, "[%s] %s\n", timebuffer, logentry);
|
fprintf(LOGOUTPUT, "[%s] %s\n", timebuffer, logentry);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function used to detatch the pg_autovacuum daemon from the tty and go into the background *
|
/* Function used to detatch the pg_autovacuum daemon from the tty and go into the background *
|
||||||
* This code is mostly ripped directly from pm_dameonize in postmaster.c *
|
* This code is mostly ripped directly from pm_dameonize in postmaster.c *
|
||||||
* with unneeded code removed. */
|
* with unneeded code removed. */
|
||||||
void daemonize ()
|
void
|
||||||
|
daemonize()
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
@ -60,7 +63,8 @@ init_table_info (PGresult * res, int row, db_info *dbi)
|
|||||||
{
|
{
|
||||||
tbl_info *new_tbl = (tbl_info *) malloc(sizeof(tbl_info));
|
tbl_info *new_tbl = (tbl_info *) malloc(sizeof(tbl_info));
|
||||||
|
|
||||||
if (!new_tbl) {
|
if (!new_tbl)
|
||||||
|
{
|
||||||
log_entry("init_table_info: Cannot get memory");
|
log_entry("init_table_info: Cannot get memory");
|
||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -73,7 +77,8 @@ init_table_info (PGresult * res, int row, db_info *dbi)
|
|||||||
|
|
||||||
new_tbl->schema_name = (char *)
|
new_tbl->schema_name = (char *)
|
||||||
malloc(strlen(PQgetvalue(res, row, PQfnumber(res, "schemaname"))) + 1);
|
malloc(strlen(PQgetvalue(res, row, PQfnumber(res, "schemaname"))) + 1);
|
||||||
if (!new_tbl->schema_name) {
|
if (!new_tbl->schema_name)
|
||||||
|
{
|
||||||
log_entry("init_table_info: malloc failed on new_tbl->schema_name");
|
log_entry("init_table_info: malloc failed on new_tbl->schema_name");
|
||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -84,7 +89,8 @@ init_table_info (PGresult * res, int row, db_info *dbi)
|
|||||||
new_tbl->table_name = (char *)
|
new_tbl->table_name = (char *)
|
||||||
malloc(strlen(PQgetvalue(res, row, PQfnumber(res, "relname"))) +
|
malloc(strlen(PQgetvalue(res, row, PQfnumber(res, "relname"))) +
|
||||||
strlen(new_tbl->schema_name) + 2);
|
strlen(new_tbl->schema_name) + 2);
|
||||||
if (!new_tbl->table_name) {
|
if (!new_tbl->table_name)
|
||||||
|
{
|
||||||
log_entry("init_table_info: malloc failed on new_tbl->table_name");
|
log_entry("init_table_info: malloc failed on new_tbl->table_name");
|
||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -112,9 +118,8 @@ init_table_info (PGresult * res, int row, db_info *dbi)
|
|||||||
new_tbl->vacuum_threshold =
|
new_tbl->vacuum_threshold =
|
||||||
args->vacuum_base_threshold + args->vacuum_scaling_factor * new_tbl->reltuples;
|
args->vacuum_base_threshold + args->vacuum_scaling_factor * new_tbl->reltuples;
|
||||||
|
|
||||||
if (args->debug >= 2) {
|
if (args->debug >= 2)
|
||||||
print_table_info(new_tbl);
|
print_table_info(new_tbl);
|
||||||
}
|
|
||||||
|
|
||||||
return new_tbl;
|
return new_tbl;
|
||||||
}
|
}
|
||||||
@ -128,20 +133,26 @@ update_table_thresholds (db_info * dbi, tbl_info * tbl,int vacuum_type)
|
|||||||
int disconnect = 0;
|
int disconnect = 0;
|
||||||
char query[128];
|
char query[128];
|
||||||
|
|
||||||
if (NULL == dbi->conn) {
|
if (NULL == dbi->conn)
|
||||||
|
{
|
||||||
dbi->conn = db_connect(dbi);
|
dbi->conn = db_connect(dbi);
|
||||||
disconnect = 1;
|
disconnect = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL != dbi->conn) {
|
if (NULL != dbi->conn)
|
||||||
|
{
|
||||||
snprintf(query, sizeof(query), PAGES_QUERY, tbl->relfilenode);
|
snprintf(query, sizeof(query), PAGES_QUERY, tbl->relfilenode);
|
||||||
res = send_query(query, dbi);
|
res = send_query(query, dbi);
|
||||||
if (NULL != res) {
|
if (NULL != res)
|
||||||
|
{
|
||||||
tbl->reltuples =
|
tbl->reltuples =
|
||||||
atoi(PQgetvalue(res, 0, PQfnumber(res, "reltuples")));
|
atoi(PQgetvalue(res, 0, PQfnumber(res, "reltuples")));
|
||||||
tbl->relpages = atoi(PQgetvalue(res, 0, PQfnumber(res, "relpages")));
|
tbl->relpages = atoi(PQgetvalue(res, 0, PQfnumber(res, "relpages")));
|
||||||
|
|
||||||
/* update vacuum thresholds only of we just did a vacuum analyze */
|
/*
|
||||||
|
* update vacuum thresholds only of we just did a vacuum
|
||||||
|
* analyze
|
||||||
|
*/
|
||||||
if (VACUUM_ANALYZE == vacuum_type)
|
if (VACUUM_ANALYZE == vacuum_type)
|
||||||
{
|
{
|
||||||
tbl->vacuum_threshold =
|
tbl->vacuum_threshold =
|
||||||
@ -156,8 +167,11 @@ update_table_thresholds (db_info * dbi, tbl_info * tbl,int vacuum_type)
|
|||||||
|
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
/* If the stats collector is reporting fewer updates then we have on record
|
/*
|
||||||
then the stats were probably reset, so we need to reset also */
|
* If the stats collector is reporting fewer updates then we
|
||||||
|
* have on record then the stats were probably reset, so we
|
||||||
|
* need to reset also
|
||||||
|
*/
|
||||||
if ((tbl->curr_analyze_count < tbl->CountAtLastAnalyze) ||
|
if ((tbl->curr_analyze_count < tbl->CountAtLastAnalyze) ||
|
||||||
(tbl->curr_vacuum_count < tbl->CountAtLastVacuum))
|
(tbl->curr_vacuum_count < tbl->CountAtLastVacuum))
|
||||||
{
|
{
|
||||||
@ -177,46 +191,62 @@ update_table_list (db_info * dbi)
|
|||||||
PGresult *res = NULL;
|
PGresult *res = NULL;
|
||||||
tbl_info *tbl = NULL;
|
tbl_info *tbl = NULL;
|
||||||
Dlelem *tbl_elem = DLGetHead(dbi->table_list);
|
Dlelem *tbl_elem = DLGetHead(dbi->table_list);
|
||||||
int i = 0, t = 0, found_match = 0;
|
int i = 0,
|
||||||
|
t = 0,
|
||||||
|
found_match = 0;
|
||||||
|
|
||||||
if (NULL == dbi->conn) {
|
if (NULL == dbi->conn)
|
||||||
|
{
|
||||||
dbi->conn = db_connect(dbi);
|
dbi->conn = db_connect(dbi);
|
||||||
disconnect = 1;
|
disconnect = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL != dbi->conn) {
|
if (NULL != dbi->conn)
|
||||||
/* Get a result set that has all the information
|
{
|
||||||
we will need to both remove tables from the list
|
/*
|
||||||
that no longer exist and add tables to the list
|
* Get a result set that has all the information we will need to
|
||||||
that are new */
|
* both remove tables from the list that no longer exist and add
|
||||||
|
* tables to the list that are new
|
||||||
|
*/
|
||||||
res = send_query(query_table_stats(dbi), dbi);
|
res = send_query(query_table_stats(dbi), dbi);
|
||||||
t = PQntuples(res);
|
t = PQntuples(res);
|
||||||
|
|
||||||
/* First: use the tbl_list as the outer loop and
|
/*
|
||||||
the result set as the inner loop, this will
|
* First: use the tbl_list as the outer loop and the result set as
|
||||||
determine what tables should be removed */
|
* the inner loop, this will determine what tables should be
|
||||||
while (NULL != tbl_elem) {
|
* removed
|
||||||
|
*/
|
||||||
|
while (NULL != tbl_elem)
|
||||||
|
{
|
||||||
tbl = ((tbl_info *) DLE_VAL(tbl_elem));
|
tbl = ((tbl_info *) DLE_VAL(tbl_elem));
|
||||||
found_match = 0;
|
found_match = 0;
|
||||||
|
|
||||||
for (i = 0; i < t; i++) { /* loop through result set looking for a match */
|
for (i = 0; i < t; i++)
|
||||||
if (tbl->relfilenode == atoi (PQgetvalue (res, i, PQfnumber (res, "relfilenode")))) {
|
{ /* loop through result set looking for a
|
||||||
|
* match */
|
||||||
|
if (tbl->relfilenode == atoi(PQgetvalue(res, i, PQfnumber(res, "relfilenode"))))
|
||||||
|
{
|
||||||
found_match = 1;
|
found_match = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (0 == found_match) { /* then we didn't find this tbl_elem in the result set */
|
if (0 == found_match)
|
||||||
|
{ /* then we didn't find this tbl_elem in
|
||||||
|
* the result set */
|
||||||
Dlelem *elem_to_remove = tbl_elem;
|
Dlelem *elem_to_remove = tbl_elem;
|
||||||
|
|
||||||
tbl_elem = DLGetSucc(tbl_elem);
|
tbl_elem = DLGetSucc(tbl_elem);
|
||||||
remove_table_from_list(elem_to_remove);
|
remove_table_from_list(elem_to_remove);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
tbl_elem = DLGetSucc(tbl_elem);
|
tbl_elem = DLGetSucc(tbl_elem);
|
||||||
} /* Done removing dropped tables from the table_list */
|
} /* Done removing dropped tables from the
|
||||||
|
* table_list */
|
||||||
|
|
||||||
/* Then loop use result set as outer loop and
|
/*
|
||||||
tbl_list as the inner loop to determine
|
* Then loop use result set as outer loop and tbl_list as the
|
||||||
what tables are new */
|
* inner loop to determine what tables are new
|
||||||
|
*/
|
||||||
for (i = 0; i < t; i++)
|
for (i = 0; i < t; i++)
|
||||||
{
|
{
|
||||||
tbl_elem = DLGetHead(dbi->table_list);
|
tbl_elem = DLGetHead(dbi->table_list);
|
||||||
@ -231,7 +261,8 @@ update_table_list (db_info * dbi)
|
|||||||
}
|
}
|
||||||
tbl_elem = DLGetSucc(tbl_elem);
|
tbl_elem = DLGetSucc(tbl_elem);
|
||||||
}
|
}
|
||||||
if (0 == found_match) /*then we didn't find this result now in the tbl_list */
|
if (0 == found_match) /* then we didn't find this result
|
||||||
|
* now in the tbl_list */
|
||||||
{
|
{
|
||||||
DLAddTail(dbi->table_list, DLNewElem(init_table_info(res, i, dbi)));
|
DLAddTail(dbi->table_list, DLNewElem(init_table_info(res, i, dbi)));
|
||||||
if (args->debug >= 1)
|
if (args->debug >= 1)
|
||||||
@ -245,9 +276,8 @@ update_table_list (db_info * dbi)
|
|||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
res = NULL;
|
res = NULL;
|
||||||
if (args->debug >= 3) {
|
if (args->debug >= 3)
|
||||||
print_table_list(dbi->table_list);
|
print_table_list(dbi->table_list);
|
||||||
}
|
|
||||||
if (disconnect)
|
if (disconnect)
|
||||||
db_disconnect(dbi);
|
db_disconnect(dbi);
|
||||||
}
|
}
|
||||||
@ -259,22 +289,26 @@ remove_table_from_list (Dlelem * tbl_to_remove)
|
|||||||
{
|
{
|
||||||
tbl_info *tbl = ((tbl_info *) DLE_VAL(tbl_to_remove));
|
tbl_info *tbl = ((tbl_info *) DLE_VAL(tbl_to_remove));
|
||||||
|
|
||||||
if (args->debug >= 1) {
|
if (args->debug >= 1)
|
||||||
|
{
|
||||||
sprintf(logbuffer, "Removing table: %s from list.", tbl->table_name);
|
sprintf(logbuffer, "Removing table: %s from list.", tbl->table_name);
|
||||||
log_entry(logbuffer);
|
log_entry(logbuffer);
|
||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
}
|
}
|
||||||
DLRemove(tbl_to_remove);
|
DLRemove(tbl_to_remove);
|
||||||
|
|
||||||
if (tbl->schema_name) {
|
if (tbl->schema_name)
|
||||||
|
{
|
||||||
free(tbl->schema_name);
|
free(tbl->schema_name);
|
||||||
tbl->schema_name = NULL;
|
tbl->schema_name = NULL;
|
||||||
}
|
}
|
||||||
if (tbl->table_name) {
|
if (tbl->table_name)
|
||||||
|
{
|
||||||
free(tbl->table_name);
|
free(tbl->table_name);
|
||||||
tbl->table_name = NULL;
|
tbl->table_name = NULL;
|
||||||
}
|
}
|
||||||
if (tbl) {
|
if (tbl)
|
||||||
|
{
|
||||||
free(tbl);
|
free(tbl);
|
||||||
tbl = NULL;
|
tbl = NULL;
|
||||||
}
|
}
|
||||||
@ -287,7 +321,9 @@ free_tbl_list (Dllist * tbl_list)
|
|||||||
{
|
{
|
||||||
Dlelem *tbl_elem = DLGetHead(tbl_list);
|
Dlelem *tbl_elem = DLGetHead(tbl_list);
|
||||||
Dlelem *tbl_elem_to_remove = NULL;
|
Dlelem *tbl_elem_to_remove = NULL;
|
||||||
while (NULL != tbl_elem) {
|
|
||||||
|
while (NULL != tbl_elem)
|
||||||
|
{
|
||||||
tbl_elem_to_remove = tbl_elem;
|
tbl_elem_to_remove = tbl_elem;
|
||||||
tbl_elem = DLGetSucc(tbl_elem);
|
tbl_elem = DLGetSucc(tbl_elem);
|
||||||
remove_table_from_list(tbl_elem_to_remove);
|
remove_table_from_list(tbl_elem_to_remove);
|
||||||
@ -299,7 +335,9 @@ void
|
|||||||
print_table_list(Dllist *table_list)
|
print_table_list(Dllist *table_list)
|
||||||
{
|
{
|
||||||
Dlelem *table_elem = DLGetHead(table_list);
|
Dlelem *table_elem = DLGetHead(table_list);
|
||||||
while (NULL != table_elem) {
|
|
||||||
|
while (NULL != table_elem)
|
||||||
|
{
|
||||||
print_table_info(((tbl_info *) DLE_VAL(table_elem)));
|
print_table_info(((tbl_info *) DLE_VAL(table_elem)));
|
||||||
table_elem = DLGetSucc(table_elem);
|
table_elem = DLGetSucc(table_elem);
|
||||||
}
|
}
|
||||||
@ -339,27 +377,31 @@ init_db_list ()
|
|||||||
PGresult *res = NULL;
|
PGresult *res = NULL;
|
||||||
|
|
||||||
DLAddHead(db_list, DLNewElem(init_dbinfo((char *) "template1", 0, 0)));
|
DLAddHead(db_list, DLNewElem(init_dbinfo((char *) "template1", 0, 0)));
|
||||||
if (NULL == DLGetHead (db_list)) { /* Make sure init_dbinfo was successful */
|
if (NULL == DLGetHead(db_list))
|
||||||
|
{ /* Make sure init_dbinfo was successful */
|
||||||
log_entry("init_db_list(): Error creating db_list for db: template1.");
|
log_entry("init_db_list(): Error creating db_list for db: template1.");
|
||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We do this just so we can set the proper oid for the template1 database */
|
/*
|
||||||
|
* We do this just so we can set the proper oid for the template1
|
||||||
|
* database
|
||||||
|
*/
|
||||||
dbs = ((db_info *) DLE_VAL(DLGetHead(db_list)));
|
dbs = ((db_info *) DLE_VAL(DLGetHead(db_list)));
|
||||||
dbs->conn = db_connect(dbs);
|
dbs->conn = db_connect(dbs);
|
||||||
|
|
||||||
if (NULL != dbs->conn) {
|
if (NULL != dbs->conn)
|
||||||
|
{
|
||||||
res = send_query(FROZENOID_QUERY, dbs);
|
res = send_query(FROZENOID_QUERY, dbs);
|
||||||
dbs->oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "oid")));
|
dbs->oid = atoi(PQgetvalue(res, 0, PQfnumber(res, "oid")));
|
||||||
dbs->age = atoi(PQgetvalue(res, 0, PQfnumber(res, "age")));
|
dbs->age = atoi(PQgetvalue(res, 0, PQfnumber(res, "age")));
|
||||||
if (res)
|
if (res)
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
if (args->debug >= 2) {
|
if (args->debug >= 2)
|
||||||
print_db_list(db_list, 0);
|
print_db_list(db_list, 0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return db_list;
|
return db_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,17 +411,20 @@ db_info *
|
|||||||
init_dbinfo(char *dbname, int oid, int age)
|
init_dbinfo(char *dbname, int oid, int age)
|
||||||
{
|
{
|
||||||
db_info *newdbinfo = (db_info *) malloc(sizeof(db_info));
|
db_info *newdbinfo = (db_info *) malloc(sizeof(db_info));
|
||||||
|
|
||||||
newdbinfo->analyze_threshold = args->vacuum_base_threshold;
|
newdbinfo->analyze_threshold = args->vacuum_base_threshold;
|
||||||
newdbinfo->vacuum_threshold = args->analyze_base_threshold;
|
newdbinfo->vacuum_threshold = args->analyze_base_threshold;
|
||||||
newdbinfo->dbname = (char *) malloc(strlen(dbname) + 1);
|
newdbinfo->dbname = (char *) malloc(strlen(dbname) + 1);
|
||||||
strcpy(newdbinfo->dbname, dbname);
|
strcpy(newdbinfo->dbname, dbname);
|
||||||
newdbinfo->username = NULL;
|
newdbinfo->username = NULL;
|
||||||
if (NULL != args->user) {
|
if (NULL != args->user)
|
||||||
|
{
|
||||||
newdbinfo->username = (char *) malloc(strlen(args->user) + 1);
|
newdbinfo->username = (char *) malloc(strlen(args->user) + 1);
|
||||||
strcpy(newdbinfo->username, args->user);
|
strcpy(newdbinfo->username, args->user);
|
||||||
}
|
}
|
||||||
newdbinfo->password = NULL;
|
newdbinfo->password = NULL;
|
||||||
if (NULL != args->password) {
|
if (NULL != args->password)
|
||||||
|
{
|
||||||
newdbinfo->password = (char *) malloc(strlen(args->password) + 1);
|
newdbinfo->password = (char *) malloc(strlen(args->password) + 1);
|
||||||
strcpy(newdbinfo->password, args->password);
|
strcpy(newdbinfo->password, args->password);
|
||||||
}
|
}
|
||||||
@ -388,9 +433,8 @@ init_dbinfo (char *dbname, int oid, int age)
|
|||||||
newdbinfo->table_list = DLNewList();
|
newdbinfo->table_list = DLNewList();
|
||||||
newdbinfo->conn = NULL;
|
newdbinfo->conn = NULL;
|
||||||
|
|
||||||
if (args->debug >= 2) {
|
if (args->debug >= 2)
|
||||||
print_table_list(newdbinfo->table_list);
|
print_table_list(newdbinfo->table_list);
|
||||||
}
|
|
||||||
|
|
||||||
return newdbinfo;
|
return newdbinfo;
|
||||||
}
|
}
|
||||||
@ -404,53 +448,74 @@ update_db_list (Dllist * db_list)
|
|||||||
Dlelem *db_elem = DLGetHead(db_list);
|
Dlelem *db_elem = DLGetHead(db_list);
|
||||||
db_info *dbi = NULL;
|
db_info *dbi = NULL;
|
||||||
db_info *dbi_template1 = DLE_VAL(db_elem);
|
db_info *dbi_template1 = DLE_VAL(db_elem);
|
||||||
int i = 0, t = 0, found_match = 0;
|
int i = 0,
|
||||||
|
t = 0,
|
||||||
|
found_match = 0;
|
||||||
|
|
||||||
if (args->debug >= 2) {
|
if (args->debug >= 2)
|
||||||
|
{
|
||||||
log_entry("updating the database list");
|
log_entry("updating the database list");
|
||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL == dbi_template1->conn) {
|
if (NULL == dbi_template1->conn)
|
||||||
|
{
|
||||||
dbi_template1->conn = db_connect(dbi_template1);
|
dbi_template1->conn = db_connect(dbi_template1);
|
||||||
disconnect = 1;
|
disconnect = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL != dbi_template1->conn) {
|
if (NULL != dbi_template1->conn)
|
||||||
/* Get a result set that has all the information
|
{
|
||||||
we will need to both remove databasews from the list
|
/*
|
||||||
that no longer exist and add databases to the list
|
* Get a result set that has all the information we will need to
|
||||||
that are new */
|
* both remove databasews from the list that no longer exist and
|
||||||
|
* add databases to the list that are new
|
||||||
|
*/
|
||||||
res = send_query(FROZENOID_QUERY2, dbi_template1);
|
res = send_query(FROZENOID_QUERY2, dbi_template1);
|
||||||
t = PQntuples(res);
|
t = PQntuples(res);
|
||||||
|
|
||||||
/* First: use the db_list as the outer loop and
|
/*
|
||||||
the result set as the inner loop, this will
|
* First: use the db_list as the outer loop and the result set as
|
||||||
determine what databases should be removed */
|
* the inner loop, this will determine what databases should be
|
||||||
while (NULL != db_elem) {
|
* removed
|
||||||
|
*/
|
||||||
|
while (NULL != db_elem)
|
||||||
|
{
|
||||||
dbi = ((db_info *) DLE_VAL(db_elem));
|
dbi = ((db_info *) DLE_VAL(db_elem));
|
||||||
found_match = 0;
|
found_match = 0;
|
||||||
|
|
||||||
for (i = 0; i < t; i++) { /* loop through result set looking for a match */
|
for (i = 0; i < t; i++)
|
||||||
if (dbi->oid == atoi (PQgetvalue (res, i, PQfnumber (res, "oid")))) {
|
{ /* loop through result set looking for a
|
||||||
|
* match */
|
||||||
|
if (dbi->oid == atoi(PQgetvalue(res, i, PQfnumber(res, "oid"))))
|
||||||
|
{
|
||||||
found_match = 1;
|
found_match = 1;
|
||||||
/* update the dbi->age so that we ensure xid_wraparound won't happen */
|
|
||||||
|
/*
|
||||||
|
* update the dbi->age so that we ensure
|
||||||
|
* xid_wraparound won't happen
|
||||||
|
*/
|
||||||
dbi->age = atoi(PQgetvalue(res, i, PQfnumber(res, "age")));
|
dbi->age = atoi(PQgetvalue(res, i, PQfnumber(res, "age")));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (0 == found_match) { /*then we didn't find this db_elem in the result set */
|
if (0 == found_match)
|
||||||
|
{ /* then we didn't find this db_elem in the
|
||||||
|
* result set */
|
||||||
Dlelem *elem_to_remove = db_elem;
|
Dlelem *elem_to_remove = db_elem;
|
||||||
|
|
||||||
db_elem = DLGetSucc(db_elem);
|
db_elem = DLGetSucc(db_elem);
|
||||||
remove_db_from_list(elem_to_remove);
|
remove_db_from_list(elem_to_remove);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
db_elem = DLGetSucc(db_elem);
|
db_elem = DLGetSucc(db_elem);
|
||||||
} /* Done removing dropped databases from the table_list */
|
} /* Done removing dropped databases from
|
||||||
|
* the table_list */
|
||||||
|
|
||||||
/* Then loop use result set as outer loop and
|
/*
|
||||||
db_list as the inner loop to determine
|
* Then loop use result set as outer loop and db_list as the inner
|
||||||
what databases are new */
|
* loop to determine what databases are new
|
||||||
|
*/
|
||||||
for (i = 0; i < t; i++)
|
for (i = 0; i < t; i++)
|
||||||
{
|
{
|
||||||
db_elem = DLGetHead(db_list);
|
db_elem = DLGetHead(db_list);
|
||||||
@ -465,7 +530,8 @@ update_db_list (Dllist * db_list)
|
|||||||
}
|
}
|
||||||
db_elem = DLGetSucc(db_elem);
|
db_elem = DLGetSucc(db_elem);
|
||||||
}
|
}
|
||||||
if (0 == found_match) /*then we didn't find this result now in the tbl_list */
|
if (0 == found_match) /* then we didn't find this result
|
||||||
|
* now in the tbl_list */
|
||||||
{
|
{
|
||||||
DLAddTail(db_list, DLNewElem(init_dbinfo
|
DLAddTail(db_list, DLNewElem(init_dbinfo
|
||||||
(PQgetvalue(res, i, PQfnumber(res, "datname")),
|
(PQgetvalue(res, i, PQfnumber(res, "datname")),
|
||||||
@ -481,9 +547,8 @@ update_db_list (Dllist * db_list)
|
|||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
res = NULL;
|
res = NULL;
|
||||||
if (args->debug >= 3) {
|
if (args->debug >= 3)
|
||||||
print_db_list(db_list, 0);
|
print_db_list(db_list, 0);
|
||||||
}
|
|
||||||
if (disconnect)
|
if (disconnect)
|
||||||
db_disconnect(dbi_template1);
|
db_disconnect(dbi_template1);
|
||||||
}
|
}
|
||||||
@ -506,11 +571,16 @@ return 1 if the database needed a database wide vacuum
|
|||||||
int
|
int
|
||||||
xid_wraparound_check(db_info * dbi)
|
xid_wraparound_check(db_info * dbi)
|
||||||
{
|
{
|
||||||
/* FIXME: should probably do something better here so that we don't vacuum all the
|
/*
|
||||||
databases on the server at the same time. We have 500million xacts to work with so
|
* FIXME: should probably do something better here so that we don't
|
||||||
we should be able to spread the load of full database vacuums a bit */
|
* vacuum all the databases on the server at the same time. We have
|
||||||
if (1500000000 < dbi->age) {
|
* 500million xacts to work with so we should be able to spread the
|
||||||
|
* load of full database vacuums a bit
|
||||||
|
*/
|
||||||
|
if (1500000000 < dbi->age)
|
||||||
|
{
|
||||||
PGresult *res = NULL;
|
PGresult *res = NULL;
|
||||||
|
|
||||||
res = send_query("vacuum", dbi);
|
res = send_query("vacuum", dbi);
|
||||||
/* FIXME: Perhaps should add a check for PQ_COMMAND_OK */
|
/* FIXME: Perhaps should add a check for PQ_COMMAND_OK */
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
@ -525,7 +595,8 @@ remove_db_from_list (Dlelem * db_to_remove)
|
|||||||
{
|
{
|
||||||
db_info *dbi = ((db_info *) DLE_VAL(db_to_remove));
|
db_info *dbi = ((db_info *) DLE_VAL(db_to_remove));
|
||||||
|
|
||||||
if (args->debug >= 1) {
|
if (args->debug >= 1)
|
||||||
|
{
|
||||||
sprintf(logbuffer, "Removing db: %s from list.", dbi->dbname);
|
sprintf(logbuffer, "Removing db: %s from list.", dbi->dbname);
|
||||||
log_entry(logbuffer);
|
log_entry(logbuffer);
|
||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
@ -533,23 +604,28 @@ remove_db_from_list (Dlelem * db_to_remove)
|
|||||||
DLRemove(db_to_remove);
|
DLRemove(db_to_remove);
|
||||||
if (dbi->conn)
|
if (dbi->conn)
|
||||||
db_disconnect(dbi);
|
db_disconnect(dbi);
|
||||||
if (dbi->dbname) {
|
if (dbi->dbname)
|
||||||
|
{
|
||||||
free(dbi->dbname);
|
free(dbi->dbname);
|
||||||
dbi->dbname = NULL;
|
dbi->dbname = NULL;
|
||||||
}
|
}
|
||||||
if (dbi->username) {
|
if (dbi->username)
|
||||||
|
{
|
||||||
free(dbi->username);
|
free(dbi->username);
|
||||||
dbi->username = NULL;
|
dbi->username = NULL;
|
||||||
}
|
}
|
||||||
if (dbi->password) {
|
if (dbi->password)
|
||||||
|
{
|
||||||
free(dbi->password);
|
free(dbi->password);
|
||||||
dbi->password = NULL;
|
dbi->password = NULL;
|
||||||
}
|
}
|
||||||
if (dbi->table_list) {
|
if (dbi->table_list)
|
||||||
|
{
|
||||||
free_tbl_list(dbi->table_list);
|
free_tbl_list(dbi->table_list);
|
||||||
dbi->table_list = NULL;
|
dbi->table_list = NULL;
|
||||||
}
|
}
|
||||||
if (dbi) {
|
if (dbi)
|
||||||
|
{
|
||||||
free(dbi);
|
free(dbi);
|
||||||
dbi = NULL;
|
dbi = NULL;
|
||||||
}
|
}
|
||||||
@ -563,7 +639,9 @@ free_db_list (Dllist * db_list)
|
|||||||
{
|
{
|
||||||
Dlelem *db_elem = DLGetHead(db_list);
|
Dlelem *db_elem = DLGetHead(db_list);
|
||||||
Dlelem *db_elem_to_remove = NULL;
|
Dlelem *db_elem_to_remove = NULL;
|
||||||
while (NULL != db_elem) {
|
|
||||||
|
while (NULL != db_elem)
|
||||||
|
{
|
||||||
db_elem_to_remove = db_elem;
|
db_elem_to_remove = db_elem;
|
||||||
db_elem = DLGetSucc(db_elem);
|
db_elem = DLGetSucc(db_elem);
|
||||||
remove_db_from_list(db_elem_to_remove);
|
remove_db_from_list(db_elem_to_remove);
|
||||||
@ -576,7 +654,9 @@ void
|
|||||||
print_db_list(Dllist *db_list, int print_table_lists)
|
print_db_list(Dllist *db_list, int print_table_lists)
|
||||||
{
|
{
|
||||||
Dlelem *db_elem = DLGetHead(db_list);
|
Dlelem *db_elem = DLGetHead(db_list);
|
||||||
while (NULL != db_elem) {
|
|
||||||
|
while (NULL != db_elem)
|
||||||
|
{
|
||||||
print_db_info(((db_info *) DLE_VAL(db_elem)), print_table_lists);
|
print_db_info(((db_info *) DLE_VAL(db_elem)), print_table_lists);
|
||||||
db_elem = DLGetSucc(db_elem);
|
db_elem = DLGetSucc(db_elem);
|
||||||
}
|
}
|
||||||
@ -609,7 +689,9 @@ print_db_info (db_info * dbi, int print_tbl_list)
|
|||||||
char *
|
char *
|
||||||
query_table_stats(db_info * dbi)
|
query_table_stats(db_info * dbi)
|
||||||
{
|
{
|
||||||
if (!strcmp (dbi->dbname, "template1")) /* Use template1 to monitor the system tables */
|
if (!strcmp(dbi->dbname, "template1")) /* Use template1 to
|
||||||
|
* monitor the system
|
||||||
|
* tables */
|
||||||
return (char *) TABLE_STATS_ALL;
|
return (char *) TABLE_STATS_ALL;
|
||||||
else
|
else
|
||||||
return (char *) TABLE_STATS_USER;
|
return (char *) TABLE_STATS_USER;
|
||||||
@ -623,7 +705,8 @@ db_connect (db_info * dbi)
|
|||||||
PQsetdbLogin(args->host, args->port, NULL, NULL, dbi->dbname,
|
PQsetdbLogin(args->host, args->port, NULL, NULL, dbi->dbname,
|
||||||
dbi->username, dbi->password);
|
dbi->username, dbi->password);
|
||||||
|
|
||||||
if (CONNECTION_OK != PQstatus (db_conn)) {
|
if (CONNECTION_OK != PQstatus(db_conn))
|
||||||
|
{
|
||||||
sprintf(logbuffer, "Failed connection to database %s with error: %s.",
|
sprintf(logbuffer, "Failed connection to database %s with error: %s.",
|
||||||
dbi->dbname, PQerrorMessage(db_conn));
|
dbi->dbname, PQerrorMessage(db_conn));
|
||||||
log_entry(logbuffer);
|
log_entry(logbuffer);
|
||||||
@ -637,7 +720,8 @@ db_connect (db_info * dbi)
|
|||||||
void
|
void
|
||||||
db_disconnect(db_info * dbi)
|
db_disconnect(db_info * dbi)
|
||||||
{
|
{
|
||||||
if (NULL != dbi->conn) {
|
if (NULL != dbi->conn)
|
||||||
|
{
|
||||||
PQfinish(dbi->conn);
|
PQfinish(dbi->conn);
|
||||||
dbi->conn = NULL;
|
dbi->conn = NULL;
|
||||||
}
|
}
|
||||||
@ -648,6 +732,7 @@ check_stats_enabled (db_info * dbi)
|
|||||||
{
|
{
|
||||||
PGresult *res = NULL;
|
PGresult *res = NULL;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
res = send_query("show stats_row_level", dbi);
|
res = send_query("show stats_row_level", dbi);
|
||||||
ret =
|
ret =
|
||||||
strcmp("on", PQgetvalue(res, 0, PQfnumber(res, "stats_row_level")));
|
strcmp("on", PQgetvalue(res, 0, PQfnumber(res, "stats_row_level")));
|
||||||
@ -665,7 +750,8 @@ send_query (const char *query, db_info * dbi)
|
|||||||
|
|
||||||
res = PQexec(dbi->conn, query);
|
res = PQexec(dbi->conn, query);
|
||||||
|
|
||||||
if (!res) {
|
if (!res)
|
||||||
|
{
|
||||||
sprintf(logbuffer,
|
sprintf(logbuffer,
|
||||||
"Fatal error occured while sending query (%s) to database %s",
|
"Fatal error occured while sending query (%s) to database %s",
|
||||||
query, dbi->dbname);
|
query, dbi->dbname);
|
||||||
@ -676,7 +762,8 @@ send_query (const char *query, db_info * dbi)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (PQresultStatus(res) != PGRES_TUPLES_OK
|
if (PQresultStatus(res) != PGRES_TUPLES_OK
|
||||||
&& PQresultStatus (res) != PGRES_COMMAND_OK) {
|
&& PQresultStatus(res) != PGRES_COMMAND_OK)
|
||||||
|
{
|
||||||
sprintf(logbuffer,
|
sprintf(logbuffer,
|
||||||
"Can not refresh statistics information from the database %s.",
|
"Can not refresh statistics information from the database %s.",
|
||||||
dbi->dbname);
|
dbi->dbname);
|
||||||
@ -694,7 +781,8 @@ send_query (const char *query, db_info * dbi)
|
|||||||
void
|
void
|
||||||
free_cmd_args()
|
free_cmd_args()
|
||||||
{
|
{
|
||||||
if (NULL != args) {
|
if (NULL != args)
|
||||||
|
{
|
||||||
if (NULL != args->user)
|
if (NULL != args->user)
|
||||||
free(args->user);
|
free(args->user);
|
||||||
if (NULL != args->user)
|
if (NULL != args->user)
|
||||||
@ -707,6 +795,7 @@ cmd_args *
|
|||||||
get_cmd_args(int argc, char *argv[])
|
get_cmd_args(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
|
|
||||||
args = (cmd_args *) malloc(sizeof(cmd_args));
|
args = (cmd_args *) malloc(sizeof(cmd_args));
|
||||||
args->sleep_base_value = SLEEPBASEVALUE;
|
args->sleep_base_value = SLEEPBASEVALUE;
|
||||||
args->sleep_scaling_factor = SLEEPSCALINGFACTOR;
|
args->sleep_scaling_factor = SLEEPSCALINGFACTOR;
|
||||||
@ -717,9 +806,14 @@ get_cmd_args (int argc, char *argv[])
|
|||||||
args->debug = AUTOVACUUM_DEBUG;
|
args->debug = AUTOVACUUM_DEBUG;
|
||||||
args->daemonize = 0;
|
args->daemonize = 0;
|
||||||
|
|
||||||
/* Fixme: Should add some sanity checking such as positive integer values etc */
|
/*
|
||||||
while (-1 != (c = getopt (argc, argv, "s:S:v:V:a:A:d:U:P:H:L:p:hD"))) {
|
* Fixme: Should add some sanity checking such as positive integer
|
||||||
switch (c) {
|
* values etc
|
||||||
|
*/
|
||||||
|
while (-1 != (c = getopt(argc, argv, "s:S:v:V:a:A:d:U:P:H:L:p:hD")))
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
case 's':
|
case 's':
|
||||||
args->sleep_base_value = atoi(optarg);
|
args->sleep_base_value = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
@ -763,15 +857,21 @@ get_cmd_args (int argc, char *argv[])
|
|||||||
usage();
|
usage();
|
||||||
exit(0);
|
exit(0);
|
||||||
default:
|
default:
|
||||||
/* It's here that we know that things are invalid...
|
|
||||||
It is not forcibly an error to call usage */
|
/*
|
||||||
|
* It's here that we know that things are invalid... It is
|
||||||
|
* not forcibly an error to call usage
|
||||||
|
*/
|
||||||
fprintf(stderr, "Error: Invalid Command Line Options.\n");
|
fprintf(stderr, "Error: Invalid Command Line Options.\n");
|
||||||
usage();
|
usage();
|
||||||
exit(1);
|
exit(1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
/* if values for insert thresholds are not specified,
|
|
||||||
then they default to 1/2 of the delete values */
|
/*
|
||||||
|
* if values for insert thresholds are not specified, then they
|
||||||
|
* default to 1/2 of the delete values
|
||||||
|
*/
|
||||||
if (-1 == args->analyze_base_threshold)
|
if (-1 == args->analyze_base_threshold)
|
||||||
args->analyze_base_threshold = args->vacuum_base_threshold / 2;
|
args->analyze_base_threshold = args->vacuum_base_threshold / 2;
|
||||||
if (-1 == args->analyze_scaling_factor)
|
if (-1 == args->analyze_scaling_factor)
|
||||||
@ -780,10 +880,12 @@ get_cmd_args (int argc, char *argv[])
|
|||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
void usage()
|
void
|
||||||
|
usage()
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
float f = 0;
|
float f = 0;
|
||||||
|
|
||||||
fprintf(stderr, "usage: pg_autovacuum \n");
|
fprintf(stderr, "usage: pg_autovacuum \n");
|
||||||
fprintf(stderr, " [-D] Daemonize (Detach from tty and run in the background)\n");
|
fprintf(stderr, " [-D] Daemonize (Detach from tty and run in the background)\n");
|
||||||
i = AUTOVACUUM_DEBUG;
|
i = AUTOVACUUM_DEBUG;
|
||||||
@ -854,42 +956,49 @@ int
|
|||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
char buf[256];
|
char buf[256];
|
||||||
int j = 0, loops = 0;
|
int j = 0,
|
||||||
|
loops = 0;
|
||||||
|
|
||||||
/* int numInserts, numDeletes, */
|
/* int numInserts, numDeletes, */
|
||||||
int sleep_secs;
|
int sleep_secs;
|
||||||
Dllist *db_list;
|
Dllist *db_list;
|
||||||
Dlelem *db_elem, *tbl_elem;
|
Dlelem *db_elem,
|
||||||
|
*tbl_elem;
|
||||||
db_info *dbs;
|
db_info *dbs;
|
||||||
tbl_info *tbl;
|
tbl_info *tbl;
|
||||||
PGresult *res = NULL;
|
PGresult *res = NULL;
|
||||||
long long diff = 0;
|
long long diff = 0;
|
||||||
struct timeval now, then;
|
struct timeval now,
|
||||||
|
then;
|
||||||
|
|
||||||
args = get_cmd_args (argc, argv); /* Get Command Line Args and put them in the args struct */
|
args = get_cmd_args(argc, argv); /* Get Command Line Args and put
|
||||||
|
* them in the args struct */
|
||||||
|
|
||||||
/* Dameonize if requested */
|
/* Dameonize if requested */
|
||||||
if (1 == args->daemonize){ daemonize(); }
|
if (1 == args->daemonize)
|
||||||
|
daemonize();
|
||||||
|
|
||||||
if (args->logfile) {
|
if (args->logfile)
|
||||||
|
{
|
||||||
LOGOUTPUT = fopen(args->logfile, "a");
|
LOGOUTPUT = fopen(args->logfile, "a");
|
||||||
if (!LOGOUTPUT) {
|
if (!LOGOUTPUT)
|
||||||
|
{
|
||||||
fprintf(stderr, "Could not open log file - [%s]\n", args->logfile);
|
fprintf(stderr, "Could not open log file - [%s]\n", args->logfile);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
LOGOUTPUT = stderr;
|
LOGOUTPUT = stderr;
|
||||||
}
|
if (args->debug >= 2)
|
||||||
if (args->debug >= 2) {
|
|
||||||
print_cmd_args();
|
print_cmd_args();
|
||||||
}
|
|
||||||
|
|
||||||
/* Init the db list with template1 */
|
/* Init the db list with template1 */
|
||||||
db_list = init_db_list();
|
db_list = init_db_list();
|
||||||
if (NULL == db_list)
|
if (NULL == db_list)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (0 != check_stats_enabled (((db_info *) DLE_VAL (DLGetHead (db_list))))) {
|
if (0 != check_stats_enabled(((db_info *) DLE_VAL(DLGetHead(db_list)))))
|
||||||
|
{
|
||||||
log_entry("Error: GUC variable stats_row_level must be enabled.");
|
log_entry("Error: GUC variable stats_row_level must be enabled.");
|
||||||
log_entry(" Please fix the problems and try again.");
|
log_entry(" Please fix the problems and try again.");
|
||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
@ -899,13 +1008,19 @@ main (int argc, char *argv[])
|
|||||||
|
|
||||||
gettimeofday(&then, 0); /* for use later to caluculate sleep time */
|
gettimeofday(&then, 0); /* for use later to caluculate sleep time */
|
||||||
|
|
||||||
while (1) { /* Main Loop */
|
while (1)
|
||||||
db_elem = DLGetHead (db_list); /* Reset cur_db_node to the beginning of the db_list */
|
{ /* Main Loop */
|
||||||
|
db_elem = DLGetHead(db_list); /* Reset cur_db_node to the
|
||||||
|
* beginning of the db_list */
|
||||||
|
|
||||||
dbs = ((db_info *) DLE_VAL (db_elem)); /* get pointer to cur_db's db_info struct */
|
dbs = ((db_info *) DLE_VAL(db_elem)); /* get pointer to cur_db's
|
||||||
if (NULL == dbs->conn) {
|
* db_info struct */
|
||||||
|
if (NULL == dbs->conn)
|
||||||
|
{
|
||||||
dbs->conn = db_connect(dbs);
|
dbs->conn = db_connect(dbs);
|
||||||
if (NULL == dbs->conn) { /* Serious problem: We can't connect to template1 */
|
if (NULL == dbs->conn)
|
||||||
|
{ /* Serious problem: We can't connect to
|
||||||
|
* template1 */
|
||||||
log_entry("Error: Cannot connect to template1, exiting.");
|
log_entry("Error: Cannot connect to template1, exiting.");
|
||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
fclose(LOGOUTPUT);
|
fclose(LOGOUTPUT);
|
||||||
@ -913,26 +1028,41 @@ main (int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 == (loops % UPDATE_INTERVAL)) /* Update the list if it's time */
|
if (0 == (loops % UPDATE_INTERVAL)) /* Update the list if it's
|
||||||
update_db_list (db_list); /* Add and remove databases from the list */
|
* time */
|
||||||
|
update_db_list(db_list); /* Add and remove databases from
|
||||||
|
* the list */
|
||||||
|
|
||||||
while (NULL != db_elem) { /* Loop through databases in list */
|
while (NULL != db_elem)
|
||||||
dbs = ((db_info *) DLE_VAL (db_elem)); /* get pointer to cur_db's db_info struct */
|
{ /* Loop through databases in list */
|
||||||
|
dbs = ((db_info *) DLE_VAL(db_elem)); /* get pointer to
|
||||||
|
* cur_db's db_info
|
||||||
|
* struct */
|
||||||
if (NULL == dbs->conn)
|
if (NULL == dbs->conn)
|
||||||
dbs->conn = db_connect(dbs);
|
dbs->conn = db_connect(dbs);
|
||||||
|
|
||||||
if (NULL != dbs->conn) {
|
if (NULL != dbs->conn)
|
||||||
if (0 == (loops % UPDATE_INTERVAL)) /* Update the list if it's time */
|
{
|
||||||
update_table_list (dbs); /* Add and remove tables from the list */
|
if (0 == (loops % UPDATE_INTERVAL)) /* Update the list if
|
||||||
|
* it's time */
|
||||||
|
update_table_list(dbs); /* Add and remove tables
|
||||||
|
* from the list */
|
||||||
|
|
||||||
if (0 == xid_wraparound_check(dbs));
|
if (0 == xid_wraparound_check(dbs));
|
||||||
{
|
{
|
||||||
res = send_query (query_table_stats (dbs), dbs); /* Get an updated snapshot of this dbs table stats */
|
res = send_query(query_table_stats(dbs), dbs); /* Get an updated
|
||||||
for (j = 0; j < PQntuples (res); j++) { /* loop through result set */
|
* snapshot of this dbs
|
||||||
tbl_elem = DLGetHead (dbs->table_list); /* Reset tbl_elem to top of dbs->table_list */
|
* table stats */
|
||||||
while (NULL != tbl_elem) { /* Loop through tables in list */
|
for (j = 0; j < PQntuples(res); j++)
|
||||||
tbl = ((tbl_info *) DLE_VAL (tbl_elem)); /* set tbl_info = current_table */
|
{ /* loop through result set */
|
||||||
if (tbl->relfilenode == atoi (PQgetvalue(res, j, PQfnumber (res, "relfilenode")))) {
|
tbl_elem = DLGetHead(dbs->table_list); /* Reset tbl_elem to top
|
||||||
|
* of dbs->table_list */
|
||||||
|
while (NULL != tbl_elem)
|
||||||
|
{ /* Loop through tables in list */
|
||||||
|
tbl = ((tbl_info *) DLE_VAL(tbl_elem)); /* set tbl_info =
|
||||||
|
* current_table */
|
||||||
|
if (tbl->relfilenode == atoi(PQgetvalue(res, j, PQfnumber(res, "relfilenode"))))
|
||||||
|
{
|
||||||
tbl->curr_analyze_count =
|
tbl->curr_analyze_count =
|
||||||
(atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_ins"))) +
|
(atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_ins"))) +
|
||||||
atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_upd"))) +
|
atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_upd"))) +
|
||||||
@ -941,38 +1071,52 @@ main (int argc, char *argv[])
|
|||||||
(atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_del"))) +
|
(atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_del"))) +
|
||||||
atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_upd"))));
|
atol(PQgetvalue(res, j, PQfnumber(res, "n_tup_upd"))));
|
||||||
|
|
||||||
/* Check numDeletes to see if we need to vacuum, if so:
|
/*
|
||||||
Run vacuum analyze (adding analyze is small so we might as well)
|
* Check numDeletes to see if we need to
|
||||||
Update table thresholds and related information
|
* vacuum, if so: Run vacuum analyze
|
||||||
if numDeletes is not big enough for vacuum then check numInserts for analyze */
|
* (adding analyze is small so we might as
|
||||||
|
* well) Update table thresholds and
|
||||||
|
* related information if numDeletes is
|
||||||
|
* not big enough for vacuum then check
|
||||||
|
* numInserts for analyze
|
||||||
|
*/
|
||||||
if ((tbl->curr_vacuum_count - tbl->CountAtLastVacuum) >= tbl->vacuum_threshold)
|
if ((tbl->curr_vacuum_count - tbl->CountAtLastVacuum) >= tbl->vacuum_threshold)
|
||||||
{
|
{
|
||||||
snprintf(buf, sizeof(buf), "vacuum analyze %s", tbl->table_name);
|
snprintf(buf, sizeof(buf), "vacuum analyze %s", tbl->table_name);
|
||||||
if (args->debug >= 1) {
|
if (args->debug >= 1)
|
||||||
|
{
|
||||||
sprintf(logbuffer, "Performing: %s", buf);
|
sprintf(logbuffer, "Performing: %s", buf);
|
||||||
log_entry(logbuffer);
|
log_entry(logbuffer);
|
||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
}
|
}
|
||||||
send_query(buf, dbs);
|
send_query(buf, dbs);
|
||||||
update_table_thresholds(dbs, tbl, VACUUM_ANALYZE);
|
update_table_thresholds(dbs, tbl, VACUUM_ANALYZE);
|
||||||
if (args->debug >= 2) {print_table_info (tbl);}
|
if (args->debug >= 2)
|
||||||
|
print_table_info(tbl);
|
||||||
}
|
}
|
||||||
else if ((tbl->curr_analyze_count - tbl->CountAtLastAnalyze) >= tbl->analyze_threshold)
|
else if ((tbl->curr_analyze_count - tbl->CountAtLastAnalyze) >= tbl->analyze_threshold)
|
||||||
{
|
{
|
||||||
snprintf(buf, sizeof(buf), "analyze %s", tbl->table_name);
|
snprintf(buf, sizeof(buf), "analyze %s", tbl->table_name);
|
||||||
if (args->debug >= 1) {
|
if (args->debug >= 1)
|
||||||
|
{
|
||||||
sprintf(logbuffer, "Performing: %s", buf);
|
sprintf(logbuffer, "Performing: %s", buf);
|
||||||
log_entry(logbuffer);
|
log_entry(logbuffer);
|
||||||
fflush(LOGOUTPUT);
|
fflush(LOGOUTPUT);
|
||||||
}
|
}
|
||||||
send_query(buf, dbs);
|
send_query(buf, dbs);
|
||||||
update_table_thresholds(dbs, tbl, ANALYZE_ONLY);
|
update_table_thresholds(dbs, tbl, ANALYZE_ONLY);
|
||||||
if (args->debug >= 2) { print_table_info (tbl); }
|
if (args->debug >= 2)
|
||||||
|
print_table_info(tbl);
|
||||||
}
|
}
|
||||||
|
|
||||||
break; /* once we have found a match, no need to keep checking. */
|
break; /* once we have found a match, no
|
||||||
|
* need to keep checking. */
|
||||||
}
|
}
|
||||||
/* Advance the table pointers for the next loop */
|
|
||||||
|
/*
|
||||||
|
* Advance the table pointers for the next
|
||||||
|
* loop
|
||||||
|
*/
|
||||||
tbl_elem = DLGetSucc(tbl_elem);
|
tbl_elem = DLGetSucc(tbl_elem);
|
||||||
|
|
||||||
} /* end for table while loop */
|
} /* end for table while loop */
|
||||||
@ -983,7 +1127,8 @@ main (int argc, char *argv[])
|
|||||||
res = NULL;
|
res = NULL;
|
||||||
db_disconnect(dbs);
|
db_disconnect(dbs);
|
||||||
}
|
}
|
||||||
db_elem = DLGetSucc (db_elem); /* move on to next DB regardless */
|
db_elem = DLGetSucc(db_elem); /* move on to next DB
|
||||||
|
* regardless */
|
||||||
} /* end of db_list while loop */
|
} /* end of db_list while loop */
|
||||||
|
|
||||||
/* Figure out how long to sleep etc ... */
|
/* Figure out how long to sleep etc ... */
|
||||||
@ -992,7 +1137,8 @@ main (int argc, char *argv[])
|
|||||||
|
|
||||||
sleep_secs = args->sleep_base_value + args->sleep_scaling_factor * diff / 1000000;
|
sleep_secs = args->sleep_base_value + args->sleep_scaling_factor * diff / 1000000;
|
||||||
loops++;
|
loops++;
|
||||||
if (args->debug >= 2) {
|
if (args->debug >= 2)
|
||||||
|
{
|
||||||
sprintf(logbuffer,
|
sprintf(logbuffer,
|
||||||
"%i All DBs checked in: %lld usec, will sleep for %i secs.",
|
"%i All DBs checked in: %lld usec, will sleep for %i secs.",
|
||||||
loops, diff, sleep_secs);
|
loops, diff, sleep_secs);
|
||||||
@ -1005,7 +1151,10 @@ main (int argc, char *argv[])
|
|||||||
|
|
||||||
} /* end of while loop */
|
} /* end of while loop */
|
||||||
|
|
||||||
/* program is exiting, this should never run, but is here to make compiler / valgrind happy */
|
/*
|
||||||
|
* program is exiting, this should never run, but is here to make
|
||||||
|
* compiler / valgrind happy
|
||||||
|
*/
|
||||||
free_db_list(db_list);
|
free_db_list(db_list);
|
||||||
free_cmd_args();
|
free_cmd_args();
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
@ -44,9 +44,19 @@
|
|||||||
/* define cmd_args stucture */
|
/* define cmd_args stucture */
|
||||||
struct cmdargs
|
struct cmdargs
|
||||||
{
|
{
|
||||||
int vacuum_base_threshold, analyze_base_threshold, sleep_base_value, debug, daemonize;
|
int vacuum_base_threshold,
|
||||||
float vacuum_scaling_factor, analyze_scaling_factor, sleep_scaling_factor;
|
analyze_base_threshold,
|
||||||
char *user, *password, *host, *logfile, *port;
|
sleep_base_value,
|
||||||
|
debug,
|
||||||
|
daemonize;
|
||||||
|
float vacuum_scaling_factor,
|
||||||
|
analyze_scaling_factor,
|
||||||
|
sleep_scaling_factor;
|
||||||
|
char *user,
|
||||||
|
*password,
|
||||||
|
*host,
|
||||||
|
*logfile,
|
||||||
|
*port;
|
||||||
};
|
};
|
||||||
typedef struct cmdargs cmd_args;
|
typedef struct cmdargs cmd_args;
|
||||||
|
|
||||||
@ -57,23 +67,38 @@ cmd_args *args;
|
|||||||
I think we need to guarantee this happens approx every 1Million TX's */
|
I think we need to guarantee this happens approx every 1Million TX's */
|
||||||
struct dbinfo
|
struct dbinfo
|
||||||
{
|
{
|
||||||
int oid, age;
|
int oid,
|
||||||
int analyze_threshold, vacuum_threshold; /* Use these as defaults for table thresholds */
|
age;
|
||||||
|
int analyze_threshold,
|
||||||
|
vacuum_threshold; /* Use these as defaults for table
|
||||||
|
* thresholds */
|
||||||
PGconn *conn;
|
PGconn *conn;
|
||||||
char *dbname, *username, *password;
|
char *dbname,
|
||||||
|
*username,
|
||||||
|
*password;
|
||||||
Dllist *table_list;
|
Dllist *table_list;
|
||||||
};
|
};
|
||||||
typedef struct dbinfo db_info;
|
typedef struct dbinfo db_info;
|
||||||
|
|
||||||
struct tableinfo
|
struct tableinfo
|
||||||
{
|
{
|
||||||
char *schema_name, *table_name;
|
char *schema_name,
|
||||||
int relfilenode, reltuples, relpages;
|
*table_name;
|
||||||
long analyze_threshold, vacuum_threshold;
|
int relfilenode,
|
||||||
long CountAtLastAnalyze; /* equal to: inserts + updates as of the last analyze or initial values at startup */
|
reltuples,
|
||||||
long CountAtLastVacuum; /* equal to: deletes + updates as of the last vacuum or initial values at startup */
|
relpages;
|
||||||
long curr_analyze_count, curr_vacuum_count; /* Latest values from stats system */
|
long analyze_threshold,
|
||||||
db_info *dbi; /* pointer to the database that this table belongs to */
|
vacuum_threshold;
|
||||||
|
long CountAtLastAnalyze; /* equal to: inserts + updates as
|
||||||
|
* of the last analyze or initial
|
||||||
|
* values at startup */
|
||||||
|
long CountAtLastVacuum; /* equal to: deletes + updates as
|
||||||
|
* of the last vacuum or initial
|
||||||
|
* values at startup */
|
||||||
|
long curr_analyze_count,
|
||||||
|
curr_vacuum_count; /* Latest values from stats system */
|
||||||
|
db_info *dbi; /* pointer to the database that this table
|
||||||
|
* belongs to */
|
||||||
};
|
};
|
||||||
typedef struct tableinfo tbl_info;
|
typedef struct tableinfo tbl_info;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* -------------------------------------------------------------------------
|
/* -------------------------------------------------------------------------
|
||||||
* pg_dumplo
|
* pg_dumplo
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/contrib/pg_dumplo/Attic/main.c,v 1.16 2003/05/14 03:25:56 tgl Exp $
|
* $Header: /cvsroot/pgsql/contrib/pg_dumplo/Attic/main.c,v 1.17 2003/08/04 00:43:11 momjian Exp $
|
||||||
*
|
*
|
||||||
* Karel Zak 1999-2000
|
* Karel Zak 1999-2000
|
||||||
* -------------------------------------------------------------------------
|
* -------------------------------------------------------------------------
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Header: /cvsroot/pgsql/contrib/pgbench/pgbench.c,v 1.25 2003/08/01 02:21:17 tgl Exp $
|
* $Header: /cvsroot/pgsql/contrib/pgbench/pgbench.c,v 1.26 2003/08/04 00:43:11 momjian Exp $
|
||||||
*
|
*
|
||||||
* pgbench: a simple TPC-B like benchmark program for PostgreSQL
|
* pgbench: a simple TPC-B like benchmark program for PostgreSQL
|
||||||
* written by Tatsuo Ishii
|
* written by Tatsuo Ishii
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id: openssl.c,v 1.11 2002/11/15 02:54:44 momjian Exp $
|
* $Id: openssl.c,v 1.12 2003/08/04 00:43:11 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <postgres.h>
|
#include <postgres.h>
|
||||||
@ -134,7 +134,8 @@ px_find_digest(const char *name, PX_MD ** res)
|
|||||||
* So need to manage ciphers ourselves.
|
* So need to manage ciphers ourselves.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct ossl_cipher {
|
struct ossl_cipher
|
||||||
|
{
|
||||||
int (*init) (PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv);
|
int (*init) (PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv);
|
||||||
int (*encrypt) (PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res);
|
int (*encrypt) (PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res);
|
||||||
int (*decrypt) (PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res);
|
int (*decrypt) (PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res);
|
||||||
@ -510,8 +511,10 @@ px_find_cipher(const char *name, PX_Cipher ** res)
|
|||||||
const struct ossl_cipher *ossl_ciph = NULL;
|
const struct ossl_cipher *ossl_ciph = NULL;
|
||||||
|
|
||||||
name = px_resolve_alias(ossl_aliases, name);
|
name = px_resolve_alias(ossl_aliases, name);
|
||||||
for (i = 0; ossl_cipher_types[i].name; i++) {
|
for (i = 0; ossl_cipher_types[i].name; i++)
|
||||||
if (!strcmp(ossl_cipher_types[i].name, name)) {
|
{
|
||||||
|
if (!strcmp(ossl_cipher_types[i].name, name))
|
||||||
|
{
|
||||||
ossl_ciph = ossl_cipher_types[i].ciph;
|
ossl_ciph = ossl_cipher_types[i].ciph;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id: pgcrypto.c,v 1.13 2003/07/24 17:52:33 tgl Exp $
|
* $Id: pgcrypto.c,v 1.14 2003/08/04 00:43:11 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <postgres.h>
|
#include <postgres.h>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.11 2003/08/01 02:21:17 tgl Exp $
|
* $Header: /cvsroot/pgsql/contrib/pgstattuple/pgstattuple.c,v 1.12 2003/08/04 00:43:11 momjian Exp $
|
||||||
*
|
*
|
||||||
* Copyright (c) 2001,2002 Tatsuo Ishii
|
* Copyright (c) 2001,2002 Tatsuo Ishii
|
||||||
*
|
*
|
||||||
|
@ -261,7 +261,8 @@ timetravel(PG_FUNCTION_ARGS)
|
|||||||
relname, args[a_time_on], args[a_time_off]);
|
relname, args[a_time_on], args[a_time_off]);
|
||||||
}
|
}
|
||||||
if (oldtimeoff != NOEND_ABSTIME)
|
if (oldtimeoff != NOEND_ABSTIME)
|
||||||
{ /* current record is a deleted/updated record */
|
{ /* current record is a deleted/updated
|
||||||
|
* record */
|
||||||
pfree(relname);
|
pfree(relname);
|
||||||
return PointerGetDatum(NULL);
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
@ -282,7 +283,8 @@ timetravel(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* change date column(s) */
|
/* change date column(s) */
|
||||||
cvals[attnum[a_time_off] - 1] = newtimeoff; /* stop_date eq current date */
|
cvals[attnum[a_time_off] - 1] = newtimeoff; /* stop_date eq current
|
||||||
|
* date */
|
||||||
cnulls[attnum[a_time_off] - 1] = ' ';
|
cnulls[attnum[a_time_off] - 1] = ' ';
|
||||||
|
|
||||||
if (!newtuple)
|
if (!newtuple)
|
||||||
@ -399,7 +401,8 @@ timetravel(PG_FUNCTION_ARGS)
|
|||||||
*/
|
*/
|
||||||
/* SPI_pfree(tmptuple); */
|
/* SPI_pfree(tmptuple); */
|
||||||
}
|
}
|
||||||
else /* DELETE case */
|
else
|
||||||
|
/* DELETE case */
|
||||||
rettuple = trigtuple;
|
rettuple = trigtuple;
|
||||||
|
|
||||||
SPI_finish(); /* don't forget say Bye to SPI mgr */
|
SPI_finish(); /* don't forget say Bye to SPI mgr */
|
||||||
@ -423,7 +426,8 @@ set_timetravel(PG_FUNCTION_ARGS)
|
|||||||
char *d;
|
char *d;
|
||||||
char *s;
|
char *s;
|
||||||
int32 ret;
|
int32 ret;
|
||||||
TTOffList *p,*pp;
|
TTOffList *p,
|
||||||
|
*pp;
|
||||||
|
|
||||||
for (pp = (p = &TTOff)->next; pp; pp = (p = pp)->next)
|
for (pp = (p = &TTOff)->next; pp; pp = (p = pp)->next)
|
||||||
{
|
{
|
||||||
@ -492,6 +496,7 @@ static int
|
|||||||
findTTStatus(char *name)
|
findTTStatus(char *name)
|
||||||
{
|
{
|
||||||
TTOffList *pp;
|
TTOffList *pp;
|
||||||
|
|
||||||
for (pp = TTOff.next; pp; pp = pp->next)
|
for (pp = TTOff.next; pp; pp = pp->next)
|
||||||
if (strcasecmp(name, pp->name) == 0)
|
if (strcasecmp(name, pp->name) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -729,9 +729,9 @@ crosstab_hash(PG_FUNCTION_ARGS)
|
|||||||
/*
|
/*
|
||||||
* Check to make sure we have a reasonable tuple descriptor
|
* Check to make sure we have a reasonable tuple descriptor
|
||||||
*
|
*
|
||||||
* Note we will attempt to coerce the values into whatever
|
* Note we will attempt to coerce the values into whatever the return
|
||||||
* the return attribute type is and depend on the "in"
|
* attribute type is and depend on the "in" function to complain if
|
||||||
* function to complain if needed.
|
* needed.
|
||||||
*/
|
*/
|
||||||
if (tupdesc->natts < 2)
|
if (tupdesc->natts < 2)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -781,8 +781,8 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
|
|||||||
ctl.entrysize = sizeof(crosstab_HashEnt);
|
ctl.entrysize = sizeof(crosstab_HashEnt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* use INIT_CATS, defined above as a guess of how
|
* use INIT_CATS, defined above as a guess of how many hash table
|
||||||
* many hash table entries to create, initially
|
* entries to create, initially
|
||||||
*/
|
*/
|
||||||
crosstab_HashTable = hash_create("crosstab hash", INIT_CATS, &ctl, HASH_ELEM);
|
crosstab_HashTable = hash_create("crosstab hash", INIT_CATS, &ctl, HASH_ELEM);
|
||||||
|
|
||||||
@ -803,8 +803,8 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The provided categories SQL query must always return one column:
|
* The provided categories SQL query must always return one
|
||||||
* category - the label or identifier for each column
|
* column: category - the label or identifier for each column
|
||||||
*/
|
*/
|
||||||
if (spi_tupdesc->natts != 1)
|
if (spi_tupdesc->natts != 1)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -890,21 +890,24 @@ get_crosstab_tuplestore(char *sql,
|
|||||||
int ncols = spi_tupdesc->natts;
|
int ncols = spi_tupdesc->natts;
|
||||||
char *rowid;
|
char *rowid;
|
||||||
char *lastrowid = NULL;
|
char *lastrowid = NULL;
|
||||||
int i, j;
|
int i,
|
||||||
|
j;
|
||||||
int result_ncols;
|
int result_ncols;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The provided SQL query must always return at least three columns:
|
* The provided SQL query must always return at least three
|
||||||
|
* columns:
|
||||||
*
|
*
|
||||||
* 1. rowname the label for each row - column 1 in the final result
|
* 1. rowname the label for each row - column 1 in the final result
|
||||||
* 2. category the label for each value-column in the final result
|
* 2. category the label for each value-column in the final
|
||||||
* 3. value the values used to populate the value-columns
|
* result 3. value the values used to populate the
|
||||||
|
* value-columns
|
||||||
*
|
*
|
||||||
* If there are more than three columns, the last two are taken as
|
* If there are more than three columns, the last two are taken as
|
||||||
* "category" and "values". The first column is taken as "rowname".
|
* "category" and "values". The first column is taken as
|
||||||
* Additional columns (2 thru N-2) are assumed the same for the same
|
* "rowname". Additional columns (2 thru N-2) are assumed the same
|
||||||
* "rowname", and are copied into the result tuple from the first
|
* for the same "rowname", and are copied into the result tuple
|
||||||
* time we encounter a particular rowname.
|
* from the first time we encounter a particular rowname.
|
||||||
*/
|
*/
|
||||||
if (ncols < 3)
|
if (ncols < 3)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -958,7 +961,10 @@ get_crosstab_tuplestore(char *sql,
|
|||||||
*/
|
*/
|
||||||
if (lastrowid != NULL)
|
if (lastrowid != NULL)
|
||||||
{
|
{
|
||||||
/* switch to appropriate context while storing the tuple */
|
/*
|
||||||
|
* switch to appropriate context while storing the
|
||||||
|
* tuple
|
||||||
|
*/
|
||||||
SPIcontext = MemoryContextSwitchTo(per_query_ctx);
|
SPIcontext = MemoryContextSwitchTo(per_query_ctx);
|
||||||
|
|
||||||
/* rowid changed, flush the previous output row */
|
/* rowid changed, flush the previous output row */
|
||||||
|
@ -51,7 +51,8 @@ DICT dicts[] = {
|
|||||||
#undef DICT_TABLE
|
#undef DICT_TABLE
|
||||||
|
|
||||||
/* array for storing dictionary's objects (if needed) */
|
/* array for storing dictionary's objects (if needed) */
|
||||||
void *dictobjs[lengthof(dicts)];
|
void *dictobjs[
|
||||||
|
lengthof(dicts)];
|
||||||
|
|
||||||
#define STOPLEXEM -2
|
#define STOPLEXEM -2
|
||||||
#define BYLOCALE -1
|
#define BYLOCALE -1
|
||||||
|
@ -5,43 +5,59 @@
|
|||||||
#include "dict.h"
|
#include "dict.h"
|
||||||
|
|
||||||
text *
|
text *
|
||||||
char2text(char* in) {
|
char2text(char *in)
|
||||||
|
{
|
||||||
return charl2text(in, strlen(in));
|
return charl2text(in, strlen(in));
|
||||||
}
|
}
|
||||||
|
|
||||||
text* charl2text(char* in, int len) {
|
text *
|
||||||
|
charl2text(char *in, int len)
|
||||||
|
{
|
||||||
text *out = (text *) palloc(len + VARHDRSZ);
|
text *out = (text *) palloc(len + VARHDRSZ);
|
||||||
|
|
||||||
memcpy(VARDATA(out), in, len);
|
memcpy(VARDATA(out), in, len);
|
||||||
VARATT_SIZEP(out) = len + VARHDRSZ;
|
VARATT_SIZEP(out) = len + VARHDRSZ;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
char
|
char
|
||||||
*text2char(text* in) {
|
*
|
||||||
|
text2char(text *in)
|
||||||
|
{
|
||||||
char *out = palloc(VARSIZE(in));
|
char *out = palloc(VARSIZE(in));
|
||||||
|
|
||||||
memcpy(out, VARDATA(in), VARSIZE(in) - VARHDRSZ);
|
memcpy(out, VARDATA(in), VARSIZE(in) - VARHDRSZ);
|
||||||
out[VARSIZE(in) - VARHDRSZ] = '\0';
|
out[VARSIZE(in) - VARHDRSZ] = '\0';
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
char
|
char
|
||||||
*pnstrdup(char* in, int len) {
|
*
|
||||||
|
pnstrdup(char *in, int len)
|
||||||
|
{
|
||||||
char *out = palloc(len + 1);
|
char *out = palloc(len + 1);
|
||||||
|
|
||||||
memcpy(out, in, len);
|
memcpy(out, in, len);
|
||||||
out[len] = '\0';
|
out[len] = '\0';
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
text
|
text
|
||||||
*ptextdup(text* in) {
|
*
|
||||||
|
ptextdup(text *in)
|
||||||
|
{
|
||||||
text *out = (text *) palloc(VARSIZE(in));
|
text *out = (text *) palloc(VARSIZE(in));
|
||||||
|
|
||||||
memcpy(out, in, VARSIZE(in));
|
memcpy(out, in, VARSIZE(in));
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
text
|
text
|
||||||
*mtextdup(text* in) {
|
*
|
||||||
|
mtextdup(text *in)
|
||||||
|
{
|
||||||
text *out = (text *) malloc(VARSIZE(in));
|
text *out = (text *) malloc(VARSIZE(in));
|
||||||
|
|
||||||
if (!out)
|
if (!out)
|
||||||
ts_error(ERROR, "No memory");
|
ts_error(ERROR, "No memory");
|
||||||
memcpy(out, in, VARSIZE(in));
|
memcpy(out, in, VARSIZE(in));
|
||||||
@ -49,9 +65,11 @@ text
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ts_error(int state, const char *format, ...) {
|
ts_error(int state, const char *format,...)
|
||||||
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
int tlen = 128, len=0;
|
int tlen = 128,
|
||||||
|
len = 0;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
reset_cfg();
|
reset_cfg();
|
||||||
@ -61,7 +79,8 @@ ts_error(int state, const char *format, ...) {
|
|||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
buf = palloc(tlen);
|
buf = palloc(tlen);
|
||||||
len = vsnprintf(buf, tlen - 1, format, args);
|
len = vsnprintf(buf, tlen - 1, format, args);
|
||||||
if ( len >= tlen ) {
|
if (len >= tlen)
|
||||||
|
{
|
||||||
tlen = len + 1;
|
tlen = len + 1;
|
||||||
buf = repalloc(buf, tlen);
|
buf = repalloc(buf, tlen);
|
||||||
vsnprintf(buf, tlen - 1, format, args);
|
vsnprintf(buf, tlen - 1, format, args);
|
||||||
@ -74,10 +93,10 @@ ts_error(int state, const char *format, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
text_cmp(text *a, text *b) {
|
text_cmp(text *a, text *b)
|
||||||
|
{
|
||||||
if (VARSIZE(a) == VARSIZE(b))
|
if (VARSIZE(a) == VARSIZE(b))
|
||||||
return strncmp(VARDATA(a), VARDATA(b), VARSIZE(a) - VARHDRSZ);
|
return strncmp(VARDATA(a), VARDATA(b), VARSIZE(a) - VARHDRSZ);
|
||||||
return (int) VARSIZE(a) - (int) VARSIZE(b);
|
return (int) VARSIZE(a) - (int) VARSIZE(b);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
static void *plan_getdict = NULL;
|
static void *plan_getdict = NULL;
|
||||||
|
|
||||||
void
|
void
|
||||||
init_dict(Oid id, DictInfo *dict) {
|
init_dict(Oid id, DictInfo * dict)
|
||||||
|
{
|
||||||
Oid arg[1] = {OIDOID};
|
Oid arg[1] = {OIDOID};
|
||||||
bool isnull;
|
bool isnull;
|
||||||
Datum pars[1] = {ObjectIdGetDatum(id)};
|
Datum pars[1] = {ObjectIdGetDatum(id)};
|
||||||
@ -30,7 +31,8 @@ init_dict(Oid id, DictInfo *dict) {
|
|||||||
|
|
||||||
memset(dict, 0, sizeof(DictInfo));
|
memset(dict, 0, sizeof(DictInfo));
|
||||||
SPI_connect();
|
SPI_connect();
|
||||||
if ( !plan_getdict ) {
|
if (!plan_getdict)
|
||||||
|
{
|
||||||
plan_getdict = SPI_saveplan(SPI_prepare("select dict_init, dict_initoption, dict_lexize from pg_ts_dict where oid = $1", 1, arg));
|
plan_getdict = SPI_saveplan(SPI_prepare("select dict_init, dict_initoption, dict_lexize from pg_ts_dict where oid = $1", 1, arg));
|
||||||
if (!plan_getdict)
|
if (!plan_getdict)
|
||||||
ts_error(ERROR, "SPI_prepare() failed");
|
ts_error(ERROR, "SPI_prepare() failed");
|
||||||
@ -39,11 +41,14 @@ init_dict(Oid id, DictInfo *dict) {
|
|||||||
stat = SPI_execp(plan_getdict, pars, " ", 1);
|
stat = SPI_execp(plan_getdict, pars, " ", 1);
|
||||||
if (stat < 0)
|
if (stat < 0)
|
||||||
ts_error(ERROR, "SPI_execp return %d", stat);
|
ts_error(ERROR, "SPI_execp return %d", stat);
|
||||||
if ( SPI_processed > 0 ) {
|
if (SPI_processed > 0)
|
||||||
|
{
|
||||||
Datum opt;
|
Datum opt;
|
||||||
Oid oid = InvalidOid;
|
Oid oid = InvalidOid;
|
||||||
|
|
||||||
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
||||||
if ( !(isnull || oid==InvalidOid) ) {
|
if (!(isnull || oid == InvalidOid))
|
||||||
|
{
|
||||||
opt = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull);
|
opt = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull);
|
||||||
dict->dictionary = (void *) DatumGetPointer(OidFunctionCall1(oid, opt));
|
dict->dictionary = (void *) DatumGetPointer(OidFunctionCall1(oid, opt));
|
||||||
}
|
}
|
||||||
@ -52,12 +57,14 @@ init_dict(Oid id, DictInfo *dict) {
|
|||||||
ts_error(ERROR, "Null dict_lexize for dictonary %d", id);
|
ts_error(ERROR, "Null dict_lexize for dictonary %d", id);
|
||||||
fmgr_info_cxt(oid, &(dict->lexize_info), TopMemoryContext);
|
fmgr_info_cxt(oid, &(dict->lexize_info), TopMemoryContext);
|
||||||
dict->dict_id = id;
|
dict->dict_id = id;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ts_error(ERROR, "No dictionary with id %d", id);
|
ts_error(ERROR, "No dictionary with id %d", id);
|
||||||
SPI_finish();
|
SPI_finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
DictInfo *last_dict;
|
DictInfo *last_dict;
|
||||||
int len;
|
int len;
|
||||||
int reallen;
|
int reallen;
|
||||||
@ -68,7 +75,8 @@ typedef struct {
|
|||||||
static DictList DList = {NULL, 0, 0, NULL, {0, 0, NULL}};
|
static DictList DList = {NULL, 0, 0, NULL, {0, 0, NULL}};
|
||||||
|
|
||||||
void
|
void
|
||||||
reset_dict(void) {
|
reset_dict(void)
|
||||||
|
{
|
||||||
freeSNMap(&(DList.name2id_map));
|
freeSNMap(&(DList.name2id_map));
|
||||||
/* XXX need to free DList.list[*].dictionary */
|
/* XXX need to free DList.list[*].dictionary */
|
||||||
if (DList.list)
|
if (DList.list)
|
||||||
@ -78,20 +86,24 @@ reset_dict(void) {
|
|||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
comparedict(const void *a, const void *b) {
|
comparedict(const void *a, const void *b)
|
||||||
|
{
|
||||||
return ((DictInfo *) a)->dict_id - ((DictInfo *) b)->dict_id;
|
return ((DictInfo *) a)->dict_id - ((DictInfo *) b)->dict_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
DictInfo *
|
DictInfo *
|
||||||
finddict(Oid id) {
|
finddict(Oid id)
|
||||||
|
{
|
||||||
/* last used dict */
|
/* last used dict */
|
||||||
if (DList.last_dict && DList.last_dict->dict_id == id)
|
if (DList.last_dict && DList.last_dict->dict_id == id)
|
||||||
return DList.last_dict;
|
return DList.last_dict;
|
||||||
|
|
||||||
|
|
||||||
/* already used dict */
|
/* already used dict */
|
||||||
if ( DList.len != 0 ) {
|
if (DList.len != 0)
|
||||||
|
{
|
||||||
DictInfo key;
|
DictInfo key;
|
||||||
|
|
||||||
key.dict_id = id;
|
key.dict_id = id;
|
||||||
DList.last_dict = bsearch(&key, DList.list, DList.len, sizeof(DictInfo), comparedict);
|
DList.last_dict = bsearch(&key, DList.list, DList.len, sizeof(DictInfo), comparedict);
|
||||||
if (DList.last_dict != NULL)
|
if (DList.last_dict != NULL)
|
||||||
@ -99,9 +111,11 @@ finddict(Oid id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* last chance */
|
/* last chance */
|
||||||
if ( DList.len==DList.reallen ) {
|
if (DList.len == DList.reallen)
|
||||||
|
{
|
||||||
DictInfo *tmp;
|
DictInfo *tmp;
|
||||||
int reallen = (DList.reallen) ? 2 * DList.reallen : 16;
|
int reallen = (DList.reallen) ? 2 * DList.reallen : 16;
|
||||||
|
|
||||||
tmp = (DictInfo *) realloc(DList.list, sizeof(DictInfo) * reallen);
|
tmp = (DictInfo *) realloc(DList.list, sizeof(DictInfo) * reallen);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
ts_error(ERROR, "No memory");
|
ts_error(ERROR, "No memory");
|
||||||
@ -119,7 +133,8 @@ finddict(Oid id) {
|
|||||||
static void *plan_name2id = NULL;
|
static void *plan_name2id = NULL;
|
||||||
|
|
||||||
Oid
|
Oid
|
||||||
name2id_dict(text *name) {
|
name2id_dict(text *name)
|
||||||
|
{
|
||||||
Oid arg[1] = {TEXTOID};
|
Oid arg[1] = {TEXTOID};
|
||||||
bool isnull;
|
bool isnull;
|
||||||
Datum pars[1] = {PointerGetDatum(name)};
|
Datum pars[1] = {PointerGetDatum(name)};
|
||||||
@ -130,7 +145,8 @@ name2id_dict(text *name) {
|
|||||||
return id;
|
return id;
|
||||||
|
|
||||||
SPI_connect();
|
SPI_connect();
|
||||||
if ( !plan_name2id ) {
|
if (!plan_name2id)
|
||||||
|
{
|
||||||
plan_name2id = SPI_saveplan(SPI_prepare("select oid from pg_ts_dict where dict_name = $1", 1, arg));
|
plan_name2id = SPI_saveplan(SPI_prepare("select oid from pg_ts_dict where dict_name = $1", 1, arg));
|
||||||
if (!plan_name2id)
|
if (!plan_name2id)
|
||||||
ts_error(ERROR, "SPI_prepare() failed");
|
ts_error(ERROR, "SPI_prepare() failed");
|
||||||
@ -154,10 +170,12 @@ PG_FUNCTION_INFO_V1(lexize);
|
|||||||
Datum lexize(PG_FUNCTION_ARGS);
|
Datum lexize(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
lexize(PG_FUNCTION_ARGS) {
|
lexize(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
text *in = PG_GETARG_TEXT_P(1);
|
text *in = PG_GETARG_TEXT_P(1);
|
||||||
DictInfo *dict = finddict(PG_GETARG_OID(0));
|
DictInfo *dict = finddict(PG_GETARG_OID(0));
|
||||||
char **res, **ptr;
|
char **res,
|
||||||
|
**ptr;
|
||||||
Datum *da;
|
Datum *da;
|
||||||
ArrayType *a;
|
ArrayType *a;
|
||||||
|
|
||||||
@ -170,17 +188,20 @@ lexize(PG_FUNCTION_ARGS) {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
PG_FREE_IF_COPY(in, 1);
|
PG_FREE_IF_COPY(in, 1);
|
||||||
if ( !res ) {
|
if (!res)
|
||||||
|
{
|
||||||
if (PG_NARGS() > 2)
|
if (PG_NARGS() > 2)
|
||||||
PG_RETURN_POINTER(NULL);
|
PG_RETURN_POINTER(NULL);
|
||||||
else
|
else
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
}
|
}
|
||||||
|
|
||||||
while(*ptr) ptr++;
|
while (*ptr)
|
||||||
|
ptr++;
|
||||||
da = (Datum *) palloc(sizeof(Datum) * (ptr - res + 1));
|
da = (Datum *) palloc(sizeof(Datum) * (ptr - res + 1));
|
||||||
ptr = res;
|
ptr = res;
|
||||||
while(*ptr) {
|
while (*ptr)
|
||||||
|
{
|
||||||
da[ptr - res] = PointerGetDatum(char2text(*ptr));
|
da[ptr - res] = PointerGetDatum(char2text(*ptr));
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
@ -195,7 +216,8 @@ lexize(PG_FUNCTION_ARGS) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
ptr = res;
|
ptr = res;
|
||||||
while(*ptr) {
|
while (*ptr)
|
||||||
|
{
|
||||||
pfree(DatumGetPointer(da[ptr - res]));
|
pfree(DatumGetPointer(da[ptr - res]));
|
||||||
pfree(*ptr);
|
pfree(*ptr);
|
||||||
ptr++;
|
ptr++;
|
||||||
@ -209,7 +231,8 @@ lexize(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(lexize_byname);
|
PG_FUNCTION_INFO_V1(lexize_byname);
|
||||||
Datum lexize_byname(PG_FUNCTION_ARGS);
|
Datum lexize_byname(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
lexize_byname(PG_FUNCTION_ARGS) {
|
lexize_byname(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
text *dictname = PG_GETARG_TEXT_P(0);
|
text *dictname = PG_GETARG_TEXT_P(0);
|
||||||
Datum res;
|
Datum res;
|
||||||
|
|
||||||
@ -232,7 +255,8 @@ static Oid currect_dictionary_id=0;
|
|||||||
PG_FUNCTION_INFO_V1(set_curdict);
|
PG_FUNCTION_INFO_V1(set_curdict);
|
||||||
Datum set_curdict(PG_FUNCTION_ARGS);
|
Datum set_curdict(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
set_curdict(PG_FUNCTION_ARGS) {
|
set_curdict(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
finddict(PG_GETARG_OID(0));
|
finddict(PG_GETARG_OID(0));
|
||||||
currect_dictionary_id = PG_GETARG_OID(0);
|
currect_dictionary_id = PG_GETARG_OID(0);
|
||||||
PG_RETURN_VOID();
|
PG_RETURN_VOID();
|
||||||
@ -241,7 +265,8 @@ set_curdict(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(set_curdict_byname);
|
PG_FUNCTION_INFO_V1(set_curdict_byname);
|
||||||
Datum set_curdict_byname(PG_FUNCTION_ARGS);
|
Datum set_curdict_byname(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
set_curdict_byname(PG_FUNCTION_ARGS) {
|
set_curdict_byname(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
text *dictname = PG_GETARG_TEXT_P(0);
|
text *dictname = PG_GETARG_TEXT_P(0);
|
||||||
|
|
||||||
DirectFunctionCall1(
|
DirectFunctionCall1(
|
||||||
@ -255,8 +280,10 @@ set_curdict_byname(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(lexize_bycurrent);
|
PG_FUNCTION_INFO_V1(lexize_bycurrent);
|
||||||
Datum lexize_bycurrent(PG_FUNCTION_ARGS);
|
Datum lexize_bycurrent(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
lexize_bycurrent(PG_FUNCTION_ARGS) {
|
lexize_bycurrent(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
Datum res;
|
Datum res;
|
||||||
|
|
||||||
if (currect_dictionary_id == 0)
|
if (currect_dictionary_id == 0)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||||
@ -274,5 +301,3 @@ lexize_bycurrent(PG_FUNCTION_ARGS) {
|
|||||||
else
|
else
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int len;
|
int len;
|
||||||
char **stop;
|
char **stop;
|
||||||
char *(*wordop) (char *);
|
char *(*wordop) (char *);
|
||||||
@ -15,7 +16,8 @@ void readstoplist(text *in, StopList *s);
|
|||||||
bool searchstoplist(StopList * s, char *key);
|
bool searchstoplist(StopList * s, char *key);
|
||||||
char *lowerstr(char *str);
|
char *lowerstr(char *str);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
Oid dict_id;
|
Oid dict_id;
|
||||||
FmgrInfo lexize_info;
|
FmgrInfo lexize_info;
|
||||||
void *dictionary;
|
void *dictionary;
|
||||||
@ -28,7 +30,8 @@ void reset_dict(void);
|
|||||||
|
|
||||||
|
|
||||||
/* simple parser of cfg string */
|
/* simple parser of cfg string */
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
char *key;
|
char *key;
|
||||||
char *value;
|
char *value;
|
||||||
} Map;
|
} Map;
|
||||||
|
@ -11,18 +11,21 @@
|
|||||||
#include "dict.h"
|
#include "dict.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
StopList stoplist;
|
StopList stoplist;
|
||||||
} DictExample;
|
} DictExample;
|
||||||
|
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(dex_init);
|
PG_FUNCTION_INFO_V1(dex_init);
|
||||||
Datum dex_init(PG_FUNCTION_ARGS);
|
Datum dex_init(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(dex_lexize);
|
PG_FUNCTION_INFO_V1(dex_lexize);
|
||||||
Datum dex_lexize(PG_FUNCTION_ARGS);
|
Datum dex_lexize(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
dex_init(PG_FUNCTION_ARGS) {
|
dex_init(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
DictExample *d = (DictExample *) malloc(sizeof(DictExample));
|
DictExample *d = (DictExample *) malloc(sizeof(DictExample));
|
||||||
|
|
||||||
if (!d)
|
if (!d)
|
||||||
@ -33,8 +36,10 @@ dex_init(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
d->stoplist.wordop = lowerstr;
|
d->stoplist.wordop = lowerstr;
|
||||||
|
|
||||||
if ( !PG_ARGISNULL(0) && PG_GETARG_POINTER(0)!=NULL ) {
|
if (!PG_ARGISNULL(0) && PG_GETARG_POINTER(0) != NULL)
|
||||||
|
{
|
||||||
text *in = PG_GETARG_TEXT_P(0);
|
text *in = PG_GETARG_TEXT_P(0);
|
||||||
|
|
||||||
readstoplist(in, &(d->stoplist));
|
readstoplist(in, &(d->stoplist));
|
||||||
sortstoplist(&(d->stoplist));
|
sortstoplist(&(d->stoplist));
|
||||||
PG_FREE_IF_COPY(in, 0);
|
PG_FREE_IF_COPY(in, 0);
|
||||||
@ -44,16 +49,19 @@ dex_init(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
dex_lexize(PG_FUNCTION_ARGS) {
|
dex_lexize(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
DictExample *d = (DictExample *) PG_GETARG_POINTER(0);
|
DictExample *d = (DictExample *) PG_GETARG_POINTER(0);
|
||||||
char *in = (char *) PG_GETARG_POINTER(1);
|
char *in = (char *) PG_GETARG_POINTER(1);
|
||||||
char *txt = pnstrdup(in, PG_GETARG_INT32(2));
|
char *txt = pnstrdup(in, PG_GETARG_INT32(2));
|
||||||
char **res = palloc(sizeof(char *) * 2);
|
char **res = palloc(sizeof(char *) * 2);
|
||||||
|
|
||||||
if ( *txt=='\0' || searchstoplist(&(d->stoplist),txt) ) {
|
if (*txt == '\0' || searchstoplist(&(d->stoplist), txt))
|
||||||
|
{
|
||||||
pfree(txt);
|
pfree(txt);
|
||||||
res[0] = NULL;
|
res[0] = NULL;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
res[0] = txt;
|
res[0] = txt;
|
||||||
res[1] = NULL;
|
res[1] = NULL;
|
||||||
|
|
||||||
|
@ -12,29 +12,36 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "ispell/spell.h"
|
#include "ispell/spell.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
StopList stoplist;
|
StopList stoplist;
|
||||||
IspellDict obj;
|
IspellDict obj;
|
||||||
} DictISpell;
|
} DictISpell;
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(spell_init);
|
PG_FUNCTION_INFO_V1(spell_init);
|
||||||
Datum spell_init(PG_FUNCTION_ARGS);
|
Datum spell_init(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(spell_lexize);
|
PG_FUNCTION_INFO_V1(spell_lexize);
|
||||||
Datum spell_lexize(PG_FUNCTION_ARGS);
|
Datum spell_lexize(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
static void
|
static void
|
||||||
freeDictISpell(DictISpell *d) {
|
freeDictISpell(DictISpell * d)
|
||||||
|
{
|
||||||
FreeIspell(&(d->obj));
|
FreeIspell(&(d->obj));
|
||||||
freestoplist(&(d->stoplist));
|
freestoplist(&(d->stoplist));
|
||||||
free(d);
|
free(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
spell_init(PG_FUNCTION_ARGS) {
|
spell_init(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
DictISpell *d;
|
DictISpell *d;
|
||||||
Map *cfg, *pcfg;
|
Map *cfg,
|
||||||
|
*pcfg;
|
||||||
text *in;
|
text *in;
|
||||||
bool affloaded=false, dictloaded=false, stoploaded=false;
|
bool affloaded = false,
|
||||||
|
dictloaded = false,
|
||||||
|
stoploaded = false;
|
||||||
|
|
||||||
if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
|
if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -53,15 +60,19 @@ spell_init(PG_FUNCTION_ARGS) {
|
|||||||
parse_cfgdict(in, &cfg);
|
parse_cfgdict(in, &cfg);
|
||||||
PG_FREE_IF_COPY(in, 0);
|
PG_FREE_IF_COPY(in, 0);
|
||||||
pcfg = cfg;
|
pcfg = cfg;
|
||||||
while(pcfg->key) {
|
while (pcfg->key)
|
||||||
if ( strcasecmp("DictFile", pcfg->key) == 0 ) {
|
{
|
||||||
if ( dictloaded ) {
|
if (strcasecmp("DictFile", pcfg->key) == 0)
|
||||||
|
{
|
||||||
|
if (dictloaded)
|
||||||
|
{
|
||||||
freeDictISpell(d);
|
freeDictISpell(d);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||||
errmsg("dictionary already loaded")));
|
errmsg("dictionary already loaded")));
|
||||||
}
|
}
|
||||||
if ( ImportDictionary(&(d->obj), pcfg->value) ) {
|
if (ImportDictionary(&(d->obj), pcfg->value))
|
||||||
|
{
|
||||||
freeDictISpell(d);
|
freeDictISpell(d);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||||
@ -69,14 +80,18 @@ spell_init(PG_FUNCTION_ARGS) {
|
|||||||
pcfg->value)));
|
pcfg->value)));
|
||||||
}
|
}
|
||||||
dictloaded = true;
|
dictloaded = true;
|
||||||
} else if ( strcasecmp("AffFile", pcfg->key) == 0 ) {
|
}
|
||||||
if ( affloaded ) {
|
else if (strcasecmp("AffFile", pcfg->key) == 0)
|
||||||
|
{
|
||||||
|
if (affloaded)
|
||||||
|
{
|
||||||
freeDictISpell(d);
|
freeDictISpell(d);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||||
errmsg("affixes already loaded")));
|
errmsg("affixes already loaded")));
|
||||||
}
|
}
|
||||||
if ( ImportAffixes(&(d->obj), pcfg->value) ) {
|
if (ImportAffixes(&(d->obj), pcfg->value))
|
||||||
|
{
|
||||||
freeDictISpell(d);
|
freeDictISpell(d);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||||
@ -84,9 +99,13 @@ spell_init(PG_FUNCTION_ARGS) {
|
|||||||
pcfg->value)));
|
pcfg->value)));
|
||||||
}
|
}
|
||||||
affloaded = true;
|
affloaded = true;
|
||||||
} else if ( strcasecmp("StopFile", pcfg->key) == 0 ) {
|
}
|
||||||
|
else if (strcasecmp("StopFile", pcfg->key) == 0)
|
||||||
|
{
|
||||||
text *tmp = char2text(pcfg->value);
|
text *tmp = char2text(pcfg->value);
|
||||||
if ( stoploaded ) {
|
|
||||||
|
if (stoploaded)
|
||||||
|
{
|
||||||
freeDictISpell(d);
|
freeDictISpell(d);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||||
@ -96,7 +115,9 @@ spell_init(PG_FUNCTION_ARGS) {
|
|||||||
sortstoplist(&(d->stoplist));
|
sortstoplist(&(d->stoplist));
|
||||||
pfree(tmp);
|
pfree(tmp);
|
||||||
stoploaded = true;
|
stoploaded = true;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
freeDictISpell(d);
|
freeDictISpell(d);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
@ -109,15 +130,20 @@ spell_init(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
pfree(cfg);
|
pfree(cfg);
|
||||||
|
|
||||||
if ( affloaded && dictloaded ) {
|
if (affloaded && dictloaded)
|
||||||
|
{
|
||||||
SortDictionary(&(d->obj));
|
SortDictionary(&(d->obj));
|
||||||
SortAffixes(&(d->obj));
|
SortAffixes(&(d->obj));
|
||||||
} else if ( !affloaded ) {
|
}
|
||||||
|
else if (!affloaded)
|
||||||
|
{
|
||||||
freeDictISpell(d);
|
freeDictISpell(d);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||||
errmsg("no affixes")));
|
errmsg("no affixes")));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
freeDictISpell(d);
|
freeDictISpell(d);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||||
@ -128,12 +154,14 @@ spell_init(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
spell_lexize(PG_FUNCTION_ARGS) {
|
spell_lexize(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
DictISpell *d = (DictISpell *) PG_GETARG_POINTER(0);
|
DictISpell *d = (DictISpell *) PG_GETARG_POINTER(0);
|
||||||
char *in = (char *) PG_GETARG_POINTER(1);
|
char *in = (char *) PG_GETARG_POINTER(1);
|
||||||
char *txt;
|
char *txt;
|
||||||
char **res;
|
char **res;
|
||||||
char **ptr, **cptr;
|
char **ptr,
|
||||||
|
**cptr;
|
||||||
|
|
||||||
if (!PG_GETARG_INT32(2))
|
if (!PG_GETARG_INT32(2))
|
||||||
PG_RETURN_POINTER(NULL);
|
PG_RETURN_POINTER(NULL);
|
||||||
@ -147,18 +175,22 @@ spell_lexize(PG_FUNCTION_ARGS) {
|
|||||||
PG_RETURN_POINTER(NULL);
|
PG_RETURN_POINTER(NULL);
|
||||||
|
|
||||||
ptr = cptr = res;
|
ptr = cptr = res;
|
||||||
while(*ptr) {
|
while (*ptr)
|
||||||
if ( searchstoplist(&(d->stoplist),*ptr) ) {
|
{
|
||||||
|
if (searchstoplist(&(d->stoplist), *ptr))
|
||||||
|
{
|
||||||
pfree(*ptr);
|
pfree(*ptr);
|
||||||
*ptr = NULL;
|
*ptr = NULL;
|
||||||
ptr++;
|
ptr++;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
*cptr = *ptr;
|
*cptr = *ptr;
|
||||||
cptr++; ptr++;
|
cptr++;
|
||||||
|
ptr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*cptr = NULL;
|
*cptr = NULL;
|
||||||
|
|
||||||
PG_RETURN_POINTER(res);
|
PG_RETURN_POINTER(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,8 @@
|
|||||||
#include "snowball/english_stem.h"
|
#include "snowball/english_stem.h"
|
||||||
#include "snowball/russian_stem.h"
|
#include "snowball/russian_stem.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
struct SN_env *z;
|
struct SN_env *z;
|
||||||
StopList stoplist;
|
StopList stoplist;
|
||||||
int (*stem) (struct SN_env * z);
|
int (*stem) (struct SN_env * z);
|
||||||
@ -23,13 +24,16 @@ typedef struct {
|
|||||||
|
|
||||||
PG_FUNCTION_INFO_V1(snb_en_init);
|
PG_FUNCTION_INFO_V1(snb_en_init);
|
||||||
Datum snb_en_init(PG_FUNCTION_ARGS);
|
Datum snb_en_init(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(snb_ru_init);
|
PG_FUNCTION_INFO_V1(snb_ru_init);
|
||||||
Datum snb_ru_init(PG_FUNCTION_ARGS);
|
Datum snb_ru_init(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(snb_lexize);
|
PG_FUNCTION_INFO_V1(snb_lexize);
|
||||||
Datum snb_lexize(PG_FUNCTION_ARGS);
|
Datum snb_lexize(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
snb_en_init(PG_FUNCTION_ARGS) {
|
snb_en_init(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
DictSnowball *d = (DictSnowball *) malloc(sizeof(DictSnowball));
|
DictSnowball *d = (DictSnowball *) malloc(sizeof(DictSnowball));
|
||||||
|
|
||||||
if (!d)
|
if (!d)
|
||||||
@ -39,15 +43,18 @@ snb_en_init(PG_FUNCTION_ARGS) {
|
|||||||
memset(d, 0, sizeof(DictSnowball));
|
memset(d, 0, sizeof(DictSnowball));
|
||||||
d->stoplist.wordop = lowerstr;
|
d->stoplist.wordop = lowerstr;
|
||||||
|
|
||||||
if ( !PG_ARGISNULL(0) && PG_GETARG_POINTER(0)!=NULL ) {
|
if (!PG_ARGISNULL(0) && PG_GETARG_POINTER(0) != NULL)
|
||||||
|
{
|
||||||
text *in = PG_GETARG_TEXT_P(0);
|
text *in = PG_GETARG_TEXT_P(0);
|
||||||
|
|
||||||
readstoplist(in, &(d->stoplist));
|
readstoplist(in, &(d->stoplist));
|
||||||
sortstoplist(&(d->stoplist));
|
sortstoplist(&(d->stoplist));
|
||||||
PG_FREE_IF_COPY(in, 0);
|
PG_FREE_IF_COPY(in, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
d->z = english_create_env();
|
d->z = english_create_env();
|
||||||
if (!d->z) {
|
if (!d->z)
|
||||||
|
{
|
||||||
freestoplist(&(d->stoplist));
|
freestoplist(&(d->stoplist));
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||||
@ -59,7 +66,8 @@ snb_en_init(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
snb_ru_init(PG_FUNCTION_ARGS) {
|
snb_ru_init(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
DictSnowball *d = (DictSnowball *) malloc(sizeof(DictSnowball));
|
DictSnowball *d = (DictSnowball *) malloc(sizeof(DictSnowball));
|
||||||
|
|
||||||
if (!d)
|
if (!d)
|
||||||
@ -69,15 +77,18 @@ snb_ru_init(PG_FUNCTION_ARGS) {
|
|||||||
memset(d, 0, sizeof(DictSnowball));
|
memset(d, 0, sizeof(DictSnowball));
|
||||||
d->stoplist.wordop = lowerstr;
|
d->stoplist.wordop = lowerstr;
|
||||||
|
|
||||||
if ( !PG_ARGISNULL(0) && PG_GETARG_POINTER(0)!=NULL ) {
|
if (!PG_ARGISNULL(0) && PG_GETARG_POINTER(0) != NULL)
|
||||||
|
{
|
||||||
text *in = PG_GETARG_TEXT_P(0);
|
text *in = PG_GETARG_TEXT_P(0);
|
||||||
|
|
||||||
readstoplist(in, &(d->stoplist));
|
readstoplist(in, &(d->stoplist));
|
||||||
sortstoplist(&(d->stoplist));
|
sortstoplist(&(d->stoplist));
|
||||||
PG_FREE_IF_COPY(in, 0);
|
PG_FREE_IF_COPY(in, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
d->z = russian_create_env();
|
d->z = russian_create_env();
|
||||||
if (!d->z) {
|
if (!d->z)
|
||||||
|
{
|
||||||
freestoplist(&(d->stoplist));
|
freestoplist(&(d->stoplist));
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||||
@ -89,19 +100,24 @@ snb_ru_init(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
snb_lexize(PG_FUNCTION_ARGS) {
|
snb_lexize(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
DictSnowball *d = (DictSnowball *) PG_GETARG_POINTER(0);
|
DictSnowball *d = (DictSnowball *) PG_GETARG_POINTER(0);
|
||||||
char *in = (char *) PG_GETARG_POINTER(1);
|
char *in = (char *) PG_GETARG_POINTER(1);
|
||||||
char *txt = pnstrdup(in, PG_GETARG_INT32(2));
|
char *txt = pnstrdup(in, PG_GETARG_INT32(2));
|
||||||
char **res = palloc(sizeof(char *) * 2);
|
char **res = palloc(sizeof(char *) * 2);
|
||||||
|
|
||||||
if ( *txt=='\0' || searchstoplist(&(d->stoplist),txt) ) {
|
if (*txt == '\0' || searchstoplist(&(d->stoplist), txt))
|
||||||
|
{
|
||||||
pfree(txt);
|
pfree(txt);
|
||||||
res[0] = NULL;
|
res[0] = NULL;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
SN_set_current(d->z, strlen(txt), txt);
|
SN_set_current(d->z, strlen(txt), txt);
|
||||||
(d->stem) (d->z);
|
(d->stem) (d->z);
|
||||||
if ( d->z->p && d->z->l ) {
|
if (d->z->p && d->z->l)
|
||||||
|
{
|
||||||
txt = repalloc(txt, d->z->l + 1);
|
txt = repalloc(txt, d->z->l + 1);
|
||||||
memcpy(txt, d->z->p, d->z->l);
|
memcpy(txt, d->z->p, d->z->l);
|
||||||
txt[d->z->l] = '\0';
|
txt[d->z->l] = '\0';
|
||||||
@ -113,4 +129,3 @@ snb_lexize(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
PG_RETURN_POINTER(res);
|
PG_RETURN_POINTER(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,23 +13,27 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#define SYNBUFLEN 4096
|
#define SYNBUFLEN 4096
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
char *in;
|
char *in;
|
||||||
char *out;
|
char *out;
|
||||||
} Syn;
|
} Syn;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int len;
|
int len;
|
||||||
Syn *syn;
|
Syn *syn;
|
||||||
} DictSyn;
|
} DictSyn;
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(syn_init);
|
PG_FUNCTION_INFO_V1(syn_init);
|
||||||
Datum syn_init(PG_FUNCTION_ARGS);
|
Datum syn_init(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(syn_lexize);
|
PG_FUNCTION_INFO_V1(syn_lexize);
|
||||||
Datum syn_lexize(PG_FUNCTION_ARGS);
|
Datum syn_lexize(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
findwrd(char *in, char **end) {
|
findwrd(char *in, char **end)
|
||||||
|
{
|
||||||
char *start;
|
char *start;
|
||||||
|
|
||||||
*end = NULL;
|
*end = NULL;
|
||||||
@ -48,20 +52,24 @@ findwrd(char *in, char **end) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
compareSyn(const void *a, const void *b) {
|
compareSyn(const void *a, const void *b)
|
||||||
|
{
|
||||||
return strcmp(((Syn *) a)->in, ((Syn *) b)->in);
|
return strcmp(((Syn *) a)->in, ((Syn *) b)->in);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
syn_init(PG_FUNCTION_ARGS) {
|
syn_init(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
text *in;
|
text *in;
|
||||||
DictSyn *d;
|
DictSyn *d;
|
||||||
int cur = 0;
|
int cur = 0;
|
||||||
FILE *fin;
|
FILE *fin;
|
||||||
char *filename;
|
char *filename;
|
||||||
char buf[SYNBUFLEN];
|
char buf[SYNBUFLEN];
|
||||||
char *starti,*starto,*end=NULL;
|
char *starti,
|
||||||
|
*starto,
|
||||||
|
*end = NULL;
|
||||||
int slen;
|
int slen;
|
||||||
|
|
||||||
if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
|
if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
|
||||||
@ -84,7 +92,8 @@ syn_init(PG_FUNCTION_ARGS) {
|
|||||||
filename)));
|
filename)));
|
||||||
|
|
||||||
d = (DictSyn *) malloc(sizeof(DictSyn));
|
d = (DictSyn *) malloc(sizeof(DictSyn));
|
||||||
if ( !d ) {
|
if (!d)
|
||||||
|
{
|
||||||
fclose(fin);
|
fclose(fin);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||||
@ -92,14 +101,18 @@ syn_init(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
memset(d, 0, sizeof(DictSyn));
|
memset(d, 0, sizeof(DictSyn));
|
||||||
|
|
||||||
while( fgets(buf,SYNBUFLEN,fin) ) {
|
while (fgets(buf, SYNBUFLEN, fin))
|
||||||
|
{
|
||||||
slen = strlen(buf) - 1;
|
slen = strlen(buf) - 1;
|
||||||
buf[slen] = '\0';
|
buf[slen] = '\0';
|
||||||
if ( *buf=='\0' ) continue;
|
if (*buf == '\0')
|
||||||
if (cur==d->len) {
|
continue;
|
||||||
|
if (cur == d->len)
|
||||||
|
{
|
||||||
d->len = (d->len) ? 2 * d->len : 16;
|
d->len = (d->len) ? 2 * d->len : 16;
|
||||||
d->syn = (Syn *) realloc(d->syn, sizeof(Syn) * d->len);
|
d->syn = (Syn *) realloc(d->syn, sizeof(Syn) * d->len);
|
||||||
if ( !d->syn ) {
|
if (!d->syn)
|
||||||
|
{
|
||||||
fclose(fin);
|
fclose(fin);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||||
@ -121,7 +134,8 @@ syn_init(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
d->syn[cur].in = strdup(lowerstr(starti));
|
d->syn[cur].in = strdup(lowerstr(starti));
|
||||||
d->syn[cur].out = strdup(lowerstr(starto));
|
d->syn[cur].out = strdup(lowerstr(starto));
|
||||||
if ( !(d->syn[cur].in && d->syn[cur].out) ) {
|
if (!(d->syn[cur].in && d->syn[cur].out))
|
||||||
|
{
|
||||||
fclose(fin);
|
fclose(fin);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||||
@ -142,10 +156,12 @@ syn_init(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
syn_lexize(PG_FUNCTION_ARGS) {
|
syn_lexize(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
DictSyn *d = (DictSyn *) PG_GETARG_POINTER(0);
|
DictSyn *d = (DictSyn *) PG_GETARG_POINTER(0);
|
||||||
char *in = (char *) PG_GETARG_POINTER(1);
|
char *in = (char *) PG_GETARG_POINTER(1);
|
||||||
Syn key,*found;
|
Syn key,
|
||||||
|
*found;
|
||||||
char **res = NULL;
|
char **res = NULL;
|
||||||
|
|
||||||
if (!PG_GETARG_INT32(2))
|
if (!PG_GETARG_INT32(2))
|
||||||
@ -167,4 +183,3 @@ syn_lexize(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
PG_RETURN_POINTER(res);
|
PG_RETURN_POINTER(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,14 +11,19 @@
|
|||||||
|
|
||||||
#define STRNCASECMP(x,y) (strncasecmp(x,y,strlen(y)))
|
#define STRNCASECMP(x,y) (strncasecmp(x,y,strlen(y)))
|
||||||
|
|
||||||
static int cmpspell(const void *s1,const void *s2){
|
static int
|
||||||
|
cmpspell(const void *s1, const void *s2)
|
||||||
|
{
|
||||||
return (strcmp(((const SPELL *) s1)->word, ((const SPELL *) s2)->word));
|
return (strcmp(((const SPELL *) s1)->word, ((const SPELL *) s2)->word));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
strlower( char * str ) {
|
strlower(char *str)
|
||||||
|
{
|
||||||
unsigned char *ptr = (unsigned char *) str;
|
unsigned char *ptr = (unsigned char *) str;
|
||||||
while ( *ptr ) {
|
|
||||||
|
while (*ptr)
|
||||||
|
{
|
||||||
*ptr = tolower(*ptr);
|
*ptr = tolower(*ptr);
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
@ -26,38 +31,60 @@ strlower( char * str ) {
|
|||||||
|
|
||||||
/* backward string compaire for suffix tree operations */
|
/* backward string compaire for suffix tree operations */
|
||||||
static int
|
static int
|
||||||
strbcmp(const char *s1, const char *s2) {
|
strbcmp(const char *s1, const char *s2)
|
||||||
int l1 = strlen(s1)-1, l2 = strlen(s2)-1;
|
{
|
||||||
while (l1 >= 0 && l2 >= 0) {
|
int l1 = strlen(s1) - 1,
|
||||||
if (s1[l1] < s2[l2]) return -1;
|
l2 = strlen(s2) - 1;
|
||||||
if (s1[l1] > s2[l2]) return 1;
|
|
||||||
l1--; l2--;
|
while (l1 >= 0 && l2 >= 0)
|
||||||
|
{
|
||||||
|
if (s1[l1] < s2[l2])
|
||||||
|
return -1;
|
||||||
|
if (s1[l1] > s2[l2])
|
||||||
|
return 1;
|
||||||
|
l1--;
|
||||||
|
l2--;
|
||||||
}
|
}
|
||||||
if (l1 < l2) return -1;
|
if (l1 < l2)
|
||||||
if (l1 > l2) return 1;
|
return -1;
|
||||||
|
if (l1 > l2)
|
||||||
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
static int
|
static int
|
||||||
strbncmp(const char *s1, const char *s2, size_t count) {
|
strbncmp(const char *s1, const char *s2, size_t count)
|
||||||
int l1 = strlen(s1) - 1, l2 = strlen(s2) - 1, l = count;
|
{
|
||||||
while (l1 >= 0 && l2 >= 0 && l > 0) {
|
int l1 = strlen(s1) - 1,
|
||||||
if (s1[l1] < s2[l2]) return -1;
|
l2 = strlen(s2) - 1,
|
||||||
if (s1[l1] > s2[l2]) return 1;
|
l = count;
|
||||||
|
|
||||||
|
while (l1 >= 0 && l2 >= 0 && l > 0)
|
||||||
|
{
|
||||||
|
if (s1[l1] < s2[l2])
|
||||||
|
return -1;
|
||||||
|
if (s1[l1] > s2[l2])
|
||||||
|
return 1;
|
||||||
l1--;
|
l1--;
|
||||||
l2--;
|
l2--;
|
||||||
l--;
|
l--;
|
||||||
}
|
}
|
||||||
if (l == 0) return 0;
|
if (l == 0)
|
||||||
if (l1 < l2) return -1;
|
return 0;
|
||||||
if (l1 > l2) return 1;
|
if (l1 < l2)
|
||||||
|
return -1;
|
||||||
|
if (l1 > l2)
|
||||||
|
return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cmpaffix(const void *s1,const void *s2){
|
cmpaffix(const void *s1, const void *s2)
|
||||||
if (((const AFFIX*)s1)->type < ((const AFFIX*)s2)->type) return -1;
|
{
|
||||||
if (((const AFFIX*)s1)->type > ((const AFFIX*)s2)->type) return 1;
|
if (((const AFFIX *) s1)->type < ((const AFFIX *) s2)->type)
|
||||||
|
return -1;
|
||||||
|
if (((const AFFIX *) s1)->type > ((const AFFIX *) s2)->type)
|
||||||
|
return 1;
|
||||||
if (((const AFFIX *) s1)->type == 'p')
|
if (((const AFFIX *) s1)->type == 'p')
|
||||||
return (strcmp(((const AFFIX *) s1)->repl, ((const AFFIX *) s2)->repl));
|
return (strcmp(((const AFFIX *) s1)->repl, ((const AFFIX *) s2)->repl));
|
||||||
else
|
else
|
||||||
@ -65,12 +92,17 @@ cmpaffix(const void *s1,const void *s2){
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
AddSpell(IspellDict * Conf,const char * word,const char *flag){
|
AddSpell(IspellDict * Conf, const char *word, const char *flag)
|
||||||
if(Conf->nspell>=Conf->mspell){
|
{
|
||||||
if(Conf->mspell){
|
if (Conf->nspell >= Conf->mspell)
|
||||||
|
{
|
||||||
|
if (Conf->mspell)
|
||||||
|
{
|
||||||
Conf->mspell += 1024 * 20;
|
Conf->mspell += 1024 * 20;
|
||||||
Conf->Spell = (SPELL *) realloc(Conf->Spell, Conf->mspell * sizeof(SPELL));
|
Conf->Spell = (SPELL *) realloc(Conf->Spell, Conf->mspell * sizeof(SPELL));
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Conf->mspell = 1024 * 20;
|
Conf->mspell = 1024 * 20;
|
||||||
Conf->Spell = (SPELL *) malloc(Conf->mspell * sizeof(SPELL));
|
Conf->Spell = (SPELL *) malloc(Conf->mspell * sizeof(SPELL));
|
||||||
}
|
}
|
||||||
@ -91,37 +123,47 @@ AddSpell(IspellDict * Conf,const char * word,const char *flag){
|
|||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
ImportDictionary(IspellDict * Conf,const char *filename){
|
ImportDictionary(IspellDict * Conf, const char *filename)
|
||||||
|
{
|
||||||
unsigned char str[BUFSIZ];
|
unsigned char str[BUFSIZ];
|
||||||
FILE *dict;
|
FILE *dict;
|
||||||
|
|
||||||
if(!(dict=fopen(filename,"r")))return(1);
|
if (!(dict = fopen(filename, "r")))
|
||||||
while(fgets(str,sizeof(str),dict)){
|
return (1);
|
||||||
|
while (fgets(str, sizeof(str), dict))
|
||||||
|
{
|
||||||
unsigned char *s;
|
unsigned char *s;
|
||||||
const unsigned char *flag;
|
const unsigned char *flag;
|
||||||
|
|
||||||
flag = NULL;
|
flag = NULL;
|
||||||
if((s=strchr(str,'/'))){
|
if ((s = strchr(str, '/')))
|
||||||
|
{
|
||||||
*s = 0;
|
*s = 0;
|
||||||
s++;flag=s;
|
s++;
|
||||||
while(*s){
|
flag = s;
|
||||||
|
while (*s)
|
||||||
|
{
|
||||||
if (((*s >= 'A') && (*s <= 'Z')) || ((*s >= 'a') && (*s <= 'z')))
|
if (((*s >= 'A') && (*s <= 'Z')) || ((*s >= 'a') && (*s <= 'z')))
|
||||||
s++;
|
s++;
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
*s = 0;
|
*s = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}else{
|
|
||||||
flag="";
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
flag = "";
|
||||||
strlower(str);
|
strlower(str);
|
||||||
/* Dont load words if first letter is not required */
|
/* Dont load words if first letter is not required */
|
||||||
/* It allows to optimize loading at search time */
|
/* It allows to optimize loading at search time */
|
||||||
s = str;
|
s = str;
|
||||||
while(*s){
|
while (*s)
|
||||||
if(*s=='\r')*s=0;
|
{
|
||||||
if(*s=='\n')*s=0;
|
if (*s == '\r')
|
||||||
|
*s = 0;
|
||||||
|
if (*s == '\n')
|
||||||
|
*s = 0;
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
AddSpell(Conf, str, flag);
|
AddSpell(Conf, str, flag);
|
||||||
@ -132,37 +174,48 @@ ImportDictionary(IspellDict * Conf,const char *filename){
|
|||||||
|
|
||||||
|
|
||||||
static SPELL *
|
static SPELL *
|
||||||
FindWord(IspellDict * Conf, const char *word, int affixflag) {
|
FindWord(IspellDict * Conf, const char *word, int affixflag)
|
||||||
int l,c,r,resc,resl,resr, i;
|
{
|
||||||
|
int l,
|
||||||
|
c,
|
||||||
|
r,
|
||||||
|
resc,
|
||||||
|
resl,
|
||||||
|
resr,
|
||||||
|
i;
|
||||||
|
|
||||||
i = (int) (*word) & 255;
|
i = (int) (*word) & 255;
|
||||||
l = Conf->SpellTree.Left[i];
|
l = Conf->SpellTree.Left[i];
|
||||||
r = Conf->SpellTree.Right[i];
|
r = Conf->SpellTree.Right[i];
|
||||||
if (l == -1) return (NULL);
|
if (l == -1)
|
||||||
while(l<=r){
|
return (NULL);
|
||||||
|
while (l <= r)
|
||||||
|
{
|
||||||
c = (l + r) >> 1;
|
c = (l + r) >> 1;
|
||||||
resc = strcmp(Conf->Spell[c].word, word);
|
resc = strcmp(Conf->Spell[c].word, word);
|
||||||
if ((resc == 0) &&
|
if ((resc == 0) &&
|
||||||
((affixflag == 0) || (strchr(Conf->Spell[c].flag, affixflag) != NULL)) ) {
|
((affixflag == 0) || (strchr(Conf->Spell[c].flag, affixflag) != NULL)))
|
||||||
return (&Conf->Spell[c]);
|
return (&Conf->Spell[c]);
|
||||||
}
|
|
||||||
resl = strcmp(Conf->Spell[l].word, word);
|
resl = strcmp(Conf->Spell[l].word, word);
|
||||||
if ((resl == 0) &&
|
if ((resl == 0) &&
|
||||||
((affixflag == 0) || (strchr(Conf->Spell[l].flag, affixflag) != NULL)) ) {
|
((affixflag == 0) || (strchr(Conf->Spell[l].flag, affixflag) != NULL)))
|
||||||
return (&Conf->Spell[l]);
|
return (&Conf->Spell[l]);
|
||||||
}
|
|
||||||
resr = strcmp(Conf->Spell[r].word, word);
|
resr = strcmp(Conf->Spell[r].word, word);
|
||||||
if ((resr == 0) &&
|
if ((resr == 0) &&
|
||||||
((affixflag == 0) || (strchr(Conf->Spell[r].flag, affixflag) != NULL)) ) {
|
((affixflag == 0) || (strchr(Conf->Spell[r].flag, affixflag) != NULL)))
|
||||||
return (&Conf->Spell[r]);
|
return (&Conf->Spell[r]);
|
||||||
}
|
if (resc < 0)
|
||||||
if(resc < 0){
|
{
|
||||||
l = c + 1;
|
l = c + 1;
|
||||||
r--;
|
r--;
|
||||||
} else if(resc > 0){
|
}
|
||||||
|
else if (resc > 0)
|
||||||
|
{
|
||||||
r = c - 1;
|
r = c - 1;
|
||||||
l++;
|
l++;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
l++;
|
l++;
|
||||||
r--;
|
r--;
|
||||||
}
|
}
|
||||||
@ -171,12 +224,17 @@ FindWord(IspellDict * Conf, const char *word, int affixflag) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
AddAffix(IspellDict * Conf,int flag,const char *mask,const char *find,const char *repl,int type) {
|
AddAffix(IspellDict * Conf, int flag, const char *mask, const char *find, const char *repl, int type)
|
||||||
if(Conf->naffixes>=Conf->maffixes){
|
{
|
||||||
if(Conf->maffixes){
|
if (Conf->naffixes >= Conf->maffixes)
|
||||||
|
{
|
||||||
|
if (Conf->maffixes)
|
||||||
|
{
|
||||||
Conf->maffixes += 16;
|
Conf->maffixes += 16;
|
||||||
Conf->Affix = (AFFIX *) realloc((void *) Conf->Affix, Conf->maffixes * sizeof(AFFIX));
|
Conf->Affix = (AFFIX *) realloc((void *) Conf->Affix, Conf->maffixes * sizeof(AFFIX));
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Conf->maffixes = 16;
|
Conf->maffixes = 16;
|
||||||
Conf->Affix = (AFFIX *) malloc(Conf->maffixes * sizeof(AFFIX));
|
Conf->Affix = (AFFIX *) malloc(Conf->maffixes * sizeof(AFFIX));
|
||||||
}
|
}
|
||||||
@ -185,11 +243,10 @@ AddAffix(IspellDict * Conf,int flag,const char *mask,const char *find,const char
|
|||||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||||
errmsg("out of memory")));
|
errmsg("out of memory")));
|
||||||
}
|
}
|
||||||
if (type=='s') {
|
if (type == 's')
|
||||||
sprintf(Conf->Affix[Conf->naffixes].mask, "%s$", mask);
|
sprintf(Conf->Affix[Conf->naffixes].mask, "%s$", mask);
|
||||||
} else {
|
else
|
||||||
sprintf(Conf->Affix[Conf->naffixes].mask, "^%s", mask);
|
sprintf(Conf->Affix[Conf->naffixes].mask, "^%s", mask);
|
||||||
}
|
|
||||||
Conf->Affix[Conf->naffixes].compile = 1;
|
Conf->Affix[Conf->naffixes].compile = 1;
|
||||||
Conf->Affix[Conf->naffixes].flag = flag;
|
Conf->Affix[Conf->naffixes].flag = flag;
|
||||||
Conf->Affix[Conf->naffixes].type = type;
|
Conf->Affix[Conf->naffixes].type = type;
|
||||||
@ -202,12 +259,17 @@ AddAffix(IspellDict * Conf,int flag,const char *mask,const char *find,const char
|
|||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
remove_spaces(char *dist,char *src){
|
remove_spaces(char *dist, char *src)
|
||||||
char *d,*s;
|
{
|
||||||
|
char *d,
|
||||||
|
*s;
|
||||||
|
|
||||||
d = dist;
|
d = dist;
|
||||||
s = src;
|
s = src;
|
||||||
while(*s){
|
while (*s)
|
||||||
if(*s!=' '&&*s!='-'&&*s!='\t'){
|
{
|
||||||
|
if (*s != ' ' && *s != '-' && *s != '\t')
|
||||||
|
{
|
||||||
*d = *s;
|
*d = *s;
|
||||||
d++;
|
d++;
|
||||||
}
|
}
|
||||||
@ -219,7 +281,8 @@ char *d,*s;
|
|||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
ImportAffixes(IspellDict * Conf,const char *filename){
|
ImportAffixes(IspellDict * Conf, const char *filename)
|
||||||
|
{
|
||||||
unsigned char str[BUFSIZ];
|
unsigned char str[BUFSIZ];
|
||||||
unsigned char flag = 0;
|
unsigned char flag = 0;
|
||||||
unsigned char mask[BUFSIZ] = "";
|
unsigned char mask[BUFSIZ] = "";
|
||||||
@ -234,40 +297,52 @@ ImportAffixes(IspellDict * Conf,const char *filename){
|
|||||||
if (!(affix = fopen(filename, "r")))
|
if (!(affix = fopen(filename, "r")))
|
||||||
return (1);
|
return (1);
|
||||||
|
|
||||||
while(fgets(str,sizeof(str),affix)){
|
while (fgets(str, sizeof(str), affix))
|
||||||
if(!STRNCASECMP(str,"suffixes")){
|
{
|
||||||
|
if (!STRNCASECMP(str, "suffixes"))
|
||||||
|
{
|
||||||
suffixes = 1;
|
suffixes = 1;
|
||||||
prefixes = 0;
|
prefixes = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(!STRNCASECMP(str,"prefixes")){
|
if (!STRNCASECMP(str, "prefixes"))
|
||||||
|
{
|
||||||
suffixes = 0;
|
suffixes = 0;
|
||||||
prefixes = 1;
|
prefixes = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(!STRNCASECMP(str,"flag ")){
|
if (!STRNCASECMP(str, "flag "))
|
||||||
|
{
|
||||||
s = str + 5;
|
s = str + 5;
|
||||||
while (strchr("* ", *s))
|
while (strchr("* ", *s))
|
||||||
s++;
|
s++;
|
||||||
flag = *s;
|
flag = *s;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if((!suffixes)&&(!prefixes))continue;
|
if ((!suffixes) && (!prefixes))
|
||||||
if((s=strchr(str,'#')))*s=0;
|
continue;
|
||||||
if(!*str)continue;
|
if ((s = strchr(str, '#')))
|
||||||
|
*s = 0;
|
||||||
|
if (!*str)
|
||||||
|
continue;
|
||||||
strlower(str);
|
strlower(str);
|
||||||
strcpy(mask, "");
|
strcpy(mask, "");
|
||||||
strcpy(find, "");
|
strcpy(find, "");
|
||||||
strcpy(repl, "");
|
strcpy(repl, "");
|
||||||
i = sscanf(str, "%[^>\n]>%[^,\n],%[^\n]", mask, find, repl);
|
i = sscanf(str, "%[^>\n]>%[^,\n],%[^\n]", mask, find, repl);
|
||||||
remove_spaces(str,repl);strcpy(repl,str);
|
remove_spaces(str, repl);
|
||||||
remove_spaces(str,find);strcpy(find,str);
|
strcpy(repl, str);
|
||||||
remove_spaces(str,mask);strcpy(mask,str);
|
remove_spaces(str, find);
|
||||||
switch(i){
|
strcpy(find, str);
|
||||||
|
remove_spaces(str, mask);
|
||||||
|
strcpy(mask, str);
|
||||||
|
switch (i)
|
||||||
|
{
|
||||||
case 3:
|
case 3:
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if(*find != '\0'){
|
if (*find != '\0')
|
||||||
|
{
|
||||||
strcpy(repl, find);
|
strcpy(repl, find);
|
||||||
strcpy(find, "");
|
strcpy(find, "");
|
||||||
}
|
}
|
||||||
@ -285,17 +360,22 @@ ImportAffixes(IspellDict * Conf,const char *filename){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SortDictionary(IspellDict * Conf){
|
SortDictionary(IspellDict * Conf)
|
||||||
int CurLet = -1, Let;size_t i;
|
{
|
||||||
|
int CurLet = -1,
|
||||||
|
Let;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
qsort((void *) Conf->Spell, Conf->nspell, sizeof(SPELL), cmpspell);
|
qsort((void *) Conf->Spell, Conf->nspell, sizeof(SPELL), cmpspell);
|
||||||
|
|
||||||
for (i = 0; i < 256; i++)
|
for (i = 0; i < 256; i++)
|
||||||
Conf->SpellTree.Left[i] = -1;
|
Conf->SpellTree.Left[i] = -1;
|
||||||
|
|
||||||
for(i = 0; i < Conf->nspell; i++) {
|
for (i = 0; i < Conf->nspell; i++)
|
||||||
|
{
|
||||||
Let = (int) (*(Conf->Spell[i].word)) & 255;
|
Let = (int) (*(Conf->Spell[i].word)) & 255;
|
||||||
if (CurLet != Let) {
|
if (CurLet != Let)
|
||||||
|
{
|
||||||
Conf->SpellTree.Left[Let] = i;
|
Conf->SpellTree.Left[Let] = i;
|
||||||
CurLet = Let;
|
CurLet = Let;
|
||||||
}
|
}
|
||||||
@ -304,29 +384,40 @@ SortDictionary(IspellDict * Conf){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
SortAffixes(IspellDict * Conf) {
|
SortAffixes(IspellDict * Conf)
|
||||||
int CurLetP = -1, CurLetS = -1, Let;
|
{
|
||||||
AFFIX *Affix; size_t i;
|
int CurLetP = -1,
|
||||||
|
CurLetS = -1,
|
||||||
|
Let;
|
||||||
|
AFFIX *Affix;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
if (Conf->naffixes > 1)
|
if (Conf->naffixes > 1)
|
||||||
qsort((void *) Conf->Affix, Conf->naffixes, sizeof(AFFIX), cmpaffix);
|
qsort((void *) Conf->Affix, Conf->naffixes, sizeof(AFFIX), cmpaffix);
|
||||||
for(i = 0; i < 256; i++) {
|
for (i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
Conf->PrefixTree.Left[i] = Conf->PrefixTree.Right[i] = -1;
|
Conf->PrefixTree.Left[i] = Conf->PrefixTree.Right[i] = -1;
|
||||||
Conf->SuffixTree.Left[i] = Conf->SuffixTree.Right[i] = -1;
|
Conf->SuffixTree.Left[i] = Conf->SuffixTree.Right[i] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i = 0; i < Conf->naffixes; i++) {
|
for (i = 0; i < Conf->naffixes; i++)
|
||||||
|
{
|
||||||
Affix = &(((AFFIX *) Conf->Affix)[i]);
|
Affix = &(((AFFIX *) Conf->Affix)[i]);
|
||||||
if(Affix->type == 'p') {
|
if (Affix->type == 'p')
|
||||||
|
{
|
||||||
Let = (int) (*(Affix->repl)) & 255;
|
Let = (int) (*(Affix->repl)) & 255;
|
||||||
if (CurLetP != Let) {
|
if (CurLetP != Let)
|
||||||
|
{
|
||||||
Conf->PrefixTree.Left[Let] = i;
|
Conf->PrefixTree.Left[Let] = i;
|
||||||
CurLetP = Let;
|
CurLetP = Let;
|
||||||
}
|
}
|
||||||
Conf->PrefixTree.Right[Let] = i;
|
Conf->PrefixTree.Right[Let] = i;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Let = (Affix->replen) ? (int) (Affix->repl[Affix->replen - 1]) & 255 : 0;
|
Let = (Affix->replen) ? (int) (Affix->repl[Affix->replen - 1]) & 255 : 0;
|
||||||
if (CurLetS != Let) {
|
if (CurLetS != Let)
|
||||||
|
{
|
||||||
Conf->SuffixTree.Left[Let] = i;
|
Conf->SuffixTree.Left[Let] = i;
|
||||||
CurLetS = Let;
|
CurLetS = Let;
|
||||||
}
|
}
|
||||||
@ -336,31 +427,33 @@ SortAffixes(IspellDict * Conf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
CheckSuffix(const char *word, size_t len, AFFIX *Affix, int *res, IspellDict *Conf) {
|
CheckSuffix(const char *word, size_t len, AFFIX * Affix, int *res, IspellDict * Conf)
|
||||||
|
{
|
||||||
regmatch_t subs[2]; /* workaround for apache&linux */
|
regmatch_t subs[2]; /* workaround for apache&linux */
|
||||||
char newword[2 * MAXNORMLEN] = "";
|
char newword[2 * MAXNORMLEN] = "";
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
*res = strbncmp(word, Affix->repl, Affix->replen);
|
*res = strbncmp(word, Affix->repl, Affix->replen);
|
||||||
if (*res < 0) {
|
if (*res < 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
if (*res > 0)
|
||||||
if (*res > 0) {
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
strcpy(newword, word);
|
strcpy(newword, word);
|
||||||
strcpy(newword + len - Affix->replen, Affix->find);
|
strcpy(newword + len - Affix->replen, Affix->find);
|
||||||
|
|
||||||
if (Affix->compile) {
|
if (Affix->compile)
|
||||||
|
{
|
||||||
err = regcomp(&(Affix->reg), Affix->mask, REG_EXTENDED | REG_ICASE | REG_NOSUB);
|
err = regcomp(&(Affix->reg), Affix->mask, REG_EXTENDED | REG_ICASE | REG_NOSUB);
|
||||||
if(err){
|
if (err)
|
||||||
|
{
|
||||||
/* regerror(err, &(Affix->reg), regerrstr, ERRSTRSIZE); */
|
/* regerror(err, &(Affix->reg), regerrstr, ERRSTRSIZE); */
|
||||||
regfree(&(Affix->reg));
|
regfree(&(Affix->reg));
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
Affix->compile = 0;
|
Affix->compile = 0;
|
||||||
}
|
}
|
||||||
if(!(err=regexec(&(Affix->reg),newword,1,subs,0))){
|
if (!(err = regexec(&(Affix->reg), newword, 1, subs, 0)))
|
||||||
|
{
|
||||||
if (FindWord(Conf, newword, Affix->flag))
|
if (FindWord(Conf, newword, Affix->flag))
|
||||||
return pstrdup(newword);
|
return pstrdup(newword);
|
||||||
}
|
}
|
||||||
@ -371,44 +464,56 @@ CheckSuffix(const char *word, size_t len, AFFIX *Affix, int *res, IspellDict *Co
|
|||||||
#define MAX_NORM 512
|
#define MAX_NORM 512
|
||||||
static int
|
static int
|
||||||
CheckPrefix(const char *word, size_t len, AFFIX * Affix, IspellDict * Conf, int pi,
|
CheckPrefix(const char *word, size_t len, AFFIX * Affix, IspellDict * Conf, int pi,
|
||||||
char **forms, char ***cur ) {
|
char **forms, char ***cur)
|
||||||
|
{
|
||||||
regmatch_t subs[NS * 2];
|
regmatch_t subs[NS * 2];
|
||||||
char newword[2 * MAXNORMLEN] = "";
|
char newword[2 * MAXNORMLEN] = "";
|
||||||
int err, ls, res, lres;
|
int err,
|
||||||
|
ls,
|
||||||
|
res,
|
||||||
|
lres;
|
||||||
size_t newlen;
|
size_t newlen;
|
||||||
AFFIX *CAffix = Conf->Affix;
|
AFFIX *CAffix = Conf->Affix;
|
||||||
|
|
||||||
res = strncmp(word, Affix->repl, Affix->replen);
|
res = strncmp(word, Affix->repl, Affix->replen);
|
||||||
if (res != 0) {
|
if (res != 0)
|
||||||
return res;
|
return res;
|
||||||
}
|
|
||||||
strcpy(newword, Affix->find);
|
strcpy(newword, Affix->find);
|
||||||
strcat(newword, word + Affix->replen);
|
strcat(newword, word + Affix->replen);
|
||||||
|
|
||||||
if (Affix->compile) {
|
if (Affix->compile)
|
||||||
|
{
|
||||||
err = regcomp(&(Affix->reg), Affix->mask, REG_EXTENDED | REG_ICASE | REG_NOSUB);
|
err = regcomp(&(Affix->reg), Affix->mask, REG_EXTENDED | REG_ICASE | REG_NOSUB);
|
||||||
if(err){
|
if (err)
|
||||||
|
{
|
||||||
/* regerror(err, &(Affix->reg), regerrstr, ERRSTRSIZE); */
|
/* regerror(err, &(Affix->reg), regerrstr, ERRSTRSIZE); */
|
||||||
regfree(&(Affix->reg));
|
regfree(&(Affix->reg));
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
Affix->compile = 0;
|
Affix->compile = 0;
|
||||||
}
|
}
|
||||||
if(!(err=regexec(&(Affix->reg),newword,1,subs,0))){
|
if (!(err = regexec(&(Affix->reg), newword, 1, subs, 0)))
|
||||||
|
{
|
||||||
SPELL *curspell;
|
SPELL *curspell;
|
||||||
|
|
||||||
if((curspell=FindWord(Conf, newword, Affix->flag))){
|
if ((curspell = FindWord(Conf, newword, Affix->flag)))
|
||||||
if ((*cur - forms) < (MAX_NORM-1)) {
|
{
|
||||||
|
if ((*cur - forms) < (MAX_NORM - 1))
|
||||||
|
{
|
||||||
**cur = pstrdup(newword);
|
**cur = pstrdup(newword);
|
||||||
(*cur)++; **cur = NULL;
|
(*cur)++;
|
||||||
|
**cur = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
newlen = strlen(newword);
|
newlen = strlen(newword);
|
||||||
ls = Conf->SuffixTree.Left[pi];
|
ls = Conf->SuffixTree.Left[pi];
|
||||||
if ( ls>=0 && ((*cur - forms) < (MAX_NORM-1)) ) {
|
if (ls >= 0 && ((*cur - forms) < (MAX_NORM - 1)))
|
||||||
|
{
|
||||||
**cur = CheckSuffix(newword, newlen, &CAffix[ls], &lres, Conf);
|
**cur = CheckSuffix(newword, newlen, &CAffix[ls], &lres, Conf);
|
||||||
if (**cur) {
|
if (**cur)
|
||||||
(*cur)++; **cur = NULL;
|
{
|
||||||
|
(*cur)++;
|
||||||
|
**cur = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -417,14 +522,24 @@ CheckPrefix(const char *word, size_t len, AFFIX *Affix, IspellDict *Conf, int pi
|
|||||||
|
|
||||||
|
|
||||||
char **
|
char **
|
||||||
NormalizeWord(IspellDict * Conf,char *word){
|
NormalizeWord(IspellDict * Conf, char *word)
|
||||||
|
{
|
||||||
/*regmatch_t subs[NS];*/
|
/*regmatch_t subs[NS];*/
|
||||||
size_t len;
|
size_t len;
|
||||||
char **forms;
|
char **forms;
|
||||||
char **cur;
|
char **cur;
|
||||||
AFFIX *Affix;
|
AFFIX *Affix;
|
||||||
int ri, pi, ipi, lp, rp, cp, ls, rs;
|
int ri,
|
||||||
int lres, rres, cres = 0;
|
pi,
|
||||||
|
ipi,
|
||||||
|
lp,
|
||||||
|
rp,
|
||||||
|
cp,
|
||||||
|
ls,
|
||||||
|
rs;
|
||||||
|
int lres,
|
||||||
|
rres,
|
||||||
|
cres = 0;
|
||||||
SPELL *spell;
|
SPELL *spell;
|
||||||
|
|
||||||
len = strlen(word);
|
len = strlen(word);
|
||||||
@ -434,44 +549,51 @@ int lres, rres, cres = 0;
|
|||||||
strlower(word);
|
strlower(word);
|
||||||
|
|
||||||
forms = (char **) palloc(MAX_NORM * sizeof(char **));
|
forms = (char **) palloc(MAX_NORM * sizeof(char **));
|
||||||
cur=forms;*cur=NULL;
|
cur = forms;
|
||||||
|
*cur = NULL;
|
||||||
|
|
||||||
ri = (int) (*word) & 255;
|
ri = (int) (*word) & 255;
|
||||||
pi = (int) (word[strlen(word) - 1]) & 255;
|
pi = (int) (word[strlen(word) - 1]) & 255;
|
||||||
Affix = (AFFIX *) Conf->Affix;
|
Affix = (AFFIX *) Conf->Affix;
|
||||||
|
|
||||||
/* Check that the word itself is normal form */
|
/* Check that the word itself is normal form */
|
||||||
if((spell = FindWord(Conf, word, 0))){
|
if ((spell = FindWord(Conf, word, 0)))
|
||||||
|
{
|
||||||
*cur = pstrdup(word);
|
*cur = pstrdup(word);
|
||||||
cur++;*cur=NULL;
|
cur++;
|
||||||
|
*cur = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find all other NORMAL forms of the 'word' */
|
/* Find all other NORMAL forms of the 'word' */
|
||||||
|
|
||||||
for (ipi = 0; ipi <= pi; ipi += pi) {
|
for (ipi = 0; ipi <= pi; ipi += pi)
|
||||||
|
{
|
||||||
|
|
||||||
/* check prefix */
|
/* check prefix */
|
||||||
lp = Conf->PrefixTree.Left[ri];
|
lp = Conf->PrefixTree.Left[ri];
|
||||||
rp = Conf->PrefixTree.Right[ri];
|
rp = Conf->PrefixTree.Right[ri];
|
||||||
while (lp >= 0 && lp <= rp) {
|
while (lp >= 0 && lp <= rp)
|
||||||
|
{
|
||||||
cp = (lp + rp) >> 1;
|
cp = (lp + rp) >> 1;
|
||||||
cres = 0;
|
cres = 0;
|
||||||
if ((cur - forms) < (MAX_NORM-1)) {
|
if ((cur - forms) < (MAX_NORM - 1))
|
||||||
cres = CheckPrefix(word, len, &Affix[cp], Conf, ipi, forms, &cur);
|
cres = CheckPrefix(word, len, &Affix[cp], Conf, ipi, forms, &cur);
|
||||||
}
|
if ((lp < cp) && ((cur - forms) < (MAX_NORM - 1)))
|
||||||
if ((lp < cp) && ((cur - forms) < (MAX_NORM-1)) ) {
|
|
||||||
lres = CheckPrefix(word, len, &Affix[lp], Conf, ipi, forms, &cur);
|
lres = CheckPrefix(word, len, &Affix[lp], Conf, ipi, forms, &cur);
|
||||||
}
|
if ((rp > cp) && ((cur - forms) < (MAX_NORM - 1)))
|
||||||
if ( (rp > cp) && ((cur - forms) < (MAX_NORM-1)) ) {
|
|
||||||
rres = CheckPrefix(word, len, &Affix[rp], Conf, ipi, forms, &cur);
|
rres = CheckPrefix(word, len, &Affix[rp], Conf, ipi, forms, &cur);
|
||||||
}
|
if (cres < 0)
|
||||||
if (cres < 0) {
|
{
|
||||||
rp = cp - 1;
|
rp = cp - 1;
|
||||||
lp++;
|
lp++;
|
||||||
} else if (cres > 0) {
|
}
|
||||||
|
else if (cres > 0)
|
||||||
|
{
|
||||||
lp = cp + 1;
|
lp = cp + 1;
|
||||||
rp--;
|
rp--;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
lp++;
|
lp++;
|
||||||
rp--;
|
rp--;
|
||||||
}
|
}
|
||||||
@ -480,17 +602,24 @@ int lres, rres, cres = 0;
|
|||||||
/* check suffix */
|
/* check suffix */
|
||||||
ls = Conf->SuffixTree.Left[ipi];
|
ls = Conf->SuffixTree.Left[ipi];
|
||||||
rs = Conf->SuffixTree.Right[ipi];
|
rs = Conf->SuffixTree.Right[ipi];
|
||||||
while (ls >= 0 && ls <= rs) {
|
while (ls >= 0 && ls <= rs)
|
||||||
if ( ((cur - forms) < (MAX_NORM-1)) ) {
|
{
|
||||||
|
if (((cur - forms) < (MAX_NORM - 1)))
|
||||||
|
{
|
||||||
*cur = CheckSuffix(word, len, &Affix[ls], &lres, Conf);
|
*cur = CheckSuffix(word, len, &Affix[ls], &lres, Conf);
|
||||||
if (*cur) {
|
if (*cur)
|
||||||
cur++; *cur = NULL;
|
{
|
||||||
|
cur++;
|
||||||
|
*cur = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( (rs > ls) && ((cur - forms) < (MAX_NORM-1)) ) {
|
if ((rs > ls) && ((cur - forms) < (MAX_NORM - 1)))
|
||||||
|
{
|
||||||
*cur = CheckSuffix(word, len, &Affix[rs], &rres, Conf);
|
*cur = CheckSuffix(word, len, &Affix[rs], &rres, Conf);
|
||||||
if (*cur) {
|
if (*cur)
|
||||||
cur++; *cur = NULL;
|
{
|
||||||
|
cur++;
|
||||||
|
*cur = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ls++;
|
ls++;
|
||||||
@ -499,7 +628,8 @@ int lres, rres, cres = 0;
|
|||||||
|
|
||||||
} /* for ipi */
|
} /* for ipi */
|
||||||
|
|
||||||
if(cur==forms){
|
if (cur == forms)
|
||||||
|
{
|
||||||
pfree(forms);
|
pfree(forms);
|
||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
@ -507,18 +637,18 @@ int lres, rres, cres = 0;
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
FreeIspell (IspellDict *Conf) {
|
FreeIspell(IspellDict * Conf)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
AFFIX *Affix = (AFFIX *) Conf->Affix;
|
AFFIX *Affix = (AFFIX *) Conf->Affix;
|
||||||
|
|
||||||
for (i = 0; i < Conf->naffixes; i++) {
|
for (i = 0; i < Conf->naffixes; i++)
|
||||||
if (Affix[i].compile == 0) {
|
{
|
||||||
|
if (Affix[i].compile == 0)
|
||||||
regfree(&(Affix[i].reg));
|
regfree(&(Affix[i].reg));
|
||||||
}
|
}
|
||||||
}
|
for (i = 0; i < Conf->naffixes; i++)
|
||||||
for (i = 0; i < Conf->naffixes; i++) {
|
|
||||||
free(Conf->Spell[i].word);
|
free(Conf->Spell[i].word);
|
||||||
}
|
|
||||||
free(Conf->Affix);
|
free(Conf->Affix);
|
||||||
free(Conf->Spell);
|
free(Conf->Spell);
|
||||||
memset((void *) Conf, 0, sizeof(IspellDict));
|
memset((void *) Conf, 0, sizeof(IspellDict));
|
||||||
|
@ -4,12 +4,14 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
|
|
||||||
typedef struct spell_struct {
|
typedef struct spell_struct
|
||||||
|
{
|
||||||
char *word;
|
char *word;
|
||||||
char flag[10];
|
char flag[10];
|
||||||
} SPELL;
|
} SPELL;
|
||||||
|
|
||||||
typedef struct aff_struct {
|
typedef struct aff_struct
|
||||||
|
{
|
||||||
char flag;
|
char flag;
|
||||||
char type;
|
char type;
|
||||||
char mask[33];
|
char mask[33];
|
||||||
@ -20,11 +22,14 @@ typedef struct aff_struct {
|
|||||||
char compile;
|
char compile;
|
||||||
} AFFIX;
|
} AFFIX;
|
||||||
|
|
||||||
typedef struct Tree_struct {
|
typedef struct Tree_struct
|
||||||
int Left[256], Right[256];
|
{
|
||||||
|
int Left[256],
|
||||||
|
Right[256];
|
||||||
} Tree_struct;
|
} Tree_struct;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int maffixes;
|
int maffixes;
|
||||||
int naffixes;
|
int naffixes;
|
||||||
AFFIX *Affix;
|
AFFIX *Affix;
|
||||||
|
@ -22,15 +22,21 @@
|
|||||||
#define CS_IN2ESC 8
|
#define CS_IN2ESC 8
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
nstrdup(char *ptr, int len) {
|
nstrdup(char *ptr, int len)
|
||||||
char *res=palloc(len+1), *cptr;
|
{
|
||||||
|
char *res = palloc(len + 1),
|
||||||
|
*cptr;
|
||||||
|
|
||||||
memcpy(res, ptr, len);
|
memcpy(res, ptr, len);
|
||||||
res[len] = '\0';
|
res[len] = '\0';
|
||||||
cptr = ptr = res;
|
cptr = ptr = res;
|
||||||
while(*ptr) {
|
while (*ptr)
|
||||||
|
{
|
||||||
if (*ptr == '\\')
|
if (*ptr == '\\')
|
||||||
ptr++;
|
ptr++;
|
||||||
*cptr=*ptr; ptr++; cptr++;
|
*cptr = *ptr;
|
||||||
|
ptr++;
|
||||||
|
cptr++;
|
||||||
}
|
}
|
||||||
*cptr = '\0';
|
*cptr = '\0';
|
||||||
|
|
||||||
@ -38,45 +44,61 @@ nstrdup(char *ptr, int len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
parse_cfgdict(text *in, Map **m) {
|
parse_cfgdict(text *in, Map ** m)
|
||||||
|
{
|
||||||
Map *mptr;
|
Map *mptr;
|
||||||
char *ptr=VARDATA(in), *begin=NULL;
|
char *ptr = VARDATA(in),
|
||||||
|
*begin = NULL;
|
||||||
char num = 0;
|
char num = 0;
|
||||||
int state = CS_WAITKEY;
|
int state = CS_WAITKEY;
|
||||||
|
|
||||||
while( ptr-VARDATA(in) < VARSIZE(in) - VARHDRSZ ) {
|
while (ptr - VARDATA(in) < VARSIZE(in) - VARHDRSZ)
|
||||||
if ( *ptr==',' ) num++;
|
{
|
||||||
|
if (*ptr == ',')
|
||||||
|
num++;
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*m = mptr = (Map *) palloc(sizeof(Map) * (num + 2));
|
*m = mptr = (Map *) palloc(sizeof(Map) * (num + 2));
|
||||||
memset(mptr, 0, sizeof(Map) * (num + 2));
|
memset(mptr, 0, sizeof(Map) * (num + 2));
|
||||||
ptr = VARDATA(in);
|
ptr = VARDATA(in);
|
||||||
while( ptr-VARDATA(in) < VARSIZE(in) - VARHDRSZ ) {
|
while (ptr - VARDATA(in) < VARSIZE(in) - VARHDRSZ)
|
||||||
if (state==CS_WAITKEY) {
|
{
|
||||||
if (isalpha(*ptr)) {
|
if (state == CS_WAITKEY)
|
||||||
|
{
|
||||||
|
if (isalpha(*ptr))
|
||||||
|
{
|
||||||
begin = ptr;
|
begin = ptr;
|
||||||
state = CS_INKEY;
|
state = CS_INKEY;
|
||||||
} else if ( !isspace(*ptr) )
|
}
|
||||||
|
else if (!isspace(*ptr))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("syntax error"),
|
errmsg("syntax error"),
|
||||||
errdetail("Syntax error in position %d near \"%c\"",
|
errdetail("Syntax error in position %d near \"%c\"",
|
||||||
(int) (ptr - VARDATA(in)), *ptr)));
|
(int) (ptr - VARDATA(in)), *ptr)));
|
||||||
} else if (state==CS_INKEY) {
|
}
|
||||||
if ( isspace(*ptr) ) {
|
else if (state == CS_INKEY)
|
||||||
|
{
|
||||||
|
if (isspace(*ptr))
|
||||||
|
{
|
||||||
mptr->key = nstrdup(begin, ptr - begin);
|
mptr->key = nstrdup(begin, ptr - begin);
|
||||||
state = CS_WAITEQ;
|
state = CS_WAITEQ;
|
||||||
} else if ( *ptr=='=' ) {
|
}
|
||||||
|
else if (*ptr == '=')
|
||||||
|
{
|
||||||
mptr->key = nstrdup(begin, ptr - begin);
|
mptr->key = nstrdup(begin, ptr - begin);
|
||||||
state = CS_WAITVALUE;
|
state = CS_WAITVALUE;
|
||||||
} else if ( !isalpha(*ptr) )
|
}
|
||||||
|
else if (!isalpha(*ptr))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("syntax error"),
|
errmsg("syntax error"),
|
||||||
errdetail("Syntax error in position %d near \"%c\"",
|
errdetail("Syntax error in position %d near \"%c\"",
|
||||||
(int) (ptr - VARDATA(in)), *ptr)));
|
(int) (ptr - VARDATA(in)), *ptr)));
|
||||||
} else if ( state==CS_WAITEQ ) {
|
}
|
||||||
|
else if (state == CS_WAITEQ)
|
||||||
|
{
|
||||||
if (*ptr == '=')
|
if (*ptr == '=')
|
||||||
state = CS_WAITVALUE;
|
state = CS_WAITVALUE;
|
||||||
else if (!isspace(*ptr))
|
else if (!isspace(*ptr))
|
||||||
@ -85,29 +107,44 @@ parse_cfgdict(text *in, Map **m) {
|
|||||||
errmsg("syntax error"),
|
errmsg("syntax error"),
|
||||||
errdetail("Syntax error in position %d near \"%c\"",
|
errdetail("Syntax error in position %d near \"%c\"",
|
||||||
(int) (ptr - VARDATA(in)), *ptr)));
|
(int) (ptr - VARDATA(in)), *ptr)));
|
||||||
} else if ( state==CS_WAITVALUE ) {
|
}
|
||||||
if ( *ptr=='"' ) {
|
else if (state == CS_WAITVALUE)
|
||||||
|
{
|
||||||
|
if (*ptr == '"')
|
||||||
|
{
|
||||||
begin = ptr + 1;
|
begin = ptr + 1;
|
||||||
state = CS_INVALUE;
|
state = CS_INVALUE;
|
||||||
} else if ( !isspace(*ptr) ) {
|
}
|
||||||
|
else if (!isspace(*ptr))
|
||||||
|
{
|
||||||
begin = ptr;
|
begin = ptr;
|
||||||
state = CS_IN2VALUE;
|
state = CS_IN2VALUE;
|
||||||
}
|
}
|
||||||
} else if ( state==CS_INVALUE ) {
|
}
|
||||||
if ( *ptr=='"' ) {
|
else if (state == CS_INVALUE)
|
||||||
|
{
|
||||||
|
if (*ptr == '"')
|
||||||
|
{
|
||||||
mptr->value = nstrdup(begin, ptr - begin);
|
mptr->value = nstrdup(begin, ptr - begin);
|
||||||
mptr++;
|
mptr++;
|
||||||
state = CS_WAITDELIM;
|
state = CS_WAITDELIM;
|
||||||
} else if ( *ptr=='\\' )
|
}
|
||||||
|
else if (*ptr == '\\')
|
||||||
state = CS_INESC;
|
state = CS_INESC;
|
||||||
} else if ( state==CS_IN2VALUE ) {
|
}
|
||||||
if ( isspace(*ptr) || *ptr==',' ) {
|
else if (state == CS_IN2VALUE)
|
||||||
|
{
|
||||||
|
if (isspace(*ptr) || *ptr == ',')
|
||||||
|
{
|
||||||
mptr->value = nstrdup(begin, ptr - begin);
|
mptr->value = nstrdup(begin, ptr - begin);
|
||||||
mptr++;
|
mptr++;
|
||||||
state = (*ptr == ',') ? CS_WAITKEY : CS_WAITDELIM;
|
state = (*ptr == ',') ? CS_WAITKEY : CS_WAITDELIM;
|
||||||
} else if ( *ptr=='\\' )
|
}
|
||||||
|
else if (*ptr == '\\')
|
||||||
state = CS_INESC;
|
state = CS_INESC;
|
||||||
} else if ( state==CS_WAITDELIM ) {
|
}
|
||||||
|
else if (state == CS_WAITDELIM)
|
||||||
|
{
|
||||||
if (*ptr == ',')
|
if (*ptr == ',')
|
||||||
state = CS_WAITKEY;
|
state = CS_WAITKEY;
|
||||||
else if (!isspace(*ptr))
|
else if (!isspace(*ptr))
|
||||||
@ -116,11 +153,12 @@ parse_cfgdict(text *in, Map **m) {
|
|||||||
errmsg("syntax error"),
|
errmsg("syntax error"),
|
||||||
errdetail("Syntax error in position %d near \"%c\"",
|
errdetail("Syntax error in position %d near \"%c\"",
|
||||||
(int) (ptr - VARDATA(in)), *ptr)));
|
(int) (ptr - VARDATA(in)), *ptr)));
|
||||||
} else if ( state == CS_INESC ) {
|
}
|
||||||
|
else if (state == CS_INESC)
|
||||||
state = CS_INVALUE;
|
state = CS_INVALUE;
|
||||||
} else if ( state == CS_IN2ESC ) {
|
else if (state == CS_IN2ESC)
|
||||||
state = CS_IN2VALUE;
|
state = CS_IN2VALUE;
|
||||||
} else
|
else
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("bad parser state"),
|
errmsg("bad parser state"),
|
||||||
@ -129,13 +167,13 @@ parse_cfgdict(text *in, Map **m) {
|
|||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state==CS_IN2VALUE) {
|
if (state == CS_IN2VALUE)
|
||||||
|
{
|
||||||
mptr->value = nstrdup(begin, ptr - begin);
|
mptr->value = nstrdup(begin, ptr - begin);
|
||||||
mptr++;
|
mptr++;
|
||||||
} else if ( !(state==CS_WAITDELIM || state==CS_WAITKEY) )
|
}
|
||||||
|
else if (!(state == CS_WAITDELIM || state == CS_WAITKEY))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("unexpected end of line")));
|
errmsg("unexpected end of line")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,20 +103,32 @@ typedef struct
|
|||||||
} QPRS_STATE;
|
} QPRS_STATE;
|
||||||
|
|
||||||
static char *
|
static char *
|
||||||
get_weight(char *buf, int2 *weight) {
|
get_weight(char *buf, int2 *weight)
|
||||||
|
{
|
||||||
*weight = 0;
|
*weight = 0;
|
||||||
|
|
||||||
if (*buf != ':')
|
if (*buf != ':')
|
||||||
return buf;
|
return buf;
|
||||||
|
|
||||||
buf++;
|
buf++;
|
||||||
while( *buf ) {
|
while (*buf)
|
||||||
switch(tolower(*buf)) {
|
{
|
||||||
case 'a': *weight |= 1<<3; break;
|
switch (tolower(*buf))
|
||||||
case 'b': *weight |= 1<<2; break;
|
{
|
||||||
case 'c': *weight |= 1<<1; break;
|
case 'a':
|
||||||
case 'd': *weight |= 1; break;
|
*weight |= 1 << 3;
|
||||||
default: return buf;
|
break;
|
||||||
|
case 'b':
|
||||||
|
*weight |= 1 << 2;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
*weight |= 1 << 1;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
*weight |= 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return buf;
|
||||||
}
|
}
|
||||||
buf++;
|
buf++;
|
||||||
}
|
}
|
||||||
@ -146,11 +158,15 @@ gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, int2
|
|||||||
state->count++;
|
state->count++;
|
||||||
(state->buf)++;
|
(state->buf)++;
|
||||||
return OPEN;
|
return OPEN;
|
||||||
} else if ( *(state->buf) == ':' ) {
|
}
|
||||||
|
else if (*(state->buf) == ':')
|
||||||
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("error at start of operand")));
|
errmsg("error at start of operand")));
|
||||||
} else if (*(state->buf) != ' ') {
|
}
|
||||||
|
else if (*(state->buf) != ' ')
|
||||||
|
{
|
||||||
state->valstate.prsbuf = state->buf;
|
state->valstate.prsbuf = state->buf;
|
||||||
state->state = WAITOPERATOR;
|
state->state = WAITOPERATOR;
|
||||||
if (gettoken_tsvector(&(state->valstate)))
|
if (gettoken_tsvector(&(state->valstate)))
|
||||||
@ -266,7 +282,8 @@ pushval_morph(QPRS_STATE * state, int typeval, char *strval, int lenval, int2 we
|
|||||||
|
|
||||||
parsetext_v2(findcfg(state->cfg_id), &prs, strval, lenval);
|
parsetext_v2(findcfg(state->cfg_id), &prs, strval, lenval);
|
||||||
|
|
||||||
for(count=0;count<prs.curwords;count++) {
|
for (count = 0; count < prs.curwords; count++)
|
||||||
|
{
|
||||||
pushval_asis(state, VAL, prs.words[count].word, prs.words[count].len, weight);
|
pushval_asis(state, VAL, prs.words[count].word, prs.words[count].len, weight);
|
||||||
pfree(prs.words[count].word);
|
pfree(prs.words[count].word);
|
||||||
if (count)
|
if (count)
|
||||||
@ -381,10 +398,13 @@ ValCompare(CHKVAL * chkval, WordEntry * ptr, ITEM * item)
|
|||||||
* check weight info
|
* check weight info
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
checkclass_str(CHKVAL * chkval, WordEntry * val, ITEM * item) {
|
checkclass_str(CHKVAL * chkval, WordEntry * val, ITEM * item)
|
||||||
|
{
|
||||||
WordEntryPos *ptr = (WordEntryPos *) (chkval->values + val->pos + SHORTALIGN(val->len) + sizeof(uint16));
|
WordEntryPos *ptr = (WordEntryPos *) (chkval->values + val->pos + SHORTALIGN(val->len) + sizeof(uint16));
|
||||||
uint16 len = *((uint16 *) (chkval->values + val->pos + SHORTALIGN(val->len)));
|
uint16 len = *((uint16 *) (chkval->values + val->pos + SHORTALIGN(val->len)));
|
||||||
while (len--) {
|
|
||||||
|
while (len--)
|
||||||
|
{
|
||||||
if (item->weight & (1 << ptr->weight))
|
if (item->weight & (1 << ptr->weight))
|
||||||
return true;
|
return true;
|
||||||
ptr++;
|
ptr++;
|
||||||
@ -678,12 +698,30 @@ infix(INFIX * in, bool first)
|
|||||||
}
|
}
|
||||||
*(in->cur) = '\'';
|
*(in->cur) = '\'';
|
||||||
in->cur++;
|
in->cur++;
|
||||||
if ( in->curpol->weight ) {
|
if (in->curpol->weight)
|
||||||
*(in->cur) = ':'; in->cur++;
|
{
|
||||||
if ( in->curpol->weight & (1<<3) ) { *(in->cur) = 'A'; in->cur++; }
|
*(in->cur) = ':';
|
||||||
if ( in->curpol->weight & (1<<2) ) { *(in->cur) = 'B'; in->cur++; }
|
in->cur++;
|
||||||
if ( in->curpol->weight & (1<<1) ) { *(in->cur) = 'C'; in->cur++; }
|
if (in->curpol->weight & (1 << 3))
|
||||||
if ( in->curpol->weight & 1 ) { *(in->cur) = 'D'; in->cur++; }
|
{
|
||||||
|
*(in->cur) = 'A';
|
||||||
|
in->cur++;
|
||||||
|
}
|
||||||
|
if (in->curpol->weight & (1 << 2))
|
||||||
|
{
|
||||||
|
*(in->cur) = 'B';
|
||||||
|
in->cur++;
|
||||||
|
}
|
||||||
|
if (in->curpol->weight & (1 << 1))
|
||||||
|
{
|
||||||
|
*(in->cur) = 'C';
|
||||||
|
in->cur++;
|
||||||
|
}
|
||||||
|
if (in->curpol->weight & 1)
|
||||||
|
{
|
||||||
|
*(in->cur) = 'D';
|
||||||
|
in->cur++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*(in->cur) = '\0';
|
*(in->cur) = '\0';
|
||||||
in->curpol++;
|
in->curpol++;
|
||||||
@ -827,7 +865,8 @@ tsquerytree(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
to_tsquery(PG_FUNCTION_ARGS) {
|
to_tsquery(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
text *in = PG_GETARG_TEXT_P(1);
|
text *in = PG_GETARG_TEXT_P(1);
|
||||||
char *str;
|
char *str;
|
||||||
QUERYTYPE *query;
|
QUERYTYPE *query;
|
||||||
@ -851,7 +890,8 @@ to_tsquery(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
to_tsquery_name(PG_FUNCTION_ARGS) {
|
to_tsquery_name(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
text *name = PG_GETARG_TEXT_P(0);
|
text *name = PG_GETARG_TEXT_P(0);
|
||||||
Datum res = DirectFunctionCall2(
|
Datum res = DirectFunctionCall2(
|
||||||
to_tsquery,
|
to_tsquery,
|
||||||
@ -864,12 +904,11 @@ to_tsquery_name(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
to_tsquery_current(PG_FUNCTION_ARGS) {
|
to_tsquery_current(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
PG_RETURN_DATUM(DirectFunctionCall2(
|
PG_RETURN_DATUM(DirectFunctionCall2(
|
||||||
to_tsquery,
|
to_tsquery,
|
||||||
Int32GetDatum(get_currcfg()),
|
Int32GetDatum(get_currcfg()),
|
||||||
PG_GETARG_DATUM(0)
|
PG_GETARG_DATUM(0)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,7 +46,9 @@ static float weights[]={0.1, 0.2, 0.4, 1.0};
|
|||||||
/*
|
/*
|
||||||
* Returns a weight of a word collocation
|
* Returns a weight of a word collocation
|
||||||
*/
|
*/
|
||||||
static float4 word_distance ( int4 w ) {
|
static float4
|
||||||
|
word_distance(int4 w)
|
||||||
|
{
|
||||||
if (w > 100)
|
if (w > 100)
|
||||||
return 1e-30;
|
return 1e-30;
|
||||||
|
|
||||||
@ -54,11 +56,15 @@ static float4 word_distance ( int4 w ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
cnt_length( tsvector *t ) {
|
cnt_length(tsvector * t)
|
||||||
WordEntry *ptr=ARRPTR(t), *end=(WordEntry*)STRPTR(t);
|
{
|
||||||
int len = 0, clen;
|
WordEntry *ptr = ARRPTR(t),
|
||||||
|
*end = (WordEntry *) STRPTR(t);
|
||||||
|
int len = 0,
|
||||||
|
clen;
|
||||||
|
|
||||||
while(ptr < end) {
|
while (ptr < end)
|
||||||
|
{
|
||||||
if ((clen = POSDATALEN(t, ptr)) == 0)
|
if ((clen = POSDATALEN(t, ptr)) == 0)
|
||||||
len += 1;
|
len += 1;
|
||||||
else
|
else
|
||||||
@ -70,7 +76,8 @@ cnt_length( tsvector *t ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int4
|
static int4
|
||||||
WordECompareITEM(char *eval, char *qval, WordEntry * ptr, ITEM * item) {
|
WordECompareITEM(char *eval, char *qval, WordEntry * ptr, ITEM * item)
|
||||||
|
{
|
||||||
if (ptr->len == item->length)
|
if (ptr->len == item->length)
|
||||||
return strncmp(
|
return strncmp(
|
||||||
eval + ptr->pos,
|
eval + ptr->pos,
|
||||||
@ -81,7 +88,8 @@ WordECompareITEM(char *eval, char *qval, WordEntry * ptr, ITEM * item) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static WordEntry *
|
static WordEntry *
|
||||||
find_wordentry(tsvector *t, QUERYTYPE *q, ITEM *item) {
|
find_wordentry(tsvector * t, QUERYTYPE * q, ITEM * item)
|
||||||
|
{
|
||||||
WordEntry *StopLow = ARRPTR(t);
|
WordEntry *StopLow = ARRPTR(t);
|
||||||
WordEntry *StopHigh = (WordEntry *) STRPTR(t);
|
WordEntry *StopHigh = (WordEntry *) STRPTR(t);
|
||||||
WordEntry *StopMiddle;
|
WordEntry *StopMiddle;
|
||||||
@ -110,19 +118,27 @@ static WordEntryPos POSNULL[]={
|
|||||||
};
|
};
|
||||||
|
|
||||||
static float
|
static float
|
||||||
calc_rank_and(float *w, tsvector *t, QUERYTYPE *q) {
|
calc_rank_and(float *w, tsvector * t, QUERYTYPE * q)
|
||||||
|
{
|
||||||
uint16 **pos = (uint16 **) palloc(sizeof(uint16 *) * q->size);
|
uint16 **pos = (uint16 **) palloc(sizeof(uint16 *) * q->size);
|
||||||
int i,k,l,p;
|
int i,
|
||||||
|
k,
|
||||||
|
l,
|
||||||
|
p;
|
||||||
WordEntry *entry;
|
WordEntry *entry;
|
||||||
WordEntryPos *post,*ct;
|
WordEntryPos *post,
|
||||||
int4 dimt,lenct,dist;
|
*ct;
|
||||||
|
int4 dimt,
|
||||||
|
lenct,
|
||||||
|
dist;
|
||||||
float res = -1.0;
|
float res = -1.0;
|
||||||
ITEM *item = GETQUERY(q);
|
ITEM *item = GETQUERY(q);
|
||||||
|
|
||||||
memset(pos, 0, sizeof(uint16 **) * q->size);
|
memset(pos, 0, sizeof(uint16 **) * q->size);
|
||||||
*(uint16 *) POSNULL = lengthof(POSNULL) - 1;
|
*(uint16 *) POSNULL = lengthof(POSNULL) - 1;
|
||||||
|
|
||||||
for(i=0; i<q->size; i++) {
|
for (i = 0; i < q->size; i++)
|
||||||
|
{
|
||||||
|
|
||||||
if (item[i].type != VAL)
|
if (item[i].type != VAL)
|
||||||
continue;
|
continue;
|
||||||
@ -139,16 +155,23 @@ calc_rank_and(float *w, tsvector *t, QUERYTYPE *q) {
|
|||||||
|
|
||||||
dimt = *(uint16 *) (pos[i]);
|
dimt = *(uint16 *) (pos[i]);
|
||||||
post = (WordEntryPos *) (pos[i] + 1);
|
post = (WordEntryPos *) (pos[i] + 1);
|
||||||
for( k=0; k<i; k++ ) {
|
for (k = 0; k < i; k++)
|
||||||
if ( !pos[k] ) continue;
|
{
|
||||||
|
if (!pos[k])
|
||||||
|
continue;
|
||||||
lenct = *(uint16 *) (pos[k]);
|
lenct = *(uint16 *) (pos[k]);
|
||||||
ct = (WordEntryPos *) (pos[k] + 1);
|
ct = (WordEntryPos *) (pos[k] + 1);
|
||||||
for(l=0; l<dimt; l++) {
|
for (l = 0; l < dimt; l++)
|
||||||
for(p=0; p<lenct; p++) {
|
{
|
||||||
|
for (p = 0; p < lenct; p++)
|
||||||
|
{
|
||||||
dist = abs(post[l].pos - ct[p].pos);
|
dist = abs(post[l].pos - ct[p].pos);
|
||||||
if ( dist || (dist==0 && (pos[i]==(uint16*)POSNULL || pos[k]==(uint16*)POSNULL) ) ) {
|
if (dist || (dist == 0 && (pos[i] == (uint16 *) POSNULL || pos[k] == (uint16 *) POSNULL)))
|
||||||
|
{
|
||||||
float curw;
|
float curw;
|
||||||
if ( !dist ) dist=MAXENTRYPOS;
|
|
||||||
|
if (!dist)
|
||||||
|
dist = MAXENTRYPOS;
|
||||||
curw = sqrt(wpos(&(post[l])) * wpos(&(ct[p])) * word_distance(dist));
|
curw = sqrt(wpos(&(post[l])) * wpos(&(ct[p])) * word_distance(dist));
|
||||||
res = (res < 0) ? curw : 1.0 - (1.0 - res) * (1.0 - curw);
|
res = (res < 0) ? curw : 1.0 - (1.0 - res) * (1.0 - curw);
|
||||||
}
|
}
|
||||||
@ -161,16 +184,20 @@ calc_rank_and(float *w, tsvector *t, QUERYTYPE *q) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static float
|
static float
|
||||||
calc_rank_or(float *w, tsvector *t, QUERYTYPE *q) {
|
calc_rank_or(float *w, tsvector * t, QUERYTYPE * q)
|
||||||
|
{
|
||||||
WordEntry *entry;
|
WordEntry *entry;
|
||||||
WordEntryPos *post;
|
WordEntryPos *post;
|
||||||
int4 dimt,j,i;
|
int4 dimt,
|
||||||
|
j,
|
||||||
|
i;
|
||||||
float res = -1.0;
|
float res = -1.0;
|
||||||
ITEM *item = GETQUERY(q);
|
ITEM *item = GETQUERY(q);
|
||||||
|
|
||||||
*(uint16 *) POSNULL = lengthof(POSNULL) - 1;
|
*(uint16 *) POSNULL = lengthof(POSNULL) - 1;
|
||||||
|
|
||||||
for(i=0; i<q->size; i++) {
|
for (i = 0; i < q->size; i++)
|
||||||
|
{
|
||||||
if (item[i].type != VAL)
|
if (item[i].type != VAL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -178,15 +205,19 @@ calc_rank_or(float *w, tsvector *t, QUERYTYPE *q) {
|
|||||||
if (!entry)
|
if (!entry)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( entry->haspos ) {
|
if (entry->haspos)
|
||||||
|
{
|
||||||
dimt = POSDATALEN(t, entry);
|
dimt = POSDATALEN(t, entry);
|
||||||
post = POSDATAPTR(t, entry);
|
post = POSDATAPTR(t, entry);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
dimt = *(uint16 *) POSNULL;
|
dimt = *(uint16 *) POSNULL;
|
||||||
post = POSNULL + 1;
|
post = POSNULL + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(j=0;j<dimt;j++) {
|
for (j = 0; j < dimt; j++)
|
||||||
|
{
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
res = wpos(&(post[j]));
|
res = wpos(&(post[j]));
|
||||||
else
|
else
|
||||||
@ -197,7 +228,8 @@ calc_rank_or(float *w, tsvector *t, QUERYTYPE *q) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static float
|
static float
|
||||||
calc_rank(float *w, tsvector *t, QUERYTYPE *q, int4 method) {
|
calc_rank(float *w, tsvector * t, QUERYTYPE * q, int4 method)
|
||||||
|
{
|
||||||
ITEM *item = GETQUERY(q);
|
ITEM *item = GETQUERY(q);
|
||||||
float res = 0.0;
|
float res = 0.0;
|
||||||
|
|
||||||
@ -210,10 +242,16 @@ calc_rank(float *w, tsvector *t, QUERYTYPE *q, int4 method) {
|
|||||||
if (res < 0)
|
if (res < 0)
|
||||||
res = 1e-20;
|
res = 1e-20;
|
||||||
|
|
||||||
switch(method) {
|
switch (method)
|
||||||
case 0: break;
|
{
|
||||||
case 1: res /= log((float)cnt_length(t)); break;
|
case 0:
|
||||||
case 2: res /= (float)cnt_length(t); break;
|
break;
|
||||||
|
case 1:
|
||||||
|
res /= log((float) cnt_length(t));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
res /= (float) cnt_length(t);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* internal error */
|
/* internal error */
|
||||||
elog(ERROR, "unrecognized normalization method: %d", method);
|
elog(ERROR, "unrecognized normalization method: %d", method);
|
||||||
@ -223,7 +261,8 @@ calc_rank(float *w, tsvector *t, QUERYTYPE *q, int4 method) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
rank(PG_FUNCTION_ARGS) {
|
rank(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
ArrayType *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
ArrayType *win = (ArrayType *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||||
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||||
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
|
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
|
||||||
@ -242,7 +281,8 @@ rank(PG_FUNCTION_ARGS) {
|
|||||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||||
errmsg("array of weight is too short")));
|
errmsg("array of weight is too short")));
|
||||||
|
|
||||||
for(i=0;i<lengthof(weights);i++) {
|
for (i = 0; i < lengthof(weights); i++)
|
||||||
|
{
|
||||||
ws[i] = (((float4 *) ARR_DATA_PTR(win))[i] >= 0) ? ((float4 *) ARR_DATA_PTR(win))[i] : weights[i];
|
ws[i] = (((float4 *) ARR_DATA_PTR(win))[i] >= 0) ? ((float4 *) ARR_DATA_PTR(win))[i] : weights[i];
|
||||||
if (ws[i] > 1.0)
|
if (ws[i] > 1.0)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -262,7 +302,8 @@ rank(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
rank_def(PG_FUNCTION_ARGS) {
|
rank_def(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||||
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||||
float res = 0.0;
|
float res = 0.0;
|
||||||
@ -279,29 +320,34 @@ rank_def(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
ITEM *item;
|
ITEM *item;
|
||||||
int32 pos;
|
int32 pos;
|
||||||
} DocRepresentation;
|
} DocRepresentation;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
compareDocR(const void *a, const void *b) {
|
compareDocR(const void *a, const void *b)
|
||||||
|
{
|
||||||
if (((DocRepresentation *) a)->pos == ((DocRepresentation *) b)->pos)
|
if (((DocRepresentation *) a)->pos == ((DocRepresentation *) b)->pos)
|
||||||
return 1;
|
return 1;
|
||||||
return (((DocRepresentation *) a)->pos > ((DocRepresentation *) b)->pos) ? 1 : -1;
|
return (((DocRepresentation *) a)->pos > ((DocRepresentation *) b)->pos) ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
DocRepresentation *doc;
|
DocRepresentation *doc;
|
||||||
int len;
|
int len;
|
||||||
} ChkDocR;
|
} ChkDocR;
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
checkcondition_DR(void *checkval, ITEM *val) {
|
checkcondition_DR(void *checkval, ITEM * val)
|
||||||
|
{
|
||||||
DocRepresentation *ptr = ((ChkDocR *) checkval)->doc;
|
DocRepresentation *ptr = ((ChkDocR *) checkval)->doc;
|
||||||
|
|
||||||
while( ptr - ((ChkDocR*)checkval)->doc < ((ChkDocR*)checkval)->len ) {
|
while (ptr - ((ChkDocR *) checkval)->doc < ((ChkDocR *) checkval)->len)
|
||||||
|
{
|
||||||
if (val == ptr->item)
|
if (val == ptr->item)
|
||||||
return true;
|
return true;
|
||||||
ptr++;
|
ptr++;
|
||||||
@ -312,9 +358,11 @@ checkcondition_DR(void *checkval, ITEM *val) {
|
|||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
Cover(DocRepresentation *doc, int len, QUERYTYPE *query, int *pos, int *p, int *q) {
|
Cover(DocRepresentation * doc, int len, QUERYTYPE * query, int *pos, int *p, int *q)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
DocRepresentation *ptr,*f=(DocRepresentation*)0xffffffff;
|
DocRepresentation *ptr,
|
||||||
|
*f = (DocRepresentation *) 0xffffffff;
|
||||||
ITEM *item = GETQUERY(query);
|
ITEM *item = GETQUERY(query);
|
||||||
int lastpos = *pos;
|
int lastpos = *pos;
|
||||||
int oldq = *q;
|
int oldq = *q;
|
||||||
@ -322,16 +370,21 @@ Cover(DocRepresentation *doc, int len, QUERYTYPE *query, int *pos, int *p, int *
|
|||||||
*p = 0x7fffffff;
|
*p = 0x7fffffff;
|
||||||
*q = 0;
|
*q = 0;
|
||||||
|
|
||||||
for(i=0; i<query->size; i++) {
|
for (i = 0; i < query->size; i++)
|
||||||
if ( item->type != VAL ) {
|
{
|
||||||
|
if (item->type != VAL)
|
||||||
|
{
|
||||||
item++;
|
item++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ptr = doc + *pos;
|
ptr = doc + *pos;
|
||||||
|
|
||||||
while(ptr-doc<len) {
|
while (ptr - doc < len)
|
||||||
if ( ptr->item == item ) {
|
{
|
||||||
if ( ptr->pos > *q ) {
|
if (ptr->item == item)
|
||||||
|
{
|
||||||
|
if (ptr->pos > *q)
|
||||||
|
{
|
||||||
*q = ptr->pos;
|
*q = ptr->pos;
|
||||||
lastpos = ptr - doc;
|
lastpos = ptr - doc;
|
||||||
}
|
}
|
||||||
@ -346,22 +399,28 @@ Cover(DocRepresentation *doc, int len, QUERYTYPE *query, int *pos, int *p, int *
|
|||||||
if (*q == 0)
|
if (*q == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (*q==oldq) { /* already check this pos */
|
if (*q == oldq)
|
||||||
|
{ /* already check this pos */
|
||||||
(*pos)++;
|
(*pos)++;
|
||||||
return Cover(doc, len, query, pos, p, q);
|
return Cover(doc, len, query, pos, p, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
item = GETQUERY(query);
|
item = GETQUERY(query);
|
||||||
for(i=0; i<query->size; i++) {
|
for (i = 0; i < query->size; i++)
|
||||||
if ( item->type != VAL ) {
|
{
|
||||||
|
if (item->type != VAL)
|
||||||
|
{
|
||||||
item++;
|
item++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ptr = doc + lastpos;
|
ptr = doc + lastpos;
|
||||||
|
|
||||||
while(ptr>=doc+*pos) {
|
while (ptr >= doc + *pos)
|
||||||
if ( ptr->item == item ) {
|
{
|
||||||
if ( ptr->pos < *p ) {
|
if (ptr->item == item)
|
||||||
|
{
|
||||||
|
if (ptr->pos < *p)
|
||||||
|
{
|
||||||
*p = ptr->pos;
|
*p = ptr->pos;
|
||||||
f = ptr;
|
f = ptr;
|
||||||
}
|
}
|
||||||
@ -372,13 +431,20 @@ Cover(DocRepresentation *doc, int len, QUERYTYPE *query, int *pos, int *p, int *
|
|||||||
item++;
|
item++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( *p<=*q ) {
|
if (*p <= *q)
|
||||||
|
{
|
||||||
ChkDocR ch = {f, (doc + lastpos) - f + 1};
|
ChkDocR ch = {f, (doc + lastpos) - f + 1};
|
||||||
|
|
||||||
*pos = f - doc + 1;
|
*pos = f - doc + 1;
|
||||||
if ( TS_execute(GETQUERY(query), &ch, false, checkcondition_DR) ) {
|
if (TS_execute(GETQUERY(query), &ch, false, checkcondition_DR))
|
||||||
/*elog(NOTICE,"OP:%d NP:%d P:%d Q:%d", *pos, lastpos, *p, *q);*/
|
{
|
||||||
|
/*
|
||||||
|
* elog(NOTICE,"OP:%d NP:%d P:%d Q:%d", *pos, lastpos, *p,
|
||||||
|
* *q);
|
||||||
|
*/
|
||||||
return true;
|
return true;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
return Cover(doc, len, query, pos, p, q);
|
return Cover(doc, len, query, pos, p, q);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,17 +452,22 @@ Cover(DocRepresentation *doc, int len, QUERYTYPE *query, int *pos, int *p, int *
|
|||||||
}
|
}
|
||||||
|
|
||||||
static DocRepresentation *
|
static DocRepresentation *
|
||||||
get_docrep(tsvector *txt, QUERYTYPE *query, int *doclen) {
|
get_docrep(tsvector * txt, QUERYTYPE * query, int *doclen)
|
||||||
|
{
|
||||||
ITEM *item = GETQUERY(query);
|
ITEM *item = GETQUERY(query);
|
||||||
WordEntry *entry;
|
WordEntry *entry;
|
||||||
WordEntryPos *post;
|
WordEntryPos *post;
|
||||||
int4 dimt,j,i;
|
int4 dimt,
|
||||||
int len=query->size*4,cur=0;
|
j,
|
||||||
|
i;
|
||||||
|
int len = query->size * 4,
|
||||||
|
cur = 0;
|
||||||
DocRepresentation *doc;
|
DocRepresentation *doc;
|
||||||
|
|
||||||
*(uint16 *) POSNULL = lengthof(POSNULL) - 1;
|
*(uint16 *) POSNULL = lengthof(POSNULL) - 1;
|
||||||
doc = (DocRepresentation *) palloc(sizeof(DocRepresentation) * len);
|
doc = (DocRepresentation *) palloc(sizeof(DocRepresentation) * len);
|
||||||
for(i=0; i<query->size; i++) {
|
for (i = 0; i < query->size; i++)
|
||||||
|
{
|
||||||
if (item[i].type != VAL)
|
if (item[i].type != VAL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -404,20 +475,25 @@ get_docrep(tsvector *txt, QUERYTYPE *query, int *doclen) {
|
|||||||
if (!entry)
|
if (!entry)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( entry->haspos ) {
|
if (entry->haspos)
|
||||||
|
{
|
||||||
dimt = POSDATALEN(txt, entry);
|
dimt = POSDATALEN(txt, entry);
|
||||||
post = POSDATAPTR(txt, entry);
|
post = POSDATAPTR(txt, entry);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
dimt = *(uint16 *) POSNULL;
|
dimt = *(uint16 *) POSNULL;
|
||||||
post = POSNULL + 1;
|
post = POSNULL + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while( cur+dimt >= len ) {
|
while (cur + dimt >= len)
|
||||||
|
{
|
||||||
len *= 2;
|
len *= 2;
|
||||||
doc = (DocRepresentation *) repalloc(doc, sizeof(DocRepresentation) * len);
|
doc = (DocRepresentation *) repalloc(doc, sizeof(DocRepresentation) * len);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(j=0;j<dimt;j++) {
|
for (j = 0; j < dimt; j++)
|
||||||
|
{
|
||||||
doc[cur].item = &(item[i]);
|
doc[cur].item = &(item[i]);
|
||||||
doc[cur].pos = post[j].pos;
|
doc[cur].pos = post[j].pos;
|
||||||
cur++;
|
cur++;
|
||||||
@ -426,7 +502,8 @@ get_docrep(tsvector *txt, QUERYTYPE *query, int *doclen) {
|
|||||||
|
|
||||||
*doclen = cur;
|
*doclen = cur;
|
||||||
|
|
||||||
if ( cur>0 ) {
|
if (cur > 0)
|
||||||
|
{
|
||||||
if (cur > 1)
|
if (cur > 1)
|
||||||
qsort((void *) doc, cur, sizeof(DocRepresentation), compareDocR);
|
qsort((void *) doc, cur, sizeof(DocRepresentation), compareDocR);
|
||||||
return doc;
|
return doc;
|
||||||
@ -438,17 +515,22 @@ get_docrep(tsvector *txt, QUERYTYPE *query, int *doclen) {
|
|||||||
|
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
rank_cd(PG_FUNCTION_ARGS) {
|
rank_cd(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
int K = PG_GETARG_INT32(0);
|
int K = PG_GETARG_INT32(0);
|
||||||
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||||
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
|
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
|
||||||
int method = DEF_NORM_METHOD;
|
int method = DEF_NORM_METHOD;
|
||||||
DocRepresentation *doc;
|
DocRepresentation *doc;
|
||||||
float res = 0.0;
|
float res = 0.0;
|
||||||
int p=0,q=0,len,cur;
|
int p = 0,
|
||||||
|
q = 0,
|
||||||
|
len,
|
||||||
|
cur;
|
||||||
|
|
||||||
doc = get_docrep(txt, query, &len);
|
doc = get_docrep(txt, query, &len);
|
||||||
if ( !doc ) {
|
if (!doc)
|
||||||
|
{
|
||||||
PG_FREE_IF_COPY(txt, 1);
|
PG_FREE_IF_COPY(txt, 1);
|
||||||
PG_FREE_IF_COPY(query, 2);
|
PG_FREE_IF_COPY(query, 2);
|
||||||
PG_RETURN_FLOAT4(0.0);
|
PG_RETURN_FLOAT4(0.0);
|
||||||
@ -463,10 +545,16 @@ rank_cd(PG_FUNCTION_ARGS) {
|
|||||||
if (PG_NARGS() == 4)
|
if (PG_NARGS() == 4)
|
||||||
method = PG_GETARG_INT32(3);
|
method = PG_GETARG_INT32(3);
|
||||||
|
|
||||||
switch(method) {
|
switch (method)
|
||||||
case 0: break;
|
{
|
||||||
case 1: res /= log((float)cnt_length(txt)); break;
|
case 0:
|
||||||
case 2: res /= (float)cnt_length(txt); break;
|
break;
|
||||||
|
case 1:
|
||||||
|
res /= log((float) cnt_length(txt));
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
res /= (float) cnt_length(txt);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
/* internal error */
|
/* internal error */
|
||||||
elog(ERROR, "unrecognized normalization method: %d", method);
|
elog(ERROR, "unrecognized normalization method: %d", method);
|
||||||
@ -481,7 +569,8 @@ rank_cd(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
rank_cd_def(PG_FUNCTION_ARGS) {
|
rank_cd_def(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
PG_RETURN_DATUM(DirectFunctionCall4(
|
PG_RETURN_DATUM(DirectFunctionCall4(
|
||||||
rank_cd,
|
rank_cd,
|
||||||
Int32GetDatum(-1),
|
Int32GetDatum(-1),
|
||||||
@ -493,7 +582,8 @@ rank_cd_def(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
/**************debug*************/
|
/**************debug*************/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
char *w;
|
char *w;
|
||||||
int2 len;
|
int2 len;
|
||||||
int2 pos;
|
int2 pos;
|
||||||
@ -502,7 +592,8 @@ typedef struct {
|
|||||||
} DocWord;
|
} DocWord;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
compareDocWord(const void *a, const void *b) {
|
compareDocWord(const void *a, const void *b)
|
||||||
|
{
|
||||||
if (((DocWord *) a)->pos == ((DocWord *) b)->pos)
|
if (((DocWord *) a)->pos == ((DocWord *) b)->pos)
|
||||||
return 1;
|
return 1;
|
||||||
return (((DocWord *) a)->pos > ((DocWord *) b)->pos) ? 1 : -1;
|
return (((DocWord *) a)->pos > ((DocWord *) b)->pos) ? 1 : -1;
|
||||||
@ -510,21 +601,32 @@ compareDocWord(const void *a, const void *b) {
|
|||||||
|
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
get_covers(PG_FUNCTION_ARGS) {
|
get_covers(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||||
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||||
WordEntry *pptr = ARRPTR(txt);
|
WordEntry *pptr = ARRPTR(txt);
|
||||||
int i,dlen=0,j,cur=0,len=0,rlen;
|
int i,
|
||||||
DocWord *dw,*dwptr;
|
dlen = 0,
|
||||||
|
j,
|
||||||
|
cur = 0,
|
||||||
|
len = 0,
|
||||||
|
rlen;
|
||||||
|
DocWord *dw,
|
||||||
|
*dwptr;
|
||||||
text *out;
|
text *out;
|
||||||
char *cptr;
|
char *cptr;
|
||||||
DocRepresentation *doc;
|
DocRepresentation *doc;
|
||||||
int pos=0,p,q,olddwpos=0;
|
int pos = 0,
|
||||||
|
p,
|
||||||
|
q,
|
||||||
|
olddwpos = 0;
|
||||||
int ncover = 1;
|
int ncover = 1;
|
||||||
|
|
||||||
doc = get_docrep(txt, query, &rlen);
|
doc = get_docrep(txt, query, &rlen);
|
||||||
|
|
||||||
if ( !doc ) {
|
if (!doc)
|
||||||
|
{
|
||||||
out = palloc(VARHDRSZ);
|
out = palloc(VARHDRSZ);
|
||||||
VARATT_SIZEP(out) = VARHDRSZ;
|
VARATT_SIZEP(out) = VARHDRSZ;
|
||||||
PG_FREE_IF_COPY(txt, 0);
|
PG_FREE_IF_COPY(txt, 0);
|
||||||
@ -532,7 +634,8 @@ get_covers(PG_FUNCTION_ARGS) {
|
|||||||
PG_RETURN_POINTER(out);
|
PG_RETURN_POINTER(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=0;i<txt->size;i++) {
|
for (i = 0; i < txt->size; i++)
|
||||||
|
{
|
||||||
if (!pptr[i].haspos)
|
if (!pptr[i].haspos)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
@ -543,9 +646,12 @@ get_covers(PG_FUNCTION_ARGS) {
|
|||||||
dwptr = dw = palloc(sizeof(DocWord) * dlen);
|
dwptr = dw = palloc(sizeof(DocWord) * dlen);
|
||||||
memset(dw, 0, sizeof(DocWord) * dlen);
|
memset(dw, 0, sizeof(DocWord) * dlen);
|
||||||
|
|
||||||
for(i=0;i<txt->size;i++) {
|
for (i = 0; i < txt->size; i++)
|
||||||
|
{
|
||||||
WordEntryPos *posdata = POSDATAPTR(txt, &(pptr[i]));
|
WordEntryPos *posdata = POSDATAPTR(txt, &(pptr[i]));
|
||||||
for(j=0;j<POSDATALEN(txt,&(pptr[i]));j++) {
|
|
||||||
|
for (j = 0; j < POSDATALEN(txt, &(pptr[i])); j++)
|
||||||
|
{
|
||||||
dw[cur].w = STRPTR(txt) + pptr[i].pos;
|
dw[cur].w = STRPTR(txt) + pptr[i].pos;
|
||||||
dw[cur].len = pptr[i].len;
|
dw[cur].len = pptr[i].len;
|
||||||
dw[cur].pos = posdata[j].pos;
|
dw[cur].pos = posdata[j].pos;
|
||||||
@ -555,7 +661,8 @@ get_covers(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
qsort((void *) dw, dlen, sizeof(DocWord), compareDocWord);
|
qsort((void *) dw, dlen, sizeof(DocWord), compareDocWord);
|
||||||
|
|
||||||
while( Cover(doc, rlen, query, &pos, &p, &q) ) {
|
while (Cover(doc, rlen, query, &pos, &p, &q))
|
||||||
|
{
|
||||||
dwptr = dw + olddwpos;
|
dwptr = dw + olddwpos;
|
||||||
while (dwptr->pos < p && dwptr - dw < dlen)
|
while (dwptr->pos < p && dwptr - dw < dlen)
|
||||||
dwptr++;
|
dwptr++;
|
||||||
@ -572,8 +679,10 @@ get_covers(PG_FUNCTION_ARGS) {
|
|||||||
cptr = ((char *) out) + VARHDRSZ;
|
cptr = ((char *) out) + VARHDRSZ;
|
||||||
dwptr = dw;
|
dwptr = dw;
|
||||||
|
|
||||||
while( dwptr-dw < dlen) {
|
while (dwptr - dw < dlen)
|
||||||
if ( dwptr->start ) {
|
{
|
||||||
|
if (dwptr->start)
|
||||||
|
{
|
||||||
sprintf(cptr, "{%d ", dwptr->start);
|
sprintf(cptr, "{%d ", dwptr->start);
|
||||||
cptr = strchr(cptr, '\0');
|
cptr = strchr(cptr, '\0');
|
||||||
}
|
}
|
||||||
@ -581,7 +690,8 @@ get_covers(PG_FUNCTION_ARGS) {
|
|||||||
cptr += dwptr->len;
|
cptr += dwptr->len;
|
||||||
*cptr = ' ';
|
*cptr = ' ';
|
||||||
cptr++;
|
cptr++;
|
||||||
if ( dwptr->finish ) {
|
if (dwptr->finish)
|
||||||
|
{
|
||||||
sprintf(cptr, "}%d ", dwptr->finish);
|
sprintf(cptr, "}%d ", dwptr->finish);
|
||||||
cptr = strchr(cptr, '\0');
|
cptr = strchr(cptr, '\0');
|
||||||
}
|
}
|
||||||
@ -597,4 +707,3 @@ get_covers(PG_FUNCTION_ARGS) {
|
|||||||
PG_FREE_IF_COPY(query, 1);
|
PG_FREE_IF_COPY(query, 1);
|
||||||
PG_RETURN_POINTER(out);
|
PG_RETURN_POINTER(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,15 +11,19 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
static int
|
static int
|
||||||
compareSNMapEntry(const void *a, const void *b) {
|
compareSNMapEntry(const void *a, const void *b)
|
||||||
|
{
|
||||||
return strcmp(((SNMapEntry *) a)->key, ((SNMapEntry *) b)->key);
|
return strcmp(((SNMapEntry *) a)->key, ((SNMapEntry *) b)->key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
addSNMap( SNMap *map, char *key, Oid value ) {
|
addSNMap(SNMap * map, char *key, Oid value)
|
||||||
if (map->len>=map->reallen) {
|
{
|
||||||
|
if (map->len >= map->reallen)
|
||||||
|
{
|
||||||
SNMapEntry *tmp;
|
SNMapEntry *tmp;
|
||||||
int len = (map->reallen) ? 2 * map->reallen : 16;
|
int len = (map->reallen) ? 2 * map->reallen : 16;
|
||||||
|
|
||||||
tmp = (SNMapEntry *) realloc(map->list, sizeof(SNMapEntry) * len);
|
tmp = (SNMapEntry *) realloc(map->list, sizeof(SNMapEntry) * len);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -35,20 +39,25 @@ addSNMap( SNMap *map, char *key, Oid value ) {
|
|||||||
errmsg("out of memory")));
|
errmsg("out of memory")));
|
||||||
map->list[map->len].value = value;
|
map->list[map->len].value = value;
|
||||||
map->len++;
|
map->len++;
|
||||||
if ( map->len>1 ) qsort(map->list, map->len, sizeof(SNMapEntry), compareSNMapEntry);
|
if (map->len > 1)
|
||||||
|
qsort(map->list, map->len, sizeof(SNMapEntry), compareSNMapEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
addSNMap_t( SNMap *map, text *key, Oid value ) {
|
addSNMap_t(SNMap * map, text *key, Oid value)
|
||||||
|
{
|
||||||
char *k = text2char(key);
|
char *k = text2char(key);
|
||||||
|
|
||||||
addSNMap(map, k, value);
|
addSNMap(map, k, value);
|
||||||
pfree(k);
|
pfree(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
Oid
|
Oid
|
||||||
findSNMap( SNMap *map, char *key ) {
|
findSNMap(SNMap * map, char *key)
|
||||||
|
{
|
||||||
SNMapEntry *ptr;
|
SNMapEntry *ptr;
|
||||||
SNMapEntry ks = {key, 0};
|
SNMapEntry ks = {key, 0};
|
||||||
|
|
||||||
if (map->len == 0 || !map->list)
|
if (map->len == 0 || !map->list)
|
||||||
return 0;
|
return 0;
|
||||||
ptr = (SNMapEntry *) bsearch(&ks, map->list, map->len, sizeof(SNMapEntry), compareSNMapEntry);
|
ptr = (SNMapEntry *) bsearch(&ks, map->list, map->len, sizeof(SNMapEntry), compareSNMapEntry);
|
||||||
@ -56,24 +65,31 @@ findSNMap( SNMap *map, char *key ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Oid
|
Oid
|
||||||
findSNMap_t( SNMap *map, text *key ) {
|
findSNMap_t(SNMap * map, text *key)
|
||||||
|
{
|
||||||
char *k = text2char(key);
|
char *k = text2char(key);
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = findSNMap(map, k);
|
res = findSNMap(map, k);
|
||||||
pfree(k);
|
pfree(k);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void freeSNMap( SNMap *map ) {
|
void
|
||||||
|
freeSNMap(SNMap * map)
|
||||||
|
{
|
||||||
SNMapEntry *entry = map->list;
|
SNMapEntry *entry = map->list;
|
||||||
if ( map->list ) {
|
|
||||||
while( map->len ) {
|
if (map->list)
|
||||||
if ( entry->key ) free(entry->key);
|
{
|
||||||
entry++; map->len--;
|
while (map->len)
|
||||||
|
{
|
||||||
|
if (entry->key)
|
||||||
|
free(entry->key);
|
||||||
|
entry++;
|
||||||
|
map->len--;
|
||||||
}
|
}
|
||||||
free(map->list);
|
free(map->list);
|
||||||
}
|
}
|
||||||
memset(map, 0, sizeof(SNMap));
|
memset(map, 0, sizeof(SNMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
char *key;
|
char *key;
|
||||||
Oid value;
|
Oid value;
|
||||||
} SNMapEntry;
|
} SNMapEntry;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int len;
|
int len;
|
||||||
int reallen;
|
int reallen;
|
||||||
SNMapEntry *list;
|
SNMapEntry *list;
|
||||||
|
@ -2,48 +2,64 @@
|
|||||||
|
|
||||||
#include "header.h"
|
#include "header.h"
|
||||||
|
|
||||||
extern struct SN_env * SN_create_env(int S_size, int I_size, int B_size)
|
extern struct SN_env *
|
||||||
{ struct SN_env * z = (struct SN_env *) calloc(1, sizeof(struct SN_env));
|
SN_create_env(int S_size, int I_size, int B_size)
|
||||||
|
{
|
||||||
|
struct SN_env *z = (struct SN_env *) calloc(1, sizeof(struct SN_env));
|
||||||
|
|
||||||
z->p = create_s();
|
z->p = create_s();
|
||||||
if (S_size)
|
if (S_size)
|
||||||
{ z->S = (symbol * *) calloc(S_size, sizeof(symbol *));
|
{
|
||||||
{ int i;
|
z->S = (symbol * *) calloc(S_size, sizeof(symbol *));
|
||||||
for (i = 0; i < S_size; i++) z->S[i] = create_s();
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < S_size; i++)
|
||||||
|
z->S[i] = create_s();
|
||||||
}
|
}
|
||||||
z->S_size = S_size;
|
z->S_size = S_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (I_size)
|
if (I_size)
|
||||||
{ z->I = (int *) calloc(I_size, sizeof(int));
|
{
|
||||||
|
z->I = (int *) calloc(I_size, sizeof(int));
|
||||||
z->I_size = I_size;
|
z->I_size = I_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (B_size)
|
if (B_size)
|
||||||
{ z->B = (symbol *) calloc(B_size, sizeof(symbol));
|
{
|
||||||
|
z->B = (symbol *) calloc(B_size, sizeof(symbol));
|
||||||
z->B_size = B_size;
|
z->B_size = B_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void SN_close_env(struct SN_env * z)
|
extern void
|
||||||
|
SN_close_env(struct SN_env * z)
|
||||||
{
|
{
|
||||||
if (z->S_size)
|
if (z->S_size)
|
||||||
{
|
{
|
||||||
{ int i;
|
{
|
||||||
for (i = 0; i < z->S_size; i++) lose_s(z->S[i]);
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < z->S_size; i++)
|
||||||
|
lose_s(z->S[i]);
|
||||||
}
|
}
|
||||||
free(z->S);
|
free(z->S);
|
||||||
}
|
}
|
||||||
if (z->I_size) free(z->I);
|
if (z->I_size)
|
||||||
if (z->B_size) free(z->B);
|
free(z->I);
|
||||||
if (z->p) lose_s(z->p);
|
if (z->B_size)
|
||||||
|
free(z->B);
|
||||||
|
if (z->p)
|
||||||
|
lose_s(z->p);
|
||||||
free(z);
|
free(z);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void SN_set_current(struct SN_env * z, int size, const symbol * s)
|
extern void
|
||||||
|
SN_set_current(struct SN_env * z, int size, const symbol * s)
|
||||||
{
|
{
|
||||||
replace_s(z, 0, z->l, size, s);
|
replace_s(z, 0, z->l, size, s);
|
||||||
z->c = 0;
|
z->c = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,10 +11,18 @@ typedef unsigned char symbol;
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct SN_env {
|
struct SN_env
|
||||||
|
{
|
||||||
symbol *p;
|
symbol *p;
|
||||||
int c; int a; int l; int lb; int bra; int ket;
|
int c;
|
||||||
int S_size; int I_size; int B_size;
|
int a;
|
||||||
|
int l;
|
||||||
|
int lb;
|
||||||
|
int bra;
|
||||||
|
int ket;
|
||||||
|
int S_size;
|
||||||
|
int I_size;
|
||||||
|
int B_size;
|
||||||
symbol **S;
|
symbol **S;
|
||||||
int *I;
|
int *I;
|
||||||
symbol *B;
|
symbol *B;
|
||||||
@ -24,4 +32,3 @@ extern struct SN_env * SN_create_env(int S_size, int I_size, int B_size);
|
|||||||
extern void SN_close_env(struct SN_env * z);
|
extern void SN_close_env(struct SN_env * z);
|
||||||
|
|
||||||
extern void SN_set_current(struct SN_env * z, int size, const symbol * s);
|
extern void SN_set_current(struct SN_env * z, int size, const symbol * s);
|
||||||
|
|
||||||
|
@ -338,32 +338,47 @@ static symbol s_46[] = { 's', 'i', 'n', 'g', 'l' };
|
|||||||
static symbol s_47[] = {'Y'};
|
static symbol s_47[] = {'Y'};
|
||||||
static symbol s_48[] = {'y'};
|
static symbol s_48[] = {'y'};
|
||||||
|
|
||||||
static int r_prelude(struct SN_env * z) {
|
static int
|
||||||
|
r_prelude(struct SN_env * z)
|
||||||
|
{
|
||||||
z->B[0] = 0; /* unset Y_found, line 24 */
|
z->B[0] = 0; /* unset Y_found, line 24 */
|
||||||
{ int c = z->c; /* do, line 25 */
|
{
|
||||||
|
int c = z->c; /* do, line 25 */
|
||||||
|
|
||||||
z->bra = z->c; /* [, line 25 */
|
z->bra = z->c; /* [, line 25 */
|
||||||
if (!(eq_s(z, 1, s_0))) goto lab0;
|
if (!(eq_s(z, 1, s_0)))
|
||||||
|
goto lab0;
|
||||||
z->ket = z->c; /* ], line 25 */
|
z->ket = z->c; /* ], line 25 */
|
||||||
if (!(in_grouping(z, g_v, 97, 121))) goto lab0;
|
if (!(in_grouping(z, g_v, 97, 121)))
|
||||||
|
goto lab0;
|
||||||
slice_from_s(z, 1, s_1); /* <-, line 25 */
|
slice_from_s(z, 1, s_1); /* <-, line 25 */
|
||||||
z->B[0] = 1; /* set Y_found, line 25 */
|
z->B[0] = 1; /* set Y_found, line 25 */
|
||||||
lab0:
|
lab0:
|
||||||
z->c = c;
|
z->c = c;
|
||||||
}
|
}
|
||||||
{ int c = z->c; /* do, line 26 */
|
{
|
||||||
while(1) { /* repeat, line 26 */
|
int c = z->c; /* do, line 26 */
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{ /* repeat, line 26 */
|
||||||
int c = z->c;
|
int c = z->c;
|
||||||
while(1) { /* goto, line 26 */
|
|
||||||
|
while (1)
|
||||||
|
{ /* goto, line 26 */
|
||||||
int c = z->c;
|
int c = z->c;
|
||||||
if (!(in_grouping(z, g_v, 97, 121))) goto lab3;
|
|
||||||
|
if (!(in_grouping(z, g_v, 97, 121)))
|
||||||
|
goto lab3;
|
||||||
z->bra = z->c; /* [, line 26 */
|
z->bra = z->c; /* [, line 26 */
|
||||||
if (!(eq_s(z, 1, s_2))) goto lab3;
|
if (!(eq_s(z, 1, s_2)))
|
||||||
|
goto lab3;
|
||||||
z->ket = z->c; /* ], line 26 */
|
z->ket = z->c; /* ], line 26 */
|
||||||
z->c = c;
|
z->c = c;
|
||||||
break;
|
break;
|
||||||
lab3:
|
lab3:
|
||||||
z->c = c;
|
z->c = c;
|
||||||
if (z->c >= z->l) goto lab2;
|
if (z->c >= z->l)
|
||||||
|
goto lab2;
|
||||||
z->c++;
|
z->c++;
|
||||||
}
|
}
|
||||||
slice_from_s(z, 1, s_3); /* <-, line 26 */
|
slice_from_s(z, 1, s_3); /* <-, line 26 */
|
||||||
@ -378,44 +393,63 @@ static int r_prelude(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_mark_regions(struct SN_env * z) {
|
static int
|
||||||
|
r_mark_regions(struct SN_env * z)
|
||||||
|
{
|
||||||
z->I[0] = z->l;
|
z->I[0] = z->l;
|
||||||
z->I[1] = z->l;
|
z->I[1] = z->l;
|
||||||
{ int c = z->c; /* do, line 32 */
|
{
|
||||||
{ int c = z->c; /* or, line 36 */
|
int c = z->c; /* do, line 32 */
|
||||||
if (!(find_among(z, a_0, 1))) goto lab2; /* among, line 33 */
|
|
||||||
|
{
|
||||||
|
int c = z->c; /* or, line 36 */
|
||||||
|
|
||||||
|
if (!(find_among(z, a_0, 1)))
|
||||||
|
goto lab2; /* among, line 33 */
|
||||||
goto lab1;
|
goto lab1;
|
||||||
lab2:
|
lab2:
|
||||||
z->c = c;
|
z->c = c;
|
||||||
while(1) { /* gopast, line 36 */
|
while (1)
|
||||||
if (!(in_grouping(z, g_v, 97, 121))) goto lab3;
|
{ /* gopast, line 36 */
|
||||||
|
if (!(in_grouping(z, g_v, 97, 121)))
|
||||||
|
goto lab3;
|
||||||
break;
|
break;
|
||||||
lab3:
|
lab3:
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++;
|
z->c++;
|
||||||
}
|
}
|
||||||
while(1) { /* gopast, line 36 */
|
while (1)
|
||||||
if (!(out_grouping(z, g_v, 97, 121))) goto lab4;
|
{ /* gopast, line 36 */
|
||||||
|
if (!(out_grouping(z, g_v, 97, 121)))
|
||||||
|
goto lab4;
|
||||||
break;
|
break;
|
||||||
lab4:
|
lab4:
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++;
|
z->c++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lab1:
|
lab1:
|
||||||
z->I[0] = z->c; /* setmark p1, line 37 */
|
z->I[0] = z->c; /* setmark p1, line 37 */
|
||||||
while(1) { /* gopast, line 38 */
|
while (1)
|
||||||
if (!(in_grouping(z, g_v, 97, 121))) goto lab5;
|
{ /* gopast, line 38 */
|
||||||
|
if (!(in_grouping(z, g_v, 97, 121)))
|
||||||
|
goto lab5;
|
||||||
break;
|
break;
|
||||||
lab5:
|
lab5:
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++;
|
z->c++;
|
||||||
}
|
}
|
||||||
while(1) { /* gopast, line 38 */
|
while (1)
|
||||||
if (!(out_grouping(z, g_v, 97, 121))) goto lab6;
|
{ /* gopast, line 38 */
|
||||||
|
if (!(out_grouping(z, g_v, 97, 121)))
|
||||||
|
goto lab6;
|
||||||
break;
|
break;
|
||||||
lab6:
|
lab6:
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++;
|
z->c++;
|
||||||
}
|
}
|
||||||
z->I[1] = z->c; /* setmark p2, line 38 */
|
z->I[1] = z->c; /* setmark p2, line 38 */
|
||||||
@ -425,48 +459,74 @@ static int r_mark_regions(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_shortv(struct SN_env * z) {
|
static int
|
||||||
{ int m = z->l - z->c; /* or, line 46 */
|
r_shortv(struct SN_env * z)
|
||||||
if (!(out_grouping_b(z, g_v_WXY, 89, 121))) goto lab1;
|
{
|
||||||
if (!(in_grouping_b(z, g_v, 97, 121))) goto lab1;
|
{
|
||||||
if (!(out_grouping_b(z, g_v, 97, 121))) goto lab1;
|
int m = z->l - z->c; /* or, line 46 */
|
||||||
|
|
||||||
|
if (!(out_grouping_b(z, g_v_WXY, 89, 121)))
|
||||||
|
goto lab1;
|
||||||
|
if (!(in_grouping_b(z, g_v, 97, 121)))
|
||||||
|
goto lab1;
|
||||||
|
if (!(out_grouping_b(z, g_v, 97, 121)))
|
||||||
|
goto lab1;
|
||||||
goto lab0;
|
goto lab0;
|
||||||
lab1:
|
lab1:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
if (!(out_grouping_b(z, g_v, 97, 121))) return 0;
|
if (!(out_grouping_b(z, g_v, 97, 121)))
|
||||||
if (!(in_grouping_b(z, g_v, 97, 121))) return 0;
|
return 0;
|
||||||
if (z->c > z->lb) return 0; /* atlimit, line 47 */
|
if (!(in_grouping_b(z, g_v, 97, 121)))
|
||||||
|
return 0;
|
||||||
|
if (z->c > z->lb)
|
||||||
|
return 0; /* atlimit, line 47 */
|
||||||
}
|
}
|
||||||
lab0:
|
lab0:
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_R1(struct SN_env * z) {
|
static int
|
||||||
if (!(z->I[0] <= z->c)) return 0;
|
r_R1(struct SN_env * z)
|
||||||
|
{
|
||||||
|
if (!(z->I[0] <= z->c))
|
||||||
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_R2(struct SN_env * z) {
|
static int
|
||||||
if (!(z->I[1] <= z->c)) return 0;
|
r_R2(struct SN_env * z)
|
||||||
|
{
|
||||||
|
if (!(z->I[1] <= z->c))
|
||||||
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_Step_1a(struct SN_env * z) {
|
static int
|
||||||
|
r_Step_1a(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 54 */
|
z->ket = z->c; /* [, line 54 */
|
||||||
among_var = find_among_b(z, a_1, 6); /* substring, line 54 */
|
among_var = find_among_b(z, a_1, 6); /* substring, line 54 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 54 */
|
z->bra = z->c; /* ], line 54 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
slice_from_s(z, 2, s_4); /* <-, line 55 */
|
slice_from_s(z, 2, s_4); /* <-, line 55 */
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
{ int m = z->l - z->c; /* or, line 57 */
|
{
|
||||||
if (z->c <= z->lb) goto lab1;
|
int m = z->l - z->c; /* or, line 57 */
|
||||||
|
|
||||||
|
if (z->c <= z->lb)
|
||||||
|
goto lab1;
|
||||||
z->c--; /* next, line 57 */
|
z->c--; /* next, line 57 */
|
||||||
if (z->c > z->lb) goto lab1; /* atlimit, line 57 */
|
if (z->c > z->lb)
|
||||||
|
goto lab1; /* atlimit, line 57 */
|
||||||
slice_from_s(z, 2, s_5); /* <-, line 57 */
|
slice_from_s(z, 2, s_5); /* <-, line 57 */
|
||||||
goto lab0;
|
goto lab0;
|
||||||
lab1:
|
lab1:
|
||||||
@ -476,13 +536,17 @@ static int r_Step_1a(struct SN_env * z) {
|
|||||||
lab0:
|
lab0:
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (z->c <= z->lb) return 0;
|
if (z->c <= z->lb)
|
||||||
|
return 0;
|
||||||
z->c--; /* next, line 58 */
|
z->c--; /* next, line 58 */
|
||||||
while(1) { /* gopast, line 58 */
|
while (1)
|
||||||
if (!(in_grouping_b(z, g_v, 97, 121))) goto lab2;
|
{ /* gopast, line 58 */
|
||||||
|
if (!(in_grouping_b(z, g_v, 97, 121)))
|
||||||
|
goto lab2;
|
||||||
break;
|
break;
|
||||||
lab2:
|
lab2:
|
||||||
if (z->c <= z->lb) return 0;
|
if (z->c <= z->lb)
|
||||||
|
return 0;
|
||||||
z->c--;
|
z->c--;
|
||||||
}
|
}
|
||||||
slice_del(z); /* delete, line 58 */
|
slice_del(z); /* delete, line 58 */
|
||||||
@ -491,57 +555,83 @@ static int r_Step_1a(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_Step_1b(struct SN_env * z) {
|
static int
|
||||||
|
r_Step_1b(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 64 */
|
z->ket = z->c; /* [, line 64 */
|
||||||
among_var = find_among_b(z, a_3, 6); /* substring, line 64 */
|
among_var = find_among_b(z, a_3, 6); /* substring, line 64 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 64 */
|
z->bra = z->c; /* ], line 64 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
if (!r_R1(z)) return 0; /* call R1, line 66 */
|
if (!r_R1(z))
|
||||||
|
return 0; /* call R1, line 66 */
|
||||||
slice_from_s(z, 2, s_7); /* <-, line 66 */
|
slice_from_s(z, 2, s_7); /* <-, line 66 */
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
{ int m_test = z->l - z->c; /* test, line 69 */
|
{
|
||||||
while(1) { /* gopast, line 69 */
|
int m_test = z->l - z->c; /* test, line 69 */
|
||||||
if (!(in_grouping_b(z, g_v, 97, 121))) goto lab0;
|
|
||||||
|
while (1)
|
||||||
|
{ /* gopast, line 69 */
|
||||||
|
if (!(in_grouping_b(z, g_v, 97, 121)))
|
||||||
|
goto lab0;
|
||||||
break;
|
break;
|
||||||
lab0:
|
lab0:
|
||||||
if (z->c <= z->lb) return 0;
|
if (z->c <= z->lb)
|
||||||
|
return 0;
|
||||||
z->c--;
|
z->c--;
|
||||||
}
|
}
|
||||||
z->c = z->l - m_test;
|
z->c = z->l - m_test;
|
||||||
}
|
}
|
||||||
slice_del(z); /* delete, line 69 */
|
slice_del(z); /* delete, line 69 */
|
||||||
{ int m_test = z->l - z->c; /* test, line 70 */
|
{
|
||||||
|
int m_test = z->l - z->c; /* test, line 70 */
|
||||||
|
|
||||||
among_var = find_among_b(z, a_2, 13); /* substring, line 70 */
|
among_var = find_among_b(z, a_2, 13); /* substring, line 70 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->c = z->l - m_test;
|
z->c = z->l - m_test;
|
||||||
}
|
}
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
{ int c = z->c;
|
{
|
||||||
|
int c = z->c;
|
||||||
|
|
||||||
insert_s(z, z->c, z->c, 1, s_8); /* <+, line 72 */
|
insert_s(z, z->c, z->c, 1, s_8); /* <+, line 72 */
|
||||||
z->c = c;
|
z->c = c;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
z->ket = z->c; /* [, line 75 */
|
z->ket = z->c; /* [, line 75 */
|
||||||
if (z->c <= z->lb) return 0;
|
if (z->c <= z->lb)
|
||||||
|
return 0;
|
||||||
z->c--; /* next, line 75 */
|
z->c--; /* next, line 75 */
|
||||||
z->bra = z->c; /* ], line 75 */
|
z->bra = z->c; /* ], line 75 */
|
||||||
slice_del(z); /* delete, line 75 */
|
slice_del(z); /* delete, line 75 */
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
if (z->c != z->I[0]) return 0; /* atmark, line 76 */
|
if (z->c != z->I[0])
|
||||||
{ int m_test = z->l - z->c; /* test, line 76 */
|
return 0; /* atmark, line 76 */
|
||||||
if (!r_shortv(z)) return 0; /* call shortv, line 76 */
|
{
|
||||||
|
int m_test = z->l - z->c; /* test, line 76 */
|
||||||
|
|
||||||
|
if (!r_shortv(z))
|
||||||
|
return 0; /* call shortv, line 76 */
|
||||||
z->c = z->l - m_test;
|
z->c = z->l - m_test;
|
||||||
}
|
}
|
||||||
{ int c = z->c;
|
{
|
||||||
|
int c = z->c;
|
||||||
|
|
||||||
insert_s(z, z->c, z->c, 1, s_9); /* <+, line 76 */
|
insert_s(z, z->c, z->c, 1, s_9); /* <+, line 76 */
|
||||||
z->c = c;
|
z->c = c;
|
||||||
}
|
}
|
||||||
@ -552,20 +642,30 @@ static int r_Step_1b(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_Step_1c(struct SN_env * z) {
|
static int
|
||||||
|
r_Step_1c(struct SN_env * z)
|
||||||
|
{
|
||||||
z->ket = z->c; /* [, line 83 */
|
z->ket = z->c; /* [, line 83 */
|
||||||
{ int m = z->l - z->c; /* or, line 83 */
|
{
|
||||||
if (!(eq_s_b(z, 1, s_10))) goto lab1;
|
int m = z->l - z->c; /* or, line 83 */
|
||||||
|
|
||||||
|
if (!(eq_s_b(z, 1, s_10)))
|
||||||
|
goto lab1;
|
||||||
goto lab0;
|
goto lab0;
|
||||||
lab1:
|
lab1:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
if (!(eq_s_b(z, 1, s_11))) return 0;
|
if (!(eq_s_b(z, 1, s_11)))
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
lab0:
|
lab0:
|
||||||
z->bra = z->c; /* ], line 83 */
|
z->bra = z->c; /* ], line 83 */
|
||||||
if (!(out_grouping_b(z, g_v, 97, 121))) return 0;
|
if (!(out_grouping_b(z, g_v, 97, 121)))
|
||||||
{ int m = z->l - z->c; /* not, line 84 */
|
return 0;
|
||||||
if (z->c > z->lb) goto lab2; /* atlimit, line 84 */
|
{
|
||||||
|
int m = z->l - z->c; /* not, line 84 */
|
||||||
|
|
||||||
|
if (z->c > z->lb)
|
||||||
|
goto lab2; /* atlimit, line 84 */
|
||||||
return 0;
|
return 0;
|
||||||
lab2:
|
lab2:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
@ -574,15 +674,22 @@ lab0:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_Step_2(struct SN_env * z) {
|
static int
|
||||||
|
r_Step_2(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 89 */
|
z->ket = z->c; /* [, line 89 */
|
||||||
among_var = find_among_b(z, a_4, 24); /* substring, line 89 */
|
among_var = find_among_b(z, a_4, 24); /* substring, line 89 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 89 */
|
z->bra = z->c; /* ], line 89 */
|
||||||
if (!r_R1(z)) return 0; /* call R1, line 89 */
|
if (!r_R1(z))
|
||||||
switch(among_var) {
|
return 0; /* call R1, line 89 */
|
||||||
case 0: return 0;
|
switch (among_var)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
slice_from_s(z, 4, s_13); /* <-, line 90 */
|
slice_from_s(z, 4, s_13); /* <-, line 90 */
|
||||||
break;
|
break;
|
||||||
@ -620,7 +727,8 @@ static int r_Step_2(struct SN_env * z) {
|
|||||||
slice_from_s(z, 3, s_24); /* <-, line 107 */
|
slice_from_s(z, 3, s_24); /* <-, line 107 */
|
||||||
break;
|
break;
|
||||||
case 13:
|
case 13:
|
||||||
if (!(eq_s_b(z, 1, s_25))) return 0;
|
if (!(eq_s_b(z, 1, s_25)))
|
||||||
|
return 0;
|
||||||
slice_from_s(z, 2, s_26); /* <-, line 108 */
|
slice_from_s(z, 2, s_26); /* <-, line 108 */
|
||||||
break;
|
break;
|
||||||
case 14:
|
case 14:
|
||||||
@ -630,22 +738,30 @@ static int r_Step_2(struct SN_env * z) {
|
|||||||
slice_from_s(z, 4, s_28); /* <-, line 110 */
|
slice_from_s(z, 4, s_28); /* <-, line 110 */
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
if (!(in_grouping_b(z, g_valid_LI, 99, 116))) return 0;
|
if (!(in_grouping_b(z, g_valid_LI, 99, 116)))
|
||||||
|
return 0;
|
||||||
slice_del(z); /* delete, line 111 */
|
slice_del(z); /* delete, line 111 */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_Step_3(struct SN_env * z) {
|
static int
|
||||||
|
r_Step_3(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 116 */
|
z->ket = z->c; /* [, line 116 */
|
||||||
among_var = find_among_b(z, a_5, 9); /* substring, line 116 */
|
among_var = find_among_b(z, a_5, 9); /* substring, line 116 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 116 */
|
z->bra = z->c; /* ], line 116 */
|
||||||
if (!r_R1(z)) return 0; /* call R1, line 116 */
|
if (!r_R1(z))
|
||||||
switch(among_var) {
|
return 0; /* call R1, line 116 */
|
||||||
case 0: return 0;
|
switch (among_var)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
slice_from_s(z, 4, s_29); /* <-, line 117 */
|
slice_from_s(z, 4, s_29); /* <-, line 117 */
|
||||||
break;
|
break;
|
||||||
@ -662,32 +778,44 @@ static int r_Step_3(struct SN_env * z) {
|
|||||||
slice_del(z); /* delete, line 123 */
|
slice_del(z); /* delete, line 123 */
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
if (!r_R2(z)) return 0; /* call R2, line 125 */
|
if (!r_R2(z))
|
||||||
|
return 0; /* call R2, line 125 */
|
||||||
slice_del(z); /* delete, line 125 */
|
slice_del(z); /* delete, line 125 */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_Step_4(struct SN_env * z) {
|
static int
|
||||||
|
r_Step_4(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 130 */
|
z->ket = z->c; /* [, line 130 */
|
||||||
among_var = find_among_b(z, a_6, 18); /* substring, line 130 */
|
among_var = find_among_b(z, a_6, 18); /* substring, line 130 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 130 */
|
z->bra = z->c; /* ], line 130 */
|
||||||
if (!r_R2(z)) return 0; /* call R2, line 130 */
|
if (!r_R2(z))
|
||||||
switch(among_var) {
|
return 0; /* call R2, line 130 */
|
||||||
case 0: return 0;
|
switch (among_var)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
slice_del(z); /* delete, line 133 */
|
slice_del(z); /* delete, line 133 */
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
{ int m = z->l - z->c; /* or, line 134 */
|
{
|
||||||
if (!(eq_s_b(z, 1, s_33))) goto lab1;
|
int m = z->l - z->c; /* or, line 134 */
|
||||||
|
|
||||||
|
if (!(eq_s_b(z, 1, s_33)))
|
||||||
|
goto lab1;
|
||||||
goto lab0;
|
goto lab0;
|
||||||
lab1:
|
lab1:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
if (!(eq_s_b(z, 1, s_34))) return 0;
|
if (!(eq_s_b(z, 1, s_34)))
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
lab0:
|
lab0:
|
||||||
slice_del(z); /* delete, line 134 */
|
slice_del(z); /* delete, line 134 */
|
||||||
@ -696,23 +824,36 @@ static int r_Step_4(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_Step_5(struct SN_env * z) {
|
static int
|
||||||
|
r_Step_5(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 139 */
|
z->ket = z->c; /* [, line 139 */
|
||||||
among_var = find_among_b(z, a_7, 2); /* substring, line 139 */
|
among_var = find_among_b(z, a_7, 2); /* substring, line 139 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 139 */
|
z->bra = z->c; /* ], line 139 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
{ int m = z->l - z->c; /* or, line 140 */
|
{
|
||||||
if (!r_R2(z)) goto lab1; /* call R2, line 140 */
|
int m = z->l - z->c; /* or, line 140 */
|
||||||
|
|
||||||
|
if (!r_R2(z))
|
||||||
|
goto lab1; /* call R2, line 140 */
|
||||||
goto lab0;
|
goto lab0;
|
||||||
lab1:
|
lab1:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
if (!r_R1(z)) return 0; /* call R1, line 140 */
|
if (!r_R1(z))
|
||||||
{ int m = z->l - z->c; /* not, line 140 */
|
return 0; /* call R1, line 140 */
|
||||||
if (!r_shortv(z)) goto lab2; /* call shortv, line 140 */
|
{
|
||||||
|
int m = z->l - z->c; /* not, line 140 */
|
||||||
|
|
||||||
|
if (!r_shortv(z))
|
||||||
|
goto lab2; /* call shortv, line 140 */
|
||||||
return 0;
|
return 0;
|
||||||
lab2:
|
lab2:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
@ -722,31 +863,44 @@ static int r_Step_5(struct SN_env * z) {
|
|||||||
slice_del(z); /* delete, line 140 */
|
slice_del(z); /* delete, line 140 */
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (!r_R2(z)) return 0; /* call R2, line 141 */
|
if (!r_R2(z))
|
||||||
if (!(eq_s_b(z, 1, s_35))) return 0;
|
return 0; /* call R2, line 141 */
|
||||||
|
if (!(eq_s_b(z, 1, s_35)))
|
||||||
|
return 0;
|
||||||
slice_del(z); /* delete, line 141 */
|
slice_del(z); /* delete, line 141 */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_exception2(struct SN_env * z) {
|
static int
|
||||||
|
r_exception2(struct SN_env * z)
|
||||||
|
{
|
||||||
z->ket = z->c; /* [, line 147 */
|
z->ket = z->c; /* [, line 147 */
|
||||||
if (!(find_among_b(z, a_8, 8))) return 0; /* substring, line 147 */
|
if (!(find_among_b(z, a_8, 8)))
|
||||||
|
return 0; /* substring, line 147 */
|
||||||
z->bra = z->c; /* ], line 147 */
|
z->bra = z->c; /* ], line 147 */
|
||||||
if (z->c > z->lb) return 0; /* atlimit, line 147 */
|
if (z->c > z->lb)
|
||||||
|
return 0; /* atlimit, line 147 */
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_exception1(struct SN_env * z) {
|
static int
|
||||||
|
r_exception1(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->bra = z->c; /* [, line 159 */
|
z->bra = z->c; /* [, line 159 */
|
||||||
among_var = find_among(z, a_9, 18); /* substring, line 159 */
|
among_var = find_among(z, a_9, 18); /* substring, line 159 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->ket = z->c; /* ], line 159 */
|
z->ket = z->c; /* ], line 159 */
|
||||||
if (z->c < z->l) return 0; /* atlimit, line 159 */
|
if (z->c < z->l)
|
||||||
switch(among_var) {
|
return 0; /* atlimit, line 159 */
|
||||||
case 0: return 0;
|
switch (among_var)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
slice_from_s(z, 3, s_36); /* <-, line 163 */
|
slice_from_s(z, 3, s_36); /* <-, line 163 */
|
||||||
break;
|
break;
|
||||||
@ -784,20 +938,29 @@ static int r_exception1(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_postlude(struct SN_env * z) {
|
static int
|
||||||
if (!(z->B[0])) return 0; /* Boolean test Y_found, line 192 */
|
r_postlude(struct SN_env * z)
|
||||||
while(1) { /* repeat, line 192 */
|
{
|
||||||
|
if (!(z->B[0]))
|
||||||
|
return 0; /* Boolean test Y_found, line 192 */
|
||||||
|
while (1)
|
||||||
|
{ /* repeat, line 192 */
|
||||||
int c = z->c;
|
int c = z->c;
|
||||||
while(1) { /* goto, line 192 */
|
|
||||||
|
while (1)
|
||||||
|
{ /* goto, line 192 */
|
||||||
int c = z->c;
|
int c = z->c;
|
||||||
|
|
||||||
z->bra = z->c; /* [, line 192 */
|
z->bra = z->c; /* [, line 192 */
|
||||||
if (!(eq_s(z, 1, s_47))) goto lab1;
|
if (!(eq_s(z, 1, s_47)))
|
||||||
|
goto lab1;
|
||||||
z->ket = z->c; /* ], line 192 */
|
z->ket = z->c; /* ], line 192 */
|
||||||
z->c = c;
|
z->c = c;
|
||||||
break;
|
break;
|
||||||
lab1:
|
lab1:
|
||||||
z->c = c;
|
z->c = c;
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++;
|
z->c++;
|
||||||
}
|
}
|
||||||
slice_from_s(z, 1, s_48); /* <-, line 192 */
|
slice_from_s(z, 1, s_48); /* <-, line 192 */
|
||||||
@ -809,76 +972,120 @@ static int r_postlude(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int english_stem(struct SN_env * z) {
|
extern int
|
||||||
{ int c = z->c; /* or, line 196 */
|
english_stem(struct SN_env * z)
|
||||||
if (!r_exception1(z)) goto lab1; /* call exception1, line 196 */
|
{
|
||||||
|
{
|
||||||
|
int c = z->c; /* or, line 196 */
|
||||||
|
|
||||||
|
if (!r_exception1(z))
|
||||||
|
goto lab1; /* call exception1, line 196 */
|
||||||
goto lab0;
|
goto lab0;
|
||||||
lab1:
|
lab1:
|
||||||
z->c = c;
|
z->c = c;
|
||||||
{ int c_test = z->c; /* test, line 198 */
|
{
|
||||||
{ int c = z->c + 3;
|
int c_test = z->c; /* test, line 198 */
|
||||||
if (0 > c || c > z->l) return 0;
|
|
||||||
|
{
|
||||||
|
int c = z->c + 3;
|
||||||
|
|
||||||
|
if (0 > c || c > z->l)
|
||||||
|
return 0;
|
||||||
z->c = c; /* hop, line 198 */
|
z->c = c; /* hop, line 198 */
|
||||||
}
|
}
|
||||||
z->c = c_test;
|
z->c = c_test;
|
||||||
}
|
}
|
||||||
{ int c = z->c; /* do, line 199 */
|
{
|
||||||
if (!r_prelude(z)) goto lab2; /* call prelude, line 199 */
|
int c = z->c; /* do, line 199 */
|
||||||
|
|
||||||
|
if (!r_prelude(z))
|
||||||
|
goto lab2; /* call prelude, line 199 */
|
||||||
lab2:
|
lab2:
|
||||||
z->c = c;
|
z->c = c;
|
||||||
}
|
}
|
||||||
{ int c = z->c; /* do, line 200 */
|
{
|
||||||
if (!r_mark_regions(z)) goto lab3; /* call mark_regions, line 200 */
|
int c = z->c; /* do, line 200 */
|
||||||
|
|
||||||
|
if (!r_mark_regions(z))
|
||||||
|
goto lab3; /* call mark_regions, line 200 */
|
||||||
lab3:
|
lab3:
|
||||||
z->c = c;
|
z->c = c;
|
||||||
}
|
}
|
||||||
z->lb = z->c; z->c = z->l; /* backwards, line 201 */
|
z->lb = z->c;
|
||||||
|
z->c = z->l; /* backwards, line 201 */
|
||||||
|
|
||||||
{ int m = z->l - z->c; /* do, line 203 */
|
{
|
||||||
if (!r_Step_1a(z)) goto lab4; /* call Step_1a, line 203 */
|
int m = z->l - z->c; /* do, line 203 */
|
||||||
|
|
||||||
|
if (!r_Step_1a(z))
|
||||||
|
goto lab4; /* call Step_1a, line 203 */
|
||||||
lab4:
|
lab4:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; /* or, line 205 */
|
{
|
||||||
if (!r_exception2(z)) goto lab6; /* call exception2, line 205 */
|
int m = z->l - z->c; /* or, line 205 */
|
||||||
|
|
||||||
|
if (!r_exception2(z))
|
||||||
|
goto lab6; /* call exception2, line 205 */
|
||||||
goto lab5;
|
goto lab5;
|
||||||
lab6:
|
lab6:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
{ int m = z->l - z->c; /* do, line 207 */
|
{
|
||||||
if (!r_Step_1b(z)) goto lab7; /* call Step_1b, line 207 */
|
int m = z->l - z->c; /* do, line 207 */
|
||||||
|
|
||||||
|
if (!r_Step_1b(z))
|
||||||
|
goto lab7; /* call Step_1b, line 207 */
|
||||||
lab7:
|
lab7:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; /* do, line 208 */
|
{
|
||||||
if (!r_Step_1c(z)) goto lab8; /* call Step_1c, line 208 */
|
int m = z->l - z->c; /* do, line 208 */
|
||||||
|
|
||||||
|
if (!r_Step_1c(z))
|
||||||
|
goto lab8; /* call Step_1c, line 208 */
|
||||||
lab8:
|
lab8:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; /* do, line 210 */
|
{
|
||||||
if (!r_Step_2(z)) goto lab9; /* call Step_2, line 210 */
|
int m = z->l - z->c; /* do, line 210 */
|
||||||
|
|
||||||
|
if (!r_Step_2(z))
|
||||||
|
goto lab9; /* call Step_2, line 210 */
|
||||||
lab9:
|
lab9:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; /* do, line 211 */
|
{
|
||||||
if (!r_Step_3(z)) goto lab10; /* call Step_3, line 211 */
|
int m = z->l - z->c; /* do, line 211 */
|
||||||
|
|
||||||
|
if (!r_Step_3(z))
|
||||||
|
goto lab10; /* call Step_3, line 211 */
|
||||||
lab10:
|
lab10:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; /* do, line 212 */
|
{
|
||||||
if (!r_Step_4(z)) goto lab11; /* call Step_4, line 212 */
|
int m = z->l - z->c; /* do, line 212 */
|
||||||
|
|
||||||
|
if (!r_Step_4(z))
|
||||||
|
goto lab11; /* call Step_4, line 212 */
|
||||||
lab11:
|
lab11:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; /* do, line 214 */
|
{
|
||||||
if (!r_Step_5(z)) goto lab12; /* call Step_5, line 214 */
|
int m = z->l - z->c; /* do, line 214 */
|
||||||
|
|
||||||
|
if (!r_Step_5(z))
|
||||||
|
goto lab12; /* call Step_5, line 214 */
|
||||||
lab12:
|
lab12:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lab5:
|
lab5:
|
||||||
z->c = z->lb;
|
z->c = z->lb;
|
||||||
{ int c = z->c; /* do, line 217 */
|
{
|
||||||
if (!r_postlude(z)) goto lab13; /* call postlude, line 217 */
|
int c = z->c; /* do, line 217 */
|
||||||
|
|
||||||
|
if (!r_postlude(z))
|
||||||
|
goto lab13; /* call postlude, line 217 */
|
||||||
lab13:
|
lab13:
|
||||||
z->c = c;
|
z->c = c;
|
||||||
}
|
}
|
||||||
@ -887,7 +1094,12 @@ lab0:
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct SN_env * english_create_env(void) { return SN_create_env(0, 2, 1); }
|
extern struct SN_env *english_create_env(void)
|
||||||
|
{
|
||||||
extern void english_close_env(struct SN_env * z) { SN_close_env(z); }
|
return SN_create_env(0, 2, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void english_close_env(struct SN_env * z)
|
||||||
|
{
|
||||||
|
SN_close_env(z);
|
||||||
|
}
|
||||||
|
@ -5,4 +5,3 @@ extern struct SN_env * english_create_env(void);
|
|||||||
extern void english_close_env(struct SN_env * z);
|
extern void english_close_env(struct SN_env * z);
|
||||||
|
|
||||||
extern int english_stem(struct SN_env * z);
|
extern int english_stem(struct SN_env * z);
|
||||||
|
|
||||||
|
@ -7,7 +7,8 @@
|
|||||||
#define CAPACITY(p) ((int *)(p))[-2]
|
#define CAPACITY(p) ((int *)(p))[-2]
|
||||||
|
|
||||||
struct among
|
struct among
|
||||||
{ int s_size; /* number of chars in string */
|
{
|
||||||
|
int s_size; /* number of chars in string */
|
||||||
symbol *s; /* search string */
|
symbol *s; /* search string */
|
||||||
int substring_i; /* index to longest matching substring */
|
int substring_i; /* index to longest matching substring */
|
||||||
int result; /* result of the lookup */
|
int result; /* result of the lookup */
|
||||||
@ -48,4 +49,3 @@ extern symbol * slice_to(struct SN_env * z, symbol * p);
|
|||||||
extern symbol *assign_to(struct SN_env * z, symbol * p);
|
extern symbol *assign_to(struct SN_env * z, symbol * p);
|
||||||
|
|
||||||
extern void debug(struct SN_env * z, int number, int line_count);
|
extern void debug(struct SN_env * z, int number, int line_count);
|
||||||
|
|
||||||
|
@ -337,37 +337,53 @@ static symbol s_7[] = { 206 };
|
|||||||
static symbol s_8[] = {206};
|
static symbol s_8[] = {206};
|
||||||
static symbol s_9[] = {201};
|
static symbol s_9[] = {201};
|
||||||
|
|
||||||
static int r_mark_regions(struct SN_env * z) {
|
static int
|
||||||
|
r_mark_regions(struct SN_env * z)
|
||||||
|
{
|
||||||
z->I[0] = z->l;
|
z->I[0] = z->l;
|
||||||
z->I[1] = z->l;
|
z->I[1] = z->l;
|
||||||
{ int c = z->c; /* do, line 100 */
|
{
|
||||||
while(1) { /* gopast, line 101 */
|
int c = z->c; /* do, line 100 */
|
||||||
if (!(in_grouping(z, g_v, 192, 220))) goto lab1;
|
|
||||||
|
while (1)
|
||||||
|
{ /* gopast, line 101 */
|
||||||
|
if (!(in_grouping(z, g_v, 192, 220)))
|
||||||
|
goto lab1;
|
||||||
break;
|
break;
|
||||||
lab1:
|
lab1:
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++;
|
z->c++;
|
||||||
}
|
}
|
||||||
z->I[0] = z->c; /* setmark pV, line 101 */
|
z->I[0] = z->c; /* setmark pV, line 101 */
|
||||||
while(1) { /* gopast, line 101 */
|
while (1)
|
||||||
if (!(out_grouping(z, g_v, 192, 220))) goto lab2;
|
{ /* gopast, line 101 */
|
||||||
|
if (!(out_grouping(z, g_v, 192, 220)))
|
||||||
|
goto lab2;
|
||||||
break;
|
break;
|
||||||
lab2:
|
lab2:
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++;
|
z->c++;
|
||||||
}
|
}
|
||||||
while(1) { /* gopast, line 102 */
|
while (1)
|
||||||
if (!(in_grouping(z, g_v, 192, 220))) goto lab3;
|
{ /* gopast, line 102 */
|
||||||
|
if (!(in_grouping(z, g_v, 192, 220)))
|
||||||
|
goto lab3;
|
||||||
break;
|
break;
|
||||||
lab3:
|
lab3:
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++;
|
z->c++;
|
||||||
}
|
}
|
||||||
while(1) { /* gopast, line 102 */
|
while (1)
|
||||||
if (!(out_grouping(z, g_v, 192, 220))) goto lab4;
|
{ /* gopast, line 102 */
|
||||||
|
if (!(out_grouping(z, g_v, 192, 220)))
|
||||||
|
goto lab4;
|
||||||
break;
|
break;
|
||||||
lab4:
|
lab4:
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++;
|
z->c++;
|
||||||
}
|
}
|
||||||
z->I[1] = z->c; /* setmark p2, line 102 */
|
z->I[1] = z->c; /* setmark p2, line 102 */
|
||||||
@ -377,26 +393,39 @@ static int r_mark_regions(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_R2(struct SN_env * z) {
|
static int
|
||||||
if (!(z->I[1] <= z->c)) return 0;
|
r_R2(struct SN_env * z)
|
||||||
|
{
|
||||||
|
if (!(z->I[1] <= z->c))
|
||||||
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_perfective_gerund(struct SN_env * z) {
|
static int
|
||||||
|
r_perfective_gerund(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 111 */
|
z->ket = z->c; /* [, line 111 */
|
||||||
among_var = find_among_b(z, a_0, 9); /* substring, line 111 */
|
among_var = find_among_b(z, a_0, 9); /* substring, line 111 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 111 */
|
z->bra = z->c; /* ], line 111 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
{ int m = z->l - z->c; /* or, line 115 */
|
{
|
||||||
if (!(eq_s_b(z, 1, s_0))) goto lab1;
|
int m = z->l - z->c; /* or, line 115 */
|
||||||
|
|
||||||
|
if (!(eq_s_b(z, 1, s_0)))
|
||||||
|
goto lab1;
|
||||||
goto lab0;
|
goto lab0;
|
||||||
lab1:
|
lab1:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
if (!(eq_s_b(z, 1, s_1))) return 0;
|
if (!(eq_s_b(z, 1, s_1)))
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
lab0:
|
lab0:
|
||||||
slice_del(z); /* delete, line 115 */
|
slice_del(z); /* delete, line 115 */
|
||||||
@ -408,14 +437,20 @@ static int r_perfective_gerund(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_adjective(struct SN_env * z) {
|
static int
|
||||||
|
r_adjective(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 127 */
|
z->ket = z->c; /* [, line 127 */
|
||||||
among_var = find_among_b(z, a_1, 26); /* substring, line 127 */
|
among_var = find_among_b(z, a_1, 26); /* substring, line 127 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 127 */
|
z->bra = z->c; /* ], line 127 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
slice_del(z); /* delete, line 136 */
|
slice_del(z); /* delete, line 136 */
|
||||||
break;
|
break;
|
||||||
@ -423,23 +458,45 @@ static int r_adjective(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_adjectival(struct SN_env * z) {
|
static int
|
||||||
|
r_adjectival(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
if (!r_adjective(z)) return 0; /* call adjective, line 141 */
|
|
||||||
{ int m = z->l - z->c; /* try, line 148 */
|
if (!r_adjective(z))
|
||||||
|
return 0; /* call adjective, line 141 */
|
||||||
|
{
|
||||||
|
int m = z->l - z->c; /* try, line 148 */
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 149 */
|
z->ket = z->c; /* [, line 149 */
|
||||||
among_var = find_among_b(z, a_2, 8); /* substring, line 149 */
|
among_var = find_among_b(z, a_2, 8); /* substring, line 149 */
|
||||||
if (!(among_var)) { z->c = z->l - m; goto lab0; }
|
if (!(among_var))
|
||||||
|
{
|
||||||
|
z->c = z->l - m;
|
||||||
|
goto lab0;
|
||||||
|
}
|
||||||
z->bra = z->c; /* ], line 149 */
|
z->bra = z->c; /* ], line 149 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: { z->c = z->l - m; goto lab0; }
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
z->c = z->l - m;
|
||||||
|
goto lab0;
|
||||||
|
}
|
||||||
case 1:
|
case 1:
|
||||||
{ int m = z->l - z->c; /* or, line 154 */
|
{
|
||||||
if (!(eq_s_b(z, 1, s_2))) goto lab2;
|
int m = z->l - z->c; /* or, line 154 */
|
||||||
|
|
||||||
|
if (!(eq_s_b(z, 1, s_2)))
|
||||||
|
goto lab2;
|
||||||
goto lab1;
|
goto lab1;
|
||||||
lab2:
|
lab2:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
if (!(eq_s_b(z, 1, s_3))) { z->c = z->l - m; goto lab0; }
|
if (!(eq_s_b(z, 1, s_3)))
|
||||||
|
{
|
||||||
|
z->c = z->l - m;
|
||||||
|
goto lab0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lab1:
|
lab1:
|
||||||
slice_del(z); /* delete, line 154 */
|
slice_del(z); /* delete, line 154 */
|
||||||
@ -454,14 +511,20 @@ static int r_adjectival(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_reflexive(struct SN_env * z) {
|
static int
|
||||||
|
r_reflexive(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 168 */
|
z->ket = z->c; /* [, line 168 */
|
||||||
among_var = find_among_b(z, a_3, 2); /* substring, line 168 */
|
among_var = find_among_b(z, a_3, 2); /* substring, line 168 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 168 */
|
z->bra = z->c; /* ], line 168 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
slice_del(z); /* delete, line 171 */
|
slice_del(z); /* delete, line 171 */
|
||||||
break;
|
break;
|
||||||
@ -469,21 +532,31 @@ static int r_reflexive(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_verb(struct SN_env * z) {
|
static int
|
||||||
|
r_verb(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 176 */
|
z->ket = z->c; /* [, line 176 */
|
||||||
among_var = find_among_b(z, a_4, 46); /* substring, line 176 */
|
among_var = find_among_b(z, a_4, 46); /* substring, line 176 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 176 */
|
z->bra = z->c; /* ], line 176 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
{ int m = z->l - z->c; /* or, line 182 */
|
{
|
||||||
if (!(eq_s_b(z, 1, s_4))) goto lab1;
|
int m = z->l - z->c; /* or, line 182 */
|
||||||
|
|
||||||
|
if (!(eq_s_b(z, 1, s_4)))
|
||||||
|
goto lab1;
|
||||||
goto lab0;
|
goto lab0;
|
||||||
lab1:
|
lab1:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
if (!(eq_s_b(z, 1, s_5))) return 0;
|
if (!(eq_s_b(z, 1, s_5)))
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
lab0:
|
lab0:
|
||||||
slice_del(z); /* delete, line 182 */
|
slice_del(z); /* delete, line 182 */
|
||||||
@ -495,14 +568,20 @@ static int r_verb(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_noun(struct SN_env * z) {
|
static int
|
||||||
|
r_noun(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 199 */
|
z->ket = z->c; /* [, line 199 */
|
||||||
among_var = find_among_b(z, a_5, 36); /* substring, line 199 */
|
among_var = find_among_b(z, a_5, 36); /* substring, line 199 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 199 */
|
z->bra = z->c; /* ], line 199 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
slice_del(z); /* delete, line 206 */
|
slice_del(z); /* delete, line 206 */
|
||||||
break;
|
break;
|
||||||
@ -510,15 +589,22 @@ static int r_noun(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_derivational(struct SN_env * z) {
|
static int
|
||||||
|
r_derivational(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 215 */
|
z->ket = z->c; /* [, line 215 */
|
||||||
among_var = find_among_b(z, a_6, 2); /* substring, line 215 */
|
among_var = find_among_b(z, a_6, 2); /* substring, line 215 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 215 */
|
z->bra = z->c; /* ], line 215 */
|
||||||
if (!r_R2(z)) return 0; /* call R2, line 215 */
|
if (!r_R2(z))
|
||||||
switch(among_var) {
|
return 0; /* call R2, line 215 */
|
||||||
case 0: return 0;
|
switch (among_var)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
slice_del(z); /* delete, line 218 */
|
slice_del(z); /* delete, line 218 */
|
||||||
break;
|
break;
|
||||||
@ -526,24 +612,33 @@ static int r_derivational(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_tidy_up(struct SN_env * z) {
|
static int
|
||||||
|
r_tidy_up(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 223 */
|
z->ket = z->c; /* [, line 223 */
|
||||||
among_var = find_among_b(z, a_7, 4); /* substring, line 223 */
|
among_var = find_among_b(z, a_7, 4); /* substring, line 223 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 223 */
|
z->bra = z->c; /* ], line 223 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
slice_del(z); /* delete, line 227 */
|
slice_del(z); /* delete, line 227 */
|
||||||
z->ket = z->c; /* [, line 228 */
|
z->ket = z->c; /* [, line 228 */
|
||||||
if (!(eq_s_b(z, 1, s_6))) return 0;
|
if (!(eq_s_b(z, 1, s_6)))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 228 */
|
z->bra = z->c; /* ], line 228 */
|
||||||
if (!(eq_s_b(z, 1, s_7))) return 0;
|
if (!(eq_s_b(z, 1, s_7)))
|
||||||
|
return 0;
|
||||||
slice_del(z); /* delete, line 228 */
|
slice_del(z); /* delete, line 228 */
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (!(eq_s_b(z, 1, s_8))) return 0;
|
if (!(eq_s_b(z, 1, s_8)))
|
||||||
|
return 0;
|
||||||
slice_del(z); /* delete, line 231 */
|
slice_del(z); /* delete, line 231 */
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
@ -553,41 +648,67 @@ static int r_tidy_up(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int russian_stem(struct SN_env * z) {
|
extern int
|
||||||
{ int c = z->c; /* do, line 240 */
|
russian_stem(struct SN_env * z)
|
||||||
if (!r_mark_regions(z)) goto lab0; /* call mark_regions, line 240 */
|
{
|
||||||
|
{
|
||||||
|
int c = z->c; /* do, line 240 */
|
||||||
|
|
||||||
|
if (!r_mark_regions(z))
|
||||||
|
goto lab0; /* call mark_regions, line 240 */
|
||||||
lab0:
|
lab0:
|
||||||
z->c = c;
|
z->c = c;
|
||||||
}
|
}
|
||||||
z->lb = z->c; z->c = z->l; /* backwards, line 241 */
|
z->lb = z->c;
|
||||||
|
z->c = z->l; /* backwards, line 241 */
|
||||||
|
|
||||||
{ int m = z->l - z->c; /* setlimit, line 241 */
|
{
|
||||||
|
int m = z->l - z->c; /* setlimit, line 241 */
|
||||||
int m3;
|
int m3;
|
||||||
if (z->c < z->I[0]) return 0;
|
|
||||||
|
if (z->c < z->I[0])
|
||||||
|
return 0;
|
||||||
z->c = z->I[0]; /* tomark, line 241 */
|
z->c = z->I[0]; /* tomark, line 241 */
|
||||||
m3 = z->lb; z->lb = z->c;
|
m3 = z->lb;
|
||||||
|
z->lb = z->c;
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
{ int m = z->l - z->c; /* do, line 242 */
|
{
|
||||||
{ int m = z->l - z->c; /* or, line 243 */
|
int m = z->l - z->c; /* do, line 242 */
|
||||||
if (!r_perfective_gerund(z)) goto lab3; /* call perfective_gerund, line 243 */
|
|
||||||
|
{
|
||||||
|
int m = z->l - z->c; /* or, line 243 */
|
||||||
|
|
||||||
|
if (!r_perfective_gerund(z))
|
||||||
|
goto lab3; /* call perfective_gerund, line 243 */
|
||||||
goto lab2;
|
goto lab2;
|
||||||
lab3:
|
lab3:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
{ int m = z->l - z->c; /* try, line 244 */
|
{
|
||||||
if (!r_reflexive(z)) { z->c = z->l - m; goto lab4; } /* call reflexive, line 244 */
|
int m = z->l - z->c; /* try, line 244 */
|
||||||
|
|
||||||
|
if (!r_reflexive(z))
|
||||||
|
{
|
||||||
|
z->c = z->l - m;
|
||||||
|
goto lab4;
|
||||||
|
} /* call reflexive, line 244 */
|
||||||
lab4:
|
lab4:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; /* or, line 245 */
|
{
|
||||||
if (!r_adjectival(z)) goto lab6; /* call adjectival, line 245 */
|
int m = z->l - z->c; /* or, line 245 */
|
||||||
|
|
||||||
|
if (!r_adjectival(z))
|
||||||
|
goto lab6; /* call adjectival, line 245 */
|
||||||
goto lab5;
|
goto lab5;
|
||||||
lab6:
|
lab6:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
if (!r_verb(z)) goto lab7; /* call verb, line 245 */
|
if (!r_verb(z))
|
||||||
|
goto lab7; /* call verb, line 245 */
|
||||||
goto lab5;
|
goto lab5;
|
||||||
lab7:
|
lab7:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
if (!r_noun(z)) goto lab1; /* call noun, line 245 */
|
if (!r_noun(z))
|
||||||
|
goto lab1; /* call noun, line 245 */
|
||||||
}
|
}
|
||||||
lab5:
|
lab5:
|
||||||
;
|
;
|
||||||
@ -596,21 +717,33 @@ extern int russian_stem(struct SN_env * z) {
|
|||||||
lab1:
|
lab1:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; /* try, line 248 */
|
{
|
||||||
|
int m = z->l - z->c; /* try, line 248 */
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 248 */
|
z->ket = z->c; /* [, line 248 */
|
||||||
if (!(eq_s_b(z, 1, s_9))) { z->c = z->l - m; goto lab8; }
|
if (!(eq_s_b(z, 1, s_9)))
|
||||||
|
{
|
||||||
|
z->c = z->l - m;
|
||||||
|
goto lab8;
|
||||||
|
}
|
||||||
z->bra = z->c; /* ], line 248 */
|
z->bra = z->c; /* ], line 248 */
|
||||||
slice_del(z); /* delete, line 248 */
|
slice_del(z); /* delete, line 248 */
|
||||||
lab8:
|
lab8:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; /* do, line 251 */
|
{
|
||||||
if (!r_derivational(z)) goto lab9; /* call derivational, line 251 */
|
int m = z->l - z->c; /* do, line 251 */
|
||||||
|
|
||||||
|
if (!r_derivational(z))
|
||||||
|
goto lab9; /* call derivational, line 251 */
|
||||||
lab9:
|
lab9:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; /* do, line 252 */
|
{
|
||||||
if (!r_tidy_up(z)) goto lab10; /* call tidy_up, line 252 */
|
int m = z->l - z->c; /* do, line 252 */
|
||||||
|
|
||||||
|
if (!r_tidy_up(z))
|
||||||
|
goto lab10; /* call tidy_up, line 252 */
|
||||||
lab10:
|
lab10:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
}
|
}
|
||||||
@ -620,7 +753,12 @@ extern int russian_stem(struct SN_env * z) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct SN_env * russian_create_env(void) { return SN_create_env(0, 2, 0); }
|
extern struct SN_env *russian_create_env(void)
|
||||||
|
{
|
||||||
extern void russian_close_env(struct SN_env * z) { SN_close_env(z); }
|
return SN_create_env(0, 2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void russian_close_env(struct SN_env * z)
|
||||||
|
{
|
||||||
|
SN_close_env(z);
|
||||||
|
}
|
||||||
|
@ -5,4 +5,3 @@ extern struct SN_env * russian_create_env(void);
|
|||||||
extern void russian_close_env(struct SN_env * z);
|
extern void russian_close_env(struct SN_env * z);
|
||||||
|
|
||||||
extern int russian_stem(struct SN_env * z);
|
extern int russian_stem(struct SN_env * z);
|
||||||
|
|
||||||
|
@ -9,118 +9,190 @@
|
|||||||
|
|
||||||
#define CREATE_SIZE 1
|
#define CREATE_SIZE 1
|
||||||
|
|
||||||
extern symbol * create_s(void)
|
extern symbol *
|
||||||
{ symbol * p = (symbol *) (HEAD + (char *) malloc(HEAD + (CREATE_SIZE + 1) * sizeof(symbol)));
|
create_s(void)
|
||||||
|
{
|
||||||
|
symbol *p = (symbol *) (HEAD + (char *) malloc(HEAD + (CREATE_SIZE + 1) * sizeof(symbol)));
|
||||||
|
|
||||||
CAPACITY(p) = CREATE_SIZE;
|
CAPACITY(p) = CREATE_SIZE;
|
||||||
SET_SIZE(p, CREATE_SIZE);
|
SET_SIZE(p, CREATE_SIZE);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void lose_s(symbol * p) { free((char *) p - HEAD); }
|
extern void lose_s(symbol * p)
|
||||||
|
{
|
||||||
|
free((char *) p - HEAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern int
|
||||||
|
in_grouping(struct SN_env * z, unsigned char *s, int min, int max)
|
||||||
|
{
|
||||||
|
if (z->c >= z->l)
|
||||||
|
return 0;
|
||||||
|
{
|
||||||
|
int ch = z->p[z->c];
|
||||||
|
|
||||||
extern int in_grouping(struct SN_env * z, unsigned char * s, int min, int max)
|
|
||||||
{ if (z->c >= z->l) return 0;
|
|
||||||
{ int ch = z->p[z->c];
|
|
||||||
if
|
if
|
||||||
(ch > max || (ch -= min) < 0 ||
|
(ch > max || (ch -= min) < 0 ||
|
||||||
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
z->c++; return 1;
|
z->c++;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int in_grouping_b(struct SN_env * z, unsigned char * s, int min, int max)
|
extern int
|
||||||
{ if (z->c <= z->lb) return 0;
|
in_grouping_b(struct SN_env * z, unsigned char *s, int min, int max)
|
||||||
{ int ch = z->p[z->c - 1];
|
{
|
||||||
|
if (z->c <= z->lb)
|
||||||
|
return 0;
|
||||||
|
{
|
||||||
|
int ch = z->p[z->c - 1];
|
||||||
|
|
||||||
if
|
if
|
||||||
(ch > max || (ch -= min) < 0 ||
|
(ch > max || (ch -= min) < 0 ||
|
||||||
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
z->c--; return 1;
|
z->c--;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int out_grouping(struct SN_env * z, unsigned char * s, int min, int max)
|
extern int
|
||||||
{ if (z->c >= z->l) return 0;
|
out_grouping(struct SN_env * z, unsigned char *s, int min, int max)
|
||||||
{ int ch = z->p[z->c];
|
{
|
||||||
|
if (z->c >= z->l)
|
||||||
|
return 0;
|
||||||
|
{
|
||||||
|
int ch = z->p[z->c];
|
||||||
|
|
||||||
unless
|
unless
|
||||||
(ch > max || (ch -= min) < 0 ||
|
(ch > max || (ch -= min) < 0 ||
|
||||||
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
||||||
}
|
}
|
||||||
z->c++; return 1;
|
z->c++;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int out_grouping_b(struct SN_env * z, unsigned char * s, int min, int max)
|
extern int
|
||||||
{ if (z->c <= z->lb) return 0;
|
out_grouping_b(struct SN_env * z, unsigned char *s, int min, int max)
|
||||||
{ int ch = z->p[z->c - 1];
|
{
|
||||||
|
if (z->c <= z->lb)
|
||||||
|
return 0;
|
||||||
|
{
|
||||||
|
int ch = z->p[z->c - 1];
|
||||||
|
|
||||||
unless
|
unless
|
||||||
(ch > max || (ch -= min) < 0 ||
|
(ch > max || (ch -= min) < 0 ||
|
||||||
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
||||||
}
|
}
|
||||||
z->c--; return 1;
|
z->c--;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern int in_range(struct SN_env * z, int min, int max)
|
extern int
|
||||||
{ if (z->c >= z->l) return 0;
|
in_range(struct SN_env * z, int min, int max)
|
||||||
{ int ch = z->p[z->c];
|
{
|
||||||
|
if (z->c >= z->l)
|
||||||
|
return 0;
|
||||||
|
{
|
||||||
|
int ch = z->p[z->c];
|
||||||
|
|
||||||
if
|
if
|
||||||
(ch > max || ch < min) return 0;
|
(ch > max || ch < min)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
z->c++; return 1;
|
z->c++;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int in_range_b(struct SN_env * z, int min, int max)
|
extern int
|
||||||
{ if (z->c <= z->lb) return 0;
|
in_range_b(struct SN_env * z, int min, int max)
|
||||||
{ int ch = z->p[z->c - 1];
|
{
|
||||||
|
if (z->c <= z->lb)
|
||||||
|
return 0;
|
||||||
|
{
|
||||||
|
int ch = z->p[z->c - 1];
|
||||||
|
|
||||||
if
|
if
|
||||||
(ch > max || ch < min) return 0;
|
(ch > max || ch < min)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
z->c--; return 1;
|
z->c--;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int out_range(struct SN_env * z, int min, int max)
|
extern int
|
||||||
{ if (z->c >= z->l) return 0;
|
out_range(struct SN_env * z, int min, int max)
|
||||||
{ int ch = z->p[z->c];
|
{
|
||||||
|
if (z->c >= z->l)
|
||||||
|
return 0;
|
||||||
|
{
|
||||||
|
int ch = z->p[z->c];
|
||||||
|
|
||||||
unless
|
unless
|
||||||
(ch > max || ch < min) return 0;
|
(ch > max || ch < min) return 0;
|
||||||
}
|
}
|
||||||
z->c++; return 1;
|
z->c++;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int out_range_b(struct SN_env * z, int min, int max)
|
extern int
|
||||||
{ if (z->c <= z->lb) return 0;
|
out_range_b(struct SN_env * z, int min, int max)
|
||||||
{ int ch = z->p[z->c - 1];
|
{
|
||||||
|
if (z->c <= z->lb)
|
||||||
|
return 0;
|
||||||
|
{
|
||||||
|
int ch = z->p[z->c - 1];
|
||||||
|
|
||||||
unless
|
unless
|
||||||
(ch > max || ch < min) return 0;
|
(ch > max || ch < min) return 0;
|
||||||
}
|
}
|
||||||
z->c--; return 1;
|
z->c--;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int eq_s(struct SN_env * z, int s_size, symbol * s)
|
extern int
|
||||||
{ if (z->l - z->c < s_size ||
|
eq_s(struct SN_env * z, int s_size, symbol * s)
|
||||||
memcmp(z->p + z->c, s, s_size * sizeof(symbol)) != 0) return 0;
|
{
|
||||||
z->c += s_size; return 1;
|
if (z->l - z->c < s_size ||
|
||||||
|
memcmp(z->p + z->c, s, s_size * sizeof(symbol)) != 0)
|
||||||
|
return 0;
|
||||||
|
z->c += s_size;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int eq_s_b(struct SN_env * z, int s_size, symbol * s)
|
extern int
|
||||||
{ if (z->c - z->lb < s_size ||
|
eq_s_b(struct SN_env * z, int s_size, symbol * s)
|
||||||
memcmp(z->p + z->c - s_size, s, s_size * sizeof(symbol)) != 0) return 0;
|
{
|
||||||
z->c -= s_size; return 1;
|
if (z->c - z->lb < s_size ||
|
||||||
|
memcmp(z->p + z->c - s_size, s, s_size * sizeof(symbol)) != 0)
|
||||||
|
return 0;
|
||||||
|
z->c -= s_size;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int eq_v(struct SN_env * z, symbol * p)
|
extern int
|
||||||
{ return eq_s(z, SIZE(p), p);
|
eq_v(struct SN_env * z, symbol * p)
|
||||||
|
{
|
||||||
|
return eq_s(z, SIZE(p), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int eq_v_b(struct SN_env * z, symbol * p)
|
extern int
|
||||||
{ return eq_s_b(z, SIZE(p), p);
|
eq_v_b(struct SN_env * z, symbol * p)
|
||||||
|
{
|
||||||
|
return eq_s_b(z, SIZE(p), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int find_among(struct SN_env * z, struct among * v, int v_size)
|
extern int
|
||||||
|
find_among(struct SN_env * z, struct among * v, int v_size)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = v_size;
|
int j = v_size;
|
||||||
|
|
||||||
int c = z->c; int l = z->l;
|
int c = z->c;
|
||||||
|
int l = z->l;
|
||||||
symbol *q = z->p + c;
|
symbol *q = z->p + c;
|
||||||
|
|
||||||
struct among *w;
|
struct among *w;
|
||||||
@ -131,54 +203,88 @@ extern int find_among(struct SN_env * z, struct among * v, int v_size)
|
|||||||
int first_key_inspected = 0;
|
int first_key_inspected = 0;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{ int k = i + ((j - i) >> 1);
|
{
|
||||||
|
int k = i + ((j - i) >> 1);
|
||||||
int diff = 0;
|
int diff = 0;
|
||||||
int common = common_i < common_j ? common_i : common_j; /* smaller */
|
int common = common_i < common_j ? common_i : common_j; /* smaller */
|
||||||
|
|
||||||
w = v + k;
|
w = v + k;
|
||||||
{ int i; for (i = common; i < w->s_size; i++)
|
{
|
||||||
{ if (c + common == l) { diff = -1; break; }
|
int i;
|
||||||
|
|
||||||
|
for (i = common; i < w->s_size; i++)
|
||||||
|
{
|
||||||
|
if (c + common == l)
|
||||||
|
{
|
||||||
|
diff = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
diff = q[common] - w->s[i];
|
diff = q[common] - w->s[i];
|
||||||
if (diff != 0) break;
|
if (diff != 0)
|
||||||
|
break;
|
||||||
common++;
|
common++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (diff < 0) { j = k; common_j = common; }
|
if (diff < 0)
|
||||||
else { i = k; common_i = common; }
|
{
|
||||||
|
j = k;
|
||||||
|
common_j = common;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = k;
|
||||||
|
common_i = common;
|
||||||
|
}
|
||||||
if (j - i <= 1)
|
if (j - i <= 1)
|
||||||
{ if (i > 0) break; /* v->s has been inspected */
|
{
|
||||||
if (j == i) break; /* only one item in v */
|
if (i > 0)
|
||||||
|
break; /* v->s has been inspected */
|
||||||
|
if (j == i)
|
||||||
|
break; /* only one item in v */
|
||||||
|
|
||||||
/* - but now we need to go round once more to get
|
/*
|
||||||
v->s inspected. This looks messy, but is actually
|
* - but now we need to go round once more to get v->s
|
||||||
the optimal approach. */
|
* inspected. This looks messy, but is actually the optimal
|
||||||
|
* approach.
|
||||||
|
*/
|
||||||
|
|
||||||
if (first_key_inspected) break;
|
if (first_key_inspected)
|
||||||
|
break;
|
||||||
first_key_inspected = 1;
|
first_key_inspected = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (1)
|
while (1)
|
||||||
{ w = v + i;
|
{
|
||||||
|
w = v + i;
|
||||||
if (common_i >= w->s_size)
|
if (common_i >= w->s_size)
|
||||||
{ z->c = c + w->s_size;
|
{
|
||||||
if (w->function == 0) return w->result;
|
|
||||||
{ int res = w->function(z);
|
|
||||||
z->c = c + w->s_size;
|
z->c = c + w->s_size;
|
||||||
if (res) return w->result;
|
if (w->function == 0)
|
||||||
|
return w->result;
|
||||||
|
{
|
||||||
|
int res = w->function(z);
|
||||||
|
|
||||||
|
z->c = c + w->s_size;
|
||||||
|
if (res)
|
||||||
|
return w->result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i = w->substring_i;
|
i = w->substring_i;
|
||||||
if (i < 0) return 0;
|
if (i < 0)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find_among_b is for backwards processing. Same comments apply */
|
/* find_among_b is for backwards processing. Same comments apply */
|
||||||
|
|
||||||
extern int find_among_b(struct SN_env * z, struct among * v, int v_size)
|
extern int
|
||||||
|
find_among_b(struct SN_env * z, struct among * v, int v_size)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = v_size;
|
int j = v_size;
|
||||||
|
|
||||||
int c = z->c; int lb = z->lb;
|
int c = z->c;
|
||||||
|
int lb = z->lb;
|
||||||
symbol *q = z->p + c - 1;
|
symbol *q = z->p + c - 1;
|
||||||
|
|
||||||
struct among *w;
|
struct among *w;
|
||||||
@ -189,69 +295,112 @@ extern int find_among_b(struct SN_env * z, struct among * v, int v_size)
|
|||||||
int first_key_inspected = 0;
|
int first_key_inspected = 0;
|
||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{ int k = i + ((j - i) >> 1);
|
{
|
||||||
|
int k = i + ((j - i) >> 1);
|
||||||
int diff = 0;
|
int diff = 0;
|
||||||
int common = common_i < common_j ? common_i : common_j;
|
int common = common_i < common_j ? common_i : common_j;
|
||||||
|
|
||||||
w = v + k;
|
w = v + k;
|
||||||
{ int i; for (i = w->s_size - 1 - common; i >= 0; i--)
|
{
|
||||||
{ if (c - common == lb) { diff = -1; break; }
|
int i;
|
||||||
|
|
||||||
|
for (i = w->s_size - 1 - common; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (c - common == lb)
|
||||||
|
{
|
||||||
|
diff = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
diff = q[-common] - w->s[i];
|
diff = q[-common] - w->s[i];
|
||||||
if (diff != 0) break;
|
if (diff != 0)
|
||||||
|
break;
|
||||||
common++;
|
common++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (diff < 0) { j = k; common_j = common; }
|
if (diff < 0)
|
||||||
else { i = k; common_i = common; }
|
{
|
||||||
|
j = k;
|
||||||
|
common_j = common;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = k;
|
||||||
|
common_i = common;
|
||||||
|
}
|
||||||
if (j - i <= 1)
|
if (j - i <= 1)
|
||||||
{ if (i > 0) break;
|
{
|
||||||
if (j == i) break;
|
if (i > 0)
|
||||||
if (first_key_inspected) break;
|
break;
|
||||||
|
if (j == i)
|
||||||
|
break;
|
||||||
|
if (first_key_inspected)
|
||||||
|
break;
|
||||||
first_key_inspected = 1;
|
first_key_inspected = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (1)
|
while (1)
|
||||||
{ w = v + i;
|
{
|
||||||
|
w = v + i;
|
||||||
if (common_i >= w->s_size)
|
if (common_i >= w->s_size)
|
||||||
{ z->c = c - w->s_size;
|
{
|
||||||
if (w->function == 0) return w->result;
|
|
||||||
{ int res = w->function(z);
|
|
||||||
z->c = c - w->s_size;
|
z->c = c - w->s_size;
|
||||||
if (res) return w->result;
|
if (w->function == 0)
|
||||||
|
return w->result;
|
||||||
|
{
|
||||||
|
int res = w->function(z);
|
||||||
|
|
||||||
|
z->c = c - w->s_size;
|
||||||
|
if (res)
|
||||||
|
return w->result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i = w->substring_i;
|
i = w->substring_i;
|
||||||
if (i < 0) return 0;
|
if (i < 0)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern symbol * increase_size(symbol * p, int n)
|
extern symbol *
|
||||||
{ int new_size = n + 20;
|
increase_size(symbol * p, int n)
|
||||||
|
{
|
||||||
|
int new_size = n + 20;
|
||||||
symbol *q = (symbol *) (HEAD + (char *) malloc(HEAD + (new_size + 1) * sizeof(symbol)));
|
symbol *q = (symbol *) (HEAD + (char *) malloc(HEAD + (new_size + 1) * sizeof(symbol)));
|
||||||
|
|
||||||
CAPACITY(q) = new_size;
|
CAPACITY(q) = new_size;
|
||||||
memmove(q, p, CAPACITY(p) * sizeof(symbol)); lose_s(p); return q;
|
memmove(q, p, CAPACITY(p) * sizeof(symbol));
|
||||||
|
lose_s(p);
|
||||||
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* to replace symbols between c_bra and c_ket in z->p by the
|
/* to replace symbols between c_bra and c_ket in z->p by the
|
||||||
s_size symbols at s
|
s_size symbols at s
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern int replace_s(struct SN_env * z, int c_bra, int c_ket, int s_size, const symbol * s)
|
extern int
|
||||||
{ int adjustment = s_size - (c_ket - c_bra);
|
replace_s(struct SN_env * z, int c_bra, int c_ket, int s_size, const symbol * s)
|
||||||
|
{
|
||||||
|
int adjustment = s_size - (c_ket - c_bra);
|
||||||
int len = SIZE(z->p);
|
int len = SIZE(z->p);
|
||||||
|
|
||||||
if (adjustment != 0)
|
if (adjustment != 0)
|
||||||
{ if (adjustment + len > CAPACITY(z->p)) z->p = increase_size(z->p, adjustment + len);
|
{
|
||||||
|
if (adjustment + len > CAPACITY(z->p))
|
||||||
|
z->p = increase_size(z->p, adjustment + len);
|
||||||
memmove(z->p + c_ket + adjustment, z->p + c_ket, (len - c_ket) * sizeof(symbol));
|
memmove(z->p + c_ket + adjustment, z->p + c_ket, (len - c_ket) * sizeof(symbol));
|
||||||
SET_SIZE(z->p, adjustment + len);
|
SET_SIZE(z->p, adjustment + len);
|
||||||
z->l += adjustment;
|
z->l += adjustment;
|
||||||
if (z->c >= c_ket) z->c += adjustment; else
|
if (z->c >= c_ket)
|
||||||
if (z->c > c_bra) z->c = c_bra;
|
z->c += adjustment;
|
||||||
|
else if (z->c > c_bra)
|
||||||
|
z->c = c_bra;
|
||||||
}
|
}
|
||||||
unless(s_size == 0) memmove(z->p + c_bra, s, s_size * sizeof(symbol));
|
unless(s_size == 0) memmove(z->p + c_bra, s, s_size * sizeof(symbol));
|
||||||
return adjustment;
|
return adjustment;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void slice_check(struct SN_env * z)
|
static void
|
||||||
|
slice_check(struct SN_env * z)
|
||||||
{
|
{
|
||||||
if (!(0 <= z->bra &&
|
if (!(0 <= z->bra &&
|
||||||
z->bra <= z->ket &&
|
z->bra <= z->ket &&
|
||||||
@ -264,63 +413,101 @@ static void slice_check(struct SN_env * z)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void slice_from_s(struct SN_env * z, int s_size, symbol * s)
|
extern void
|
||||||
{ slice_check(z);
|
slice_from_s(struct SN_env * z, int s_size, symbol * s)
|
||||||
|
{
|
||||||
|
slice_check(z);
|
||||||
replace_s(z, z->bra, z->ket, s_size, s);
|
replace_s(z, z->bra, z->ket, s_size, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void slice_from_v(struct SN_env * z, symbol * p)
|
extern void
|
||||||
{ slice_from_s(z, SIZE(p), p);
|
slice_from_v(struct SN_env * z, symbol * p)
|
||||||
|
{
|
||||||
|
slice_from_s(z, SIZE(p), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void slice_del(struct SN_env * z)
|
extern void
|
||||||
{ slice_from_s(z, 0, 0);
|
slice_del(struct SN_env * z)
|
||||||
|
{
|
||||||
|
slice_from_s(z, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void insert_s(struct SN_env * z, int bra, int ket, int s_size, symbol * s)
|
extern void
|
||||||
{ int adjustment = replace_s(z, bra, ket, s_size, s);
|
insert_s(struct SN_env * z, int bra, int ket, int s_size, symbol * s)
|
||||||
if (bra <= z->bra) z->bra += adjustment;
|
{
|
||||||
if (bra <= z->ket) z->ket += adjustment;
|
int adjustment = replace_s(z, bra, ket, s_size, s);
|
||||||
|
|
||||||
|
if (bra <= z->bra)
|
||||||
|
z->bra += adjustment;
|
||||||
|
if (bra <= z->ket)
|
||||||
|
z->ket += adjustment;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void insert_v(struct SN_env * z, int bra, int ket, symbol * p)
|
extern void
|
||||||
{ int adjustment = replace_s(z, bra, ket, SIZE(p), p);
|
insert_v(struct SN_env * z, int bra, int ket, symbol * p)
|
||||||
if (bra <= z->bra) z->bra += adjustment;
|
{
|
||||||
if (bra <= z->ket) z->ket += adjustment;
|
int adjustment = replace_s(z, bra, ket, SIZE(p), p);
|
||||||
|
|
||||||
|
if (bra <= z->bra)
|
||||||
|
z->bra += adjustment;
|
||||||
|
if (bra <= z->ket)
|
||||||
|
z->ket += adjustment;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern symbol * slice_to(struct SN_env * z, symbol * p)
|
extern symbol *
|
||||||
{ slice_check(z);
|
slice_to(struct SN_env * z, symbol * p)
|
||||||
{ int len = z->ket - z->bra;
|
{
|
||||||
if (CAPACITY(p) < len) p = increase_size(p, len);
|
slice_check(z);
|
||||||
|
{
|
||||||
|
int len = z->ket - z->bra;
|
||||||
|
|
||||||
|
if (CAPACITY(p) < len)
|
||||||
|
p = increase_size(p, len);
|
||||||
memmove(p, z->p + z->bra, len * sizeof(symbol));
|
memmove(p, z->p + z->bra, len * sizeof(symbol));
|
||||||
SET_SIZE(p, len);
|
SET_SIZE(p, len);
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern symbol * assign_to(struct SN_env * z, symbol * p)
|
extern symbol *
|
||||||
{ int len = z->l;
|
assign_to(struct SN_env * z, symbol * p)
|
||||||
if (CAPACITY(p) < len) p = increase_size(p, len);
|
{
|
||||||
|
int len = z->l;
|
||||||
|
|
||||||
|
if (CAPACITY(p) < len)
|
||||||
|
p = increase_size(p, len);
|
||||||
memmove(p, z->p, len * sizeof(symbol));
|
memmove(p, z->p, len * sizeof(symbol));
|
||||||
SET_SIZE(p, len);
|
SET_SIZE(p, len);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void debug(struct SN_env * z, int number, int line_count)
|
extern void
|
||||||
{ int i;
|
debug(struct SN_env * z, int number, int line_count)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
int limit = SIZE(z->p);
|
int limit = SIZE(z->p);
|
||||||
|
|
||||||
/* if (number >= 0) printf("%3d (line %4d): '", number, line_count); */
|
/* if (number >= 0) printf("%3d (line %4d): '", number, line_count); */
|
||||||
if (number >= 0) printf("%3d (line %4d): [%d]'", number, line_count,limit);
|
if (number >= 0)
|
||||||
|
printf("%3d (line %4d): [%d]'", number, line_count, limit);
|
||||||
for (i = 0; i <= limit; i++)
|
for (i = 0; i <= limit; i++)
|
||||||
{ if (z->lb == i) printf("{");
|
{
|
||||||
if (z->bra == i) printf("[");
|
if (z->lb == i)
|
||||||
if (z->c == i) printf("|");
|
printf("{");
|
||||||
if (z->ket == i) printf("]");
|
if (z->bra == i)
|
||||||
if (z->l == i) printf("}");
|
printf("[");
|
||||||
|
if (z->c == i)
|
||||||
|
printf("|");
|
||||||
|
if (z->ket == i)
|
||||||
|
printf("]");
|
||||||
|
if (z->l == i)
|
||||||
|
printf("}");
|
||||||
if (i < limit)
|
if (i < limit)
|
||||||
{ int ch = z->p[i];
|
{
|
||||||
if (ch == 0) ch = '#';
|
int ch = z->p[i];
|
||||||
|
|
||||||
|
if (ch == 0)
|
||||||
|
ch = '#';
|
||||||
printf("%c", ch);
|
printf("%c", ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,9 +14,12 @@
|
|||||||
#define STOPBUFLEN 4096
|
#define STOPBUFLEN 4096
|
||||||
|
|
||||||
char *
|
char *
|
||||||
lowerstr(char *str) {
|
lowerstr(char *str)
|
||||||
|
{
|
||||||
char *ptr = str;
|
char *ptr = str;
|
||||||
while(*ptr) {
|
|
||||||
|
while (*ptr)
|
||||||
|
{
|
||||||
*ptr = tolower(*(unsigned char *) ptr);
|
*ptr = tolower(*(unsigned char *) ptr);
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
@ -24,22 +27,29 @@ lowerstr(char *str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
freestoplist(StopList *s) {
|
freestoplist(StopList * s)
|
||||||
|
{
|
||||||
char **ptr = s->stop;
|
char **ptr = s->stop;
|
||||||
|
|
||||||
if (ptr)
|
if (ptr)
|
||||||
while( *ptr && s->len >0 ) {
|
while (*ptr && s->len > 0)
|
||||||
|
{
|
||||||
free(*ptr);
|
free(*ptr);
|
||||||
ptr++; s->len--;
|
ptr++;
|
||||||
|
s->len--;
|
||||||
free(s->stop);
|
free(s->stop);
|
||||||
}
|
}
|
||||||
memset(s, 0, sizeof(StopList));
|
memset(s, 0, sizeof(StopList));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
readstoplist(text *in, StopList *s) {
|
readstoplist(text *in, StopList * s)
|
||||||
|
{
|
||||||
char **stop = NULL;
|
char **stop = NULL;
|
||||||
|
|
||||||
s->len = 0;
|
s->len = 0;
|
||||||
if ( in && VARSIZE(in) - VARHDRSZ > 0 ) {
|
if (in && VARSIZE(in) - VARHDRSZ > 0)
|
||||||
|
{
|
||||||
char *filename = text2char(in);
|
char *filename = text2char(in);
|
||||||
FILE *hin = NULL;
|
FILE *hin = NULL;
|
||||||
char buf[STOPBUFLEN];
|
char buf[STOPBUFLEN];
|
||||||
@ -51,15 +61,20 @@ readstoplist(text *in, StopList *s) {
|
|||||||
errmsg("could not open file \"%s\": %m",
|
errmsg("could not open file \"%s\": %m",
|
||||||
filename)));
|
filename)));
|
||||||
|
|
||||||
while( fgets(buf,STOPBUFLEN,hin) ) {
|
while (fgets(buf, STOPBUFLEN, hin))
|
||||||
|
{
|
||||||
buf[strlen(buf) - 1] = '\0';
|
buf[strlen(buf) - 1] = '\0';
|
||||||
if ( *buf=='\0' ) continue;
|
if (*buf == '\0')
|
||||||
|
continue;
|
||||||
|
|
||||||
if ( s->len>= reallen ) {
|
if (s->len >= reallen)
|
||||||
|
{
|
||||||
char **tmp;
|
char **tmp;
|
||||||
|
|
||||||
reallen = (reallen) ? reallen * 2 : 16;
|
reallen = (reallen) ? reallen * 2 : 16;
|
||||||
tmp = (char **) realloc((void *) stop, sizeof(char *) * reallen);
|
tmp = (char **) realloc((void *) stop, sizeof(char *) * reallen);
|
||||||
if (!tmp) {
|
if (!tmp)
|
||||||
|
{
|
||||||
freestoplist(s);
|
freestoplist(s);
|
||||||
fclose(hin);
|
fclose(hin);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -70,7 +85,8 @@ readstoplist(text *in, StopList *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
stop[s->len] = strdup(buf);
|
stop[s->len] = strdup(buf);
|
||||||
if ( !stop[s->len] ) {
|
if (!stop[s->len])
|
||||||
|
{
|
||||||
freestoplist(s);
|
freestoplist(s);
|
||||||
fclose(hin);
|
fclose(hin);
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -89,21 +105,22 @@ readstoplist(text *in, StopList *s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
comparestr(const void *a, const void *b) {
|
comparestr(const void *a, const void *b)
|
||||||
|
{
|
||||||
return strcmp(*(char **) a, *(char **) b);
|
return strcmp(*(char **) a, *(char **) b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
sortstoplist(StopList *s) {
|
sortstoplist(StopList * s)
|
||||||
|
{
|
||||||
if (s->stop && s->len > 0)
|
if (s->stop && s->len > 0)
|
||||||
qsort(s->stop, s->len, sizeof(char *), comparestr);
|
qsort(s->stop, s->len, sizeof(char *), comparestr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
searchstoplist(StopList *s, char *key) {
|
searchstoplist(StopList * s, char *key)
|
||||||
|
{
|
||||||
if (s->wordop)
|
if (s->wordop)
|
||||||
key = (*(s->wordop)) (key);
|
key = (*(s->wordop)) (key);
|
||||||
return (s->stop && s->len > 0 && bsearch(&key, s->stop, s->len, sizeof(char *), comparestr)) ? true : false;
|
return (s->stop && s->len > 0 && bsearch(&key, s->stop, s->len, sizeof(char *), comparestr)) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,18 +30,22 @@ static void *plan_name2id=NULL;
|
|||||||
static Oid current_cfg_id = 0;
|
static Oid current_cfg_id = 0;
|
||||||
|
|
||||||
void
|
void
|
||||||
init_cfg(Oid id, TSCfgInfo *cfg) {
|
init_cfg(Oid id, TSCfgInfo * cfg)
|
||||||
|
{
|
||||||
Oid arg[2] = {OIDOID, OIDOID};
|
Oid arg[2] = {OIDOID, OIDOID};
|
||||||
bool isnull;
|
bool isnull;
|
||||||
Datum pars[2] = {ObjectIdGetDatum(id), ObjectIdGetDatum(id)};
|
Datum pars[2] = {ObjectIdGetDatum(id), ObjectIdGetDatum(id)};
|
||||||
int stat,i,j;
|
int stat,
|
||||||
|
i,
|
||||||
|
j;
|
||||||
text *ptr;
|
text *ptr;
|
||||||
text *prsname = NULL;
|
text *prsname = NULL;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
memset(cfg, 0, sizeof(TSCfgInfo));
|
memset(cfg, 0, sizeof(TSCfgInfo));
|
||||||
SPI_connect();
|
SPI_connect();
|
||||||
if ( !plan_getcfg ) {
|
if (!plan_getcfg)
|
||||||
|
{
|
||||||
plan_getcfg = SPI_saveplan(SPI_prepare("select prs_name from pg_ts_cfg where oid = $1", 1, arg));
|
plan_getcfg = SPI_saveplan(SPI_prepare("select prs_name from pg_ts_cfg where oid = $1", 1, arg));
|
||||||
if (!plan_getcfg)
|
if (!plan_getcfg)
|
||||||
ts_error(ERROR, "SPI_prepare() failed");
|
ts_error(ERROR, "SPI_prepare() failed");
|
||||||
@ -50,7 +54,8 @@ init_cfg(Oid id, TSCfgInfo *cfg) {
|
|||||||
stat = SPI_execp(plan_getcfg, pars, " ", 1);
|
stat = SPI_execp(plan_getcfg, pars, " ", 1);
|
||||||
if (stat < 0)
|
if (stat < 0)
|
||||||
ts_error(ERROR, "SPI_execp return %d", stat);
|
ts_error(ERROR, "SPI_execp return %d", stat);
|
||||||
if ( SPI_processed > 0 ) {
|
if (SPI_processed > 0)
|
||||||
|
{
|
||||||
prsname = (text *) DatumGetPointer(
|
prsname = (text *) DatumGetPointer(
|
||||||
SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)
|
SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)
|
||||||
);
|
);
|
||||||
@ -59,11 +64,13 @@ init_cfg(Oid id, TSCfgInfo *cfg) {
|
|||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
cfg->id = id;
|
cfg->id = id;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ts_error(ERROR, "No tsearch cfg with id %d", id);
|
ts_error(ERROR, "No tsearch cfg with id %d", id);
|
||||||
|
|
||||||
arg[0] = TEXTOID;
|
arg[0] = TEXTOID;
|
||||||
if ( !plan_getmap ) {
|
if (!plan_getmap)
|
||||||
|
{
|
||||||
plan_getmap = SPI_saveplan(SPI_prepare("select lt.tokid, pg_ts_cfgmap.dict_name from pg_ts_cfgmap, pg_ts_cfg, token_type( $1 ) as lt where lt.alias = pg_ts_cfgmap.tok_alias and pg_ts_cfgmap.ts_name = pg_ts_cfg.ts_name and pg_ts_cfg.oid= $2 order by lt.tokid desc;", 2, arg));
|
plan_getmap = SPI_saveplan(SPI_prepare("select lt.tokid, pg_ts_cfgmap.dict_name from pg_ts_cfgmap, pg_ts_cfg, token_type( $1 ) as lt where lt.alias = pg_ts_cfgmap.tok_alias and pg_ts_cfgmap.ts_name = pg_ts_cfg.ts_name and pg_ts_cfg.oid= $2 order by lt.tokid desc;", 2, arg));
|
||||||
if (!plan_getmap)
|
if (!plan_getmap)
|
||||||
ts_error(ERROR, "SPI_prepare() failed");
|
ts_error(ERROR, "SPI_prepare() failed");
|
||||||
@ -76,12 +83,14 @@ init_cfg(Oid id, TSCfgInfo *cfg) {
|
|||||||
if (SPI_processed <= 0)
|
if (SPI_processed <= 0)
|
||||||
ts_error(ERROR, "No parser with id %d", id);
|
ts_error(ERROR, "No parser with id %d", id);
|
||||||
|
|
||||||
for(i=0;i<SPI_processed;i++) {
|
for (i = 0; i < SPI_processed; i++)
|
||||||
|
{
|
||||||
int lexid = DatumGetInt32(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull));
|
int lexid = DatumGetInt32(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull));
|
||||||
ArrayType *toasted_a = (ArrayType *) PointerGetDatum(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull));
|
ArrayType *toasted_a = (ArrayType *) PointerGetDatum(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull));
|
||||||
ArrayType *a;
|
ArrayType *a;
|
||||||
|
|
||||||
if ( !cfg->map ) {
|
if (!cfg->map)
|
||||||
|
{
|
||||||
cfg->len = lexid + 1;
|
cfg->len = lexid + 1;
|
||||||
cfg->map = (ListDictionary *) malloc(sizeof(ListDictionary) * cfg->len);
|
cfg->map = (ListDictionary *) malloc(sizeof(ListDictionary) * cfg->len);
|
||||||
if (!cfg->map)
|
if (!cfg->map)
|
||||||
@ -106,7 +115,8 @@ init_cfg(Oid id, TSCfgInfo *cfg) {
|
|||||||
memset(cfg->map[lexid].dict_id, 0, sizeof(Datum) * cfg->map[lexid].len);
|
memset(cfg->map[lexid].dict_id, 0, sizeof(Datum) * cfg->map[lexid].len);
|
||||||
ptr = (text *) ARR_DATA_PTR(a);
|
ptr = (text *) ARR_DATA_PTR(a);
|
||||||
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
||||||
for(j=0;j<cfg->map[lexid].len;j++) {
|
for (j = 0; j < cfg->map[lexid].len; j++)
|
||||||
|
{
|
||||||
cfg->map[lexid].dict_id[j] = PointerGetDatum(ptextdup(ptr));
|
cfg->map[lexid].dict_id[j] = PointerGetDatum(ptextdup(ptr));
|
||||||
ptr = NEXTVAL(ptr);
|
ptr = NEXTVAL(ptr);
|
||||||
}
|
}
|
||||||
@ -119,8 +129,10 @@ init_cfg(Oid id, TSCfgInfo *cfg) {
|
|||||||
SPI_finish();
|
SPI_finish();
|
||||||
cfg->prs_id = name2id_prs(prsname);
|
cfg->prs_id = name2id_prs(prsname);
|
||||||
pfree(prsname);
|
pfree(prsname);
|
||||||
for(i=0;i<cfg->len;i++) {
|
for (i = 0; i < cfg->len; i++)
|
||||||
for(j=0;j<cfg->map[i].len;j++) {
|
{
|
||||||
|
for (j = 0; j < cfg->map[i].len; j++)
|
||||||
|
{
|
||||||
ptr = (text *) DatumGetPointer(cfg->map[i].dict_id[j]);
|
ptr = (text *) DatumGetPointer(cfg->map[i].dict_id[j]);
|
||||||
cfg->map[i].dict_id[j] = ObjectIdGetDatum(name2id_dict(ptr));
|
cfg->map[i].dict_id[j] = ObjectIdGetDatum(name2id_dict(ptr));
|
||||||
pfree(ptr);
|
pfree(ptr);
|
||||||
@ -128,7 +140,8 @@ init_cfg(Oid id, TSCfgInfo *cfg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
TSCfgInfo *last_cfg;
|
TSCfgInfo *last_cfg;
|
||||||
int len;
|
int len;
|
||||||
int reallen;
|
int reallen;
|
||||||
@ -139,12 +152,17 @@ typedef struct {
|
|||||||
static CFGList CList = {NULL, 0, 0, NULL, {0, 0, NULL}};
|
static CFGList CList = {NULL, 0, 0, NULL, {0, 0, NULL}};
|
||||||
|
|
||||||
void
|
void
|
||||||
reset_cfg(void) {
|
reset_cfg(void)
|
||||||
|
{
|
||||||
freeSNMap(&(CList.name2id_map));
|
freeSNMap(&(CList.name2id_map));
|
||||||
if ( CList.list ) {
|
if (CList.list)
|
||||||
int i,j;
|
{
|
||||||
|
int i,
|
||||||
|
j;
|
||||||
|
|
||||||
for (i = 0; i < CList.len; i++)
|
for (i = 0; i < CList.len; i++)
|
||||||
if ( CList.list[i].map ) {
|
if (CList.list[i].map)
|
||||||
|
{
|
||||||
for (j = 0; j < CList.list[i].len; j++)
|
for (j = 0; j < CList.list[i].len; j++)
|
||||||
if (CList.list[i].map[j].dict_id)
|
if (CList.list[i].map[j].dict_id)
|
||||||
free(CList.list[i].map[j].dict_id);
|
free(CList.list[i].map[j].dict_id);
|
||||||
@ -156,19 +174,23 @@ reset_cfg(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
comparecfg(const void *a, const void *b) {
|
comparecfg(const void *a, const void *b)
|
||||||
|
{
|
||||||
return ((TSCfgInfo *) a)->id - ((TSCfgInfo *) b)->id;
|
return ((TSCfgInfo *) a)->id - ((TSCfgInfo *) b)->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSCfgInfo *
|
TSCfgInfo *
|
||||||
findcfg(Oid id) {
|
findcfg(Oid id)
|
||||||
|
{
|
||||||
/* last used cfg */
|
/* last used cfg */
|
||||||
if (CList.last_cfg && CList.last_cfg->id == id)
|
if (CList.last_cfg && CList.last_cfg->id == id)
|
||||||
return CList.last_cfg;
|
return CList.last_cfg;
|
||||||
|
|
||||||
/* already used cfg */
|
/* already used cfg */
|
||||||
if ( CList.len != 0 ) {
|
if (CList.len != 0)
|
||||||
|
{
|
||||||
TSCfgInfo key;
|
TSCfgInfo key;
|
||||||
|
|
||||||
key.id = id;
|
key.id = id;
|
||||||
CList.last_cfg = bsearch(&key, CList.list, CList.len, sizeof(TSCfgInfo), comparecfg);
|
CList.last_cfg = bsearch(&key, CList.list, CList.len, sizeof(TSCfgInfo), comparecfg);
|
||||||
if (CList.last_cfg != NULL)
|
if (CList.last_cfg != NULL)
|
||||||
@ -176,9 +198,11 @@ findcfg(Oid id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* last chance */
|
/* last chance */
|
||||||
if ( CList.len==CList.reallen ) {
|
if (CList.len == CList.reallen)
|
||||||
|
{
|
||||||
TSCfgInfo *tmp;
|
TSCfgInfo *tmp;
|
||||||
int reallen = (CList.reallen) ? 2 * CList.reallen : 16;
|
int reallen = (CList.reallen) ? 2 * CList.reallen : 16;
|
||||||
|
|
||||||
tmp = (TSCfgInfo *) realloc(CList.list, sizeof(TSCfgInfo) * reallen);
|
tmp = (TSCfgInfo *) realloc(CList.list, sizeof(TSCfgInfo) * reallen);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
ts_error(ERROR, "No memory");
|
ts_error(ERROR, "No memory");
|
||||||
@ -194,7 +218,8 @@ findcfg(Oid id) {
|
|||||||
|
|
||||||
|
|
||||||
Oid
|
Oid
|
||||||
name2id_cfg(text *name) {
|
name2id_cfg(text *name)
|
||||||
|
{
|
||||||
Oid arg[1] = {TEXTOID};
|
Oid arg[1] = {TEXTOID};
|
||||||
bool isnull;
|
bool isnull;
|
||||||
Datum pars[1] = {PointerGetDatum(name)};
|
Datum pars[1] = {PointerGetDatum(name)};
|
||||||
@ -205,7 +230,8 @@ name2id_cfg(text *name) {
|
|||||||
return id;
|
return id;
|
||||||
|
|
||||||
SPI_connect();
|
SPI_connect();
|
||||||
if ( !plan_name2id ) {
|
if (!plan_name2id)
|
||||||
|
{
|
||||||
plan_name2id = SPI_saveplan(SPI_prepare("select oid from pg_ts_cfg where ts_name = $1", 1, arg));
|
plan_name2id = SPI_saveplan(SPI_prepare("select oid from pg_ts_cfg where ts_name = $1", 1, arg));
|
||||||
if (!plan_name2id)
|
if (!plan_name2id)
|
||||||
/* internal error */
|
/* internal error */
|
||||||
@ -216,13 +242,15 @@ name2id_cfg(text *name) {
|
|||||||
if (stat < 0)
|
if (stat < 0)
|
||||||
/* internal error */
|
/* internal error */
|
||||||
elog(ERROR, "SPI_execp return %d", stat);
|
elog(ERROR, "SPI_execp return %d", stat);
|
||||||
if ( SPI_processed > 0 ) {
|
if (SPI_processed > 0)
|
||||||
|
{
|
||||||
id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
||||||
if (isnull)
|
if (isnull)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||||
errmsg("null id for tsearch config")));
|
errmsg("null id for tsearch config")));
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||||
errmsg("no tsearch config")));
|
errmsg("no tsearch config")));
|
||||||
@ -234,8 +262,11 @@ name2id_cfg(text *name) {
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
parsetext_v2(TSCfgInfo *cfg, PRSTEXT * prs, char *buf, int4 buflen) {
|
parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
|
||||||
int type, lenlemm, i;
|
{
|
||||||
|
int type,
|
||||||
|
lenlemm,
|
||||||
|
i;
|
||||||
char *lemm = NULL;
|
char *lemm = NULL;
|
||||||
WParserInfo *prsobj = findprs(cfg->prs_id);
|
WParserInfo *prsobj = findprs(cfg->prs_id);
|
||||||
|
|
||||||
@ -251,7 +282,8 @@ parsetext_v2(TSCfgInfo *cfg, PRSTEXT * prs, char *buf, int4 buflen) {
|
|||||||
&(prsobj->getlexeme_info),
|
&(prsobj->getlexeme_info),
|
||||||
PointerGetDatum(prsobj->prs),
|
PointerGetDatum(prsobj->prs),
|
||||||
PointerGetDatum(&lemm),
|
PointerGetDatum(&lemm),
|
||||||
PointerGetDatum(&lenlemm))) ) != 0 ) {
|
PointerGetDatum(&lenlemm)))) != 0)
|
||||||
|
{
|
||||||
|
|
||||||
if (lenlemm >= MAXSTRLEN)
|
if (lenlemm >= MAXSTRLEN)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -261,9 +293,11 @@ parsetext_v2(TSCfgInfo *cfg, PRSTEXT * prs, char *buf, int4 buflen) {
|
|||||||
if (type >= cfg->len) /* skip this type of lexem */
|
if (type >= cfg->len) /* skip this type of lexem */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for(i=0;i<cfg->map[type].len;i++) {
|
for (i = 0; i < cfg->map[type].len; i++)
|
||||||
|
{
|
||||||
DictInfo *dict = finddict(DatumGetObjectId(cfg->map[type].dict_id[i]));
|
DictInfo *dict = finddict(DatumGetObjectId(cfg->map[type].dict_id[i]));
|
||||||
char **norms, **ptr;
|
char **norms,
|
||||||
|
**ptr;
|
||||||
|
|
||||||
norms = ptr = (char **) DatumGetPointer(
|
norms = ptr = (char **) DatumGetPointer(
|
||||||
FunctionCall3(
|
FunctionCall3(
|
||||||
@ -278,8 +312,10 @@ parsetext_v2(TSCfgInfo *cfg, PRSTEXT * prs, char *buf, int4 buflen) {
|
|||||||
|
|
||||||
prs->pos++; /* set pos */
|
prs->pos++; /* set pos */
|
||||||
|
|
||||||
while( *ptr ) {
|
while (*ptr)
|
||||||
if (prs->curwords == prs->lenwords) {
|
{
|
||||||
|
if (prs->curwords == prs->lenwords)
|
||||||
|
{
|
||||||
prs->lenwords *= 2;
|
prs->lenwords *= 2;
|
||||||
prs->words = (WORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(WORD));
|
prs->words = (WORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(WORD));
|
||||||
}
|
}
|
||||||
@ -292,7 +328,8 @@ parsetext_v2(TSCfgInfo *cfg, PRSTEXT * prs, char *buf, int4 buflen) {
|
|||||||
prs->curwords++;
|
prs->curwords++;
|
||||||
}
|
}
|
||||||
pfree(norms);
|
pfree(norms);
|
||||||
break; /* lexem already normalized or is stop word*/
|
break; /* lexem already normalized or is stop
|
||||||
|
* word */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -303,8 +340,10 @@ parsetext_v2(TSCfgInfo *cfg, PRSTEXT * prs, char *buf, int4 buflen) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
hladdword(HLPRSTEXT * prs, char *buf, int4 buflen, int type) {
|
hladdword(HLPRSTEXT * prs, char *buf, int4 buflen, int type)
|
||||||
while (prs->curwords >= prs->lenwords) {
|
{
|
||||||
|
while (prs->curwords >= prs->lenwords)
|
||||||
|
{
|
||||||
prs->lenwords *= 2;
|
prs->lenwords *= 2;
|
||||||
prs->words = (HLWORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(HLWORD));
|
prs->words = (HLWORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(HLWORD));
|
||||||
}
|
}
|
||||||
@ -317,24 +356,30 @@ hladdword(HLPRSTEXT * prs, char *buf, int4 buflen, int type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
hlfinditem(HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int buflen ) {
|
hlfinditem(HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int buflen)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
ITEM *item = GETQUERY(query);
|
ITEM *item = GETQUERY(query);
|
||||||
HLWORD *word = &(prs->words[prs->curwords - 1]);
|
HLWORD *word = &(prs->words[prs->curwords - 1]);
|
||||||
|
|
||||||
while (prs->curwords + query->size >= prs->lenwords) {
|
while (prs->curwords + query->size >= prs->lenwords)
|
||||||
|
{
|
||||||
prs->lenwords *= 2;
|
prs->lenwords *= 2;
|
||||||
prs->words = (HLWORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(HLWORD));
|
prs->words = (HLWORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(HLWORD));
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=0; i<query->size; i++) {
|
for (i = 0; i < query->size; i++)
|
||||||
if ( item->type == VAL && item->length == buflen && strncmp( GETOPERAND(query) + item->distance, buf, buflen )==0 ) {
|
{
|
||||||
if ( word->item ) {
|
if (item->type == VAL && item->length == buflen && strncmp(GETOPERAND(query) + item->distance, buf, buflen) == 0)
|
||||||
|
{
|
||||||
|
if (word->item)
|
||||||
|
{
|
||||||
memcpy(&(prs->words[prs->curwords]), word, sizeof(HLWORD));
|
memcpy(&(prs->words[prs->curwords]), word, sizeof(HLWORD));
|
||||||
prs->words[prs->curwords].item = item;
|
prs->words[prs->curwords].item = item;
|
||||||
prs->words[prs->curwords].repeated = 1;
|
prs->words[prs->curwords].repeated = 1;
|
||||||
prs->curwords++;
|
prs->curwords++;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
word->item = item;
|
word->item = item;
|
||||||
}
|
}
|
||||||
item++;
|
item++;
|
||||||
@ -342,8 +387,11 @@ hlfinditem(HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int buflen ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
hlparsetext(TSCfgInfo *cfg, HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int4 buflen) {
|
hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4 buflen)
|
||||||
int type, lenlemm, i;
|
{
|
||||||
|
int type,
|
||||||
|
lenlemm,
|
||||||
|
i;
|
||||||
char *lemm = NULL;
|
char *lemm = NULL;
|
||||||
WParserInfo *prsobj = findprs(cfg->prs_id);
|
WParserInfo *prsobj = findprs(cfg->prs_id);
|
||||||
|
|
||||||
@ -359,7 +407,8 @@ hlparsetext(TSCfgInfo *cfg, HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int4 b
|
|||||||
&(prsobj->getlexeme_info),
|
&(prsobj->getlexeme_info),
|
||||||
PointerGetDatum(prsobj->prs),
|
PointerGetDatum(prsobj->prs),
|
||||||
PointerGetDatum(&lemm),
|
PointerGetDatum(&lemm),
|
||||||
PointerGetDatum(&lenlemm))) ) != 0 ) {
|
PointerGetDatum(&lenlemm)))) != 0)
|
||||||
|
{
|
||||||
|
|
||||||
if (lenlemm >= MAXSTRLEN)
|
if (lenlemm >= MAXSTRLEN)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -371,9 +420,11 @@ hlparsetext(TSCfgInfo *cfg, HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int4 b
|
|||||||
if (type >= cfg->len)
|
if (type >= cfg->len)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for(i=0;i<cfg->map[type].len;i++) {
|
for (i = 0; i < cfg->map[type].len; i++)
|
||||||
|
{
|
||||||
DictInfo *dict = finddict(DatumGetObjectId(cfg->map[type].dict_id[i]));
|
DictInfo *dict = finddict(DatumGetObjectId(cfg->map[type].dict_id[i]));
|
||||||
char **norms, **ptr;
|
char **norms,
|
||||||
|
**ptr;
|
||||||
|
|
||||||
norms = ptr = (char **) DatumGetPointer(
|
norms = ptr = (char **) DatumGetPointer(
|
||||||
FunctionCall3(
|
FunctionCall3(
|
||||||
@ -386,13 +437,15 @@ hlparsetext(TSCfgInfo *cfg, HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int4 b
|
|||||||
if (!norms) /* dictionary doesn't know this lexem */
|
if (!norms) /* dictionary doesn't know this lexem */
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
while( *ptr ) {
|
while (*ptr)
|
||||||
|
{
|
||||||
hlfinditem(prs, query, *ptr, strlen(*ptr));
|
hlfinditem(prs, query, *ptr, strlen(*ptr));
|
||||||
pfree(*ptr);
|
pfree(*ptr);
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
pfree(norms);
|
pfree(norms);
|
||||||
break; /* lexem already normalized or is stop word*/
|
break; /* lexem already normalized or is stop
|
||||||
|
* word */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +456,8 @@ hlparsetext(TSCfgInfo *cfg, HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int4 b
|
|||||||
}
|
}
|
||||||
|
|
||||||
text *
|
text *
|
||||||
genhl(HLPRSTEXT * prs) {
|
genhl(HLPRSTEXT * prs)
|
||||||
|
{
|
||||||
text *out;
|
text *out;
|
||||||
int len = 128;
|
int len = 128;
|
||||||
char *ptr;
|
char *ptr;
|
||||||
@ -412,26 +466,35 @@ genhl(HLPRSTEXT * prs) {
|
|||||||
out = (text *) palloc(len);
|
out = (text *) palloc(len);
|
||||||
ptr = ((char *) out) + VARHDRSZ;
|
ptr = ((char *) out) + VARHDRSZ;
|
||||||
|
|
||||||
while( wrd - prs->words < prs->curwords ) {
|
while (wrd - prs->words < prs->curwords)
|
||||||
while ( wrd->len + prs->stopsellen + prs->startsellen + (ptr - ((char*)out)) >= len ) {
|
{
|
||||||
|
while (wrd->len + prs->stopsellen + prs->startsellen + (ptr - ((char *) out)) >= len)
|
||||||
|
{
|
||||||
int dist = ptr - ((char *) out);
|
int dist = ptr - ((char *) out);
|
||||||
|
|
||||||
len *= 2;
|
len *= 2;
|
||||||
out = (text *) repalloc(out, len);
|
out = (text *) repalloc(out, len);
|
||||||
ptr = ((char *) out) + dist;
|
ptr = ((char *) out) + dist;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( wrd->in && !wrd->skip && !wrd->repeated ) {
|
if (wrd->in && !wrd->skip && !wrd->repeated)
|
||||||
if ( wrd->replace ) {
|
{
|
||||||
|
if (wrd->replace)
|
||||||
|
{
|
||||||
*ptr = ' ';
|
*ptr = ' ';
|
||||||
ptr++;
|
ptr++;
|
||||||
} else {
|
}
|
||||||
if (wrd->selected) {
|
else
|
||||||
|
{
|
||||||
|
if (wrd->selected)
|
||||||
|
{
|
||||||
memcpy(ptr, prs->startsel, prs->startsellen);
|
memcpy(ptr, prs->startsel, prs->startsellen);
|
||||||
ptr += prs->startsellen;
|
ptr += prs->startsellen;
|
||||||
}
|
}
|
||||||
memcpy(ptr, wrd->word, wrd->len);
|
memcpy(ptr, wrd->word, wrd->len);
|
||||||
ptr += wrd->len;
|
ptr += wrd->len;
|
||||||
if (wrd->selected) {
|
if (wrd->selected)
|
||||||
|
{
|
||||||
memcpy(ptr, prs->stopsel, prs->stopsellen);
|
memcpy(ptr, prs->stopsel, prs->stopsellen);
|
||||||
ptr += prs->stopsellen;
|
ptr += prs->stopsellen;
|
||||||
}
|
}
|
||||||
@ -449,7 +512,8 @@ genhl(HLPRSTEXT * prs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
get_currcfg(void) {
|
get_currcfg(void)
|
||||||
|
{
|
||||||
Oid arg[1] = {TEXTOID};
|
Oid arg[1] = {TEXTOID};
|
||||||
const char *curlocale;
|
const char *curlocale;
|
||||||
Datum pars[1];
|
Datum pars[1];
|
||||||
@ -460,7 +524,8 @@ get_currcfg(void) {
|
|||||||
return current_cfg_id;
|
return current_cfg_id;
|
||||||
|
|
||||||
SPI_connect();
|
SPI_connect();
|
||||||
if ( !plan_getcfg_bylocale ) {
|
if (!plan_getcfg_bylocale)
|
||||||
|
{
|
||||||
plan_getcfg_bylocale = SPI_saveplan(SPI_prepare("select oid from pg_ts_cfg where locale = $1 ", 1, arg));
|
plan_getcfg_bylocale = SPI_saveplan(SPI_prepare("select oid from pg_ts_cfg where locale = $1 ", 1, arg));
|
||||||
if (!plan_getcfg_bylocale)
|
if (!plan_getcfg_bylocale)
|
||||||
/* internal error */
|
/* internal error */
|
||||||
@ -489,7 +554,8 @@ get_currcfg(void) {
|
|||||||
PG_FUNCTION_INFO_V1(set_curcfg);
|
PG_FUNCTION_INFO_V1(set_curcfg);
|
||||||
Datum set_curcfg(PG_FUNCTION_ARGS);
|
Datum set_curcfg(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
set_curcfg(PG_FUNCTION_ARGS) {
|
set_curcfg(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
findcfg(PG_GETARG_OID(0));
|
findcfg(PG_GETARG_OID(0));
|
||||||
current_cfg_id = PG_GETARG_OID(0);
|
current_cfg_id = PG_GETARG_OID(0);
|
||||||
PG_RETURN_VOID();
|
PG_RETURN_VOID();
|
||||||
@ -498,7 +564,8 @@ set_curcfg(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(set_curcfg_byname);
|
PG_FUNCTION_INFO_V1(set_curcfg_byname);
|
||||||
Datum set_curcfg_byname(PG_FUNCTION_ARGS);
|
Datum set_curcfg_byname(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
set_curcfg_byname(PG_FUNCTION_ARGS) {
|
set_curcfg_byname(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
text *name = PG_GETARG_TEXT_P(0);
|
text *name = PG_GETARG_TEXT_P(0);
|
||||||
|
|
||||||
DirectFunctionCall1(
|
DirectFunctionCall1(
|
||||||
@ -512,14 +579,16 @@ set_curcfg_byname(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(show_curcfg);
|
PG_FUNCTION_INFO_V1(show_curcfg);
|
||||||
Datum show_curcfg(PG_FUNCTION_ARGS);
|
Datum show_curcfg(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
show_curcfg(PG_FUNCTION_ARGS) {
|
show_curcfg(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
PG_RETURN_OID(get_currcfg());
|
PG_RETURN_OID(get_currcfg());
|
||||||
}
|
}
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(reset_tsearch);
|
PG_FUNCTION_INFO_V1(reset_tsearch);
|
||||||
Datum reset_tsearch(PG_FUNCTION_ARGS);
|
Datum reset_tsearch(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
reset_tsearch(PG_FUNCTION_ARGS) {
|
reset_tsearch(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
ts_error(NOTICE, "TSearch cache cleaned");
|
ts_error(NOTICE, "TSearch cache cleaned");
|
||||||
PG_RETURN_VOID();
|
PG_RETURN_VOID();
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,14 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "query.h"
|
#include "query.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int len;
|
int len;
|
||||||
Datum *dict_id;
|
Datum *dict_id;
|
||||||
} ListDictionary;
|
} ListDictionary;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
Oid id;
|
Oid id;
|
||||||
Oid prs_id;
|
Oid prs_id;
|
||||||
int len;
|
int len;
|
||||||
@ -20,9 +22,11 @@ TSCfgInfo * findcfg(Oid id);
|
|||||||
void init_cfg(Oid id, TSCfgInfo * cfg);
|
void init_cfg(Oid id, TSCfgInfo * cfg);
|
||||||
void reset_cfg(void);
|
void reset_cfg(void);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
uint16 len;
|
uint16 len;
|
||||||
union {
|
union
|
||||||
|
{
|
||||||
uint16 pos;
|
uint16 pos;
|
||||||
uint16 *apos;
|
uint16 *apos;
|
||||||
} pos;
|
} pos;
|
||||||
@ -30,14 +34,16 @@ typedef struct {
|
|||||||
uint32 alen;
|
uint32 alen;
|
||||||
} WORD;
|
} WORD;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
WORD *words;
|
WORD *words;
|
||||||
int4 lenwords;
|
int4 lenwords;
|
||||||
int4 curwords;
|
int4 curwords;
|
||||||
int4 pos;
|
int4 pos;
|
||||||
} PRSTEXT;
|
} PRSTEXT;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
uint16 len;
|
uint16 len;
|
||||||
uint8 selected:1,
|
uint8 selected:1,
|
||||||
in:1,
|
in:1,
|
||||||
@ -49,7 +55,8 @@ typedef struct {
|
|||||||
ITEM *item;
|
ITEM *item;
|
||||||
} HLWORD;
|
} HLWORD;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
HLWORD *words;
|
HLWORD *words;
|
||||||
int4 lenwords;
|
int4 lenwords;
|
||||||
int4 curwords;
|
int4 curwords;
|
||||||
|
@ -12,8 +12,10 @@
|
|||||||
PG_FUNCTION_INFO_V1(tsstat_in);
|
PG_FUNCTION_INFO_V1(tsstat_in);
|
||||||
Datum tsstat_in(PG_FUNCTION_ARGS);
|
Datum tsstat_in(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
tsstat_in(PG_FUNCTION_ARGS) {
|
tsstat_in(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
tsstat *stat = palloc(STATHDRSIZE);
|
tsstat *stat = palloc(STATHDRSIZE);
|
||||||
|
|
||||||
stat->len = STATHDRSIZE;
|
stat->len = STATHDRSIZE;
|
||||||
stat->size = 0;
|
stat->size = 0;
|
||||||
PG_RETURN_POINTER(stat);
|
PG_RETURN_POINTER(stat);
|
||||||
@ -22,7 +24,8 @@ tsstat_in(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(tsstat_out);
|
PG_FUNCTION_INFO_V1(tsstat_out);
|
||||||
Datum tsstat_out(PG_FUNCTION_ARGS);
|
Datum tsstat_out(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
tsstat_out(PG_FUNCTION_ARGS) {
|
tsstat_out(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
errmsg("tsstat_out not implemented")));
|
errmsg("tsstat_out not implemented")));
|
||||||
@ -30,11 +33,15 @@ tsstat_out(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static WordEntry **
|
static WordEntry **
|
||||||
SEI_realloc( WordEntry** in, uint32 *len ) {
|
SEI_realloc(WordEntry ** in, uint32 *len)
|
||||||
if ( *len==0 || in==NULL ) {
|
{
|
||||||
|
if (*len == 0 || in == NULL)
|
||||||
|
{
|
||||||
*len = 8;
|
*len = 8;
|
||||||
in = palloc(sizeof(WordEntry *) * (*len));
|
in = palloc(sizeof(WordEntry *) * (*len));
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
*len *= 2;
|
*len *= 2;
|
||||||
in = repalloc(in, sizeof(WordEntry *) * (*len));
|
in = repalloc(in, sizeof(WordEntry *) * (*len));
|
||||||
}
|
}
|
||||||
@ -42,7 +49,8 @@ SEI_realloc( WordEntry** in, uint32 *len ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
compareStatWord(StatEntry *a, WordEntry *b, tsstat *stat, tsvector *txt) {
|
compareStatWord(StatEntry * a, WordEntry * b, tsstat * stat, tsvector * txt)
|
||||||
|
{
|
||||||
if (a->len == b->len)
|
if (a->len == b->len)
|
||||||
return strncmp(
|
return strncmp(
|
||||||
STATSTRPTR(stat) + a->pos,
|
STATSTRPTR(stat) + a->pos,
|
||||||
@ -53,15 +61,19 @@ compareStatWord(StatEntry *a, WordEntry *b, tsstat *stat, tsvector *txt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static tsstat *
|
static tsstat *
|
||||||
formstat(tsstat *stat, tsvector *txt, WordEntry** entry, uint32 len) {
|
formstat(tsstat * stat, tsvector * txt, WordEntry ** entry, uint32 len)
|
||||||
|
{
|
||||||
tsstat *newstat;
|
tsstat *newstat;
|
||||||
uint32 totallen, nentry;
|
uint32 totallen,
|
||||||
|
nentry;
|
||||||
uint32 slen = 0;
|
uint32 slen = 0;
|
||||||
WordEntry **ptr = entry;
|
WordEntry **ptr = entry;
|
||||||
char *curptr;
|
char *curptr;
|
||||||
StatEntry *sptr,*nptr;
|
StatEntry *sptr,
|
||||||
|
*nptr;
|
||||||
|
|
||||||
while(ptr-entry<len) {
|
while (ptr - entry < len)
|
||||||
|
{
|
||||||
slen += (*ptr)->len;
|
slen += (*ptr)->len;
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
@ -80,11 +92,13 @@ formstat(tsstat *stat, tsvector *txt, WordEntry** entry, uint32 len) {
|
|||||||
sptr = STATPTR(stat);
|
sptr = STATPTR(stat);
|
||||||
nptr = STATPTR(newstat);
|
nptr = STATPTR(newstat);
|
||||||
|
|
||||||
if ( len == 1 ) {
|
if (len == 1)
|
||||||
|
{
|
||||||
StatEntry *StopLow = STATPTR(stat);
|
StatEntry *StopLow = STATPTR(stat);
|
||||||
StatEntry *StopHigh = (StatEntry *) STATSTRPTR(stat);
|
StatEntry *StopHigh = (StatEntry *) STATSTRPTR(stat);
|
||||||
|
|
||||||
while (StopLow < StopHigh) {
|
while (StopLow < StopHigh)
|
||||||
|
{
|
||||||
sptr = StopLow + (StopHigh - StopLow) / 2;
|
sptr = StopLow + (StopHigh - StopLow) / 2;
|
||||||
if (compareStatWord(sptr, *ptr, stat, txt) < 0)
|
if (compareStatWord(sptr, *ptr, stat, txt) < 0)
|
||||||
StopLow = sptr + 1;
|
StopLow = sptr + 1;
|
||||||
@ -101,12 +115,18 @@ formstat(tsstat *stat, tsvector *txt, WordEntry** entry, uint32 len) {
|
|||||||
memcpy(curptr, STRPTR(txt) + (*ptr)->pos, nptr->len);
|
memcpy(curptr, STRPTR(txt) + (*ptr)->pos, nptr->len);
|
||||||
nptr->pos = curptr - STATSTRPTR(newstat);
|
nptr->pos = curptr - STATSTRPTR(newstat);
|
||||||
memcpy(nptr + 1, StopLow, sizeof(StatEntry) * (((StatEntry *) STATSTRPTR(stat)) - StopLow));
|
memcpy(nptr + 1, StopLow, sizeof(StatEntry) * (((StatEntry *) STATSTRPTR(stat)) - StopLow));
|
||||||
} else {
|
}
|
||||||
while( sptr-STATPTR(stat) < stat->size && ptr-entry<len) {
|
else
|
||||||
if ( compareStatWord(sptr,*ptr,stat,txt) < 0 ) {
|
{
|
||||||
|
while (sptr - STATPTR(stat) < stat->size && ptr - entry < len)
|
||||||
|
{
|
||||||
|
if (compareStatWord(sptr, *ptr, stat, txt) < 0)
|
||||||
|
{
|
||||||
memcpy(nptr, sptr, sizeof(StatEntry));
|
memcpy(nptr, sptr, sizeof(StatEntry));
|
||||||
sptr++;
|
sptr++;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
nptr->nentry = POSDATALEN(txt, *ptr);
|
nptr->nentry = POSDATALEN(txt, *ptr);
|
||||||
if (nptr->nentry == 0)
|
if (nptr->nentry == 0)
|
||||||
nptr->nentry = 1;
|
nptr->nentry = 1;
|
||||||
@ -122,7 +142,8 @@ formstat(tsstat *stat, tsvector *txt, WordEntry** entry, uint32 len) {
|
|||||||
|
|
||||||
memcpy(nptr, sptr, sizeof(StatEntry) * (stat->size - (sptr - STATPTR(stat))));
|
memcpy(nptr, sptr, sizeof(StatEntry) * (stat->size - (sptr - STATPTR(stat))));
|
||||||
|
|
||||||
while(ptr-entry<len) {
|
while (ptr - entry < len)
|
||||||
|
{
|
||||||
nptr->nentry = POSDATALEN(txt, *ptr);
|
nptr->nentry = POSDATALEN(txt, *ptr);
|
||||||
if (nptr->nentry == 0)
|
if (nptr->nentry == 0)
|
||||||
nptr->nentry = 1;
|
nptr->nentry = 1;
|
||||||
@ -131,7 +152,8 @@ formstat(tsstat *stat, tsvector *txt, WordEntry** entry, uint32 len) {
|
|||||||
memcpy(curptr, STRPTR(txt) + (*ptr)->pos, nptr->len);
|
memcpy(curptr, STRPTR(txt) + (*ptr)->pos, nptr->len);
|
||||||
nptr->pos = curptr - STATSTRPTR(newstat);
|
nptr->pos = curptr - STATSTRPTR(newstat);
|
||||||
curptr += nptr->len;
|
curptr += nptr->len;
|
||||||
ptr++; nptr++;
|
ptr++;
|
||||||
|
nptr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,22 +163,27 @@ formstat(tsstat *stat, tsvector *txt, WordEntry** entry, uint32 len) {
|
|||||||
PG_FUNCTION_INFO_V1(ts_accum);
|
PG_FUNCTION_INFO_V1(ts_accum);
|
||||||
Datum ts_accum(PG_FUNCTION_ARGS);
|
Datum ts_accum(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
ts_accum(PG_FUNCTION_ARGS) {
|
ts_accum(PG_FUNCTION_ARGS)
|
||||||
tsstat *newstat,*stat= (tsstat*)PG_GETARG_POINTER(0);
|
{
|
||||||
|
tsstat *newstat,
|
||||||
|
*stat = (tsstat *) PG_GETARG_POINTER(0);
|
||||||
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||||
WordEntry **newentry = NULL;
|
WordEntry **newentry = NULL;
|
||||||
uint32 len=0, cur=0;
|
uint32 len = 0,
|
||||||
|
cur = 0;
|
||||||
StatEntry *sptr;
|
StatEntry *sptr;
|
||||||
WordEntry *wptr;
|
WordEntry *wptr;
|
||||||
|
|
||||||
if ( stat==NULL || PG_ARGISNULL(0) ) { /* Init in first */
|
if (stat == NULL || PG_ARGISNULL(0))
|
||||||
|
{ /* Init in first */
|
||||||
stat = palloc(STATHDRSIZE);
|
stat = palloc(STATHDRSIZE);
|
||||||
stat->len = STATHDRSIZE;
|
stat->len = STATHDRSIZE;
|
||||||
stat->size = 0;
|
stat->size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* simple check of correctness */
|
/* simple check of correctness */
|
||||||
if ( txt==NULL || PG_ARGISNULL(1) || txt->size==0 ) {
|
if (txt == NULL || PG_ARGISNULL(1) || txt->size == 0)
|
||||||
|
{
|
||||||
PG_FREE_IF_COPY(txt, 1);
|
PG_FREE_IF_COPY(txt, 1);
|
||||||
PG_RETURN_POINTER(stat);
|
PG_RETURN_POINTER(stat);
|
||||||
}
|
}
|
||||||
@ -164,54 +191,74 @@ ts_accum(PG_FUNCTION_ARGS) {
|
|||||||
sptr = STATPTR(stat);
|
sptr = STATPTR(stat);
|
||||||
wptr = ARRPTR(txt);
|
wptr = ARRPTR(txt);
|
||||||
|
|
||||||
if ( stat->size < 100*txt->size ) { /* merge */
|
if (stat->size < 100 * txt->size)
|
||||||
while( sptr-STATPTR(stat) < stat->size && wptr-ARRPTR(txt) < txt->size ) {
|
{ /* merge */
|
||||||
|
while (sptr - STATPTR(stat) < stat->size && wptr - ARRPTR(txt) < txt->size)
|
||||||
|
{
|
||||||
int cmp = compareStatWord(sptr, wptr, stat, txt);
|
int cmp = compareStatWord(sptr, wptr, stat, txt);
|
||||||
if ( cmp<0 ) {
|
|
||||||
|
if (cmp < 0)
|
||||||
sptr++;
|
sptr++;
|
||||||
} else if ( cmp==0 ) {
|
else if (cmp == 0)
|
||||||
|
{
|
||||||
int n = POSDATALEN(txt, wptr);
|
int n = POSDATALEN(txt, wptr);
|
||||||
|
|
||||||
if (n==0) n=1;
|
if (n == 0)
|
||||||
|
n = 1;
|
||||||
sptr->ndoc++;
|
sptr->ndoc++;
|
||||||
sptr->nentry += n;
|
sptr->nentry += n;
|
||||||
sptr++; wptr++;
|
sptr++;
|
||||||
} else {
|
wptr++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
if (cur == len)
|
if (cur == len)
|
||||||
newentry = SEI_realloc(newentry, &len);
|
newentry = SEI_realloc(newentry, &len);
|
||||||
newentry[cur] = wptr;
|
newentry[cur] = wptr;
|
||||||
wptr++; cur++;
|
wptr++;
|
||||||
|
cur++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while( wptr-ARRPTR(txt) < txt->size ) {
|
while (wptr - ARRPTR(txt) < txt->size)
|
||||||
|
{
|
||||||
if (cur == len)
|
if (cur == len)
|
||||||
newentry = SEI_realloc(newentry, &len);
|
newentry = SEI_realloc(newentry, &len);
|
||||||
newentry[cur] = wptr;
|
newentry[cur] = wptr;
|
||||||
wptr++; cur++;
|
wptr++;
|
||||||
|
cur++;
|
||||||
}
|
}
|
||||||
} else { /* search */
|
}
|
||||||
while( wptr-ARRPTR(txt) < txt->size ) {
|
else
|
||||||
|
{ /* search */
|
||||||
|
while (wptr - ARRPTR(txt) < txt->size)
|
||||||
|
{
|
||||||
StatEntry *StopLow = STATPTR(stat);
|
StatEntry *StopLow = STATPTR(stat);
|
||||||
StatEntry *StopHigh = (StatEntry *) STATSTRPTR(stat);
|
StatEntry *StopHigh = (StatEntry *) STATSTRPTR(stat);
|
||||||
int cmp;
|
int cmp;
|
||||||
|
|
||||||
while (StopLow < StopHigh) {
|
while (StopLow < StopHigh)
|
||||||
|
{
|
||||||
sptr = StopLow + (StopHigh - StopLow) / 2;
|
sptr = StopLow + (StopHigh - StopLow) / 2;
|
||||||
cmp = compareStatWord(sptr, wptr, stat, txt);
|
cmp = compareStatWord(sptr, wptr, stat, txt);
|
||||||
if (cmp==0) {
|
if (cmp == 0)
|
||||||
|
{
|
||||||
int n = POSDATALEN(txt, wptr);
|
int n = POSDATALEN(txt, wptr);
|
||||||
if (n==0) n=1;
|
|
||||||
|
if (n == 0)
|
||||||
|
n = 1;
|
||||||
sptr->ndoc++;
|
sptr->ndoc++;
|
||||||
sptr->nentry += n;
|
sptr->nentry += n;
|
||||||
break;
|
break;
|
||||||
} else if ( cmp < 0 )
|
}
|
||||||
|
else if (cmp < 0)
|
||||||
StopLow = sptr + 1;
|
StopLow = sptr + 1;
|
||||||
else
|
else
|
||||||
StopHigh = sptr;
|
StopHigh = sptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( StopLow >= StopHigh ) { /* not found */
|
if (StopLow >= StopHigh)
|
||||||
|
{ /* not found */
|
||||||
if (cur == len)
|
if (cur == len)
|
||||||
newentry = SEI_realloc(newentry, &len);
|
newentry = SEI_realloc(newentry, &len);
|
||||||
newentry[cur] = wptr;
|
newentry[cur] = wptr;
|
||||||
@ -222,7 +269,8 @@ ts_accum(PG_FUNCTION_ARGS) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if ( cur==0 ) { /* no new words */
|
if (cur == 0)
|
||||||
|
{ /* no new words */
|
||||||
PG_FREE_IF_COPY(txt, 1);
|
PG_FREE_IF_COPY(txt, 1);
|
||||||
PG_RETURN_POINTER(stat);
|
PG_RETURN_POINTER(stat);
|
||||||
}
|
}
|
||||||
@ -235,13 +283,15 @@ ts_accum(PG_FUNCTION_ARGS) {
|
|||||||
PG_RETURN_POINTER(newstat);
|
PG_RETURN_POINTER(newstat);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
uint32 cur;
|
uint32 cur;
|
||||||
tsvector *stat;
|
tsvector *stat;
|
||||||
} StatStorage;
|
} StatStorage;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ts_setup_firstcall(FuncCallContext *funcctx, tsstat *stat) {
|
ts_setup_firstcall(FuncCallContext *funcctx, tsstat * stat)
|
||||||
|
{
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
StatStorage *st;
|
StatStorage *st;
|
||||||
@ -260,11 +310,14 @@ ts_setup_firstcall(FuncCallContext *funcctx, tsstat *stat) {
|
|||||||
|
|
||||||
|
|
||||||
static Datum
|
static Datum
|
||||||
ts_process_call(FuncCallContext *funcctx) {
|
ts_process_call(FuncCallContext *funcctx)
|
||||||
|
{
|
||||||
StatStorage *st;
|
StatStorage *st;
|
||||||
|
|
||||||
st = (StatStorage *) funcctx->user_fctx;
|
st = (StatStorage *) funcctx->user_fctx;
|
||||||
|
|
||||||
if ( st->cur < st->stat->size ) {
|
if (st->cur < st->stat->size)
|
||||||
|
{
|
||||||
Datum result;
|
Datum result;
|
||||||
char *values[3];
|
char *values[3];
|
||||||
char ndoc[16];
|
char ndoc[16];
|
||||||
@ -286,7 +339,9 @@ ts_process_call(FuncCallContext *funcctx) {
|
|||||||
pfree(values[0]);
|
pfree(values[0]);
|
||||||
st->cur++;
|
st->cur++;
|
||||||
return result;
|
return result;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
pfree(st->stat);
|
pfree(st->stat);
|
||||||
pfree(st);
|
pfree(st);
|
||||||
}
|
}
|
||||||
@ -297,11 +352,13 @@ ts_process_call(FuncCallContext *funcctx) {
|
|||||||
PG_FUNCTION_INFO_V1(ts_accum_finish);
|
PG_FUNCTION_INFO_V1(ts_accum_finish);
|
||||||
Datum ts_accum_finish(PG_FUNCTION_ARGS);
|
Datum ts_accum_finish(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
ts_accum_finish(PG_FUNCTION_ARGS) {
|
ts_accum_finish(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
FuncCallContext *funcctx;
|
FuncCallContext *funcctx;
|
||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
if (SRF_IS_FIRSTCALL()) {
|
if (SRF_IS_FIRSTCALL())
|
||||||
|
{
|
||||||
funcctx = SRF_FIRSTCALL_INIT();
|
funcctx = SRF_FIRSTCALL_INIT();
|
||||||
ts_setup_firstcall(funcctx, (tsstat *) PG_GETARG_POINTER(0));
|
ts_setup_firstcall(funcctx, (tsstat *) PG_GETARG_POINTER(0));
|
||||||
}
|
}
|
||||||
@ -314,7 +371,8 @@ ts_accum_finish(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
static Oid tiOid = InvalidOid;
|
static Oid tiOid = InvalidOid;
|
||||||
static void
|
static void
|
||||||
get_ti_Oid(void) {
|
get_ti_Oid(void)
|
||||||
|
{
|
||||||
int ret;
|
int ret;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
|
||||||
@ -332,10 +390,12 @@ get_ti_Oid(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static tsstat *
|
static tsstat *
|
||||||
ts_stat_sql(text *txt) {
|
ts_stat_sql(text *txt)
|
||||||
|
{
|
||||||
char *query = text2char(txt);
|
char *query = text2char(txt);
|
||||||
int i;
|
int i;
|
||||||
tsstat *newstat,*stat;
|
tsstat *newstat,
|
||||||
|
*stat;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
Portal portal;
|
Portal portal;
|
||||||
void *plan;
|
void *plan;
|
||||||
@ -365,11 +425,14 @@ ts_stat_sql(text *txt) {
|
|||||||
stat->len = STATHDRSIZE;
|
stat->len = STATHDRSIZE;
|
||||||
stat->size = 0;
|
stat->size = 0;
|
||||||
|
|
||||||
while(SPI_processed>0) {
|
while (SPI_processed > 0)
|
||||||
for(i=0;i<SPI_processed;i++) {
|
{
|
||||||
|
for (i = 0; i < SPI_processed; i++)
|
||||||
|
{
|
||||||
Datum data = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull);
|
Datum data = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull);
|
||||||
|
|
||||||
if ( !isnull ) {
|
if (!isnull)
|
||||||
|
{
|
||||||
newstat = (tsstat *) DatumGetPointer(DirectFunctionCall2(
|
newstat = (tsstat *) DatumGetPointer(DirectFunctionCall2(
|
||||||
ts_accum,
|
ts_accum,
|
||||||
PointerGetDatum(stat),
|
PointerGetDatum(stat),
|
||||||
@ -396,11 +459,13 @@ ts_stat_sql(text *txt) {
|
|||||||
PG_FUNCTION_INFO_V1(ts_stat);
|
PG_FUNCTION_INFO_V1(ts_stat);
|
||||||
Datum ts_stat(PG_FUNCTION_ARGS);
|
Datum ts_stat(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
ts_stat(PG_FUNCTION_ARGS) {
|
ts_stat(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
FuncCallContext *funcctx;
|
FuncCallContext *funcctx;
|
||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
if (SRF_IS_FIRSTCALL()) {
|
if (SRF_IS_FIRSTCALL())
|
||||||
|
{
|
||||||
tsstat *stat;
|
tsstat *stat;
|
||||||
text *txt = PG_GETARG_TEXT_P(0);
|
text *txt = PG_GETARG_TEXT_P(0);
|
||||||
|
|
||||||
@ -417,5 +482,3 @@ ts_stat(PG_FUNCTION_ARGS) {
|
|||||||
SRF_RETURN_NEXT(funcctx, result);
|
SRF_RETURN_NEXT(funcctx, result);
|
||||||
SRF_RETURN_DONE(funcctx);
|
SRF_RETURN_DONE(funcctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -8,14 +8,16 @@
|
|||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "storage/bufpage.h"
|
#include "storage/bufpage.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
uint32 len;
|
uint32 len;
|
||||||
uint32 pos;
|
uint32 pos;
|
||||||
uint32 ndoc;
|
uint32 ndoc;
|
||||||
uint32 nentry;
|
uint32 nentry;
|
||||||
} StatEntry;
|
} StatEntry;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int4 len;
|
int4 len;
|
||||||
int4 size;
|
int4 size;
|
||||||
char data[1];
|
char data[1];
|
||||||
|
@ -31,8 +31,10 @@ Datum tsvector_out(PG_FUNCTION_ARGS);
|
|||||||
|
|
||||||
PG_FUNCTION_INFO_V1(to_tsvector);
|
PG_FUNCTION_INFO_V1(to_tsvector);
|
||||||
Datum to_tsvector(PG_FUNCTION_ARGS);
|
Datum to_tsvector(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(to_tsvector_current);
|
PG_FUNCTION_INFO_V1(to_tsvector_current);
|
||||||
Datum to_tsvector_current(PG_FUNCTION_ARGS);
|
Datum to_tsvector_current(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(to_tsvector_name);
|
PG_FUNCTION_INFO_V1(to_tsvector_name);
|
||||||
Datum to_tsvector_name(PG_FUNCTION_ARGS);
|
Datum to_tsvector_name(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
@ -46,15 +48,18 @@ Datum tsvector_length(PG_FUNCTION_ARGS);
|
|||||||
* in/out text index type
|
* in/out text index type
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
comparePos(const void *a, const void *b) {
|
comparePos(const void *a, const void *b)
|
||||||
|
{
|
||||||
if (((WordEntryPos *) a)->pos == ((WordEntryPos *) b)->pos)
|
if (((WordEntryPos *) a)->pos == ((WordEntryPos *) b)->pos)
|
||||||
return 1;
|
return 1;
|
||||||
return (((WordEntryPos *) a)->pos > ((WordEntryPos *) b)->pos) ? 1 : -1;
|
return (((WordEntryPos *) a)->pos > ((WordEntryPos *) b)->pos) ? 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
uniquePos(WordEntryPos *a, int4 l) {
|
uniquePos(WordEntryPos * a, int4 l)
|
||||||
WordEntryPos *ptr, *res;
|
{
|
||||||
|
WordEntryPos *ptr,
|
||||||
|
*res;
|
||||||
|
|
||||||
res = a;
|
res = a;
|
||||||
if (l == 1)
|
if (l == 1)
|
||||||
@ -63,14 +68,17 @@ uniquePos(WordEntryPos *a, int4 l) {
|
|||||||
qsort((void *) a, l, sizeof(WordEntryPos), comparePos);
|
qsort((void *) a, l, sizeof(WordEntryPos), comparePos);
|
||||||
|
|
||||||
ptr = a + 1;
|
ptr = a + 1;
|
||||||
while (ptr - a < l) {
|
while (ptr - a < l)
|
||||||
if ( ptr->pos != res->pos ) {
|
{
|
||||||
|
if (ptr->pos != res->pos)
|
||||||
|
{
|
||||||
res++;
|
res++;
|
||||||
res->pos = ptr->pos;
|
res->pos = ptr->pos;
|
||||||
res->weight = ptr->weight;
|
res->weight = ptr->weight;
|
||||||
if (res - a >= MAXNUMPOS - 1 || res->pos == MAXENTRYPOS - 1)
|
if (res - a >= MAXNUMPOS - 1 || res->pos == MAXENTRYPOS - 1)
|
||||||
break;
|
break;
|
||||||
} else if ( ptr->weight > res->weight )
|
}
|
||||||
|
else if (ptr->weight > res->weight)
|
||||||
res->weight = ptr->weight;
|
res->weight = ptr->weight;
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
@ -98,8 +106,10 @@ uniqueentry(WordEntryIN * a, int4 l, char *buf, int4 *outbuflen)
|
|||||||
*res;
|
*res;
|
||||||
|
|
||||||
res = a;
|
res = a;
|
||||||
if (l == 1) {
|
if (l == 1)
|
||||||
if ( a->entry.haspos ) {
|
{
|
||||||
|
if (a->entry.haspos)
|
||||||
|
{
|
||||||
*(uint16 *) (a->pos) = uniquePos(&(a->pos[1]), *(uint16 *) (a->pos));
|
*(uint16 *) (a->pos) = uniquePos(&(a->pos[1]), *(uint16 *) (a->pos));
|
||||||
*outbuflen = SHORTALIGN(res->entry.len) + (*(uint16 *) (a->pos) + 1) * sizeof(WordEntryPos);
|
*outbuflen = SHORTALIGN(res->entry.len) + (*(uint16 *) (a->pos) + 1) * sizeof(WordEntryPos);
|
||||||
}
|
}
|
||||||
@ -115,29 +125,37 @@ uniqueentry(WordEntryIN * a, int4 l, char *buf, int4 *outbuflen)
|
|||||||
if (!(ptr->entry.len == res->entry.len &&
|
if (!(ptr->entry.len == res->entry.len &&
|
||||||
strncmp(&buf[ptr->entry.pos], &buf[res->entry.pos], res->entry.len) == 0))
|
strncmp(&buf[ptr->entry.pos], &buf[res->entry.pos], res->entry.len) == 0))
|
||||||
{
|
{
|
||||||
if ( res->entry.haspos ) {
|
if (res->entry.haspos)
|
||||||
|
{
|
||||||
*(uint16 *) (res->pos) = uniquePos(&(res->pos[1]), *(uint16 *) (res->pos));
|
*(uint16 *) (res->pos) = uniquePos(&(res->pos[1]), *(uint16 *) (res->pos));
|
||||||
*outbuflen += *(uint16 *) (res->pos) * sizeof(WordEntryPos);
|
*outbuflen += *(uint16 *) (res->pos) * sizeof(WordEntryPos);
|
||||||
}
|
}
|
||||||
*outbuflen += SHORTALIGN(res->entry.len);
|
*outbuflen += SHORTALIGN(res->entry.len);
|
||||||
res++;
|
res++;
|
||||||
memcpy(res, ptr, sizeof(WordEntryIN));
|
memcpy(res, ptr, sizeof(WordEntryIN));
|
||||||
} else if ( ptr->entry.haspos ){
|
}
|
||||||
if ( res->entry.haspos ) {
|
else if (ptr->entry.haspos)
|
||||||
|
{
|
||||||
|
if (res->entry.haspos)
|
||||||
|
{
|
||||||
int4 len = *(uint16 *) (ptr->pos) + 1 + *(uint16 *) (res->pos);
|
int4 len = *(uint16 *) (ptr->pos) + 1 + *(uint16 *) (res->pos);
|
||||||
|
|
||||||
res->pos = (WordEntryPos *) repalloc(res->pos, len * sizeof(WordEntryPos));
|
res->pos = (WordEntryPos *) repalloc(res->pos, len * sizeof(WordEntryPos));
|
||||||
memcpy(&(res->pos[*(uint16 *) (res->pos) + 1]),
|
memcpy(&(res->pos[*(uint16 *) (res->pos) + 1]),
|
||||||
&(ptr->pos[1]), *(uint16 *) (ptr->pos) * sizeof(WordEntryPos));
|
&(ptr->pos[1]), *(uint16 *) (ptr->pos) * sizeof(WordEntryPos));
|
||||||
*(uint16 *) (res->pos) += *(uint16 *) (ptr->pos);
|
*(uint16 *) (res->pos) += *(uint16 *) (ptr->pos);
|
||||||
pfree(ptr->pos);
|
pfree(ptr->pos);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
res->entry.haspos = 1;
|
res->entry.haspos = 1;
|
||||||
res->pos = ptr->pos;
|
res->pos = ptr->pos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
if ( res->entry.haspos ) {
|
if (res->entry.haspos)
|
||||||
|
{
|
||||||
*(uint16 *) (res->pos) = uniquePos(&(res->pos[1]), *(uint16 *) (res->pos));
|
*(uint16 *) (res->pos) = uniquePos(&(res->pos[1]), *(uint16 *) (res->pos));
|
||||||
*outbuflen += *(uint16 *) (res->pos) * sizeof(WordEntryPos);
|
*outbuflen += *(uint16 *) (res->pos) * sizeof(WordEntryPos);
|
||||||
}
|
}
|
||||||
@ -229,7 +247,9 @@ gettoken_tsvector(TI_IN_STATE * state)
|
|||||||
errmsg("syntax error")));
|
errmsg("syntax error")));
|
||||||
*(state->curpos) = '\0';
|
*(state->curpos) = '\0';
|
||||||
return 1;
|
return 1;
|
||||||
} else if ( *(state->prsbuf) == ':' ) {
|
}
|
||||||
|
else if (*(state->prsbuf) == ':')
|
||||||
|
{
|
||||||
if (state->curpos == state->word)
|
if (state->curpos == state->word)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
@ -257,10 +277,12 @@ gettoken_tsvector(TI_IN_STATE * state)
|
|||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("syntax error")));
|
errmsg("syntax error")));
|
||||||
if ( state->oprisdelim ) {
|
if (state->oprisdelim)
|
||||||
|
{
|
||||||
state->prsbuf++;
|
state->prsbuf++;
|
||||||
return 1;
|
return 1;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
state->state = WAITPOSINFO;
|
state->state = WAITPOSINFO;
|
||||||
}
|
}
|
||||||
else if (*(state->prsbuf) == '\\')
|
else if (*(state->prsbuf) == '\\')
|
||||||
@ -278,18 +300,26 @@ gettoken_tsvector(TI_IN_STATE * state)
|
|||||||
*(state->curpos) = *(state->prsbuf);
|
*(state->curpos) = *(state->prsbuf);
|
||||||
state->curpos++;
|
state->curpos++;
|
||||||
}
|
}
|
||||||
} else if (state->state == WAITPOSINFO) {
|
}
|
||||||
|
else if (state->state == WAITPOSINFO)
|
||||||
|
{
|
||||||
if (*(state->prsbuf) == ':')
|
if (*(state->prsbuf) == ':')
|
||||||
state->state = INPOSINFO;
|
state->state = INPOSINFO;
|
||||||
else
|
else
|
||||||
return 1;
|
return 1;
|
||||||
} else if (state->state == INPOSINFO) {
|
}
|
||||||
if ( isdigit(*(state->prsbuf)) ) {
|
else if (state->state == INPOSINFO)
|
||||||
if ( state->alen==0 ) {
|
{
|
||||||
|
if (isdigit(*(state->prsbuf)))
|
||||||
|
{
|
||||||
|
if (state->alen == 0)
|
||||||
|
{
|
||||||
state->alen = 4;
|
state->alen = 4;
|
||||||
state->pos = (WordEntryPos *) palloc(sizeof(WordEntryPos) * state->alen);
|
state->pos = (WordEntryPos *) palloc(sizeof(WordEntryPos) * state->alen);
|
||||||
*(uint16 *) (state->pos) = 0;
|
*(uint16 *) (state->pos) = 0;
|
||||||
} else if ( *(uint16*)(state->pos) +1 >= state->alen ) {
|
}
|
||||||
|
else if (*(uint16 *) (state->pos) + 1 >= state->alen)
|
||||||
|
{
|
||||||
state->alen *= 2;
|
state->alen *= 2;
|
||||||
state->pos = (WordEntryPos *) repalloc(state->pos, sizeof(WordEntryPos) * state->alen);
|
state->pos = (WordEntryPos *) repalloc(state->pos, sizeof(WordEntryPos) * state->alen);
|
||||||
}
|
}
|
||||||
@ -301,44 +331,56 @@ gettoken_tsvector(TI_IN_STATE * state)
|
|||||||
errmsg("wrong position info")));
|
errmsg("wrong position info")));
|
||||||
state->pos[*(uint16 *) (state->pos)].weight = 0;
|
state->pos[*(uint16 *) (state->pos)].weight = 0;
|
||||||
state->state = WAITPOSDELIM;
|
state->state = WAITPOSDELIM;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("syntax error")));
|
errmsg("syntax error")));
|
||||||
} else if (state->state == WAITPOSDELIM) {
|
}
|
||||||
if ( *(state->prsbuf) == ',' ) {
|
else if (state->state == WAITPOSDELIM)
|
||||||
|
{
|
||||||
|
if (*(state->prsbuf) == ',')
|
||||||
state->state = INPOSINFO;
|
state->state = INPOSINFO;
|
||||||
} else if ( tolower(*(state->prsbuf)) == 'a' || *(state->prsbuf)=='*' ) {
|
else if (tolower(*(state->prsbuf)) == 'a' || *(state->prsbuf) == '*')
|
||||||
|
{
|
||||||
if (state->pos[*(uint16 *) (state->pos)].weight)
|
if (state->pos[*(uint16 *) (state->pos)].weight)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("syntax error")));
|
errmsg("syntax error")));
|
||||||
state->pos[*(uint16 *) (state->pos)].weight = 3;
|
state->pos[*(uint16 *) (state->pos)].weight = 3;
|
||||||
} else if ( tolower(*(state->prsbuf)) == 'b' ) {
|
}
|
||||||
|
else if (tolower(*(state->prsbuf)) == 'b')
|
||||||
|
{
|
||||||
if (state->pos[*(uint16 *) (state->pos)].weight)
|
if (state->pos[*(uint16 *) (state->pos)].weight)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("syntax error")));
|
errmsg("syntax error")));
|
||||||
state->pos[*(uint16 *) (state->pos)].weight = 2;
|
state->pos[*(uint16 *) (state->pos)].weight = 2;
|
||||||
} else if ( tolower(*(state->prsbuf)) == 'c' ) {
|
}
|
||||||
|
else if (tolower(*(state->prsbuf)) == 'c')
|
||||||
|
{
|
||||||
if (state->pos[*(uint16 *) (state->pos)].weight)
|
if (state->pos[*(uint16 *) (state->pos)].weight)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("syntax error")));
|
errmsg("syntax error")));
|
||||||
state->pos[*(uint16 *) (state->pos)].weight = 1;
|
state->pos[*(uint16 *) (state->pos)].weight = 1;
|
||||||
} else if ( tolower(*(state->prsbuf)) == 'd' ) {
|
}
|
||||||
|
else if (tolower(*(state->prsbuf)) == 'd')
|
||||||
|
{
|
||||||
if (state->pos[*(uint16 *) (state->pos)].weight)
|
if (state->pos[*(uint16 *) (state->pos)].weight)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("syntax error")));
|
errmsg("syntax error")));
|
||||||
state->pos[*(uint16 *) (state->pos)].weight = 0;
|
state->pos[*(uint16 *) (state->pos)].weight = 0;
|
||||||
} else if ( isspace(*(state->prsbuf)) || *(state->prsbuf) == '\0' ) {
|
}
|
||||||
|
else if (isspace(*(state->prsbuf)) || *(state->prsbuf) == '\0')
|
||||||
return 1;
|
return 1;
|
||||||
} else if ( !isdigit(*(state->prsbuf)) )
|
else if (!isdigit(*(state->prsbuf)))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||||
errmsg("syntax error")));
|
errmsg("syntax error")));
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
/* internal error */
|
/* internal error */
|
||||||
elog(ERROR, "internal error");
|
elog(ERROR, "internal error");
|
||||||
state->prsbuf++;
|
state->prsbuf++;
|
||||||
@ -396,10 +438,12 @@ tsvector_in(PG_FUNCTION_ARGS)
|
|||||||
arr[len].entry.pos = cur - tmpbuf;
|
arr[len].entry.pos = cur - tmpbuf;
|
||||||
memcpy((void *) cur, (void *) state.word, arr[len].entry.len);
|
memcpy((void *) cur, (void *) state.word, arr[len].entry.len);
|
||||||
cur += arr[len].entry.len;
|
cur += arr[len].entry.len;
|
||||||
if ( state.alen ) {
|
if (state.alen)
|
||||||
|
{
|
||||||
arr[len].entry.haspos = 1;
|
arr[len].entry.haspos = 1;
|
||||||
arr[len].pos = state.pos;
|
arr[len].pos = state.pos;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
arr[len].entry.haspos = 0;
|
arr[len].entry.haspos = 0;
|
||||||
len++;
|
len++;
|
||||||
}
|
}
|
||||||
@ -419,7 +463,8 @@ tsvector_in(PG_FUNCTION_ARGS)
|
|||||||
memcpy((void *) cur, (void *) &tmpbuf[arr[i].entry.pos], arr[i].entry.len);
|
memcpy((void *) cur, (void *) &tmpbuf[arr[i].entry.pos], arr[i].entry.len);
|
||||||
arr[i].entry.pos = cur - STRPTR(in);
|
arr[i].entry.pos = cur - STRPTR(in);
|
||||||
cur += SHORTALIGN(arr[i].entry.len);
|
cur += SHORTALIGN(arr[i].entry.len);
|
||||||
if ( arr[i].entry.haspos ) {
|
if (arr[i].entry.haspos)
|
||||||
|
{
|
||||||
memcpy(cur, arr[i].pos, (*(uint16 *) arr[i].pos + 1) * sizeof(WordEntryPos));
|
memcpy(cur, arr[i].pos, (*(uint16 *) arr[i].pos + 1) * sizeof(WordEntryPos));
|
||||||
cur += (*(uint16 *) arr[i].pos + 1) * sizeof(WordEntryPos);
|
cur += (*(uint16 *) arr[i].pos + 1) * sizeof(WordEntryPos);
|
||||||
pfree(arr[i].pos);
|
pfree(arr[i].pos);
|
||||||
@ -448,13 +493,15 @@ tsvector_out(PG_FUNCTION_ARGS)
|
|||||||
char *outbuf;
|
char *outbuf;
|
||||||
int4 i,
|
int4 i,
|
||||||
j,
|
j,
|
||||||
lenbuf = 0, pp;
|
lenbuf = 0,
|
||||||
|
pp;
|
||||||
WordEntry *ptr = ARRPTR(out);
|
WordEntry *ptr = ARRPTR(out);
|
||||||
char *curin,
|
char *curin,
|
||||||
*curout;
|
*curout;
|
||||||
|
|
||||||
lenbuf = out->size * 2 /* '' */ + out->size - 1 /* space */ + 2 /* \0 */ ;
|
lenbuf = out->size * 2 /* '' */ + out->size - 1 /* space */ + 2 /* \0 */ ;
|
||||||
for (i = 0; i < out->size; i++) {
|
for (i = 0; i < out->size; i++)
|
||||||
|
{
|
||||||
lenbuf += ptr[i].len * 2 /* for escape */ ;
|
lenbuf += ptr[i].len * 2 /* for escape */ ;
|
||||||
if (ptr[i].haspos)
|
if (ptr[i].haspos)
|
||||||
lenbuf += 7 * POSDATALEN(out, &(ptr[i]));
|
lenbuf += 7 * POSDATALEN(out, &(ptr[i]));
|
||||||
@ -481,22 +528,35 @@ tsvector_out(PG_FUNCTION_ARGS)
|
|||||||
*curout++ = *curin++;
|
*curout++ = *curin++;
|
||||||
}
|
}
|
||||||
*curout++ = '\'';
|
*curout++ = '\'';
|
||||||
if ( (pp=POSDATALEN(out,ptr)) != 0 ) {
|
if ((pp = POSDATALEN(out, ptr)) != 0)
|
||||||
|
{
|
||||||
WordEntryPos *wptr;
|
WordEntryPos *wptr;
|
||||||
|
|
||||||
*curout++ = ':';
|
*curout++ = ':';
|
||||||
wptr = POSDATAPTR(out, ptr);
|
wptr = POSDATAPTR(out, ptr);
|
||||||
while(pp) {
|
while (pp)
|
||||||
|
{
|
||||||
sprintf(curout, "%d", wptr->pos);
|
sprintf(curout, "%d", wptr->pos);
|
||||||
curout = strchr(curout, '\0');
|
curout = strchr(curout, '\0');
|
||||||
switch( wptr->weight ) {
|
switch (wptr->weight)
|
||||||
case 3: *curout++ = 'A'; break;
|
{
|
||||||
case 2: *curout++ = 'B'; break;
|
case 3:
|
||||||
case 1: *curout++ = 'C'; break;
|
*curout++ = 'A';
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
*curout++ = 'B';
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
*curout++ = 'C';
|
||||||
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if ( pp>1 ) *curout++ = ',';
|
if (pp > 1)
|
||||||
pp--; wptr++;
|
*curout++ = ',';
|
||||||
|
pp--;
|
||||||
|
wptr++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ptr++;
|
ptr++;
|
||||||
@ -510,11 +570,13 @@ tsvector_out(PG_FUNCTION_ARGS)
|
|||||||
static int
|
static int
|
||||||
compareWORD(const void *a, const void *b)
|
compareWORD(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
if (((WORD *) a)->len == ((WORD *) b)->len) {
|
if (((WORD *) a)->len == ((WORD *) b)->len)
|
||||||
|
{
|
||||||
int res = strncmp(
|
int res = strncmp(
|
||||||
((WORD *) a)->word,
|
((WORD *) a)->word,
|
||||||
((WORD *) b)->word,
|
((WORD *) b)->word,
|
||||||
((WORD *) b)->len);
|
((WORD *) b)->len);
|
||||||
|
|
||||||
if (res == 0)
|
if (res == 0)
|
||||||
return (((WORD *) a)->pos.pos > ((WORD *) b)->pos.pos) ? 1 : -1;
|
return (((WORD *) a)->pos.pos > ((WORD *) b)->pos.pos) ? 1 : -1;
|
||||||
return res;
|
return res;
|
||||||
@ -529,7 +591,8 @@ uniqueWORD(WORD * a, int4 l)
|
|||||||
*res;
|
*res;
|
||||||
int tmppos;
|
int tmppos;
|
||||||
|
|
||||||
if (l == 1) {
|
if (l == 1)
|
||||||
|
{
|
||||||
tmppos = LIMITPOS(a->pos.pos);
|
tmppos = LIMITPOS(a->pos.pos);
|
||||||
a->alen = 2;
|
a->alen = 2;
|
||||||
a->pos.apos = (uint16 *) palloc(sizeof(uint16) * a->alen);
|
a->pos.apos = (uint16 *) palloc(sizeof(uint16) * a->alen);
|
||||||
@ -561,10 +624,14 @@ uniqueWORD(WORD * a, int4 l)
|
|||||||
res->pos.apos = (uint16 *) palloc(sizeof(uint16) * res->alen);
|
res->pos.apos = (uint16 *) palloc(sizeof(uint16) * res->alen);
|
||||||
res->pos.apos[0] = 1;
|
res->pos.apos[0] = 1;
|
||||||
res->pos.apos[1] = tmppos;
|
res->pos.apos[1] = tmppos;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
pfree(ptr->word);
|
pfree(ptr->word);
|
||||||
if ( res->pos.apos[0] < MAXNUMPOS-1 && res->pos.apos[ res->pos.apos[0] ] != MAXENTRYPOS-1 ) {
|
if (res->pos.apos[0] < MAXNUMPOS - 1 && res->pos.apos[res->pos.apos[0]] != MAXENTRYPOS - 1)
|
||||||
if ( res->pos.apos[0]+1 >= res->alen ) {
|
{
|
||||||
|
if (res->pos.apos[0] + 1 >= res->alen)
|
||||||
|
{
|
||||||
res->alen *= 2;
|
res->alen *= 2;
|
||||||
res->pos.apos = (uint16 *) repalloc(res->pos.apos, sizeof(uint16) * res->alen);
|
res->pos.apos = (uint16 *) repalloc(res->pos.apos, sizeof(uint16) * res->alen);
|
||||||
}
|
}
|
||||||
@ -584,7 +651,8 @@ uniqueWORD(WORD * a, int4 l)
|
|||||||
static tsvector *
|
static tsvector *
|
||||||
makevalue(PRSTEXT * prs)
|
makevalue(PRSTEXT * prs)
|
||||||
{
|
{
|
||||||
int4 i,j,
|
int4 i,
|
||||||
|
j,
|
||||||
lenstr = 0,
|
lenstr = 0,
|
||||||
totallen;
|
totallen;
|
||||||
tsvector *in;
|
tsvector *in;
|
||||||
@ -593,7 +661,8 @@ makevalue(PRSTEXT * prs)
|
|||||||
*cur;
|
*cur;
|
||||||
|
|
||||||
prs->curwords = uniqueWORD(prs->words, prs->curwords);
|
prs->curwords = uniqueWORD(prs->words, prs->curwords);
|
||||||
for (i = 0; i < prs->curwords; i++) {
|
for (i = 0; i < prs->curwords; i++)
|
||||||
|
{
|
||||||
lenstr += SHORTALIGN(prs->words[i].len);
|
lenstr += SHORTALIGN(prs->words[i].len);
|
||||||
|
|
||||||
if (prs->words[i].alen)
|
if (prs->words[i].alen)
|
||||||
@ -619,19 +688,22 @@ makevalue(PRSTEXT * prs)
|
|||||||
memcpy((void *) cur, (void *) prs->words[i].word, prs->words[i].len);
|
memcpy((void *) cur, (void *) prs->words[i].word, prs->words[i].len);
|
||||||
pfree(prs->words[i].word);
|
pfree(prs->words[i].word);
|
||||||
cur += SHORTALIGN(prs->words[i].len);
|
cur += SHORTALIGN(prs->words[i].len);
|
||||||
if ( prs->words[i].alen ) {
|
if (prs->words[i].alen)
|
||||||
|
{
|
||||||
WordEntryPos *wptr;
|
WordEntryPos *wptr;
|
||||||
|
|
||||||
ptr->haspos = 1;
|
ptr->haspos = 1;
|
||||||
*(uint16 *) cur = prs->words[i].pos.apos[0];
|
*(uint16 *) cur = prs->words[i].pos.apos[0];
|
||||||
wptr = POSDATAPTR(in, ptr);
|
wptr = POSDATAPTR(in, ptr);
|
||||||
for(j=0;j<*(uint16*)cur;j++) {
|
for (j = 0; j < *(uint16 *) cur; j++)
|
||||||
|
{
|
||||||
wptr[j].weight = 0;
|
wptr[j].weight = 0;
|
||||||
wptr[j].pos = prs->words[i].pos.apos[j + 1];
|
wptr[j].pos = prs->words[i].pos.apos[j + 1];
|
||||||
}
|
}
|
||||||
cur += sizeof(uint16) + prs->words[i].pos.apos[0] * sizeof(WordEntryPos);
|
cur += sizeof(uint16) + prs->words[i].pos.apos[0] * sizeof(WordEntryPos);
|
||||||
pfree(prs->words[i].pos.apos);
|
pfree(prs->words[i].pos.apos);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ptr->haspos = 0;
|
ptr->haspos = 0;
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
@ -658,7 +730,8 @@ to_tsvector(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
if (prs.curwords)
|
if (prs.curwords)
|
||||||
out = makevalue(&prs);
|
out = makevalue(&prs);
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
pfree(prs.words);
|
pfree(prs.words);
|
||||||
out = palloc(CALCDATASIZE(0, 0));
|
out = palloc(CALCDATASIZE(0, 0));
|
||||||
out->len = CALCDATASIZE(0, 0);
|
out->len = CALCDATASIZE(0, 0);
|
||||||
@ -668,7 +741,8 @@ to_tsvector(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
to_tsvector_name(PG_FUNCTION_ARGS) {
|
to_tsvector_name(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
text *cfg = PG_GETARG_TEXT_P(0);
|
text *cfg = PG_GETARG_TEXT_P(0);
|
||||||
Datum res = DirectFunctionCall3(
|
Datum res = DirectFunctionCall3(
|
||||||
to_tsvector,
|
to_tsvector,
|
||||||
@ -676,24 +750,29 @@ to_tsvector_name(PG_FUNCTION_ARGS) {
|
|||||||
PG_GETARG_DATUM(1),
|
PG_GETARG_DATUM(1),
|
||||||
(Datum) 0
|
(Datum) 0
|
||||||
);
|
);
|
||||||
|
|
||||||
PG_FREE_IF_COPY(cfg, 0);
|
PG_FREE_IF_COPY(cfg, 0);
|
||||||
PG_RETURN_DATUM(res);
|
PG_RETURN_DATUM(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
to_tsvector_current(PG_FUNCTION_ARGS) {
|
to_tsvector_current(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
Datum res = DirectFunctionCall3(
|
Datum res = DirectFunctionCall3(
|
||||||
to_tsvector,
|
to_tsvector,
|
||||||
Int32GetDatum(get_currcfg()),
|
Int32GetDatum(get_currcfg()),
|
||||||
PG_GETARG_DATUM(0),
|
PG_GETARG_DATUM(0),
|
||||||
(Datum) 0
|
(Datum) 0
|
||||||
);
|
);
|
||||||
|
|
||||||
PG_RETURN_DATUM(res);
|
PG_RETURN_DATUM(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Oid
|
static Oid
|
||||||
findFunc(char *fname) {
|
findFunc(char *fname)
|
||||||
FuncCandidateList clist,ptr;
|
{
|
||||||
|
FuncCandidateList clist,
|
||||||
|
ptr;
|
||||||
Oid funcid = InvalidOid;
|
Oid funcid = InvalidOid;
|
||||||
List *names = makeList1(makeString(fname));
|
List *names = makeList1(makeString(fname));
|
||||||
|
|
||||||
@ -703,7 +782,8 @@ findFunc(char *fname) {
|
|||||||
if (!ptr)
|
if (!ptr)
|
||||||
return funcid;
|
return funcid;
|
||||||
|
|
||||||
while(ptr) {
|
while (ptr)
|
||||||
|
{
|
||||||
if (ptr->args[0] == TEXTOID && funcid == InvalidOid)
|
if (ptr->args[0] == TEXTOID && funcid == InvalidOid)
|
||||||
funcid = ptr->oid;
|
funcid = ptr->oid;
|
||||||
clist = ptr->next;
|
clist = ptr->next;
|
||||||
@ -805,15 +885,18 @@ tsearch2(PG_FUNCTION_ARGS)
|
|||||||
if (isnull)
|
if (isnull)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if ( funcoid!=InvalidOid ) {
|
if (funcoid != InvalidOid)
|
||||||
|
{
|
||||||
text *txttmp = (text *) DatumGetPointer(OidFunctionCall1(
|
text *txttmp = (text *) DatumGetPointer(OidFunctionCall1(
|
||||||
funcoid,
|
funcoid,
|
||||||
PointerGetDatum(txt_toasted)
|
PointerGetDatum(txt_toasted)
|
||||||
));
|
));
|
||||||
|
|
||||||
txt = (text *) DatumGetPointer(PG_DETOAST_DATUM(PointerGetDatum(txttmp)));
|
txt = (text *) DatumGetPointer(PG_DETOAST_DATUM(PointerGetDatum(txttmp)));
|
||||||
if (txt == txttmp)
|
if (txt == txttmp)
|
||||||
txt_toasted = PointerGetDatum(txt);
|
txt_toasted = PointerGetDatum(txt);
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
txt = (text *) DatumGetPointer(PG_DETOAST_DATUM(PointerGetDatum(txt_toasted)));
|
txt = (text *) DatumGetPointer(PG_DETOAST_DATUM(PointerGetDatum(txt_toasted)));
|
||||||
|
|
||||||
parsetext_v2(cfg, &prs, VARDATA(txt), VARSIZE(txt) - VARHDRSZ);
|
parsetext_v2(cfg, &prs, VARDATA(txt), VARSIZE(txt) - VARHDRSZ);
|
||||||
@ -832,6 +915,7 @@ tsearch2(PG_FUNCTION_ARGS)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
tsvector *out = palloc(CALCDATASIZE(0, 0));
|
tsvector *out = palloc(CALCDATASIZE(0, 0));
|
||||||
|
|
||||||
out->len = CALCDATASIZE(0, 0);
|
out->len = CALCDATASIZE(0, 0);
|
||||||
out->size = 0;
|
out->size = 0;
|
||||||
datum = PointerGetDatum(out);
|
datum = PointerGetDatum(out);
|
||||||
|
@ -12,20 +12,24 @@
|
|||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "storage/bufpage.h"
|
#include "storage/bufpage.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
uint32
|
uint32
|
||||||
haspos:1,
|
haspos:1,
|
||||||
len:11, /* MAX 2Kb */
|
len:11, /* MAX 2Kb */
|
||||||
pos:20; /* MAX 1Mb */
|
pos:20; /* MAX 1Mb */
|
||||||
} WordEntry;
|
} WordEntry;
|
||||||
|
|
||||||
#define MAXSTRLEN ( 1<<11 )
|
#define MAXSTRLEN ( 1<<11 )
|
||||||
#define MAXSTRPOS ( 1<<20 )
|
#define MAXSTRPOS ( 1<<20 )
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
uint16
|
uint16
|
||||||
weight:2,
|
weight:2,
|
||||||
pos:14;
|
pos:14;
|
||||||
} WordEntryPos;
|
} WordEntryPos;
|
||||||
|
|
||||||
#define MAXENTRYPOS (1<<14)
|
#define MAXENTRYPOS (1<<14)
|
||||||
#define MAXNUMPOS 256
|
#define MAXNUMPOS 256
|
||||||
#define LIMITPOS(x) ( ( (x) >= MAXENTRYPOS ) ? (MAXENTRYPOS-1) : (x) )
|
#define LIMITPOS(x) ( ( (x) >= MAXENTRYPOS ) ? (MAXENTRYPOS-1) : (x) )
|
||||||
@ -47,7 +51,8 @@ typedef struct
|
|||||||
#define POSDATAPTR(x,e) ( (WordEntryPos*)( _POSDATAPTR(x,e)+sizeof(uint16) ) )
|
#define POSDATAPTR(x,e) ( (WordEntryPos*)( _POSDATAPTR(x,e)+sizeof(uint16) ) )
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
WordEntry entry;
|
WordEntry entry;
|
||||||
WordEntryPos *pos;
|
WordEntryPos *pos;
|
||||||
} WordEntryIN;
|
} WordEntryIN;
|
||||||
|
@ -35,8 +35,10 @@ strip(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||||
tsvector *out;
|
tsvector *out;
|
||||||
int i,len=0;
|
int i,
|
||||||
WordEntry *arrin=ARRPTR(in), *arrout;
|
len = 0;
|
||||||
|
WordEntry *arrin = ARRPTR(in),
|
||||||
|
*arrout;
|
||||||
char *cur;
|
char *cur;
|
||||||
|
|
||||||
for (i = 0; i < in->size; i++)
|
for (i = 0; i < in->size; i++)
|
||||||
@ -49,7 +51,8 @@ strip(PG_FUNCTION_ARGS)
|
|||||||
out->size = in->size;
|
out->size = in->size;
|
||||||
arrout = ARRPTR(out);
|
arrout = ARRPTR(out);
|
||||||
cur = STRPTR(out);
|
cur = STRPTR(out);
|
||||||
for(i=0;i<in->size;i++) {
|
for (i = 0; i < in->size; i++)
|
||||||
|
{
|
||||||
memcpy(cur, STRPTR(in) + arrin[i].pos, arrin[i].len);
|
memcpy(cur, STRPTR(in) + arrin[i].pos, arrin[i].len);
|
||||||
arrout[i].haspos = 0;
|
arrout[i].haspos = 0;
|
||||||
arrout[i].len = arrin[i].len;
|
arrout[i].len = arrin[i].len;
|
||||||
@ -67,28 +70,42 @@ setweight(PG_FUNCTION_ARGS)
|
|||||||
tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||||
char cw = PG_GETARG_CHAR(1);
|
char cw = PG_GETARG_CHAR(1);
|
||||||
tsvector *out;
|
tsvector *out;
|
||||||
int i,j;
|
int i,
|
||||||
|
j;
|
||||||
WordEntry *entry;
|
WordEntry *entry;
|
||||||
WordEntryPos *p;
|
WordEntryPos *p;
|
||||||
int w = 0;
|
int w = 0;
|
||||||
|
|
||||||
switch(tolower(cw)) {
|
switch (tolower(cw))
|
||||||
case 'a': w=3; break;
|
{
|
||||||
case 'b': w=2; break;
|
case 'a':
|
||||||
case 'c': w=1; break;
|
w = 3;
|
||||||
case 'd': w=0; break;
|
break;
|
||||||
|
case 'b':
|
||||||
|
w = 2;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
w = 1;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
w = 0;
|
||||||
|
break;
|
||||||
/* internal error */
|
/* internal error */
|
||||||
default: elog(ERROR,"unrecognized weight");
|
default:
|
||||||
|
elog(ERROR, "unrecognized weight");
|
||||||
}
|
}
|
||||||
|
|
||||||
out = (tsvector *) palloc(in->len);
|
out = (tsvector *) palloc(in->len);
|
||||||
memcpy(out, in, in->len);
|
memcpy(out, in, in->len);
|
||||||
entry = ARRPTR(out);
|
entry = ARRPTR(out);
|
||||||
i = out->size;
|
i = out->size;
|
||||||
while(i--) {
|
while (i--)
|
||||||
if ( (j=POSDATALEN(out,entry)) != 0 ) {
|
{
|
||||||
|
if ((j = POSDATALEN(out, entry)) != 0)
|
||||||
|
{
|
||||||
p = POSDATAPTR(out, entry);
|
p = POSDATAPTR(out, entry);
|
||||||
while(j--) {
|
while (j--)
|
||||||
|
{
|
||||||
p->weight = w;
|
p->weight = w;
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
@ -114,17 +131,21 @@ compareEntry(char *ptra, WordEntry* a, char *ptrb, WordEntry* b)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int4
|
static int4
|
||||||
add_pos(tsvector *src, WordEntry *srcptr, tsvector *dest, WordEntry *destptr, int4 maxpos ) {
|
add_pos(tsvector * src, WordEntry * srcptr, tsvector * dest, WordEntry * destptr, int4 maxpos)
|
||||||
|
{
|
||||||
uint16 *clen = (uint16 *) _POSDATAPTR(dest, destptr);
|
uint16 *clen = (uint16 *) _POSDATAPTR(dest, destptr);
|
||||||
int i;
|
int i;
|
||||||
uint16 slen = POSDATALEN(src, srcptr), startlen;
|
uint16 slen = POSDATALEN(src, srcptr),
|
||||||
WordEntryPos *spos=POSDATAPTR(src, srcptr), *dpos=POSDATAPTR(dest,destptr);
|
startlen;
|
||||||
|
WordEntryPos *spos = POSDATAPTR(src, srcptr),
|
||||||
|
*dpos = POSDATAPTR(dest, destptr);
|
||||||
|
|
||||||
if (!destptr->haspos)
|
if (!destptr->haspos)
|
||||||
*clen = 0;
|
*clen = 0;
|
||||||
|
|
||||||
startlen = *clen;
|
startlen = *clen;
|
||||||
for(i=0; i<slen && *clen<MAXNUMPOS && ( *clen==0 || dpos[ *clen-1 ].pos != MAXENTRYPOS-1 ) ;i++) {
|
for (i = 0; i < slen && *clen < MAXNUMPOS && (*clen == 0 || dpos[*clen - 1].pos != MAXENTRYPOS - 1); i++)
|
||||||
|
{
|
||||||
dpos[*clen].weight = spos[i].weight;
|
dpos[*clen].weight = spos[i].weight;
|
||||||
dpos[*clen].pos = LIMITPOS(spos[i].pos + maxpos);
|
dpos[*clen].pos = LIMITPOS(spos[i].pos + maxpos);
|
||||||
(*clen)++;
|
(*clen)++;
|
||||||
@ -137,23 +158,34 @@ add_pos(tsvector *src, WordEntry *srcptr, tsvector *dest, WordEntry *destptr, in
|
|||||||
|
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
concat(PG_FUNCTION_ARGS) {
|
concat(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
tsvector *in1 = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
tsvector *in1 = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||||
tsvector *in2 = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
tsvector *in2 = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||||
tsvector *out;
|
tsvector *out;
|
||||||
WordEntry *ptr;
|
WordEntry *ptr;
|
||||||
WordEntry *ptr1,*ptr2;
|
WordEntry *ptr1,
|
||||||
|
*ptr2;
|
||||||
WordEntryPos *p;
|
WordEntryPos *p;
|
||||||
int maxpos=0,i,j,i1,i2;
|
int maxpos = 0,
|
||||||
|
i,
|
||||||
|
j,
|
||||||
|
i1,
|
||||||
|
i2;
|
||||||
char *cur;
|
char *cur;
|
||||||
char *data,*data1,*data2;
|
char *data,
|
||||||
|
*data1,
|
||||||
|
*data2;
|
||||||
|
|
||||||
ptr = ARRPTR(in1);
|
ptr = ARRPTR(in1);
|
||||||
i = in1->size;
|
i = in1->size;
|
||||||
while(i--) {
|
while (i--)
|
||||||
if ( (j=POSDATALEN(in1,ptr)) != 0 ) {
|
{
|
||||||
|
if ((j = POSDATALEN(in1, ptr)) != 0)
|
||||||
|
{
|
||||||
p = POSDATAPTR(in1, ptr);
|
p = POSDATAPTR(in1, ptr);
|
||||||
while(j--) {
|
while (j--)
|
||||||
|
{
|
||||||
if (p->pos > maxpos)
|
if (p->pos > maxpos)
|
||||||
maxpos = p->pos;
|
maxpos = p->pos;
|
||||||
p++;
|
p++;
|
||||||
@ -162,93 +194,128 @@ concat(PG_FUNCTION_ARGS) {
|
|||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr1=ARRPTR(in1); ptr2=ARRPTR(in2);
|
ptr1 = ARRPTR(in1);
|
||||||
data1=STRPTR(in1); data2=STRPTR(in2);
|
ptr2 = ARRPTR(in2);
|
||||||
i1=in1->size; i2=in2->size;
|
data1 = STRPTR(in1);
|
||||||
|
data2 = STRPTR(in2);
|
||||||
|
i1 = in1->size;
|
||||||
|
i2 = in2->size;
|
||||||
out = (tsvector *) palloc(in1->len + in2->len);
|
out = (tsvector *) palloc(in1->len + in2->len);
|
||||||
memset(out, 0, in1->len + in2->len);
|
memset(out, 0, in1->len + in2->len);
|
||||||
out->len = in1->len + in2->len;
|
out->len = in1->len + in2->len;
|
||||||
out->size = in1->size + in2->size;
|
out->size = in1->size + in2->size;
|
||||||
data = cur = STRPTR(out);
|
data = cur = STRPTR(out);
|
||||||
ptr = ARRPTR(out);
|
ptr = ARRPTR(out);
|
||||||
while( i1 && i2 ) {
|
while (i1 && i2)
|
||||||
|
{
|
||||||
int cmp = compareEntry(data1, ptr1, data2, ptr2);
|
int cmp = compareEntry(data1, ptr1, data2, ptr2);
|
||||||
if ( cmp < 0 ) { /* in1 first */
|
|
||||||
|
if (cmp < 0)
|
||||||
|
{ /* in1 first */
|
||||||
ptr->haspos = ptr1->haspos;
|
ptr->haspos = ptr1->haspos;
|
||||||
ptr->len = ptr1->len;
|
ptr->len = ptr1->len;
|
||||||
memcpy(cur, data1 + ptr1->pos, ptr1->len);
|
memcpy(cur, data1 + ptr1->pos, ptr1->len);
|
||||||
ptr->pos = cur - data;
|
ptr->pos = cur - data;
|
||||||
cur += SHORTALIGN(ptr1->len);
|
cur += SHORTALIGN(ptr1->len);
|
||||||
if ( ptr->haspos ) {
|
if (ptr->haspos)
|
||||||
|
{
|
||||||
memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
|
memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
|
||||||
cur += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
|
cur += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
|
||||||
}
|
}
|
||||||
ptr++; ptr1++; i1--;
|
ptr++;
|
||||||
} else if ( cmp>0 ) { /* in2 first */
|
ptr1++;
|
||||||
|
i1--;
|
||||||
|
}
|
||||||
|
else if (cmp > 0)
|
||||||
|
{ /* in2 first */
|
||||||
ptr->haspos = ptr2->haspos;
|
ptr->haspos = ptr2->haspos;
|
||||||
ptr->len = ptr2->len;
|
ptr->len = ptr2->len;
|
||||||
memcpy(cur, data2 + ptr2->pos, ptr2->len);
|
memcpy(cur, data2 + ptr2->pos, ptr2->len);
|
||||||
ptr->pos = cur - data;
|
ptr->pos = cur - data;
|
||||||
cur += SHORTALIGN(ptr2->len);
|
cur += SHORTALIGN(ptr2->len);
|
||||||
if ( ptr->haspos ) {
|
if (ptr->haspos)
|
||||||
|
{
|
||||||
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
|
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
|
||||||
|
|
||||||
if (addlen == 0)
|
if (addlen == 0)
|
||||||
ptr->haspos = 0;
|
ptr->haspos = 0;
|
||||||
else
|
else
|
||||||
cur += addlen * sizeof(WordEntryPos) + sizeof(uint16);
|
cur += addlen * sizeof(WordEntryPos) + sizeof(uint16);
|
||||||
}
|
}
|
||||||
ptr++; ptr2++; i2--;
|
ptr++;
|
||||||
} else {
|
ptr2++;
|
||||||
|
i2--;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
ptr->haspos = ptr1->haspos | ptr2->haspos;
|
ptr->haspos = ptr1->haspos | ptr2->haspos;
|
||||||
ptr->len = ptr1->len;
|
ptr->len = ptr1->len;
|
||||||
memcpy(cur, data1 + ptr1->pos, ptr1->len);
|
memcpy(cur, data1 + ptr1->pos, ptr1->len);
|
||||||
ptr->pos = cur - data;
|
ptr->pos = cur - data;
|
||||||
cur += SHORTALIGN(ptr1->len);
|
cur += SHORTALIGN(ptr1->len);
|
||||||
if ( ptr->haspos ) {
|
if (ptr->haspos)
|
||||||
if ( ptr1->haspos ) {
|
{
|
||||||
|
if (ptr1->haspos)
|
||||||
|
{
|
||||||
memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
|
memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
|
||||||
cur += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
|
cur += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
|
||||||
if (ptr2->haspos)
|
if (ptr2->haspos)
|
||||||
cur += add_pos(in2, ptr2, out, ptr, maxpos) * sizeof(WordEntryPos);
|
cur += add_pos(in2, ptr2, out, ptr, maxpos) * sizeof(WordEntryPos);
|
||||||
} else if ( ptr2->haspos ) {
|
}
|
||||||
|
else if (ptr2->haspos)
|
||||||
|
{
|
||||||
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
|
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
|
||||||
|
|
||||||
if (addlen == 0)
|
if (addlen == 0)
|
||||||
ptr->haspos = 0;
|
ptr->haspos = 0;
|
||||||
else
|
else
|
||||||
cur += addlen * sizeof(WordEntryPos) + sizeof(uint16);
|
cur += addlen * sizeof(WordEntryPos) + sizeof(uint16);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ptr++; ptr1++; ptr2++; i1--; i2--;
|
ptr++;
|
||||||
|
ptr1++;
|
||||||
|
ptr2++;
|
||||||
|
i1--;
|
||||||
|
i2--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while(i1) {
|
while (i1)
|
||||||
|
{
|
||||||
ptr->haspos = ptr1->haspos;
|
ptr->haspos = ptr1->haspos;
|
||||||
ptr->len = ptr1->len;
|
ptr->len = ptr1->len;
|
||||||
memcpy(cur, data1 + ptr1->pos, ptr1->len);
|
memcpy(cur, data1 + ptr1->pos, ptr1->len);
|
||||||
ptr->pos = cur - data;
|
ptr->pos = cur - data;
|
||||||
cur += SHORTALIGN(ptr1->len);
|
cur += SHORTALIGN(ptr1->len);
|
||||||
if ( ptr->haspos ) {
|
if (ptr->haspos)
|
||||||
|
{
|
||||||
memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
|
memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
|
||||||
cur += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
|
cur += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
|
||||||
}
|
}
|
||||||
ptr++; ptr1++; i1--;
|
ptr++;
|
||||||
|
ptr1++;
|
||||||
|
i1--;
|
||||||
}
|
}
|
||||||
|
|
||||||
while(i2) {
|
while (i2)
|
||||||
|
{
|
||||||
ptr->haspos = ptr2->haspos;
|
ptr->haspos = ptr2->haspos;
|
||||||
ptr->len = ptr2->len;
|
ptr->len = ptr2->len;
|
||||||
memcpy(cur, data2 + ptr2->pos, ptr2->len);
|
memcpy(cur, data2 + ptr2->pos, ptr2->len);
|
||||||
ptr->pos = cur - data;
|
ptr->pos = cur - data;
|
||||||
cur += SHORTALIGN(ptr2->len);
|
cur += SHORTALIGN(ptr2->len);
|
||||||
if ( ptr->haspos ) {
|
if (ptr->haspos)
|
||||||
|
{
|
||||||
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
|
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
|
||||||
|
|
||||||
if (addlen == 0)
|
if (addlen == 0)
|
||||||
ptr->haspos = 0;
|
ptr->haspos = 0;
|
||||||
else
|
else
|
||||||
cur += addlen * sizeof(WordEntryPos) + sizeof(uint16);
|
cur += addlen * sizeof(WordEntryPos) + sizeof(uint16);
|
||||||
}
|
}
|
||||||
ptr++; ptr2++; i2--;
|
ptr++;
|
||||||
|
ptr2++;
|
||||||
|
i2--;
|
||||||
}
|
}
|
||||||
|
|
||||||
out->size = ptr - ARRPTR(out);
|
out->size = ptr - ARRPTR(out);
|
||||||
@ -260,4 +327,3 @@ concat(PG_FUNCTION_ARGS) {
|
|||||||
PG_FREE_IF_COPY(in2, 1);
|
PG_FREE_IF_COPY(in2, 1);
|
||||||
PG_RETURN_POINTER(out);
|
PG_RETURN_POINTER(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,4 +53,3 @@ const char *tok_alias[]={
|
|||||||
"uint",
|
"uint",
|
||||||
"entity"
|
"entity"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,7 +25,8 @@ static void *plan_getparser=NULL;
|
|||||||
static Oid current_parser_id = InvalidOid;
|
static Oid current_parser_id = InvalidOid;
|
||||||
|
|
||||||
void
|
void
|
||||||
init_prs(Oid id, WParserInfo *prs) {
|
init_prs(Oid id, WParserInfo * prs)
|
||||||
|
{
|
||||||
Oid arg[1] = {OIDOID};
|
Oid arg[1] = {OIDOID};
|
||||||
bool isnull;
|
bool isnull;
|
||||||
Datum pars[1] = {ObjectIdGetDatum(id)};
|
Datum pars[1] = {ObjectIdGetDatum(id)};
|
||||||
@ -33,7 +34,8 @@ init_prs(Oid id, WParserInfo *prs) {
|
|||||||
|
|
||||||
memset(prs, 0, sizeof(WParserInfo));
|
memset(prs, 0, sizeof(WParserInfo));
|
||||||
SPI_connect();
|
SPI_connect();
|
||||||
if ( !plan_getparser ) {
|
if (!plan_getparser)
|
||||||
|
{
|
||||||
plan_getparser = SPI_saveplan(SPI_prepare("select prs_start, prs_nexttoken, prs_end, prs_lextype, prs_headline from pg_ts_parser where oid = $1", 1, arg));
|
plan_getparser = SPI_saveplan(SPI_prepare("select prs_start, prs_nexttoken, prs_end, prs_lextype, prs_headline from pg_ts_parser where oid = $1", 1, arg));
|
||||||
if (!plan_getparser)
|
if (!plan_getparser)
|
||||||
ts_error(ERROR, "SPI_prepare() failed");
|
ts_error(ERROR, "SPI_prepare() failed");
|
||||||
@ -42,8 +44,10 @@ init_prs(Oid id, WParserInfo *prs) {
|
|||||||
stat = SPI_execp(plan_getparser, pars, " ", 1);
|
stat = SPI_execp(plan_getparser, pars, " ", 1);
|
||||||
if (stat < 0)
|
if (stat < 0)
|
||||||
ts_error(ERROR, "SPI_execp return %d", stat);
|
ts_error(ERROR, "SPI_execp return %d", stat);
|
||||||
if ( SPI_processed > 0 ) {
|
if (SPI_processed > 0)
|
||||||
|
{
|
||||||
Oid oid = InvalidOid;
|
Oid oid = InvalidOid;
|
||||||
|
|
||||||
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
||||||
fmgr_info_cxt(oid, &(prs->start_info), TopMemoryContext);
|
fmgr_info_cxt(oid, &(prs->start_info), TopMemoryContext);
|
||||||
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull));
|
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull));
|
||||||
@ -54,12 +58,14 @@ init_prs(Oid id, WParserInfo *prs) {
|
|||||||
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 5, &isnull));
|
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 5, &isnull));
|
||||||
fmgr_info_cxt(oid, &(prs->headline_info), TopMemoryContext);
|
fmgr_info_cxt(oid, &(prs->headline_info), TopMemoryContext);
|
||||||
prs->prs_id = id;
|
prs->prs_id = id;
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
ts_error(ERROR, "No parser with id %d", id);
|
ts_error(ERROR, "No parser with id %d", id);
|
||||||
SPI_finish();
|
SPI_finish();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
WParserInfo *last_prs;
|
WParserInfo *last_prs;
|
||||||
int len;
|
int len;
|
||||||
int reallen;
|
int reallen;
|
||||||
@ -70,7 +76,8 @@ typedef struct {
|
|||||||
static PrsList PList = {NULL, 0, 0, NULL, {0, 0, NULL}};
|
static PrsList PList = {NULL, 0, 0, NULL, {0, 0, NULL}};
|
||||||
|
|
||||||
void
|
void
|
||||||
reset_prs(void) {
|
reset_prs(void)
|
||||||
|
{
|
||||||
freeSNMap(&(PList.name2id_map));
|
freeSNMap(&(PList.name2id_map));
|
||||||
if (PList.list)
|
if (PList.list)
|
||||||
free(PList.list);
|
free(PList.list);
|
||||||
@ -78,19 +85,23 @@ reset_prs(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
compareprs(const void *a, const void *b) {
|
compareprs(const void *a, const void *b)
|
||||||
|
{
|
||||||
return ((WParserInfo *) a)->prs_id - ((WParserInfo *) b)->prs_id;
|
return ((WParserInfo *) a)->prs_id - ((WParserInfo *) b)->prs_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
WParserInfo *
|
WParserInfo *
|
||||||
findprs(Oid id) {
|
findprs(Oid id)
|
||||||
|
{
|
||||||
/* last used prs */
|
/* last used prs */
|
||||||
if (PList.last_prs && PList.last_prs->prs_id == id)
|
if (PList.last_prs && PList.last_prs->prs_id == id)
|
||||||
return PList.last_prs;
|
return PList.last_prs;
|
||||||
|
|
||||||
/* already used prs */
|
/* already used prs */
|
||||||
if ( PList.len != 0 ) {
|
if (PList.len != 0)
|
||||||
|
{
|
||||||
WParserInfo key;
|
WParserInfo key;
|
||||||
|
|
||||||
key.prs_id = id;
|
key.prs_id = id;
|
||||||
PList.last_prs = bsearch(&key, PList.list, PList.len, sizeof(WParserInfo), compareprs);
|
PList.last_prs = bsearch(&key, PList.list, PList.len, sizeof(WParserInfo), compareprs);
|
||||||
if (PList.last_prs != NULL)
|
if (PList.last_prs != NULL)
|
||||||
@ -98,9 +109,11 @@ findprs(Oid id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* last chance */
|
/* last chance */
|
||||||
if ( PList.len==PList.reallen ) {
|
if (PList.len == PList.reallen)
|
||||||
|
{
|
||||||
WParserInfo *tmp;
|
WParserInfo *tmp;
|
||||||
int reallen = (PList.reallen) ? 2 * PList.reallen : 16;
|
int reallen = (PList.reallen) ? 2 * PList.reallen : 16;
|
||||||
|
|
||||||
tmp = (WParserInfo *) realloc(PList.list, sizeof(WParserInfo) * reallen);
|
tmp = (WParserInfo *) realloc(PList.list, sizeof(WParserInfo) * reallen);
|
||||||
if (!tmp)
|
if (!tmp)
|
||||||
ts_error(ERROR, "No memory");
|
ts_error(ERROR, "No memory");
|
||||||
@ -117,7 +130,8 @@ findprs(Oid id) {
|
|||||||
static void *plan_name2id = NULL;
|
static void *plan_name2id = NULL;
|
||||||
|
|
||||||
Oid
|
Oid
|
||||||
name2id_prs(text *name) {
|
name2id_prs(text *name)
|
||||||
|
{
|
||||||
Oid arg[1] = {TEXTOID};
|
Oid arg[1] = {TEXTOID};
|
||||||
bool isnull;
|
bool isnull;
|
||||||
Datum pars[1] = {PointerGetDatum(name)};
|
Datum pars[1] = {PointerGetDatum(name)};
|
||||||
@ -129,7 +143,8 @@ name2id_prs(text *name) {
|
|||||||
|
|
||||||
|
|
||||||
SPI_connect();
|
SPI_connect();
|
||||||
if ( !plan_name2id ) {
|
if (!plan_name2id)
|
||||||
|
{
|
||||||
plan_name2id = SPI_saveplan(SPI_prepare("select oid from pg_ts_parser where prs_name = $1", 1, arg));
|
plan_name2id = SPI_saveplan(SPI_prepare("select oid from pg_ts_parser where prs_name = $1", 1, arg));
|
||||||
if (!plan_name2id)
|
if (!plan_name2id)
|
||||||
ts_error(ERROR, "SPI_prepare() failed");
|
ts_error(ERROR, "SPI_prepare() failed");
|
||||||
@ -149,13 +164,15 @@ name2id_prs(text *name) {
|
|||||||
|
|
||||||
|
|
||||||
/******sql-level interface******/
|
/******sql-level interface******/
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int cur;
|
int cur;
|
||||||
LexDescr *list;
|
LexDescr *list;
|
||||||
} TypeStorage;
|
} TypeStorage;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
setup_firstcall(FuncCallContext *funcctx, Oid prsid) {
|
setup_firstcall(FuncCallContext *funcctx, Oid prsid)
|
||||||
|
{
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
TypeStorage *st;
|
TypeStorage *st;
|
||||||
@ -176,11 +193,13 @@ setup_firstcall(FuncCallContext *funcctx, Oid prsid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Datum
|
static Datum
|
||||||
process_call(FuncCallContext *funcctx) {
|
process_call(FuncCallContext *funcctx)
|
||||||
|
{
|
||||||
TypeStorage *st;
|
TypeStorage *st;
|
||||||
|
|
||||||
st = (TypeStorage *) funcctx->user_fctx;
|
st = (TypeStorage *) funcctx->user_fctx;
|
||||||
if ( st->list && st->list[st->cur].lexid ) {
|
if (st->list && st->list[st->cur].lexid)
|
||||||
|
{
|
||||||
Datum result;
|
Datum result;
|
||||||
char *values[3];
|
char *values[3];
|
||||||
char txtid[16];
|
char txtid[16];
|
||||||
@ -198,8 +217,11 @@ process_call(FuncCallContext *funcctx) {
|
|||||||
pfree(values[2]);
|
pfree(values[2]);
|
||||||
st->cur++;
|
st->cur++;
|
||||||
return result;
|
return result;
|
||||||
} else {
|
}
|
||||||
if ( st->list ) pfree(st->list);
|
else
|
||||||
|
{
|
||||||
|
if (st->list)
|
||||||
|
pfree(st->list);
|
||||||
pfree(st);
|
pfree(st);
|
||||||
}
|
}
|
||||||
return (Datum) 0;
|
return (Datum) 0;
|
||||||
@ -209,11 +231,13 @@ PG_FUNCTION_INFO_V1(token_type);
|
|||||||
Datum token_type(PG_FUNCTION_ARGS);
|
Datum token_type(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
token_type(PG_FUNCTION_ARGS) {
|
token_type(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
FuncCallContext *funcctx;
|
FuncCallContext *funcctx;
|
||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
if (SRF_IS_FIRSTCALL()) {
|
if (SRF_IS_FIRSTCALL())
|
||||||
|
{
|
||||||
funcctx = SRF_FIRSTCALL_INIT();
|
funcctx = SRF_FIRSTCALL_INIT();
|
||||||
setup_firstcall(funcctx, PG_GETARG_OID(0));
|
setup_firstcall(funcctx, PG_GETARG_OID(0));
|
||||||
}
|
}
|
||||||
@ -228,12 +252,15 @@ token_type(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(token_type_byname);
|
PG_FUNCTION_INFO_V1(token_type_byname);
|
||||||
Datum token_type_byname(PG_FUNCTION_ARGS);
|
Datum token_type_byname(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
token_type_byname(PG_FUNCTION_ARGS) {
|
token_type_byname(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
FuncCallContext *funcctx;
|
FuncCallContext *funcctx;
|
||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
if (SRF_IS_FIRSTCALL()) {
|
if (SRF_IS_FIRSTCALL())
|
||||||
|
{
|
||||||
text *name = PG_GETARG_TEXT_P(0);
|
text *name = PG_GETARG_TEXT_P(0);
|
||||||
|
|
||||||
funcctx = SRF_FIRSTCALL_INIT();
|
funcctx = SRF_FIRSTCALL_INIT();
|
||||||
setup_firstcall(funcctx, name2id_prs(name));
|
setup_firstcall(funcctx, name2id_prs(name));
|
||||||
PG_FREE_IF_COPY(name, 0);
|
PG_FREE_IF_COPY(name, 0);
|
||||||
@ -249,11 +276,13 @@ token_type_byname(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(token_type_current);
|
PG_FUNCTION_INFO_V1(token_type_current);
|
||||||
Datum token_type_current(PG_FUNCTION_ARGS);
|
Datum token_type_current(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
token_type_current(PG_FUNCTION_ARGS) {
|
token_type_current(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
FuncCallContext *funcctx;
|
FuncCallContext *funcctx;
|
||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
if (SRF_IS_FIRSTCALL()) {
|
if (SRF_IS_FIRSTCALL())
|
||||||
|
{
|
||||||
funcctx = SRF_FIRSTCALL_INIT();
|
funcctx = SRF_FIRSTCALL_INIT();
|
||||||
if (current_parser_id == InvalidOid)
|
if (current_parser_id == InvalidOid)
|
||||||
current_parser_id = name2id_prs(char2text("default"));
|
current_parser_id = name2id_prs(char2text("default"));
|
||||||
@ -271,7 +300,8 @@ token_type_current(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(set_curprs);
|
PG_FUNCTION_INFO_V1(set_curprs);
|
||||||
Datum set_curprs(PG_FUNCTION_ARGS);
|
Datum set_curprs(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
set_curprs(PG_FUNCTION_ARGS) {
|
set_curprs(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
findprs(PG_GETARG_OID(0));
|
findprs(PG_GETARG_OID(0));
|
||||||
current_parser_id = PG_GETARG_OID(0);
|
current_parser_id = PG_GETARG_OID(0);
|
||||||
PG_RETURN_VOID();
|
PG_RETURN_VOID();
|
||||||
@ -280,7 +310,8 @@ set_curprs(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(set_curprs_byname);
|
PG_FUNCTION_INFO_V1(set_curprs_byname);
|
||||||
Datum set_curprs_byname(PG_FUNCTION_ARGS);
|
Datum set_curprs_byname(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
set_curprs_byname(PG_FUNCTION_ARGS) {
|
set_curprs_byname(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
text *name = PG_GETARG_TEXT_P(0);
|
text *name = PG_GETARG_TEXT_P(0);
|
||||||
|
|
||||||
DirectFunctionCall1(
|
DirectFunctionCall1(
|
||||||
@ -291,12 +322,14 @@ set_curprs_byname(PG_FUNCTION_ARGS) {
|
|||||||
PG_RETURN_VOID();
|
PG_RETURN_VOID();
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int type;
|
int type;
|
||||||
char *lexem;
|
char *lexem;
|
||||||
} LexemEntry;
|
} LexemEntry;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int cur;
|
int cur;
|
||||||
int len;
|
int len;
|
||||||
LexemEntry *list;
|
LexemEntry *list;
|
||||||
@ -304,13 +337,15 @@ typedef struct {
|
|||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt) {
|
prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt)
|
||||||
|
{
|
||||||
TupleDesc tupdesc;
|
TupleDesc tupdesc;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
PrsStorage *st;
|
PrsStorage *st;
|
||||||
WParserInfo *prs = findprs(prsid);
|
WParserInfo *prs = findprs(prsid);
|
||||||
char *lex = NULL;
|
char *lex = NULL;
|
||||||
int llen=0, type=0;
|
int llen = 0,
|
||||||
|
type = 0;
|
||||||
|
|
||||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||||
|
|
||||||
@ -331,9 +366,11 @@ prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt) {
|
|||||||
&(prs->getlexeme_info),
|
&(prs->getlexeme_info),
|
||||||
PointerGetDatum(prs->prs),
|
PointerGetDatum(prs->prs),
|
||||||
PointerGetDatum(&lex),
|
PointerGetDatum(&lex),
|
||||||
PointerGetDatum(&llen))) ) != 0 ) {
|
PointerGetDatum(&llen)))) != 0)
|
||||||
|
{
|
||||||
|
|
||||||
if ( st->cur>=st->len ) {
|
if (st->cur >= st->len)
|
||||||
|
{
|
||||||
st->len = 2 * st->len;
|
st->len = 2 * st->len;
|
||||||
st->list = (LexemEntry *) repalloc(st->list, sizeof(LexemEntry) * st->len);
|
st->list = (LexemEntry *) repalloc(st->list, sizeof(LexemEntry) * st->len);
|
||||||
}
|
}
|
||||||
@ -360,11 +397,13 @@ prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Datum
|
static Datum
|
||||||
prs_process_call(FuncCallContext *funcctx) {
|
prs_process_call(FuncCallContext *funcctx)
|
||||||
|
{
|
||||||
PrsStorage *st;
|
PrsStorage *st;
|
||||||
|
|
||||||
st = (PrsStorage *) funcctx->user_fctx;
|
st = (PrsStorage *) funcctx->user_fctx;
|
||||||
if ( st->cur < st->len ) {
|
if (st->cur < st->len)
|
||||||
|
{
|
||||||
Datum result;
|
Datum result;
|
||||||
char *values[2];
|
char *values[2];
|
||||||
char tid[16];
|
char tid[16];
|
||||||
@ -379,8 +418,11 @@ prs_process_call(FuncCallContext *funcctx) {
|
|||||||
pfree(values[1]);
|
pfree(values[1]);
|
||||||
st->cur++;
|
st->cur++;
|
||||||
return result;
|
return result;
|
||||||
} else {
|
}
|
||||||
if ( st->list ) pfree(st->list);
|
else
|
||||||
|
{
|
||||||
|
if (st->list)
|
||||||
|
pfree(st->list);
|
||||||
pfree(st);
|
pfree(st);
|
||||||
}
|
}
|
||||||
return (Datum) 0;
|
return (Datum) 0;
|
||||||
@ -391,12 +433,15 @@ prs_process_call(FuncCallContext *funcctx) {
|
|||||||
PG_FUNCTION_INFO_V1(parse);
|
PG_FUNCTION_INFO_V1(parse);
|
||||||
Datum parse(PG_FUNCTION_ARGS);
|
Datum parse(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
parse(PG_FUNCTION_ARGS) {
|
parse(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
FuncCallContext *funcctx;
|
FuncCallContext *funcctx;
|
||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
if (SRF_IS_FIRSTCALL()) {
|
if (SRF_IS_FIRSTCALL())
|
||||||
|
{
|
||||||
text *txt = PG_GETARG_TEXT_P(1);
|
text *txt = PG_GETARG_TEXT_P(1);
|
||||||
|
|
||||||
funcctx = SRF_FIRSTCALL_INIT();
|
funcctx = SRF_FIRSTCALL_INIT();
|
||||||
prs_setup_firstcall(funcctx, PG_GETARG_OID(0), txt);
|
prs_setup_firstcall(funcctx, PG_GETARG_OID(0), txt);
|
||||||
PG_FREE_IF_COPY(txt, 1);
|
PG_FREE_IF_COPY(txt, 1);
|
||||||
@ -412,13 +457,16 @@ parse(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(parse_byname);
|
PG_FUNCTION_INFO_V1(parse_byname);
|
||||||
Datum parse_byname(PG_FUNCTION_ARGS);
|
Datum parse_byname(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
parse_byname(PG_FUNCTION_ARGS) {
|
parse_byname(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
FuncCallContext *funcctx;
|
FuncCallContext *funcctx;
|
||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
if (SRF_IS_FIRSTCALL()) {
|
if (SRF_IS_FIRSTCALL())
|
||||||
|
{
|
||||||
text *name = PG_GETARG_TEXT_P(0);
|
text *name = PG_GETARG_TEXT_P(0);
|
||||||
text *txt = PG_GETARG_TEXT_P(1);
|
text *txt = PG_GETARG_TEXT_P(1);
|
||||||
|
|
||||||
funcctx = SRF_FIRSTCALL_INIT();
|
funcctx = SRF_FIRSTCALL_INIT();
|
||||||
prs_setup_firstcall(funcctx, name2id_prs(name), txt);
|
prs_setup_firstcall(funcctx, name2id_prs(name), txt);
|
||||||
PG_FREE_IF_COPY(name, 0);
|
PG_FREE_IF_COPY(name, 0);
|
||||||
@ -436,12 +484,15 @@ parse_byname(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(parse_current);
|
PG_FUNCTION_INFO_V1(parse_current);
|
||||||
Datum parse_current(PG_FUNCTION_ARGS);
|
Datum parse_current(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
parse_current(PG_FUNCTION_ARGS) {
|
parse_current(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
FuncCallContext *funcctx;
|
FuncCallContext *funcctx;
|
||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
if (SRF_IS_FIRSTCALL()) {
|
if (SRF_IS_FIRSTCALL())
|
||||||
|
{
|
||||||
text *txt = PG_GETARG_TEXT_P(0);
|
text *txt = PG_GETARG_TEXT_P(0);
|
||||||
|
|
||||||
funcctx = SRF_FIRSTCALL_INIT();
|
funcctx = SRF_FIRSTCALL_INIT();
|
||||||
if (current_parser_id == InvalidOid)
|
if (current_parser_id == InvalidOid)
|
||||||
current_parser_id = name2id_prs(char2text("default"));
|
current_parser_id = name2id_prs(char2text("default"));
|
||||||
@ -459,7 +510,8 @@ parse_current(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(headline);
|
PG_FUNCTION_INFO_V1(headline);
|
||||||
Datum headline(PG_FUNCTION_ARGS);
|
Datum headline(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
headline(PG_FUNCTION_ARGS) {
|
headline(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
TSCfgInfo *cfg = findcfg(PG_GETARG_OID(0));
|
TSCfgInfo *cfg = findcfg(PG_GETARG_OID(0));
|
||||||
text *in = PG_GETARG_TEXT_P(1);
|
text *in = PG_GETARG_TEXT_P(1);
|
||||||
QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(2)));
|
QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(2)));
|
||||||
@ -485,7 +537,8 @@ headline(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
PG_FREE_IF_COPY(in, 1);
|
PG_FREE_IF_COPY(in, 1);
|
||||||
PG_FREE_IF_COPY(query, 2);
|
PG_FREE_IF_COPY(query, 2);
|
||||||
if ( opt ) PG_FREE_IF_COPY(opt,3);
|
if (opt)
|
||||||
|
PG_FREE_IF_COPY(opt, 3);
|
||||||
pfree(prs.words);
|
pfree(prs.words);
|
||||||
pfree(prs.startsel);
|
pfree(prs.startsel);
|
||||||
pfree(prs.stopsel);
|
pfree(prs.stopsel);
|
||||||
@ -497,7 +550,8 @@ headline(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(headline_byname);
|
PG_FUNCTION_INFO_V1(headline_byname);
|
||||||
Datum headline_byname(PG_FUNCTION_ARGS);
|
Datum headline_byname(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
headline_byname(PG_FUNCTION_ARGS) {
|
headline_byname(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
text *cfg = PG_GETARG_TEXT_P(0);
|
text *cfg = PG_GETARG_TEXT_P(0);
|
||||||
|
|
||||||
Datum out = DirectFunctionCall4(
|
Datum out = DirectFunctionCall4(
|
||||||
@ -515,7 +569,8 @@ headline_byname(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(headline_current);
|
PG_FUNCTION_INFO_V1(headline_current);
|
||||||
Datum headline_current(PG_FUNCTION_ARGS);
|
Datum headline_current(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
headline_current(PG_FUNCTION_ARGS) {
|
headline_current(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
PG_RETURN_DATUM(DirectFunctionCall4(
|
PG_RETURN_DATUM(DirectFunctionCall4(
|
||||||
headline,
|
headline,
|
||||||
ObjectIdGetDatum(get_currcfg()),
|
ObjectIdGetDatum(get_currcfg()),
|
||||||
@ -524,6 +579,3 @@ headline_current(PG_FUNCTION_ARGS) {
|
|||||||
(PG_NARGS() > 2) ? PG_GETARG_DATUM(2) : PointerGetDatum(NULL)
|
(PG_NARGS() > 2) ? PG_GETARG_DATUM(2) : PointerGetDatum(NULL)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "fmgr.h"
|
#include "fmgr.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
Oid prs_id;
|
Oid prs_id;
|
||||||
FmgrInfo start_info;
|
FmgrInfo start_info;
|
||||||
FmgrInfo getlexeme_info;
|
FmgrInfo getlexeme_info;
|
||||||
@ -19,7 +20,8 @@ Oid name2id_prs(text *name);
|
|||||||
void reset_prs(void);
|
void reset_prs(void);
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
int lexid;
|
int lexid;
|
||||||
char *alias;
|
char *alias;
|
||||||
char *descr;
|
char *descr;
|
||||||
|
@ -20,11 +20,13 @@ PG_FUNCTION_INFO_V1(prsd_lextype);
|
|||||||
Datum prsd_lextype(PG_FUNCTION_ARGS);
|
Datum prsd_lextype(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
prsd_lextype(PG_FUNCTION_ARGS) {
|
prsd_lextype(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
LexDescr *descr = (LexDescr *) palloc(sizeof(LexDescr) * (LASTNUM + 1));
|
LexDescr *descr = (LexDescr *) palloc(sizeof(LexDescr) * (LASTNUM + 1));
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i=1;i<=LASTNUM;i++) {
|
for (i = 1; i <= LASTNUM; i++)
|
||||||
|
{
|
||||||
descr[i - 1].lexid = i;
|
descr[i - 1].lexid = i;
|
||||||
descr[i - 1].alias = pstrdup(tok_alias[i]);
|
descr[i - 1].alias = pstrdup(tok_alias[i]);
|
||||||
descr[i - 1].descr = pstrdup(lex_descr[i]);
|
descr[i - 1].descr = pstrdup(lex_descr[i]);
|
||||||
@ -38,7 +40,8 @@ prsd_lextype(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(prsd_start);
|
PG_FUNCTION_INFO_V1(prsd_start);
|
||||||
Datum prsd_start(PG_FUNCTION_ARGS);
|
Datum prsd_start(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
prsd_start(PG_FUNCTION_ARGS) {
|
prsd_start(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
start_parse_str((char *) PG_GETARG_POINTER(0), PG_GETARG_INT32(1));
|
start_parse_str((char *) PG_GETARG_POINTER(0), PG_GETARG_INT32(1));
|
||||||
PG_RETURN_POINTER(NULL);
|
PG_RETURN_POINTER(NULL);
|
||||||
}
|
}
|
||||||
@ -46,7 +49,8 @@ prsd_start(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(prsd_getlexeme);
|
PG_FUNCTION_INFO_V1(prsd_getlexeme);
|
||||||
Datum prsd_getlexeme(PG_FUNCTION_ARGS);
|
Datum prsd_getlexeme(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
prsd_getlexeme(PG_FUNCTION_ARGS) {
|
prsd_getlexeme(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
/* ParserState *p=(ParserState*)PG_GETARG_POINTER(0); */
|
/* ParserState *p=(ParserState*)PG_GETARG_POINTER(0); */
|
||||||
char **t = (char **) PG_GETARG_POINTER(1);
|
char **t = (char **) PG_GETARG_POINTER(1);
|
||||||
int *tlen = (int *) PG_GETARG_POINTER(2);
|
int *tlen = (int *) PG_GETARG_POINTER(2);
|
||||||
@ -60,7 +64,8 @@ prsd_getlexeme(PG_FUNCTION_ARGS) {
|
|||||||
PG_FUNCTION_INFO_V1(prsd_end);
|
PG_FUNCTION_INFO_V1(prsd_end);
|
||||||
Datum prsd_end(PG_FUNCTION_ARGS);
|
Datum prsd_end(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
prsd_end(PG_FUNCTION_ARGS) {
|
prsd_end(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
/* ParserState *p=(ParserState*)PG_GETARG_POINTER(0); */
|
/* ParserState *p=(ParserState*)PG_GETARG_POINTER(0); */
|
||||||
end_parse();
|
end_parse();
|
||||||
PG_RETURN_VOID();
|
PG_RETURN_VOID();
|
||||||
@ -76,15 +81,19 @@ prsd_end(PG_FUNCTION_ARGS) {
|
|||||||
#define NONWORDTOKEN(x) ( (x)==12 || HLIDIGNORE(x) )
|
#define NONWORDTOKEN(x) ( (x)==12 || HLIDIGNORE(x) )
|
||||||
#define NOENDTOKEN(x) ( NONWORDTOKEN(x) || (x)==7 || (x)==8 || (x)==20 || (x)==21 || (x)==22 || IDIGNORE(x) )
|
#define NOENDTOKEN(x) ( NONWORDTOKEN(x) || (x)==7 || (x)==8 || (x)==20 || (x)==21 || (x)==22 || IDIGNORE(x) )
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
HLWORD *words;
|
HLWORD *words;
|
||||||
int len;
|
int len;
|
||||||
} hlCheck;
|
} hlCheck;
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
checkcondition_HL(void *checkval, ITEM *val) {
|
checkcondition_HL(void *checkval, ITEM * val)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
for(i=0;i<((hlCheck*)checkval)->len;i++) {
|
|
||||||
|
for (i = 0; i < ((hlCheck *) checkval)->len; i++)
|
||||||
|
{
|
||||||
if (((hlCheck *) checkval)->words[i].item == val)
|
if (((hlCheck *) checkval)->words[i].item == val)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -93,20 +102,27 @@ checkcondition_HL(void *checkval, ITEM *val) {
|
|||||||
|
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
hlCover(HLPRSTEXT *prs, QUERYTYPE *query, int *p, int *q) {
|
hlCover(HLPRSTEXT * prs, QUERYTYPE * query, int *p, int *q)
|
||||||
int i,j;
|
{
|
||||||
|
int i,
|
||||||
|
j;
|
||||||
ITEM *item = GETQUERY(query);
|
ITEM *item = GETQUERY(query);
|
||||||
int pos = *p;
|
int pos = *p;
|
||||||
|
|
||||||
*q = 0;
|
*q = 0;
|
||||||
*p = 0x7fffffff;
|
*p = 0x7fffffff;
|
||||||
|
|
||||||
for(j=0;j<query->size;j++) {
|
for (j = 0; j < query->size; j++)
|
||||||
if ( item->type != VAL ) {
|
{
|
||||||
|
if (item->type != VAL)
|
||||||
|
{
|
||||||
item++;
|
item++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for(i=pos;i<prs->curwords;i++) {
|
for (i = pos; i < prs->curwords; i++)
|
||||||
if ( prs->words[i].item == item ) {
|
{
|
||||||
|
if (prs->words[i].item == item)
|
||||||
|
{
|
||||||
if (i > *q)
|
if (i > *q)
|
||||||
*q = i;
|
*q = i;
|
||||||
break;
|
break;
|
||||||
@ -119,13 +135,17 @@ hlCover(HLPRSTEXT *prs, QUERYTYPE *query, int *p, int *q) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
item = GETQUERY(query);
|
item = GETQUERY(query);
|
||||||
for(j=0;j<query->size;j++) {
|
for (j = 0; j < query->size; j++)
|
||||||
if ( item->type != VAL ) {
|
{
|
||||||
|
if (item->type != VAL)
|
||||||
|
{
|
||||||
item++;
|
item++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for(i=*q;i>=pos;i--) {
|
for (i = *q; i >= pos; i--)
|
||||||
if ( prs->words[i].item == item ) {
|
{
|
||||||
|
if (prs->words[i].item == item)
|
||||||
|
{
|
||||||
if (i < *p)
|
if (i < *p)
|
||||||
*p = i;
|
*p = i;
|
||||||
break;
|
break;
|
||||||
@ -134,11 +154,14 @@ hlCover(HLPRSTEXT *prs, QUERYTYPE *query, int *p, int *q) {
|
|||||||
item++;
|
item++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( *p<=*q ) {
|
if (*p <= *q)
|
||||||
|
{
|
||||||
hlCheck ch = {&(prs->words[*p]), *q - *p + 1};
|
hlCheck ch = {&(prs->words[*p]), *q - *p + 1};
|
||||||
if ( TS_execute(GETQUERY(query), &ch, false, checkcondition_HL) ) {
|
|
||||||
|
if (TS_execute(GETQUERY(query), &ch, false, checkcondition_HL))
|
||||||
return true;
|
return true;
|
||||||
} else {
|
else
|
||||||
|
{
|
||||||
(*p)++;
|
(*p)++;
|
||||||
return hlCover(prs, query, p, q);
|
return hlCover(prs, query, p, q);
|
||||||
}
|
}
|
||||||
@ -150,32 +173,41 @@ hlCover(HLPRSTEXT *prs, QUERYTYPE *query, int *p, int *q) {
|
|||||||
PG_FUNCTION_INFO_V1(prsd_headline);
|
PG_FUNCTION_INFO_V1(prsd_headline);
|
||||||
Datum prsd_headline(PG_FUNCTION_ARGS);
|
Datum prsd_headline(PG_FUNCTION_ARGS);
|
||||||
Datum
|
Datum
|
||||||
prsd_headline(PG_FUNCTION_ARGS) {
|
prsd_headline(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
HLPRSTEXT *prs = (HLPRSTEXT *) PG_GETARG_POINTER(0);
|
HLPRSTEXT *prs = (HLPRSTEXT *) PG_GETARG_POINTER(0);
|
||||||
text *opt = (text *) PG_GETARG_POINTER(1); /* can't be toasted */
|
text *opt = (text *) PG_GETARG_POINTER(1); /* can't be toasted */
|
||||||
QUERYTYPE *query = (QUERYTYPE *) PG_GETARG_POINTER(2); /* can't be toasted */
|
QUERYTYPE *query = (QUERYTYPE *) PG_GETARG_POINTER(2); /* can't be toasted */
|
||||||
|
|
||||||
/* from opt + start and and tag */
|
/* from opt + start and and tag */
|
||||||
int min_words = 15;
|
int min_words = 15;
|
||||||
int max_words = 35;
|
int max_words = 35;
|
||||||
int shortword = 3;
|
int shortword = 3;
|
||||||
|
|
||||||
int p=0,q=0;
|
int p = 0,
|
||||||
int bestb=-1,beste=-1;
|
q = 0;
|
||||||
|
int bestb = -1,
|
||||||
|
beste = -1;
|
||||||
int bestlen = -1;
|
int bestlen = -1;
|
||||||
int pose=0, poslen, curlen;
|
int pose = 0,
|
||||||
|
poslen,
|
||||||
|
curlen;
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* config */
|
/* config */
|
||||||
prs->startsel = NULL;
|
prs->startsel = NULL;
|
||||||
prs->stopsel = NULL;
|
prs->stopsel = NULL;
|
||||||
if ( opt ) {
|
if (opt)
|
||||||
Map *map,*mptr;
|
{
|
||||||
|
Map *map,
|
||||||
|
*mptr;
|
||||||
|
|
||||||
parse_cfgdict(opt, &map);
|
parse_cfgdict(opt, &map);
|
||||||
mptr = map;
|
mptr = map;
|
||||||
|
|
||||||
while(mptr && mptr->key) {
|
while (mptr && mptr->key)
|
||||||
|
{
|
||||||
if (strcasecmp(mptr->key, "MaxWords") == 0)
|
if (strcasecmp(mptr->key, "MaxWords") == 0)
|
||||||
max_words = pg_atoi(mptr->value, 4, 1);
|
max_words = pg_atoi(mptr->value, 4, 1);
|
||||||
else if (strcasecmp(mptr->key, "MinWords") == 0)
|
else if (strcasecmp(mptr->key, "MinWords") == 0)
|
||||||
@ -208,11 +240,13 @@ prsd_headline(PG_FUNCTION_ARGS) {
|
|||||||
errmsg("must be ShortWord >= 0")));
|
errmsg("must be ShortWord >= 0")));
|
||||||
}
|
}
|
||||||
|
|
||||||
while( hlCover(prs,query,&p,&q) ) {
|
while (hlCover(prs, query, &p, &q))
|
||||||
|
{
|
||||||
/* find cover len in words */
|
/* find cover len in words */
|
||||||
curlen = 0;
|
curlen = 0;
|
||||||
poslen = 0;
|
poslen = 0;
|
||||||
for(i=p;i<=q && curlen < max_words ; i++) {
|
for (i = p; i <= q && curlen < max_words; i++)
|
||||||
|
{
|
||||||
if (!NONWORDTOKEN(prs->words[i].type))
|
if (!NONWORDTOKEN(prs->words[i].type))
|
||||||
curlen++;
|
curlen++;
|
||||||
if (prs->words[i].item && !prs->words[i].repeated)
|
if (prs->words[i].item && !prs->words[i].repeated)
|
||||||
@ -220,15 +254,19 @@ prsd_headline(PG_FUNCTION_ARGS) {
|
|||||||
pose = i;
|
pose = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( poslen<bestlen && !(NOENDTOKEN(prs->words[beste].type) || prs->words[beste].len <= shortword) ) {
|
if (poslen < bestlen && !(NOENDTOKEN(prs->words[beste].type) || prs->words[beste].len <= shortword))
|
||||||
|
{
|
||||||
/* best already finded, so try one more cover */
|
/* best already finded, so try one more cover */
|
||||||
p++;
|
p++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( curlen < max_words ) { /* find good end */
|
if (curlen < max_words)
|
||||||
for(i=i-1 ;i<prs->curwords && curlen<max_words; i++) {
|
{ /* find good end */
|
||||||
if ( i!=q ) {
|
for (i = i - 1; i < prs->curwords && curlen < max_words; i++)
|
||||||
|
{
|
||||||
|
if (i != q)
|
||||||
|
{
|
||||||
if (!NONWORDTOKEN(prs->words[i].type))
|
if (!NONWORDTOKEN(prs->words[i].type))
|
||||||
curlen++;
|
curlen++;
|
||||||
if (prs->words[i].item && !prs->words[i].repeated)
|
if (prs->words[i].item && !prs->words[i].repeated)
|
||||||
@ -240,8 +278,11 @@ prsd_headline(PG_FUNCTION_ARGS) {
|
|||||||
if (curlen >= min_words)
|
if (curlen >= min_words)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else { /* shorter cover :((( */
|
}
|
||||||
for(;curlen>min_words;i--) {
|
else
|
||||||
|
{ /* shorter cover :((( */
|
||||||
|
for (; curlen > min_words; i--)
|
||||||
|
{
|
||||||
if (!NONWORDTOKEN(prs->words[i].type))
|
if (!NONWORDTOKEN(prs->words[i].type))
|
||||||
curlen--;
|
curlen--;
|
||||||
if (prs->words[i].item && !prs->words[i].repeated)
|
if (prs->words[i].item && !prs->words[i].repeated)
|
||||||
@ -255,26 +296,32 @@ prsd_headline(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
if (bestlen < 0 || (poslen > bestlen && !(NOENDTOKEN(prs->words[pose].type) || prs->words[pose].len <= shortword)) ||
|
if (bestlen < 0 || (poslen > bestlen && !(NOENDTOKEN(prs->words[pose].type) || prs->words[pose].len <= shortword)) ||
|
||||||
(bestlen >= 0 && !(NOENDTOKEN(prs->words[pose].type) || prs->words[pose].len <= shortword) &&
|
(bestlen >= 0 && !(NOENDTOKEN(prs->words[pose].type) || prs->words[pose].len <= shortword) &&
|
||||||
(NOENDTOKEN(prs->words[beste].type) || prs->words[beste].len <= shortword) ) ) {
|
(NOENDTOKEN(prs->words[beste].type) || prs->words[beste].len <= shortword)))
|
||||||
bestb=p; beste=pose;
|
{
|
||||||
|
bestb = p;
|
||||||
|
beste = pose;
|
||||||
bestlen = poslen;
|
bestlen = poslen;
|
||||||
}
|
}
|
||||||
|
|
||||||
p++;
|
p++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( bestlen<0 ) {
|
if (bestlen < 0)
|
||||||
|
{
|
||||||
curlen = 0;
|
curlen = 0;
|
||||||
poslen = 0;
|
poslen = 0;
|
||||||
for(i=0;i<prs->curwords && curlen<min_words ; i++) {
|
for (i = 0; i < prs->curwords && curlen < min_words; i++)
|
||||||
|
{
|
||||||
if (!NONWORDTOKEN(prs->words[i].type))
|
if (!NONWORDTOKEN(prs->words[i].type))
|
||||||
curlen++;
|
curlen++;
|
||||||
pose = i;
|
pose = i;
|
||||||
}
|
}
|
||||||
bestb=0; beste=pose;
|
bestb = 0;
|
||||||
|
beste = pose;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(i=bestb;i<=beste;i++) {
|
for (i = bestb; i <= beste; i++)
|
||||||
|
{
|
||||||
if (prs->words[i].item)
|
if (prs->words[i].item)
|
||||||
prs->words[i].selected = 1;
|
prs->words[i].selected = 1;
|
||||||
if (prs->words[i].repeated)
|
if (prs->words[i].repeated)
|
||||||
@ -294,4 +341,3 @@ prsd_headline(PG_FUNCTION_ARGS) {
|
|||||||
|
|
||||||
PG_RETURN_POINTER(prs);
|
PG_RETURN_POINTER(prs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.84 2003/07/21 20:29:37 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/heaptuple.c,v 1.85 2003/08/04 00:43:11 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The old interface functions have been converted to macros
|
* The old interface functions have been converted to macros
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.65 2003/07/21 20:29:37 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/indextuple.c,v 1.66 2003/08/04 00:43:11 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.75 2003/07/21 20:29:38 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.76 2003/08/04 00:43:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -81,8 +81,8 @@ printtup_create_DR(CommandDest dest, Portal portal)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* In protocol 2.0 the Bind message does not exist, so there is
|
* In protocol 2.0 the Bind message does not exist, so there is no
|
||||||
* no way for the columns to have different print formats; it's
|
* way for the columns to have different print formats; it's
|
||||||
* sufficient to look at the first one.
|
* sufficient to look at the first one.
|
||||||
*/
|
*/
|
||||||
if (portal->formats && portal->formats[0] != 0)
|
if (portal->formats && portal->formats[0] != 0)
|
||||||
@ -116,7 +116,8 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
|
|||||||
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
|
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Send portal name to frontend (obsolete cruft, gone in proto 3.0)
|
* Send portal name to frontend (obsolete cruft, gone in proto
|
||||||
|
* 3.0)
|
||||||
*
|
*
|
||||||
* If portal name not specified, use "blank" portal.
|
* If portal name not specified, use "blank" portal.
|
||||||
*/
|
*/
|
||||||
@ -129,8 +130,8 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a retrieve, and we are supposed to emit row descriptions,
|
* If this is a retrieve, and we are supposed to emit row
|
||||||
* then we send back the tuple descriptor of the tuples.
|
* descriptions, then we send back the tuple descriptor of the tuples.
|
||||||
*/
|
*/
|
||||||
if (operation == CMD_SELECT && myState->sendDescrip)
|
if (operation == CMD_SELECT && myState->sendDescrip)
|
||||||
{
|
{
|
||||||
@ -320,8 +321,8 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have a toasted datum, forcibly detoast it here to
|
* If we have a toasted datum, forcibly detoast it here to avoid
|
||||||
* avoid memory leakage inside the type's output routine.
|
* memory leakage inside the type's output routine.
|
||||||
*/
|
*/
|
||||||
if (thisState->typisvarlena)
|
if (thisState->typisvarlena)
|
||||||
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
||||||
@ -424,8 +425,8 @@ printtup_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||||||
Assert(thisState->format == 0);
|
Assert(thisState->format == 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have a toasted datum, forcibly detoast it here to
|
* If we have a toasted datum, forcibly detoast it here to avoid
|
||||||
* avoid memory leakage inside the type's output routine.
|
* memory leakage inside the type's output routine.
|
||||||
*/
|
*/
|
||||||
if (thisState->typisvarlena)
|
if (thisState->typisvarlena)
|
||||||
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
||||||
@ -536,9 +537,10 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||||||
continue;
|
continue;
|
||||||
getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
|
getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
|
||||||
&typoutput, &typelem, &typisvarlena);
|
&typoutput, &typelem, &typisvarlena);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have a toasted datum, forcibly detoast it here to
|
* If we have a toasted datum, forcibly detoast it here to avoid
|
||||||
* avoid memory leakage inside the type's output routine.
|
* memory leakage inside the type's output routine.
|
||||||
*/
|
*/
|
||||||
if (typisvarlena)
|
if (typisvarlena)
|
||||||
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
||||||
@ -627,8 +629,8 @@ printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||||||
Assert(thisState->format == 1);
|
Assert(thisState->format == 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we have a toasted datum, forcibly detoast it here to
|
* If we have a toasted datum, forcibly detoast it here to avoid
|
||||||
* avoid memory leakage inside the type's output routine.
|
* memory leakage inside the type's output routine.
|
||||||
*/
|
*/
|
||||||
if (thisState->typisvarlena)
|
if (thisState->typisvarlena)
|
||||||
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/gist/gistscan.c,v 1.45 2003/07/28 00:09:14 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/gist/gistscan.c,v 1.46 2003/08/04 00:43:12 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -104,11 +104,12 @@ gistrescan(PG_FUNCTION_ARGS)
|
|||||||
memmove(s->keyData,
|
memmove(s->keyData,
|
||||||
key,
|
key,
|
||||||
s->numberOfKeys * sizeof(ScanKeyData));
|
s->numberOfKeys * sizeof(ScanKeyData));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Play games here with the scan key to use the Consistent
|
* Play games here with the scan key to use the Consistent
|
||||||
* function for all comparisons: 1) the sk_procedure field
|
* function for all comparisons: 1) the sk_procedure field will
|
||||||
* will now be used to hold the strategy number 2) the
|
* now be used to hold the strategy number 2) the sk_func field
|
||||||
* sk_func field will point to the Consistent function
|
* will point to the Consistent function
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < s->numberOfKeys; i++)
|
for (i = 0; i < s->numberOfKeys; i++)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashfunc.c,v 1.36 2003/06/22 22:04:54 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashfunc.c,v 1.37 2003/08/04 00:43:12 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* These functions are stored in pg_amproc. For each operator class
|
* These functions are stored in pg_amproc. For each operator class
|
||||||
@ -60,9 +60,9 @@ hashfloat4(PG_FUNCTION_ARGS)
|
|||||||
float4 key = PG_GETARG_FLOAT4(0);
|
float4 key = PG_GETARG_FLOAT4(0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On IEEE-float machines, minus zero and zero have different bit patterns
|
* On IEEE-float machines, minus zero and zero have different bit
|
||||||
* but should compare as equal. We must ensure that they have the same
|
* patterns but should compare as equal. We must ensure that they
|
||||||
* hash value, which is most easily done this way:
|
* have the same hash value, which is most easily done this way:
|
||||||
*/
|
*/
|
||||||
if (key == (float4) 0)
|
if (key == (float4) 0)
|
||||||
PG_RETURN_UINT32(0);
|
PG_RETURN_UINT32(0);
|
||||||
@ -76,9 +76,9 @@ hashfloat8(PG_FUNCTION_ARGS)
|
|||||||
float8 key = PG_GETARG_FLOAT8(0);
|
float8 key = PG_GETARG_FLOAT8(0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On IEEE-float machines, minus zero and zero have different bit patterns
|
* On IEEE-float machines, minus zero and zero have different bit
|
||||||
* but should compare as equal. We must ensure that they have the same
|
* patterns but should compare as equal. We must ensure that they
|
||||||
* hash value, which is most easily done this way:
|
* have the same hash value, which is most easily done this way:
|
||||||
*/
|
*/
|
||||||
if (key == (float8) 0)
|
if (key == (float8) 0)
|
||||||
PG_RETURN_UINT32(0);
|
PG_RETURN_UINT32(0);
|
||||||
@ -121,9 +121,9 @@ hashtext(PG_FUNCTION_ARGS)
|
|||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: this is currently identical in behavior to hashvarlena,
|
* Note: this is currently identical in behavior to hashvarlena, but
|
||||||
* but it seems likely that we may need to do something different
|
* it seems likely that we may need to do something different in non-C
|
||||||
* in non-C locales. (See also hashbpchar, if so.)
|
* locales. (See also hashbpchar, if so.)
|
||||||
*/
|
*/
|
||||||
result = hash_any((unsigned char *) VARDATA(key),
|
result = hash_any((unsigned char *) VARDATA(key),
|
||||||
VARSIZE(key) - VARHDRSZ);
|
VARSIZE(key) - VARHDRSZ);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashovfl.c,v 1.35 2003/07/21 20:29:38 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/hash/hashovfl.c,v 1.36 2003/08/04 00:43:12 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Overflow pages look like ordinary relation pages.
|
* Overflow pages look like ordinary relation pages.
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.152 2003/07/21 20:29:38 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/heap/heapam.c,v 1.153 2003/08/04 00:43:14 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -1132,6 +1132,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid)
|
|||||||
xlhdr.t_natts = tup->t_data->t_natts;
|
xlhdr.t_natts = tup->t_data->t_natts;
|
||||||
xlhdr.t_infomask = tup->t_data->t_infomask;
|
xlhdr.t_infomask = tup->t_data->t_infomask;
|
||||||
xlhdr.t_hoff = tup->t_data->t_hoff;
|
xlhdr.t_hoff = tup->t_data->t_hoff;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* note we mark rdata[1] as belonging to buffer; if XLogInsert
|
* note we mark rdata[1] as belonging to buffer; if XLogInsert
|
||||||
* decides to write the whole page to the xlog, we don't need to
|
* decides to write the whole page to the xlog, we don't need to
|
||||||
@ -1149,9 +1150,9 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid)
|
|||||||
rdata[2].next = NULL;
|
rdata[2].next = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is the single and first tuple on page, we can reinit the
|
* If this is the single and first tuple on page, we can reinit
|
||||||
* page instead of restoring the whole thing. Set flag, and hide
|
* the page instead of restoring the whole thing. Set flag, and
|
||||||
* buffer references from XLogInsert.
|
* hide buffer references from XLogInsert.
|
||||||
*/
|
*/
|
||||||
if (ItemPointerGetOffsetNumber(&(tup->t_self)) == FirstOffsetNumber &&
|
if (ItemPointerGetOffsetNumber(&(tup->t_self)) == FirstOffsetNumber &&
|
||||||
PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
|
PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
|
||||||
@ -1991,9 +1992,10 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
|||||||
2 * sizeof(TransactionId));
|
2 * sizeof(TransactionId));
|
||||||
hsize += 2 * sizeof(TransactionId);
|
hsize += 2 * sizeof(TransactionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As with insert records, we need not store the rdata[2] segment
|
* As with insert records, we need not store the rdata[2] segment if
|
||||||
* if we decide to store the whole buffer instead.
|
* we decide to store the whole buffer instead.
|
||||||
*/
|
*/
|
||||||
rdata[2].buffer = newbuf;
|
rdata[2].buffer = newbuf;
|
||||||
rdata[2].data = (char *) &xlhdr;
|
rdata[2].data = (char *) &xlhdr;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.67 2003/07/21 20:29:39 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/index/indexam.c,v 1.68 2003/08/04 00:43:15 momjian Exp $
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
* index_open - open an index relation by relation OID
|
* index_open - open an index relation by relation OID
|
||||||
@ -394,8 +394,8 @@ index_restrpos(IndexScanDesc scan)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* We do not reset got_tuple; so if the scan is actually being
|
* We do not reset got_tuple; so if the scan is actually being
|
||||||
* short-circuited by index_getnext, the effective position restoration
|
* short-circuited by index_getnext, the effective position
|
||||||
* is done by restoring unique_tuple_pos.
|
* restoration is done by restoring unique_tuple_pos.
|
||||||
*/
|
*/
|
||||||
scan->unique_tuple_pos = scan->unique_tuple_mark;
|
scan->unique_tuple_pos = scan->unique_tuple_mark;
|
||||||
|
|
||||||
@ -427,20 +427,20 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we already got a tuple and it must be unique, there's no need
|
* If we already got a tuple and it must be unique, there's no need to
|
||||||
* to make the index AM look through any additional tuples. (This can
|
* make the index AM look through any additional tuples. (This can
|
||||||
* save a useful amount of work in scenarios where there are many dead
|
* save a useful amount of work in scenarios where there are many dead
|
||||||
* tuples due to heavy update activity.)
|
* tuples due to heavy update activity.)
|
||||||
*
|
*
|
||||||
* To do this we must keep track of the logical scan position
|
* To do this we must keep track of the logical scan position
|
||||||
* (before/on/after tuple). Also, we have to be sure to release scan
|
* (before/on/after tuple). Also, we have to be sure to release scan
|
||||||
* resources before returning NULL; if we fail to do so then a multi-index
|
* resources before returning NULL; if we fail to do so then a
|
||||||
* scan can easily run the system out of free buffers. We can release
|
* multi-index scan can easily run the system out of free buffers. We
|
||||||
* index-level resources fairly cheaply by calling index_rescan. This
|
* can release index-level resources fairly cheaply by calling
|
||||||
* means there are two persistent states as far as the index AM is
|
* index_rescan. This means there are two persistent states as far as
|
||||||
* concerned: on-tuple and rescanned. If we are actually asked to
|
* the index AM is concerned: on-tuple and rescanned. If we are
|
||||||
* re-fetch the single tuple, we have to go through a fresh indexscan
|
* actually asked to re-fetch the single tuple, we have to go through
|
||||||
* startup, which penalizes that (infrequent) case.
|
* a fresh indexscan startup, which penalizes that (infrequent) case.
|
||||||
*/
|
*/
|
||||||
if (scan->keys_are_unique && scan->got_tuple)
|
if (scan->keys_are_unique && scan->got_tuple)
|
||||||
{
|
{
|
||||||
@ -459,18 +459,19 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
|
|||||||
if (new_tuple_pos == 0)
|
if (new_tuple_pos == 0)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We are moving onto the unique tuple from having been off it.
|
* We are moving onto the unique tuple from having been off
|
||||||
* We just fall through and let the index AM do the work. Note
|
* it. We just fall through and let the index AM do the work.
|
||||||
* we should get the right answer regardless of scan direction.
|
* Note we should get the right answer regardless of scan
|
||||||
|
* direction.
|
||||||
*/
|
*/
|
||||||
scan->unique_tuple_pos = 0; /* need to update position */
|
scan->unique_tuple_pos = 0; /* need to update position */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Moving off the tuple; must do amrescan to release index-level
|
* Moving off the tuple; must do amrescan to release
|
||||||
* pins before we return NULL. Since index_rescan will reset
|
* index-level pins before we return NULL. Since index_rescan
|
||||||
* my state, must save and restore...
|
* will reset my state, must save and restore...
|
||||||
*/
|
*/
|
||||||
int unique_tuple_mark = scan->unique_tuple_mark;
|
int unique_tuple_mark = scan->unique_tuple_mark;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.102 2003/07/28 00:09:14 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.103 2003/08/04 00:43:15 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -432,9 +432,9 @@ _bt_insertonpg(Relation rel,
|
|||||||
*
|
*
|
||||||
* must write-lock that page before releasing write lock on
|
* must write-lock that page before releasing write lock on
|
||||||
* current page; else someone else's _bt_check_unique scan
|
* current page; else someone else's _bt_check_unique scan
|
||||||
* could fail to see our insertion. write locks on intermediate
|
* could fail to see our insertion. write locks on
|
||||||
* dead pages won't do because we don't know when they will get
|
* intermediate dead pages won't do because we don't know when
|
||||||
* de-linked from the tree.
|
* they will get de-linked from the tree.
|
||||||
*/
|
*/
|
||||||
Buffer rbuf = InvalidBuffer;
|
Buffer rbuf = InvalidBuffer;
|
||||||
|
|
||||||
@ -523,9 +523,10 @@ _bt_insertonpg(Relation rel,
|
|||||||
/*
|
/*
|
||||||
* If we are doing this insert because we split a page that was
|
* If we are doing this insert because we split a page that was
|
||||||
* the only one on its tree level, but was not the root, it may
|
* the only one on its tree level, but was not the root, it may
|
||||||
* have been the "fast root". We need to ensure that the fast root
|
* have been the "fast root". We need to ensure that the fast
|
||||||
* link points at or above the current page. We can safely acquire
|
* root link points at or above the current page. We can safely
|
||||||
* a lock on the metapage here --- see comments for _bt_newroot().
|
* acquire a lock on the metapage here --- see comments for
|
||||||
|
* _bt_newroot().
|
||||||
*/
|
*/
|
||||||
if (split_only_page)
|
if (split_only_page)
|
||||||
{
|
{
|
||||||
@ -1155,19 +1156,19 @@ _bt_insert_parent(Relation rel,
|
|||||||
bool is_only)
|
bool is_only)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Here we have to do something Lehman and Yao don't talk about:
|
* Here we have to do something Lehman and Yao don't talk about: deal
|
||||||
* deal with a root split and construction of a new root. If our
|
* with a root split and construction of a new root. If our stack is
|
||||||
* stack is empty then we have just split a node on what had been
|
* empty then we have just split a node on what had been the root
|
||||||
* the root level when we descended the tree. If it was still the
|
* level when we descended the tree. If it was still the root then we
|
||||||
* root then we perform a new-root construction. If it *wasn't*
|
* perform a new-root construction. If it *wasn't* the root anymore,
|
||||||
* the root anymore, search to find the next higher level that
|
* search to find the next higher level that someone constructed
|
||||||
* someone constructed meanwhile, and find the right place to insert
|
* meanwhile, and find the right place to insert as for the normal
|
||||||
* as for the normal case.
|
* case.
|
||||||
*
|
*
|
||||||
* If we have to search for the parent level, we do so by
|
* If we have to search for the parent level, we do so by re-descending
|
||||||
* re-descending from the root. This is not super-efficient,
|
* from the root. This is not super-efficient, but it's rare enough
|
||||||
* but it's rare enough not to matter. (This path is also taken
|
* not to matter. (This path is also taken when called from WAL
|
||||||
* when called from WAL recovery --- we have no stack in that case.)
|
* recovery --- we have no stack in that case.)
|
||||||
*/
|
*/
|
||||||
if (is_root)
|
if (is_root)
|
||||||
{
|
{
|
||||||
@ -1222,9 +1223,9 @@ _bt_insert_parent(Relation rel,
|
|||||||
/*
|
/*
|
||||||
* Find the parent buffer and get the parent page.
|
* Find the parent buffer and get the parent page.
|
||||||
*
|
*
|
||||||
* Oops - if we were moved right then we need to change stack
|
* Oops - if we were moved right then we need to change stack item!
|
||||||
* item! We want to find parent pointing to where we are,
|
* We want to find parent pointing to where we are, right ? -
|
||||||
* right ? - vadim 05/27/97
|
* vadim 05/27/97
|
||||||
*/
|
*/
|
||||||
ItemPointerSet(&(stack->bts_btitem.bti_itup.t_tid),
|
ItemPointerSet(&(stack->bts_btitem.bti_itup.t_tid),
|
||||||
bknum, P_HIKEY);
|
bknum, P_HIKEY);
|
||||||
@ -1296,16 +1297,16 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* start = InvalidOffsetNumber means "search the whole page".
|
* start = InvalidOffsetNumber means "search the whole page".
|
||||||
* We need this test anyway due to possibility that
|
* We need this test anyway due to possibility that page has a
|
||||||
* page has a high key now when it didn't before.
|
* high key now when it didn't before.
|
||||||
*/
|
*/
|
||||||
if (start < minoff)
|
if (start < minoff)
|
||||||
start = minoff;
|
start = minoff;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These loops will check every item on the page --- but in an
|
* These loops will check every item on the page --- but in an
|
||||||
* order that's attuned to the probability of where it actually
|
* order that's attuned to the probability of where it
|
||||||
* is. Scan to the right first, then to the left.
|
* actually is. Scan to the right first, then to the left.
|
||||||
*/
|
*/
|
||||||
for (offnum = start;
|
for (offnum = start;
|
||||||
offnum <= maxoff;
|
offnum <= maxoff;
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.66 2003/07/21 20:29:39 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtpage.c,v 1.67 2003/08/04 00:43:15 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Postgres btree pages look like ordinary relation pages. The opaque
|
* Postgres btree pages look like ordinary relation pages. The opaque
|
||||||
@ -181,8 +181,8 @@ _bt_getroot(Relation rel, int access)
|
|||||||
/*
|
/*
|
||||||
* Metadata initialized by someone else. In order to
|
* Metadata initialized by someone else. In order to
|
||||||
* guarantee no deadlocks, we have to release the metadata
|
* guarantee no deadlocks, we have to release the metadata
|
||||||
* page and start all over again. (Is that really true?
|
* page and start all over again. (Is that really true? But
|
||||||
* But it's hardly worth trying to optimize this case.)
|
* it's hardly worth trying to optimize this case.)
|
||||||
*/
|
*/
|
||||||
_bt_relbuf(rel, metabuf);
|
_bt_relbuf(rel, metabuf);
|
||||||
return _bt_getroot(rel, access);
|
return _bt_getroot(rel, access);
|
||||||
@ -190,8 +190,8 @@ _bt_getroot(Relation rel, int access)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Get, initialize, write, and leave a lock of the appropriate
|
* Get, initialize, write, and leave a lock of the appropriate
|
||||||
* type on the new root page. Since this is the first page in
|
* type on the new root page. Since this is the first page in the
|
||||||
* the tree, it's a leaf as well as the root.
|
* tree, it's a leaf as well as the root.
|
||||||
*/
|
*/
|
||||||
rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
|
rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
|
||||||
rootblkno = BufferGetBlockNumber(rootbuf);
|
rootblkno = BufferGetBlockNumber(rootbuf);
|
||||||
@ -284,8 +284,8 @@ _bt_getroot(Relation rel, int access)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* By here, we have a pin and read lock on the root page, and no
|
* By here, we have a pin and read lock on the root page, and no lock
|
||||||
* lock set on the metadata page. Return the root page's buffer.
|
* set on the metadata page. Return the root page's buffer.
|
||||||
*/
|
*/
|
||||||
return rootbuf;
|
return rootbuf;
|
||||||
}
|
}
|
||||||
@ -406,9 +406,9 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
|
|||||||
* First see if the FSM knows of any free pages.
|
* First see if the FSM knows of any free pages.
|
||||||
*
|
*
|
||||||
* We can't trust the FSM's report unreservedly; we have to check
|
* We can't trust the FSM's report unreservedly; we have to check
|
||||||
* that the page is still free. (For example, an already-free page
|
* that the page is still free. (For example, an already-free
|
||||||
* could have been re-used between the time the last VACUUM scanned
|
* page could have been re-used between the time the last VACUUM
|
||||||
* it and the time the VACUUM made its FSM updates.)
|
* scanned it and the time the VACUUM made its FSM updates.)
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -431,10 +431,10 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
|
|||||||
/*
|
/*
|
||||||
* Extend the relation by one page.
|
* Extend the relation by one page.
|
||||||
*
|
*
|
||||||
* We have to use a lock to ensure no one else is extending the rel at
|
* We have to use a lock to ensure no one else is extending the rel
|
||||||
* the same time, else we will both try to initialize the same new
|
* at the same time, else we will both try to initialize the same
|
||||||
* page. We can skip locking for new or temp relations, however,
|
* new page. We can skip locking for new or temp relations,
|
||||||
* since no one else could be accessing them.
|
* however, since no one else could be accessing them.
|
||||||
*/
|
*/
|
||||||
needLock = !(rel->rd_isnew || rel->rd_istemp);
|
needLock = !(rel->rd_isnew || rel->rd_istemp);
|
||||||
|
|
||||||
@ -444,8 +444,8 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
|
|||||||
buf = ReadBuffer(rel, P_NEW);
|
buf = ReadBuffer(rel, P_NEW);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release the file-extension lock; it's now OK for someone else to
|
* Release the file-extension lock; it's now OK for someone else
|
||||||
* extend the relation some more.
|
* to extend the relation some more.
|
||||||
*/
|
*/
|
||||||
if (needLock)
|
if (needLock)
|
||||||
UnlockPage(rel, 0, ExclusiveLock);
|
UnlockPage(rel, 0, ExclusiveLock);
|
||||||
@ -534,13 +534,14 @@ _bt_page_recyclable(Page page)
|
|||||||
BTPageOpaque opaque;
|
BTPageOpaque opaque;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It's possible to find an all-zeroes page in an index --- for example,
|
* It's possible to find an all-zeroes page in an index --- for
|
||||||
* a backend might successfully extend the relation one page and then
|
* example, a backend might successfully extend the relation one page
|
||||||
* crash before it is able to make a WAL entry for adding the page.
|
* and then crash before it is able to make a WAL entry for adding the
|
||||||
* If we find a zeroed page then reclaim it.
|
* page. If we find a zeroed page then reclaim it.
|
||||||
*/
|
*/
|
||||||
if (PageIsNew(page))
|
if (PageIsNew(page))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Otherwise, recycle if deleted and too old to have any processes
|
* Otherwise, recycle if deleted and too old to have any processes
|
||||||
* interested in it.
|
* interested in it.
|
||||||
@ -646,9 +647,7 @@ _bt_delitems(Relation rel, Buffer buf,
|
|||||||
* adjusting item numbers for previous deletions.
|
* adjusting item numbers for previous deletions.
|
||||||
*/
|
*/
|
||||||
for (i = nitems - 1; i >= 0; i--)
|
for (i = nitems - 1; i >= 0; i--)
|
||||||
{
|
|
||||||
PageIndexTupleDelete(page, itemnos[i]);
|
PageIndexTupleDelete(page, itemnos[i]);
|
||||||
}
|
|
||||||
|
|
||||||
/* XLOG stuff */
|
/* XLOG stuff */
|
||||||
if (!rel->rd_istemp)
|
if (!rel->rd_istemp)
|
||||||
@ -666,8 +665,8 @@ _bt_delitems(Relation rel, Buffer buf,
|
|||||||
rdata[0].next = &(rdata[1]);
|
rdata[0].next = &(rdata[1]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The target-offsets array is not in the buffer, but pretend
|
* The target-offsets array is not in the buffer, but pretend that
|
||||||
* that it is. When XLogInsert stores the whole buffer, the offsets
|
* it is. When XLogInsert stores the whole buffer, the offsets
|
||||||
* array need not be stored too.
|
* array need not be stored too.
|
||||||
*/
|
*/
|
||||||
rdata[1].buffer = buf;
|
rdata[1].buffer = buf;
|
||||||
@ -751,6 +750,7 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||||||
_bt_relbuf(rel, buf);
|
_bt_relbuf(rel, buf);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save info about page, including a copy of its high key (it must
|
* Save info about page, including a copy of its high key (it must
|
||||||
* have one, being non-rightmost).
|
* have one, being non-rightmost).
|
||||||
@ -760,12 +760,13 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||||||
leftsib = opaque->btpo_prev;
|
leftsib = opaque->btpo_prev;
|
||||||
itemid = PageGetItemId(page, P_HIKEY);
|
itemid = PageGetItemId(page, P_HIKEY);
|
||||||
targetkey = CopyBTItem((BTItem) PageGetItem(page, itemid));
|
targetkey = CopyBTItem((BTItem) PageGetItem(page, itemid));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to get an approximate pointer to the page's parent page.
|
* We need to get an approximate pointer to the page's parent page.
|
||||||
* Use the standard search mechanism to search for the page's high key;
|
* Use the standard search mechanism to search for the page's high
|
||||||
* this will give us a link to either the current parent or someplace
|
* key; this will give us a link to either the current parent or
|
||||||
* to its left (if there are multiple equal high keys). To avoid
|
* someplace to its left (if there are multiple equal high keys). To
|
||||||
* deadlocks, we'd better drop the target page lock first.
|
* avoid deadlocks, we'd better drop the target page lock first.
|
||||||
*/
|
*/
|
||||||
_bt_relbuf(rel, buf);
|
_bt_relbuf(rel, buf);
|
||||||
/* we need a scan key to do our search, so build one */
|
/* we need a scan key to do our search, so build one */
|
||||||
@ -775,9 +776,11 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||||||
&lbuf, BT_READ);
|
&lbuf, BT_READ);
|
||||||
/* don't need a pin on that either */
|
/* don't need a pin on that either */
|
||||||
_bt_relbuf(rel, lbuf);
|
_bt_relbuf(rel, lbuf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are trying to delete an interior page, _bt_search did more
|
* If we are trying to delete an interior page, _bt_search did more
|
||||||
* than we needed. Locate the stack item pointing to our parent level.
|
* than we needed. Locate the stack item pointing to our parent
|
||||||
|
* level.
|
||||||
*/
|
*/
|
||||||
ilevel = 0;
|
ilevel = 0;
|
||||||
for (;;)
|
for (;;)
|
||||||
@ -789,9 +792,11 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||||||
stack = stack->bts_parent;
|
stack = stack->bts_parent;
|
||||||
ilevel++;
|
ilevel++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to lock the pages we need to modify in the standard order:
|
* We have to lock the pages we need to modify in the standard order:
|
||||||
* moving right, then up. Else we will deadlock against other writers.
|
* moving right, then up. Else we will deadlock against other
|
||||||
|
* writers.
|
||||||
*
|
*
|
||||||
* So, we need to find and write-lock the current left sibling of the
|
* So, we need to find and write-lock the current left sibling of the
|
||||||
* target page. The sibling that was current a moment ago could have
|
* target page. The sibling that was current a moment ago could have
|
||||||
@ -823,18 +828,21 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
lbuf = InvalidBuffer;
|
lbuf = InvalidBuffer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Next write-lock the target page itself. It should be okay to take just
|
* Next write-lock the target page itself. It should be okay to take
|
||||||
* a write lock not a superexclusive lock, since no scans would stop on an
|
* just a write lock not a superexclusive lock, since no scans would
|
||||||
* empty page.
|
* stop on an empty page.
|
||||||
*/
|
*/
|
||||||
buf = _bt_getbuf(rel, target, BT_WRITE);
|
buf = _bt_getbuf(rel, target, BT_WRITE);
|
||||||
page = BufferGetPage(buf);
|
page = BufferGetPage(buf);
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check page is still empty etc, else abandon deletion. The empty check
|
* Check page is still empty etc, else abandon deletion. The empty
|
||||||
* is necessary since someone else might have inserted into it while
|
* check is necessary since someone else might have inserted into it
|
||||||
* we didn't have it locked; the others are just for paranoia's sake.
|
* while we didn't have it locked; the others are just for paranoia's
|
||||||
|
* sake.
|
||||||
*/
|
*/
|
||||||
if (P_RIGHTMOST(opaque) || P_ISROOT(opaque) || P_ISDELETED(opaque) ||
|
if (P_RIGHTMOST(opaque) || P_ISROOT(opaque) || P_ISDELETED(opaque) ||
|
||||||
P_FIRSTDATAKEY(opaque) <= PageGetMaxOffsetNumber(page))
|
P_FIRSTDATAKEY(opaque) <= PageGetMaxOffsetNumber(page))
|
||||||
@ -846,14 +854,17 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||||||
}
|
}
|
||||||
if (opaque->btpo_prev != leftsib)
|
if (opaque->btpo_prev != leftsib)
|
||||||
elog(ERROR, "left link changed unexpectedly");
|
elog(ERROR, "left link changed unexpectedly");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And next write-lock the (current) right sibling.
|
* And next write-lock the (current) right sibling.
|
||||||
*/
|
*/
|
||||||
rightsib = opaque->btpo_next;
|
rightsib = opaque->btpo_next;
|
||||||
rbuf = _bt_getbuf(rel, rightsib, BT_WRITE);
|
rbuf = _bt_getbuf(rel, rightsib, BT_WRITE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Next find and write-lock the current parent of the target page.
|
* Next find and write-lock the current parent of the target page.
|
||||||
* This is essentially the same as the corresponding step of splitting.
|
* This is essentially the same as the corresponding step of
|
||||||
|
* splitting.
|
||||||
*/
|
*/
|
||||||
ItemPointerSet(&(stack->bts_btitem.bti_itup.t_tid),
|
ItemPointerSet(&(stack->bts_btitem.bti_itup.t_tid),
|
||||||
target, P_HIKEY);
|
target, P_HIKEY);
|
||||||
@ -863,10 +874,11 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
parent = stack->bts_blkno;
|
parent = stack->bts_blkno;
|
||||||
poffset = stack->bts_offset;
|
poffset = stack->bts_offset;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the target is the rightmost child of its parent, then we can't
|
* If the target is the rightmost child of its parent, then we can't
|
||||||
* delete, unless it's also the only child --- in which case the parent
|
* delete, unless it's also the only child --- in which case the
|
||||||
* changes to half-dead status.
|
* parent changes to half-dead status.
|
||||||
*/
|
*/
|
||||||
page = BufferGetPage(pbuf);
|
page = BufferGetPage(pbuf);
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
@ -893,12 +905,13 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||||||
if (OffsetNumberNext(P_FIRSTDATAKEY(opaque)) == maxoff)
|
if (OffsetNumberNext(P_FIRSTDATAKEY(opaque)) == maxoff)
|
||||||
parent_one_child = true;
|
parent_one_child = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are deleting the next-to-last page on the target's level,
|
* If we are deleting the next-to-last page on the target's level,
|
||||||
* then the rightsib is a candidate to become the new fast root.
|
* then the rightsib is a candidate to become the new fast root. (In
|
||||||
* (In theory, it might be possible to push the fast root even further
|
* theory, it might be possible to push the fast root even further
|
||||||
* down, but the odds of doing so are slim, and the locking considerations
|
* down, but the odds of doing so are slim, and the locking
|
||||||
* daunting.)
|
* considerations daunting.)
|
||||||
*
|
*
|
||||||
* We can safely acquire a lock on the metapage here --- see comments for
|
* We can safely acquire a lock on the metapage here --- see comments for
|
||||||
* _bt_newroot().
|
* _bt_newroot().
|
||||||
@ -914,10 +927,11 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||||||
metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_WRITE);
|
metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_WRITE);
|
||||||
metapg = BufferGetPage(metabuf);
|
metapg = BufferGetPage(metabuf);
|
||||||
metad = BTPageGetMeta(metapg);
|
metad = BTPageGetMeta(metapg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The expected case here is btm_fastlevel == targetlevel+1;
|
* The expected case here is btm_fastlevel == targetlevel+1;
|
||||||
* if the fastlevel is <= targetlevel, something is wrong, and we
|
* if the fastlevel is <= targetlevel, something is wrong, and
|
||||||
* choose to overwrite it to fix it.
|
* we choose to overwrite it to fix it.
|
||||||
*/
|
*/
|
||||||
if (metad->btm_fastlevel > targetlevel + 1)
|
if (metad->btm_fastlevel > targetlevel + 1)
|
||||||
{
|
{
|
||||||
@ -937,9 +951,9 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Update parent. The normal case is a tad tricky because we want to
|
* Update parent. The normal case is a tad tricky because we want to
|
||||||
* delete the target's downlink and the *following* key. Easiest way is
|
* delete the target's downlink and the *following* key. Easiest way
|
||||||
* to copy the right sibling's downlink over the target downlink, and then
|
* is to copy the right sibling's downlink over the target downlink,
|
||||||
* delete the following item.
|
* and then delete the following item.
|
||||||
*/
|
*/
|
||||||
page = BufferGetPage(pbuf);
|
page = BufferGetPage(pbuf);
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
@ -968,8 +982,8 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update siblings' side-links. Note the target page's side-links will
|
* Update siblings' side-links. Note the target page's side-links
|
||||||
* continue to point to the siblings.
|
* will continue to point to the siblings.
|
||||||
*/
|
*/
|
||||||
if (BufferIsValid(lbuf))
|
if (BufferIsValid(lbuf))
|
||||||
{
|
{
|
||||||
@ -1096,10 +1110,11 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||||||
_bt_wrtbuf(rel, lbuf);
|
_bt_wrtbuf(rel, lbuf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If parent became half dead, recurse to try to delete it. Otherwise,
|
* If parent became half dead, recurse to try to delete it.
|
||||||
* if right sibling is empty and is now the last child of the parent,
|
* Otherwise, if right sibling is empty and is now the last child of
|
||||||
* recurse to try to delete it. (These cases cannot apply at the same
|
* the parent, recurse to try to delete it. (These cases cannot apply
|
||||||
* time, though the second case might itself recurse to the first.)
|
* at the same time, though the second case might itself recurse to
|
||||||
|
* the first.)
|
||||||
*/
|
*/
|
||||||
if (parent_half_dead)
|
if (parent_half_dead)
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.103 2003/07/21 20:29:39 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtree.c,v 1.104 2003/08/04 00:43:15 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -580,19 +580,20 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The outer loop iterates over index leaf pages, the inner over items
|
* The outer loop iterates over index leaf pages, the inner over items
|
||||||
* on a leaf page. We issue just one _bt_delitems() call per page,
|
* on a leaf page. We issue just one _bt_delitems() call per page, so
|
||||||
* so as to minimize WAL traffic.
|
* as to minimize WAL traffic.
|
||||||
*
|
*
|
||||||
* Note that we exclusive-lock every leaf page containing data items,
|
* Note that we exclusive-lock every leaf page containing data items, in
|
||||||
* in sequence left to right. It sounds attractive to only exclusive-lock
|
* sequence left to right. It sounds attractive to only
|
||||||
* those containing items we need to delete, but unfortunately that
|
* exclusive-lock those containing items we need to delete, but
|
||||||
* is not safe: we could then pass a stopped indexscan, which could
|
* unfortunately that is not safe: we could then pass a stopped
|
||||||
* in rare cases lead to deleting the item it needs to find when it
|
* indexscan, which could in rare cases lead to deleting the item it
|
||||||
* resumes. (See _bt_restscan --- this could only happen if an indexscan
|
* needs to find when it resumes. (See _bt_restscan --- this could
|
||||||
* stops on a deletable item and then a page split moves that item
|
* only happen if an indexscan stops on a deletable item and then a
|
||||||
* into a page further to its right, which the indexscan will have no
|
* page split moves that item into a page further to its right, which
|
||||||
* pin on.) We can skip obtaining exclusive lock on empty pages
|
* the indexscan will have no pin on.) We can skip obtaining
|
||||||
* though, since no indexscan could be stopped on those.
|
* exclusive lock on empty pages though, since no indexscan could be
|
||||||
|
* stopped on those.
|
||||||
*/
|
*/
|
||||||
buf = _bt_get_endpoint(rel, 0, false);
|
buf = _bt_get_endpoint(rel, 0, false);
|
||||||
if (BufferIsValid(buf)) /* check for empty index */
|
if (BufferIsValid(buf)) /* check for empty index */
|
||||||
@ -622,12 +623,14 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
|||||||
*/
|
*/
|
||||||
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
|
||||||
LockBufferForCleanup(buf);
|
LockBufferForCleanup(buf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Recompute minoff/maxoff, both of which could have changed
|
* Recompute minoff/maxoff, both of which could have
|
||||||
* while we weren't holding the lock.
|
* changed while we weren't holding the lock.
|
||||||
*/
|
*/
|
||||||
minoff = P_FIRSTDATAKEY(opaque);
|
minoff = P_FIRSTDATAKEY(opaque);
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan over all items to see which ones need deleted
|
* Scan over all items to see which ones need deleted
|
||||||
* according to the callback function.
|
* according to the callback function.
|
||||||
@ -651,6 +654,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
|||||||
num_index_tuples += 1;
|
num_index_tuples += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we need to delete anything, do it and write the buffer;
|
* If we need to delete anything, do it and write the buffer;
|
||||||
* else just release the buffer.
|
* else just release the buffer.
|
||||||
@ -662,9 +666,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
|||||||
_bt_wrtbuf(rel, buf);
|
_bt_wrtbuf(rel, buf);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
_bt_relbuf(rel, buf);
|
_bt_relbuf(rel, buf);
|
||||||
}
|
|
||||||
/* And advance to next page, if any */
|
/* And advance to next page, if any */
|
||||||
if (nextpage == P_NONE)
|
if (nextpage == P_NONE)
|
||||||
break;
|
break;
|
||||||
@ -787,10 +789,10 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* During VACUUM FULL, we truncate off any recyclable pages at the
|
* During VACUUM FULL, we truncate off any recyclable pages at the end
|
||||||
* end of the index. In a normal vacuum it'd be unsafe to do this
|
* of the index. In a normal vacuum it'd be unsafe to do this except
|
||||||
* except by acquiring exclusive lock on the index and then rechecking
|
* by acquiring exclusive lock on the index and then rechecking all
|
||||||
* all the pages; doesn't seem worth it.
|
* the pages; doesn't seem worth it.
|
||||||
*/
|
*/
|
||||||
if (info->vacuum_full && nFreePages > 0)
|
if (info->vacuum_full && nFreePages > 0)
|
||||||
{
|
{
|
||||||
@ -810,9 +812,10 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||||||
* Okay to truncate.
|
* Okay to truncate.
|
||||||
*
|
*
|
||||||
* First, flush any shared buffers for the blocks we intend to
|
* First, flush any shared buffers for the blocks we intend to
|
||||||
* delete. FlushRelationBuffers is a bit more than we need for
|
* delete. FlushRelationBuffers is a bit more than we need
|
||||||
* this, since it will also write out dirty buffers for blocks we
|
* for this, since it will also write out dirty buffers for
|
||||||
* aren't deleting, but it's the closest thing in bufmgr's API.
|
* blocks we aren't deleting, but it's the closest thing in
|
||||||
|
* bufmgr's API.
|
||||||
*/
|
*/
|
||||||
i = FlushRelationBuffers(rel, new_pages);
|
i = FlushRelationBuffers(rel, new_pages);
|
||||||
if (i < 0)
|
if (i < 0)
|
||||||
@ -822,7 +825,8 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||||||
* Do the physical truncation.
|
* Do the physical truncation.
|
||||||
*/
|
*/
|
||||||
new_pages = smgrtruncate(DEFAULT_SMGR, rel, new_pages);
|
new_pages = smgrtruncate(DEFAULT_SMGR, rel, new_pages);
|
||||||
rel->rd_nblocks = new_pages; /* update relcache immediately */
|
rel->rd_nblocks = new_pages; /* update relcache
|
||||||
|
* immediately */
|
||||||
rel->rd_targblock = InvalidBlockNumber;
|
rel->rd_targblock = InvalidBlockNumber;
|
||||||
num_pages = new_pages;
|
num_pages = new_pages;
|
||||||
}
|
}
|
||||||
@ -877,8 +881,8 @@ _bt_restscan(IndexScanDesc scan)
|
|||||||
BlockNumber blkno;
|
BlockNumber blkno;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reacquire read lock on the buffer. (We should still have
|
* Reacquire read lock on the buffer. (We should still have a
|
||||||
* a reference-count pin on it, so need not get that.)
|
* reference-count pin on it, so need not get that.)
|
||||||
*/
|
*/
|
||||||
LockBuffer(buf, BT_READ);
|
LockBuffer(buf, BT_READ);
|
||||||
|
|
||||||
@ -922,10 +926,10 @@ _bt_restscan(IndexScanDesc scan)
|
|||||||
/*
|
/*
|
||||||
* The item we're looking for moved right at least one page, so
|
* The item we're looking for moved right at least one page, so
|
||||||
* move right. We are careful here to pin and read-lock the next
|
* move right. We are careful here to pin and read-lock the next
|
||||||
* non-dead page before releasing the current one. This ensures that
|
* non-dead page before releasing the current one. This ensures
|
||||||
* a concurrent btbulkdelete scan cannot pass our position --- if it
|
* that a concurrent btbulkdelete scan cannot pass our position
|
||||||
* did, it might be able to reach and delete our target item before
|
* --- if it did, it might be able to reach and delete our target
|
||||||
* we can find it again.
|
* item before we can find it again.
|
||||||
*/
|
*/
|
||||||
if (P_RIGHTMOST(opaque))
|
if (P_RIGHTMOST(opaque))
|
||||||
elog(ERROR, "failed to re-find previous key in \"%s\"",
|
elog(ERROR, "failed to re-find previous key in \"%s\"",
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.77 2003/07/29 22:18:38 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.78 2003/08/04 00:43:15 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -64,8 +64,8 @@ _bt_search(Relation rel, int keysz, ScanKey scankey,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Race -- the page we just grabbed may have split since we read
|
* Race -- the page we just grabbed may have split since we read
|
||||||
* its pointer in the parent (or metapage). If it has, we may need
|
* its pointer in the parent (or metapage). If it has, we may
|
||||||
* to move right to its new sibling. Do that.
|
* need to move right to its new sibling. Do that.
|
||||||
*/
|
*/
|
||||||
*bufP = _bt_moveright(rel, *bufP, keysz, scankey, BT_READ);
|
*bufP = _bt_moveright(rel, *bufP, keysz, scankey, BT_READ);
|
||||||
|
|
||||||
@ -87,14 +87,14 @@ _bt_search(Relation rel, int keysz, ScanKey scankey,
|
|||||||
par_blkno = BufferGetBlockNumber(*bufP);
|
par_blkno = BufferGetBlockNumber(*bufP);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to save the location of the index entry we chose in
|
* We need to save the location of the index entry we chose in the
|
||||||
* the parent page on a stack. In case we split the tree, we'll
|
* parent page on a stack. In case we split the tree, we'll use
|
||||||
* use the stack to work back up to the parent page. We also save
|
* the stack to work back up to the parent page. We also save the
|
||||||
* the actual downlink (TID) to uniquely identify the index entry,
|
* actual downlink (TID) to uniquely identify the index entry, in
|
||||||
* in case it moves right while we're working lower in the
|
* case it moves right while we're working lower in the tree. See
|
||||||
* tree. See the paper by Lehman and Yao for how this is detected
|
* the paper by Lehman and Yao for how this is detected and
|
||||||
* and handled. (We use the child link to disambiguate duplicate
|
* handled. (We use the child link to disambiguate duplicate keys
|
||||||
* keys in the index -- Lehman and Yao disallow duplicate keys.)
|
* in the index -- Lehman and Yao disallow duplicate keys.)
|
||||||
*/
|
*/
|
||||||
new_stack = (BTStack) palloc(sizeof(BTStackData));
|
new_stack = (BTStack) palloc(sizeof(BTStackData));
|
||||||
new_stack->bts_blkno = par_blkno;
|
new_stack->bts_blkno = par_blkno;
|
||||||
@ -151,8 +151,8 @@ _bt_moveright(Relation rel,
|
|||||||
* might not need to move right; have to scan the page first anyway.)
|
* might not need to move right; have to scan the page first anyway.)
|
||||||
* It could even have split more than once, so scan as far as needed.
|
* It could even have split more than once, so scan as far as needed.
|
||||||
*
|
*
|
||||||
* We also have to move right if we followed a link that brought us to
|
* We also have to move right if we followed a link that brought us to a
|
||||||
* a dead page.
|
* dead page.
|
||||||
*/
|
*/
|
||||||
while (!P_RIGHTMOST(opaque) &&
|
while (!P_RIGHTMOST(opaque) &&
|
||||||
(P_IGNORE(opaque) ||
|
(P_IGNORE(opaque) ||
|
||||||
@ -599,8 +599,8 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
|||||||
/*
|
/*
|
||||||
* At this point we are positioned at the first item >= scan key, or
|
* At this point we are positioned at the first item >= scan key, or
|
||||||
* possibly at the end of a page on which all the existing items are
|
* possibly at the end of a page on which all the existing items are
|
||||||
* less than the scan key and we know that everything on later
|
* less than the scan key and we know that everything on later pages
|
||||||
* pages is greater than or equal to scan key.
|
* is greater than or equal to scan key.
|
||||||
*
|
*
|
||||||
* We could step forward in the latter case, but that'd be a waste of
|
* We could step forward in the latter case, but that'd be a waste of
|
||||||
* time if we want to scan backwards. So, it's now time to examine
|
* time if we want to scan backwards. So, it's now time to examine
|
||||||
@ -851,7 +851,8 @@ _bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else /* backwards scan */
|
else
|
||||||
|
/* backwards scan */
|
||||||
{
|
{
|
||||||
if (offnum > P_FIRSTDATAKEY(opaque))
|
if (offnum > P_FIRSTDATAKEY(opaque))
|
||||||
offnum = OffsetNumberPrev(offnum);
|
offnum = OffsetNumberPrev(offnum);
|
||||||
@ -860,9 +861,9 @@ _bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
|||||||
/*
|
/*
|
||||||
* Walk left to the next page with data. This is much more
|
* Walk left to the next page with data. This is much more
|
||||||
* complex than the walk-right case because of the possibility
|
* complex than the walk-right case because of the possibility
|
||||||
* that the page to our left splits while we are in flight to it,
|
* that the page to our left splits while we are in flight to
|
||||||
* plus the possibility that the page we were on gets deleted
|
* it, plus the possibility that the page we were on gets
|
||||||
* after we leave it. See nbtree/README for details.
|
* deleted after we leave it. See nbtree/README for details.
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -877,10 +878,11 @@ _bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
|||||||
}
|
}
|
||||||
page = BufferGetPage(*bufP);
|
page = BufferGetPage(*bufP);
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Okay, we managed to move left to a non-deleted page.
|
* Okay, we managed to move left to a non-deleted page.
|
||||||
* Done if it's not half-dead and not empty. Else loop back
|
* Done if it's not half-dead and not empty. Else loop
|
||||||
* and do it all again.
|
* back and do it all again.
|
||||||
*/
|
*/
|
||||||
if (!P_IGNORE(opaque))
|
if (!P_IGNORE(opaque))
|
||||||
{
|
{
|
||||||
@ -946,17 +948,18 @@ _bt_walk_left(Relation rel, Buffer buf)
|
|||||||
buf = _bt_getbuf(rel, blkno, BT_READ);
|
buf = _bt_getbuf(rel, blkno, BT_READ);
|
||||||
page = BufferGetPage(buf);
|
page = BufferGetPage(buf);
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this isn't the page we want, walk right till we find
|
* If this isn't the page we want, walk right till we find what we
|
||||||
* what we want --- but go no more than four hops (an
|
* want --- but go no more than four hops (an arbitrary limit).
|
||||||
* arbitrary limit). If we don't find the correct page by then,
|
* If we don't find the correct page by then, the most likely bet
|
||||||
* the most likely bet is that the original page got deleted
|
* is that the original page got deleted and isn't in the sibling
|
||||||
* and isn't in the sibling chain at all anymore, not that its
|
* chain at all anymore, not that its left sibling got split more
|
||||||
* left sibling got split more than four times.
|
* than four times.
|
||||||
*
|
*
|
||||||
* Note that it is correct to test P_ISDELETED not P_IGNORE
|
* Note that it is correct to test P_ISDELETED not P_IGNORE here,
|
||||||
* here, because half-dead pages are still in the sibling
|
* because half-dead pages are still in the sibling chain. Caller
|
||||||
* chain. Caller must reject half-dead pages if wanted.
|
* must reject half-dead pages if wanted.
|
||||||
*/
|
*/
|
||||||
tries = 0;
|
tries = 0;
|
||||||
for (;;)
|
for (;;)
|
||||||
@ -983,8 +986,8 @@ _bt_walk_left(Relation rel, Buffer buf)
|
|||||||
if (P_ISDELETED(opaque))
|
if (P_ISDELETED(opaque))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* It was deleted. Move right to first nondeleted page
|
* It was deleted. Move right to first nondeleted page (there
|
||||||
* (there must be one); that is the page that has acquired the
|
* must be one); that is the page that has acquired the
|
||||||
* deleted one's keyspace, so stepping left from it will take
|
* deleted one's keyspace, so stepping left from it will take
|
||||||
* us where we want to be.
|
* us where we want to be.
|
||||||
*/
|
*/
|
||||||
@ -1001,18 +1004,18 @@ _bt_walk_left(Relation rel, Buffer buf)
|
|||||||
if (!P_ISDELETED(opaque))
|
if (!P_ISDELETED(opaque))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now return to top of loop, resetting obknum to
|
* Now return to top of loop, resetting obknum to point to
|
||||||
* point to this nondeleted page, and try again.
|
* this nondeleted page, and try again.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* It wasn't deleted; the explanation had better be
|
* It wasn't deleted; the explanation had better be that the
|
||||||
* that the page to the left got split or deleted.
|
* page to the left got split or deleted. Without this check,
|
||||||
* Without this check, we'd go into an infinite loop
|
* we'd go into an infinite loop if there's anything wrong.
|
||||||
* if there's anything wrong.
|
|
||||||
*/
|
*/
|
||||||
if (opaque->btpo_prev == lblkno)
|
if (opaque->btpo_prev == lblkno)
|
||||||
elog(ERROR, "could not find left sibling in \"%s\"",
|
elog(ERROR, "could not find left sibling in \"%s\"",
|
||||||
@ -1045,8 +1048,8 @@ _bt_get_endpoint(Relation rel, uint32 level, bool rightmost)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are looking for a leaf page, okay to descend from fast root;
|
* If we are looking for a leaf page, okay to descend from fast root;
|
||||||
* otherwise better descend from true root. (There is no point in being
|
* otherwise better descend from true root. (There is no point in
|
||||||
* smarter about intermediate levels.)
|
* being smarter about intermediate levels.)
|
||||||
*/
|
*/
|
||||||
if (level == 0)
|
if (level == 0)
|
||||||
buf = _bt_getroot(rel, BT_READ);
|
buf = _bt_getroot(rel, BT_READ);
|
||||||
@ -1066,9 +1069,9 @@ _bt_get_endpoint(Relation rel, uint32 level, bool rightmost)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If we landed on a deleted page, step right to find a live page
|
* If we landed on a deleted page, step right to find a live page
|
||||||
* (there must be one). Also, if we want the rightmost page,
|
* (there must be one). Also, if we want the rightmost page, step
|
||||||
* step right if needed to get to it (this could happen if the
|
* right if needed to get to it (this could happen if the page
|
||||||
* page split since we obtained a pointer to it).
|
* split since we obtained a pointer to it).
|
||||||
*/
|
*/
|
||||||
while (P_IGNORE(opaque) ||
|
while (P_IGNORE(opaque) ||
|
||||||
(rightmost && !P_RIGHTMOST(opaque)))
|
(rightmost && !P_RIGHTMOST(opaque)))
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsort.c,v 1.73 2003/07/21 20:29:39 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtsort.c,v 1.74 2003/08/04 00:43:15 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.3 2003/02/23 22:43:08 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.4 2003/08/04 00:43:15 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -183,9 +183,7 @@ btree_xlog_insert(bool redo, bool isleaf, bool ismeta,
|
|||||||
if (redo)
|
if (redo)
|
||||||
{
|
{
|
||||||
if (XLByteLE(lsn, PageGetLSN(page)))
|
if (XLByteLE(lsn, PageGetLSN(page)))
|
||||||
{
|
|
||||||
UnlockAndReleaseBuffer(buffer);
|
UnlockAndReleaseBuffer(buffer);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (PageAddItem(page, (Item) datapos, datalen,
|
if (PageAddItem(page, (Item) datapos, datalen,
|
||||||
@ -204,15 +202,11 @@ btree_xlog_insert(bool redo, bool isleaf, bool ismeta,
|
|||||||
elog(PANIC, "btree_insert_undo: bad page LSN");
|
elog(PANIC, "btree_insert_undo: bad page LSN");
|
||||||
|
|
||||||
if (!P_ISLEAF(pageop))
|
if (!P_ISLEAF(pageop))
|
||||||
{
|
|
||||||
UnlockAndReleaseBuffer(buffer);
|
UnlockAndReleaseBuffer(buffer);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
elog(PANIC, "btree_insert_undo: unimplemented");
|
elog(PANIC, "btree_insert_undo: unimplemented");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (redo) /* metapage changes not undoable */
|
if (redo) /* metapage changes not undoable */
|
||||||
{
|
{
|
||||||
@ -338,9 +332,7 @@ btree_xlog_split(bool redo, bool onleft, bool isroot,
|
|||||||
elog(PANIC, "btree_split_redo: uninitialized next right page");
|
elog(PANIC, "btree_split_redo: uninitialized next right page");
|
||||||
|
|
||||||
if (XLByteLE(lsn, PageGetLSN(page)))
|
if (XLByteLE(lsn, PageGetLSN(page)))
|
||||||
{
|
|
||||||
UnlockAndReleaseBuffer(buffer);
|
UnlockAndReleaseBuffer(buffer);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
|
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
@ -451,9 +443,7 @@ btree_xlog_delete_page(bool redo, bool ismeta,
|
|||||||
if (PageIsNew((PageHeader) page))
|
if (PageIsNew((PageHeader) page))
|
||||||
elog(PANIC, "btree_delete_page_redo: uninitialized parent page");
|
elog(PANIC, "btree_delete_page_redo: uninitialized parent page");
|
||||||
if (XLByteLE(lsn, PageGetLSN(page)))
|
if (XLByteLE(lsn, PageGetLSN(page)))
|
||||||
{
|
|
||||||
UnlockAndReleaseBuffer(buffer);
|
UnlockAndReleaseBuffer(buffer);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
OffsetNumber poffset;
|
OffsetNumber poffset;
|
||||||
@ -494,9 +484,7 @@ btree_xlog_delete_page(bool redo, bool ismeta,
|
|||||||
if (PageIsNew((PageHeader) page))
|
if (PageIsNew((PageHeader) page))
|
||||||
elog(PANIC, "btree_delete_page_redo: uninitialized right sibling");
|
elog(PANIC, "btree_delete_page_redo: uninitialized right sibling");
|
||||||
if (XLByteLE(lsn, PageGetLSN(page)))
|
if (XLByteLE(lsn, PageGetLSN(page)))
|
||||||
{
|
|
||||||
UnlockAndReleaseBuffer(buffer);
|
UnlockAndReleaseBuffer(buffer);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
|
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
@ -520,9 +508,7 @@ btree_xlog_delete_page(bool redo, bool ismeta,
|
|||||||
if (PageIsNew((PageHeader) page))
|
if (PageIsNew((PageHeader) page))
|
||||||
elog(PANIC, "btree_delete_page_redo: uninitialized left sibling");
|
elog(PANIC, "btree_delete_page_redo: uninitialized left sibling");
|
||||||
if (XLByteLE(lsn, PageGetLSN(page)))
|
if (XLByteLE(lsn, PageGetLSN(page)))
|
||||||
{
|
|
||||||
UnlockAndReleaseBuffer(buffer);
|
UnlockAndReleaseBuffer(buffer);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
|
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.45 2003/07/28 00:09:14 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/rtree/Attic/rtscan.c,v 1.46 2003/08/04 00:43:15 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -109,10 +109,10 @@ rtrescan(PG_FUNCTION_ARGS)
|
|||||||
s->numberOfKeys * sizeof(ScanKeyData));
|
s->numberOfKeys * sizeof(ScanKeyData));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scans on internal pages use different operators than they
|
* Scans on internal pages use different operators than they do on
|
||||||
* do on leaf pages. For example, if the user wants all boxes
|
* leaf pages. For example, if the user wants all boxes that
|
||||||
* that exactly match (x1,y1,x2,y2), then on internal pages we
|
* exactly match (x1,y1,x2,y2), then on internal pages we need to
|
||||||
* need to find all boxes that contain (x1,y1,x2,y2).
|
* find all boxes that contain (x1,y1,x2,y2).
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < s->numberOfKeys; i++)
|
for (i = 0; i < s->numberOfKeys; i++)
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/clog.c,v 1.16 2003/06/11 22:37:45 momjian Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/clog.c,v 1.17 2003/08/04 00:43:15 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
*
|
*
|
||||||
* Resource managers definition
|
* Resource managers definition
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/rmgr.c,v 1.10 2003/02/21 00:06:22 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/rmgr.c,v 1.11 2003/08/04 00:43:15 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/slru.c,v 1.3 2003/07/28 00:09:14 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/slru.c,v 1.4 2003/08/04 00:43:15 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -183,12 +183,14 @@ SimpleLruInit(SlruCtl ctl, const char *name, const char *subdir)
|
|||||||
shared = (SlruShared) ptr;
|
shared = (SlruShared) ptr;
|
||||||
|
|
||||||
#ifdef EXEC_BACKEND
|
#ifdef EXEC_BACKEND
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Locks are in shared memory
|
* Locks are in shared memory
|
||||||
*/
|
*/
|
||||||
locks = (SlruLock) (ptr + MAXALIGN(sizeof(SlruSharedData)) +
|
locks = (SlruLock) (ptr + MAXALIGN(sizeof(SlruSharedData)) +
|
||||||
BLCKSZ * NUM_CLOG_BUFFERS);
|
BLCKSZ * NUM_CLOG_BUFFERS);
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Locks are in private memory
|
* Locks are in private memory
|
||||||
*/
|
*/
|
||||||
@ -539,13 +541,13 @@ SlruPhysicalWritePage(SlruCtl ctl, int pageno, int slotno)
|
|||||||
* possible for this to need to happen when writing a page that's not
|
* possible for this to need to happen when writing a page that's not
|
||||||
* first in its segment; we assume the OS can cope with that. (Note:
|
* first in its segment; we assume the OS can cope with that. (Note:
|
||||||
* it might seem that it'd be okay to create files only when
|
* it might seem that it'd be okay to create files only when
|
||||||
* SimpleLruZeroPage is called for the first page of a segment. However,
|
* SimpleLruZeroPage is called for the first page of a segment.
|
||||||
* if after a crash and restart the REDO logic elects to replay the
|
* However, if after a crash and restart the REDO logic elects to
|
||||||
* log from a checkpoint before the latest one, then it's possible
|
* replay the log from a checkpoint before the latest one, then it's
|
||||||
* that we will get commands to set transaction status of transactions
|
* possible that we will get commands to set transaction status of
|
||||||
* that have already been truncated from the commit log. Easiest way
|
* transactions that have already been truncated from the commit log.
|
||||||
* to deal with that is to accept references to nonexistent files here
|
* Easiest way to deal with that is to accept references to
|
||||||
* and in SlruPhysicalReadPage.)
|
* nonexistent files here and in SlruPhysicalReadPage.)
|
||||||
*/
|
*/
|
||||||
fd = BasicOpenFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
|
fd = BasicOpenFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
@ -665,6 +667,7 @@ static int
|
|||||||
SlruSelectLRUPage(SlruCtl ctl, int pageno)
|
SlruSelectLRUPage(SlruCtl ctl, int pageno)
|
||||||
{
|
{
|
||||||
SlruShared shared = (SlruShared) ctl->shared;
|
SlruShared shared = (SlruShared) ctl->shared;
|
||||||
|
|
||||||
/* Outer loop handles restart after I/O */
|
/* Outer loop handles restart after I/O */
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
@ -705,8 +708,8 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
|
|||||||
/*
|
/*
|
||||||
* We need to do I/O. Normal case is that we have to write it
|
* We need to do I/O. Normal case is that we have to write it
|
||||||
* out, but it's possible in the worst case to have selected a
|
* out, but it's possible in the worst case to have selected a
|
||||||
* read-busy page. In that case we use SimpleLruReadPage to wait for
|
* read-busy page. In that case we use SimpleLruReadPage to wait
|
||||||
* the read to complete.
|
* for the read to complete.
|
||||||
*/
|
*/
|
||||||
if (shared->page_status[bestslot] == SLRU_PAGE_READ_IN_PROGRESS)
|
if (shared->page_status[bestslot] == SLRU_PAGE_READ_IN_PROGRESS)
|
||||||
(void) SimpleLruReadPage(ctl, shared->page_number[bestslot],
|
(void) SimpleLruReadPage(ctl, shared->page_number[bestslot],
|
||||||
@ -747,10 +750,11 @@ SimpleLruFlush(SlruCtl ctl, bool checkpoint)
|
|||||||
for (slotno = 0; slotno < NUM_CLOG_BUFFERS; slotno++)
|
for (slotno = 0; slotno < NUM_CLOG_BUFFERS; slotno++)
|
||||||
{
|
{
|
||||||
SimpleLruWritePage(ctl, slotno);
|
SimpleLruWritePage(ctl, slotno);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When called during a checkpoint,
|
* When called during a checkpoint, we cannot assert that the slot
|
||||||
* we cannot assert that the slot is clean now, since another
|
* is clean now, since another process might have re-dirtied it
|
||||||
* process might have re-dirtied it already. That's okay.
|
* already. That's okay.
|
||||||
*/
|
*/
|
||||||
Assert(checkpoint ||
|
Assert(checkpoint ||
|
||||||
shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
|
shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
|
||||||
@ -792,10 +796,10 @@ SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
|
|||||||
CreateCheckPoint(false, true);
|
CreateCheckPoint(false, true);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan shared memory and remove any pages preceding the cutoff
|
* Scan shared memory and remove any pages preceding the cutoff page,
|
||||||
* page, to ensure we won't rewrite them later. (Any dirty pages
|
* to ensure we won't rewrite them later. (Any dirty pages should
|
||||||
* should have been flushed already during the checkpoint, we're just
|
* have been flushed already during the checkpoint, we're just being
|
||||||
* being extra careful here.)
|
* extra careful here.)
|
||||||
*/
|
*/
|
||||||
LWLockAcquire(ctl->locks->ControlLock, LW_EXCLUSIVE);
|
LWLockAcquire(ctl->locks->ControlLock, LW_EXCLUSIVE);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.149 2003/07/21 20:29:39 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/xact.c,v 1.150 2003/08/04 00:43:15 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Transaction aborts can now occur two ways:
|
* Transaction aborts can now occur two ways:
|
||||||
@ -197,8 +197,8 @@ static TransactionStateData CurrentTransactionStateData = {
|
|||||||
0, /* scan command id */
|
0, /* scan command id */
|
||||||
0x0, /* start time */
|
0x0, /* start time */
|
||||||
TRANS_DEFAULT, /* transaction state */
|
TRANS_DEFAULT, /* transaction state */
|
||||||
TBLOCK_DEFAULT /* transaction block state from
|
TBLOCK_DEFAULT /* transaction block state from the client
|
||||||
the client perspective */
|
* perspective */
|
||||||
};
|
};
|
||||||
|
|
||||||
TransactionState CurrentTransactionState = &CurrentTransactionStateData;
|
TransactionState CurrentTransactionState = &CurrentTransactionStateData;
|
||||||
@ -561,13 +561,13 @@ RecordTransactionCommit(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* We must mark the transaction committed in clog if its XID
|
* We must mark the transaction committed in clog if its XID
|
||||||
* appears either in permanent rels or in local temporary rels.
|
* appears either in permanent rels or in local temporary rels. We
|
||||||
* We test this by seeing if we made transaction-controlled
|
* test this by seeing if we made transaction-controlled entries
|
||||||
* entries *OR* local-rel tuple updates. Note that if we made
|
* *OR* local-rel tuple updates. Note that if we made only the
|
||||||
* only the latter, we have not emitted an XLOG record for our
|
* latter, we have not emitted an XLOG record for our commit, and
|
||||||
* commit, and so in the event of a crash the clog update might be
|
* so in the event of a crash the clog update might be lost. This
|
||||||
* lost. This is okay because no one else will ever care whether
|
* is okay because no one else will ever care whether we
|
||||||
* we committed.
|
* committed.
|
||||||
*/
|
*/
|
||||||
if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
|
if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
|
||||||
TransactionIdCommit(xid);
|
TransactionIdCommit(xid);
|
||||||
@ -755,9 +755,9 @@ AtAbort_Memory(void)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Make sure we are in a valid context (not a child of
|
* Make sure we are in a valid context (not a child of
|
||||||
* TopTransactionContext...). Note that it is possible for this
|
* TopTransactionContext...). Note that it is possible for this code
|
||||||
* code to be called when we aren't in a transaction at all; go
|
* to be called when we aren't in a transaction at all; go directly to
|
||||||
* directly to TopMemoryContext in that case.
|
* TopMemoryContext in that case.
|
||||||
*/
|
*/
|
||||||
if (TopTransactionContext != NULL)
|
if (TopTransactionContext != NULL)
|
||||||
{
|
{
|
||||||
@ -891,8 +891,8 @@ CommitTransaction(void)
|
|||||||
DeferredTriggerEndXact();
|
DeferredTriggerEndXact();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Similarly, let ON COMMIT management do its thing before we start
|
* Similarly, let ON COMMIT management do its thing before we start to
|
||||||
* to commit.
|
* commit.
|
||||||
*/
|
*/
|
||||||
PreCommit_on_commit_actions();
|
PreCommit_on_commit_actions();
|
||||||
|
|
||||||
@ -953,10 +953,10 @@ CommitTransaction(void)
|
|||||||
* noncritical resource releasing.
|
* noncritical resource releasing.
|
||||||
*
|
*
|
||||||
* The ordering of operations is not entirely random. The idea is:
|
* The ordering of operations is not entirely random. The idea is:
|
||||||
* release resources visible to other backends (eg, files, buffer pins);
|
* release resources visible to other backends (eg, files, buffer
|
||||||
* then release locks; then release backend-local resources. We want
|
* pins); then release locks; then release backend-local resources.
|
||||||
* to release locks at the point where any backend waiting for us will
|
* We want to release locks at the point where any backend waiting for
|
||||||
* see our transaction as being fully cleaned up.
|
* us will see our transaction as being fully cleaned up.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
smgrDoPendingDeletes(true);
|
smgrDoPendingDeletes(true);
|
||||||
@ -1194,8 +1194,8 @@ StartTransactionCommand(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must switch to TopTransactionContext before returning. This
|
* We must switch to TopTransactionContext before returning. This is
|
||||||
* is already done if we called StartTransaction, otherwise not.
|
* already done if we called StartTransaction, otherwise not.
|
||||||
*/
|
*/
|
||||||
Assert(TopTransactionContext != NULL);
|
Assert(TopTransactionContext != NULL);
|
||||||
MemoryContextSwitchTo(TopTransactionContext);
|
MemoryContextSwitchTo(TopTransactionContext);
|
||||||
@ -1373,6 +1373,7 @@ PreventTransactionChain(void *stmtNode, const char *stmtType)
|
|||||||
/* translator: %s represents an SQL statement name */
|
/* translator: %s represents an SQL statement name */
|
||||||
errmsg("%s cannot run inside a transaction block",
|
errmsg("%s cannot run inside a transaction block",
|
||||||
stmtType)));
|
stmtType)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Are we inside a function call? If the statement's parameter block
|
* Are we inside a function call? If the statement's parameter block
|
||||||
* was allocated in QueryContext, assume it is an interactive command.
|
* was allocated in QueryContext, assume it is an interactive command.
|
||||||
@ -1414,6 +1415,7 @@ RequireTransactionChain(void *stmtNode, const char *stmtType)
|
|||||||
*/
|
*/
|
||||||
if (IsTransactionBlock())
|
if (IsTransactionBlock())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Are we inside a function call? If the statement's parameter block
|
* Are we inside a function call? If the statement's parameter block
|
||||||
* was allocated in QueryContext, assume it is an interactive command.
|
* was allocated in QueryContext, assume it is an interactive command.
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.120 2003/07/28 00:09:14 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/access/transam/xlog.c,v 1.121 2003/08/04 00:43:15 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -2665,11 +2665,12 @@ StartupXLOG(void)
|
|||||||
ShmemVariableCache->oidCount = 0;
|
ShmemVariableCache->oidCount = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it was a shutdown checkpoint, then any following WAL entries were
|
* If it was a shutdown checkpoint, then any following WAL entries
|
||||||
* created under the next StartUpID; if it was a regular checkpoint then
|
* were created under the next StartUpID; if it was a regular
|
||||||
* any following WAL entries were created under the same StartUpID.
|
* checkpoint then any following WAL entries were created under the
|
||||||
* We must replay WAL entries using the same StartUpID they were created
|
* same StartUpID. We must replay WAL entries using the same StartUpID
|
||||||
* under, so temporarily adopt that SUI (see also xlog_redo()).
|
* they were created under, so temporarily adopt that SUI (see also
|
||||||
|
* xlog_redo()).
|
||||||
*/
|
*/
|
||||||
if (wasShutdown)
|
if (wasShutdown)
|
||||||
ThisStartUpID = checkPoint.ThisStartUpID + 1;
|
ThisStartUpID = checkPoint.ThisStartUpID + 1;
|
||||||
@ -2791,8 +2792,8 @@ StartupXLOG(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Tricky point here: readBuf contains the *last* block that the
|
* Tricky point here: readBuf contains the *last* block that the
|
||||||
* LastRec record spans, not the one it starts in. The last block
|
* LastRec record spans, not the one it starts in. The last block is
|
||||||
* is indeed the one we want to use.
|
* indeed the one we want to use.
|
||||||
*/
|
*/
|
||||||
Assert(readOff == (XLogCtl->xlblocks[0].xrecoff - BLCKSZ) % XLogSegSize);
|
Assert(readOff == (XLogCtl->xlblocks[0].xrecoff - BLCKSZ) % XLogSegSize);
|
||||||
memcpy((char *) Insert->currpage, readBuf, BLCKSZ);
|
memcpy((char *) Insert->currpage, readBuf, BLCKSZ);
|
||||||
@ -2818,11 +2819,12 @@ StartupXLOG(void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Whenever Write.LogwrtResult points to exactly the end of a page,
|
* Whenever Write.LogwrtResult points to exactly the end of a
|
||||||
* Write.curridx must point to the *next* page (see XLogWrite()).
|
* page, Write.curridx must point to the *next* page (see
|
||||||
|
* XLogWrite()).
|
||||||
*
|
*
|
||||||
* Note: it might seem we should do AdvanceXLInsertBuffer() here,
|
* Note: it might seem we should do AdvanceXLInsertBuffer() here, but
|
||||||
* but we can't since we haven't yet determined the correct StartUpID
|
* we can't since we haven't yet determined the correct StartUpID
|
||||||
* to put into the new page's header. The first actual attempt to
|
* to put into the new page's header. The first actual attempt to
|
||||||
* insert a log record will advance the insert state.
|
* insert a log record will advance the insert state.
|
||||||
*/
|
*/
|
||||||
@ -2885,14 +2887,15 @@ StartupXLOG(void)
|
|||||||
ThisStartUpID = ControlFile->checkPointCopy.ThisStartUpID;
|
ThisStartUpID = ControlFile->checkPointCopy.ThisStartUpID;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perform a new checkpoint to update our recovery activity to disk.
|
* Perform a new checkpoint to update our recovery activity to
|
||||||
|
* disk.
|
||||||
*
|
*
|
||||||
* Note that we write a shutdown checkpoint. This is correct since
|
* Note that we write a shutdown checkpoint. This is correct since
|
||||||
* the records following it will use SUI one more than what is shown
|
* the records following it will use SUI one more than what is
|
||||||
* in the checkpoint's ThisStartUpID.
|
* shown in the checkpoint's ThisStartUpID.
|
||||||
*
|
*
|
||||||
* In case we had to use the secondary checkpoint, make sure that
|
* In case we had to use the secondary checkpoint, make sure that it
|
||||||
* it will still be shown as the secondary checkpoint after this
|
* will still be shown as the secondary checkpoint after this
|
||||||
* CreateCheckPoint operation; we don't want the broken primary
|
* CreateCheckPoint operation; we don't want the broken primary
|
||||||
* checkpoint to become prevCheckPoint...
|
* checkpoint to become prevCheckPoint...
|
||||||
*/
|
*/
|
||||||
@ -2907,10 +2910,10 @@ StartupXLOG(void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If we are not doing recovery, then we saw a checkpoint with nothing
|
* If we are not doing recovery, then we saw a checkpoint with
|
||||||
* after it, and we can safely use StartUpID equal to one more than
|
* nothing after it, and we can safely use StartUpID equal to one
|
||||||
* the checkpoint's SUI. But just for paranoia's sake, check against
|
* more than the checkpoint's SUI. But just for paranoia's sake,
|
||||||
* pg_control too.
|
* check against pg_control too.
|
||||||
*/
|
*/
|
||||||
ThisStartUpID = checkPoint.ThisStartUpID;
|
ThisStartUpID = checkPoint.ThisStartUpID;
|
||||||
if (ThisStartUpID < ControlFile->checkPointCopy.ThisStartUpID)
|
if (ThisStartUpID < ControlFile->checkPointCopy.ThisStartUpID)
|
||||||
@ -2923,7 +2926,8 @@ StartupXLOG(void)
|
|||||||
PreallocXlogFiles(EndOfLog);
|
PreallocXlogFiles(EndOfLog);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Advance StartUpID to one more than the highest value used previously.
|
* Advance StartUpID to one more than the highest value used
|
||||||
|
* previously.
|
||||||
*/
|
*/
|
||||||
ThisStartUpID++;
|
ThisStartUpID++;
|
||||||
XLogCtl->ThisStartUpID = ThisStartUpID;
|
XLogCtl->ThisStartUpID = ThisStartUpID;
|
||||||
@ -3115,7 +3119,8 @@ CreateCheckPoint(bool shutdown, bool force)
|
|||||||
errmsg("checkpoint cannot be made inside transaction block")));
|
errmsg("checkpoint cannot be made inside transaction block")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquire CheckpointLock to ensure only one checkpoint happens at a time.
|
* Acquire CheckpointLock to ensure only one checkpoint happens at a
|
||||||
|
* time.
|
||||||
*
|
*
|
||||||
* The CheckpointLock can be held for quite a while, which is not good
|
* The CheckpointLock can be held for quite a while, which is not good
|
||||||
* because we won't respond to a cancel/die request while waiting for
|
* because we won't respond to a cancel/die request while waiting for
|
||||||
@ -3149,14 +3154,15 @@ CreateCheckPoint(bool shutdown, bool force)
|
|||||||
LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
|
LWLockAcquire(WALInsertLock, LW_EXCLUSIVE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this isn't a shutdown or forced checkpoint, and we have not inserted
|
* If this isn't a shutdown or forced checkpoint, and we have not
|
||||||
* any XLOG records since the start of the last checkpoint, skip the
|
* inserted any XLOG records since the start of the last checkpoint,
|
||||||
* checkpoint. The idea here is to avoid inserting duplicate checkpoints
|
* skip the checkpoint. The idea here is to avoid inserting duplicate
|
||||||
* when the system is idle. That wastes log space, and more importantly it
|
* checkpoints when the system is idle. That wastes log space, and
|
||||||
* exposes us to possible loss of both current and previous checkpoint
|
* more importantly it exposes us to possible loss of both current and
|
||||||
* records if the machine crashes just as we're writing the update.
|
* previous checkpoint records if the machine crashes just as we're
|
||||||
* (Perhaps it'd make even more sense to checkpoint only when the previous
|
* writing the update. (Perhaps it'd make even more sense to
|
||||||
* checkpoint record is in a different xlog page?)
|
* checkpoint only when the previous checkpoint record is in a
|
||||||
|
* different xlog page?)
|
||||||
*
|
*
|
||||||
* We have to make two tests to determine that nothing has happened since
|
* We have to make two tests to determine that nothing has happened since
|
||||||
* the start of the last checkpoint: current insertion point must
|
* the start of the last checkpoint: current insertion point must
|
||||||
@ -3204,12 +3210,13 @@ CreateCheckPoint(bool shutdown, bool force)
|
|||||||
* Here we update the shared RedoRecPtr for future XLogInsert calls;
|
* Here we update the shared RedoRecPtr for future XLogInsert calls;
|
||||||
* this must be done while holding the insert lock AND the info_lck.
|
* this must be done while holding the insert lock AND the info_lck.
|
||||||
*
|
*
|
||||||
* Note: if we fail to complete the checkpoint, RedoRecPtr will be
|
* Note: if we fail to complete the checkpoint, RedoRecPtr will be left
|
||||||
* left pointing past where it really needs to point. This is okay;
|
* pointing past where it really needs to point. This is okay; the
|
||||||
* the only consequence is that XLogInsert might back up whole buffers
|
* only consequence is that XLogInsert might back up whole buffers
|
||||||
* that it didn't really need to. We can't postpone advancing RedoRecPtr
|
* that it didn't really need to. We can't postpone advancing
|
||||||
* because XLogInserts that happen while we are dumping buffers must
|
* RedoRecPtr because XLogInserts that happen while we are dumping
|
||||||
* assume that their buffer changes are not included in the checkpoint.
|
* buffers must assume that their buffer changes are not included in
|
||||||
|
* the checkpoint.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
/* use volatile pointer to prevent code rearrangement */
|
/* use volatile pointer to prevent code rearrangement */
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.163 2003/07/27 21:49:53 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/bootstrap/bootstrap.c,v 1.164 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -347,9 +347,7 @@ BootstrapMain(int argc, char *argv[])
|
|||||||
|
|
||||||
|
|
||||||
if (IsUnderPostmaster && ExecBackend && MyProc /* ordinary backend */ )
|
if (IsUnderPostmaster && ExecBackend && MyProc /* ordinary backend */ )
|
||||||
{
|
|
||||||
AttachSharedMemoryAndSemaphores();
|
AttachSharedMemoryAndSemaphores();
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsUnderPostmaster /* when exec || ExecBackend */ )
|
if (!IsUnderPostmaster /* when exec || ExecBackend */ )
|
||||||
{
|
{
|
||||||
@ -473,8 +471,8 @@ BootstrapMain(int argc, char *argv[])
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* In NOP mode, all we really want to do is create shared memory and
|
* In NOP mode, all we really want to do is create shared memory and
|
||||||
* semaphores (just to prove we can do it with the current GUC settings).
|
* semaphores (just to prove we can do it with the current GUC
|
||||||
* So, quit now.
|
* settings). So, quit now.
|
||||||
*/
|
*/
|
||||||
if (xlogop == BS_XLOG_NOP)
|
if (xlogop == BS_XLOG_NOP)
|
||||||
proc_exit(0);
|
proc_exit(0);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.85 2003/08/01 00:15:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.86 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* See acl.h.
|
* See acl.h.
|
||||||
@ -98,25 +98,28 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
|
|||||||
if (grantee->username)
|
if (grantee->username)
|
||||||
{
|
{
|
||||||
aclitem. ai_grantee = get_usesysid(grantee->username);
|
aclitem. ai_grantee = get_usesysid(grantee->username);
|
||||||
|
|
||||||
idtype = ACL_IDTYPE_UID;
|
idtype = ACL_IDTYPE_UID;
|
||||||
}
|
}
|
||||||
else if (grantee->groupname)
|
else if (grantee->groupname)
|
||||||
{
|
{
|
||||||
aclitem. ai_grantee = get_grosysid(grantee->groupname);
|
aclitem. ai_grantee = get_grosysid(grantee->groupname);
|
||||||
|
|
||||||
idtype = ACL_IDTYPE_GID;
|
idtype = ACL_IDTYPE_GID;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
aclitem. ai_grantee = ACL_ID_WORLD;
|
aclitem. ai_grantee = ACL_ID_WORLD;
|
||||||
|
|
||||||
idtype = ACL_IDTYPE_WORLD;
|
idtype = ACL_IDTYPE_WORLD;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Grant options can only be granted to individual users, not
|
* Grant options can only be granted to individual users, not
|
||||||
* groups or public. The reason is that if a user would
|
* groups or public. The reason is that if a user would re-grant
|
||||||
* re-grant a privilege that he held through a group having a
|
* a privilege that he held through a group having a grant option,
|
||||||
* grant option, and later the user is removed from the group,
|
* and later the user is removed from the group, the situation is
|
||||||
* the situation is impossible to clean up.
|
* impossible to clean up.
|
||||||
*/
|
*/
|
||||||
if (is_grant && idtype != ACL_IDTYPE_UID && grant_option)
|
if (is_grant && idtype != ACL_IDTYPE_UID && grant_option)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -835,8 +838,8 @@ aclcheck(Acl *acl, AclId userid, AclMode mode)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* See if he has the permission via any group (do this in a
|
* See if he has the permission via any group (do this in a separate
|
||||||
* separate pass to avoid expensive(?) lookups in pg_group)
|
* pass to avoid expensive(?) lookups in pg_group)
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < num; i++)
|
for (i = 0; i < num; i++)
|
||||||
if (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_GID
|
if (ACLITEM_GET_IDTYPE(aidat[i]) == ACL_IDTYPE_GID
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.28 2003/07/28 00:09:14 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/dependency.c,v 1.29 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -158,9 +158,9 @@ performDeletion(const ObjectAddress *object,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct a list of objects that are reachable by AUTO or INTERNAL
|
* Construct a list of objects that are reachable by AUTO or INTERNAL
|
||||||
* dependencies from the target object. These should be deleted silently,
|
* dependencies from the target object. These should be deleted
|
||||||
* even if the actual deletion pass first reaches one of them via a
|
* silently, even if the actual deletion pass first reaches one of
|
||||||
* non-auto dependency.
|
* them via a non-auto dependency.
|
||||||
*/
|
*/
|
||||||
init_object_addresses(&oktodelete);
|
init_object_addresses(&oktodelete);
|
||||||
|
|
||||||
@ -212,9 +212,9 @@ deleteWhatDependsOn(const ObjectAddress *object,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct a list of objects that are reachable by AUTO or INTERNAL
|
* Construct a list of objects that are reachable by AUTO or INTERNAL
|
||||||
* dependencies from the target object. These should be deleted silently,
|
* dependencies from the target object. These should be deleted
|
||||||
* even if the actual deletion pass first reaches one of them via a
|
* silently, even if the actual deletion pass first reaches one of
|
||||||
* non-auto dependency.
|
* them via a non-auto dependency.
|
||||||
*/
|
*/
|
||||||
init_object_addresses(&oktodelete);
|
init_object_addresses(&oktodelete);
|
||||||
|
|
||||||
@ -266,9 +266,9 @@ findAutoDeletableObjects(const ObjectAddress *object,
|
|||||||
ObjectAddress otherObject;
|
ObjectAddress otherObject;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this object is already in oktodelete, then we already visited it;
|
* If this object is already in oktodelete, then we already visited
|
||||||
* don't do so again (this prevents infinite recursion if there's a loop
|
* it; don't do so again (this prevents infinite recursion if there's
|
||||||
* in pg_depend). Otherwise, add it.
|
* a loop in pg_depend). Otherwise, add it.
|
||||||
*/
|
*/
|
||||||
if (object_address_present(object, oktodelete))
|
if (object_address_present(object, oktodelete))
|
||||||
return;
|
return;
|
||||||
@ -276,8 +276,8 @@ findAutoDeletableObjects(const ObjectAddress *object,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan pg_depend records that link to this object, showing the things
|
* Scan pg_depend records that link to this object, showing the things
|
||||||
* that depend on it. For each one that is AUTO or INTERNAL, visit the
|
* that depend on it. For each one that is AUTO or INTERNAL, visit
|
||||||
* referencing object.
|
* the referencing object.
|
||||||
*
|
*
|
||||||
* When dropping a whole object (subId = 0), find pg_depend records for
|
* When dropping a whole object (subId = 0), find pg_depend records for
|
||||||
* its sub-objects too.
|
* its sub-objects too.
|
||||||
@ -319,6 +319,7 @@ findAutoDeletableObjects(const ObjectAddress *object,
|
|||||||
findAutoDeletableObjects(&otherObject, oktodelete, depRel);
|
findAutoDeletableObjects(&otherObject, oktodelete, depRel);
|
||||||
break;
|
break;
|
||||||
case DEPENDENCY_PIN:
|
case DEPENDENCY_PIN:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For a PIN dependency we just ereport immediately; there
|
* For a PIN dependency we just ereport immediately; there
|
||||||
* won't be any others to examine, and we aren't ever
|
* won't be any others to examine, and we aren't ever
|
||||||
@ -559,10 +560,9 @@ recursiveDeletion(const ObjectAddress *object,
|
|||||||
/*
|
/*
|
||||||
* Step 2: scan pg_depend records that link to this object, showing
|
* Step 2: scan pg_depend records that link to this object, showing
|
||||||
* the things that depend on it. Recursively delete those things.
|
* the things that depend on it. Recursively delete those things.
|
||||||
* Note it's important to delete the dependent objects
|
* Note it's important to delete the dependent objects before the
|
||||||
* before the referenced one, since the deletion routines might do
|
* referenced one, since the deletion routines might do things like
|
||||||
* things like try to update the pg_class record when deleting a check
|
* try to update the pg_class record when deleting a check constraint.
|
||||||
* constraint.
|
|
||||||
*/
|
*/
|
||||||
if (!deleteDependentObjects(object, objDescription,
|
if (!deleteDependentObjects(object, objDescription,
|
||||||
behavior, msglevel,
|
behavior, msglevel,
|
||||||
@ -674,11 +674,12 @@ deleteDependentObjects(const ObjectAddress *object,
|
|||||||
switch (foundDep->deptype)
|
switch (foundDep->deptype)
|
||||||
{
|
{
|
||||||
case DEPENDENCY_NORMAL:
|
case DEPENDENCY_NORMAL:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Perhaps there was another dependency path that would
|
* Perhaps there was another dependency path that would
|
||||||
* have allowed silent deletion of the otherObject, had
|
* have allowed silent deletion of the otherObject, had we
|
||||||
* we only taken that path first.
|
* only taken that path first. In that case, act like this
|
||||||
* In that case, act like this link is AUTO, too.
|
* link is AUTO, too.
|
||||||
*/
|
*/
|
||||||
if (object_address_present(&otherObject, oktodelete))
|
if (object_address_present(&otherObject, oktodelete))
|
||||||
ereport(DEBUG2,
|
ereport(DEBUG2,
|
||||||
@ -1092,7 +1093,8 @@ find_expr_references_walker(Node *node,
|
|||||||
* Add whole-relation refs for each plain relation mentioned in
|
* Add whole-relation refs for each plain relation mentioned in
|
||||||
* the subquery's rtable. (Note: query_tree_walker takes care of
|
* the subquery's rtable. (Note: query_tree_walker takes care of
|
||||||
* recursing into RTE_FUNCTION and RTE_SUBQUERY RTEs, so no need
|
* recursing into RTE_FUNCTION and RTE_SUBQUERY RTEs, so no need
|
||||||
* to do that here. But keep it from looking at join alias lists.)
|
* to do that here. But keep it from looking at join alias
|
||||||
|
* lists.)
|
||||||
*/
|
*/
|
||||||
foreach(rtable, query->rtable)
|
foreach(rtable, query->rtable)
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.249 2003/07/29 17:21:20 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.250 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -418,8 +418,8 @@ CheckAttributeType(const char *attname, Oid atttypid)
|
|||||||
* Warn user, but don't fail, if column to be created has UNKNOWN type
|
* Warn user, but don't fail, if column to be created has UNKNOWN type
|
||||||
* (usually as a result of a 'retrieve into' - jolly)
|
* (usually as a result of a 'retrieve into' - jolly)
|
||||||
*
|
*
|
||||||
* Refuse any attempt to create a pseudo-type column or one that uses
|
* Refuse any attempt to create a pseudo-type column or one that uses a
|
||||||
* a standalone composite type. (Eventually we should probably refuse
|
* standalone composite type. (Eventually we should probably refuse
|
||||||
* all references to complex types, but for now there's still some
|
* all references to complex types, but for now there's still some
|
||||||
* Berkeley-derived code that thinks it can do this...)
|
* Berkeley-derived code that thinks it can do this...)
|
||||||
*/
|
*/
|
||||||
@ -975,12 +975,13 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
|
|||||||
attStruct->attisdropped = true;
|
attStruct->attisdropped = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set the type OID to invalid. A dropped attribute's type link cannot
|
* Set the type OID to invalid. A dropped attribute's type link
|
||||||
* be relied on (once the attribute is dropped, the type might be too).
|
* cannot be relied on (once the attribute is dropped, the type might
|
||||||
* Fortunately we do not need the type row --- the only really essential
|
* be too). Fortunately we do not need the type row --- the only
|
||||||
* information is the type's typlen and typalign, which are preserved in
|
* really essential information is the type's typlen and typalign,
|
||||||
* the attribute's attlen and attalign. We set atttypid to zero here
|
* which are preserved in the attribute's attlen and attalign. We set
|
||||||
* as a means of catching code that incorrectly expects it to be valid.
|
* atttypid to zero here as a means of catching code that incorrectly
|
||||||
|
* expects it to be valid.
|
||||||
*/
|
*/
|
||||||
attStruct->atttypid = InvalidOid;
|
attStruct->atttypid = InvalidOid;
|
||||||
|
|
||||||
@ -1773,9 +1774,9 @@ cookDefault(ParseState *pstate,
|
|||||||
errmsg("cannot use aggregate in DEFAULT clause")));
|
errmsg("cannot use aggregate in DEFAULT clause")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Coerce the expression to the correct type and typmod, if given. This
|
* Coerce the expression to the correct type and typmod, if given.
|
||||||
* should match the parser's processing of non-defaulted expressions ---
|
* This should match the parser's processing of non-defaulted
|
||||||
* see updateTargetListEntry().
|
* expressions --- see updateTargetListEntry().
|
||||||
*/
|
*/
|
||||||
if (OidIsValid(atttypid))
|
if (OidIsValid(atttypid))
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.212 2003/07/21 01:59:08 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/index.c,v 1.213 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
@ -162,8 +162,8 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* now that we've determined the "from", let's copy the tuple desc
|
* now that we've determined the "from", let's copy the tuple
|
||||||
* data...
|
* desc data...
|
||||||
*/
|
*/
|
||||||
memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
|
memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
|
||||||
|
|
||||||
@ -197,7 +197,8 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||||||
sprintf(NameStr(to->attname), "pg_expression_%d", i + 1);
|
sprintf(NameStr(to->attname), "pg_expression_%d", i + 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lookup the expression type in pg_type for the type length etc.
|
* Lookup the expression type in pg_type for the type length
|
||||||
|
* etc.
|
||||||
*/
|
*/
|
||||||
keyType = exprType(indexkey);
|
keyType = exprType(indexkey);
|
||||||
tuple = SearchSysCache(TYPEOID,
|
tuple = SearchSysCache(TYPEOID,
|
||||||
@ -831,8 +832,8 @@ index_drop(Oid indexId)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* We are presently too lazy to attempt to compute the new correct
|
* We are presently too lazy to attempt to compute the new correct
|
||||||
* value of relhasindex (the next VACUUM will fix it if necessary).
|
* value of relhasindex (the next VACUUM will fix it if necessary). So
|
||||||
* So there is no need to update the pg_class tuple for the owning
|
* there is no need to update the pg_class tuple for the owning
|
||||||
* relation. But we must send out a shared-cache-inval notice on the
|
* relation. But we must send out a shared-cache-inval notice on the
|
||||||
* owning relation to ensure other backends update their relcache
|
* owning relation to ensure other backends update their relcache
|
||||||
* lists of indexes.
|
* lists of indexes.
|
||||||
@ -1326,8 +1327,8 @@ UpdateStats(Oid relid, double reltuples)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Update statistics in pg_class, if they changed. (Avoiding an
|
* Update statistics in pg_class, if they changed. (Avoiding an
|
||||||
* unnecessary update is not just a tiny performance improvement;
|
* unnecessary update is not just a tiny performance improvement; it
|
||||||
* it also reduces the window wherein concurrent CREATE INDEX commands
|
* also reduces the window wherein concurrent CREATE INDEX commands
|
||||||
* may conflict.)
|
* may conflict.)
|
||||||
*/
|
*/
|
||||||
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
|
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
|
||||||
@ -1338,8 +1339,9 @@ UpdateStats(Oid relid, double reltuples)
|
|||||||
if (in_place_upd)
|
if (in_place_upd)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* At bootstrap time, we don't need to worry about concurrency or
|
* At bootstrap time, we don't need to worry about concurrency
|
||||||
* visibility of changes, so we cheat. Also cheat if REINDEX.
|
* or visibility of changes, so we cheat. Also cheat if
|
||||||
|
* REINDEX.
|
||||||
*/
|
*/
|
||||||
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
||||||
rd_rel->relpages = (int32) relpages;
|
rd_rel->relpages = (int32) relpages;
|
||||||
@ -1454,8 +1456,8 @@ IndexBuildHeapScan(Relation heapRelation,
|
|||||||
heapDescriptor = RelationGetDescr(heapRelation);
|
heapDescriptor = RelationGetDescr(heapRelation);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need an EState for evaluation of index expressions
|
* Need an EState for evaluation of index expressions and
|
||||||
* and partial-index predicates.
|
* partial-index predicates.
|
||||||
*/
|
*/
|
||||||
estate = CreateExecutorState();
|
estate = CreateExecutorState();
|
||||||
econtext = GetPerTupleExprContext(estate);
|
econtext = GetPerTupleExprContext(estate);
|
||||||
@ -1463,7 +1465,8 @@ IndexBuildHeapScan(Relation heapRelation,
|
|||||||
/*
|
/*
|
||||||
* If this is a predicate (partial) index, we will need to evaluate
|
* If this is a predicate (partial) index, we will need to evaluate
|
||||||
* the predicate using ExecQual, which requires the current tuple to
|
* the predicate using ExecQual, which requires the current tuple to
|
||||||
* be in a slot of a TupleTable. Likewise if there are any expressions.
|
* be in a slot of a TupleTable. Likewise if there are any
|
||||||
|
* expressions.
|
||||||
*/
|
*/
|
||||||
if (indexInfo->ii_Predicate != NIL || indexInfo->ii_Expressions != NIL)
|
if (indexInfo->ii_Predicate != NIL || indexInfo->ii_Expressions != NIL)
|
||||||
{
|
{
|
||||||
@ -1741,8 +1744,8 @@ reindex_index(Oid indexId, bool force, bool inplace)
|
|||||||
* it's a nailed-in-cache index, we must do inplace processing because
|
* it's a nailed-in-cache index, we must do inplace processing because
|
||||||
* the relcache can't cope with changing its relfilenode.
|
* the relcache can't cope with changing its relfilenode.
|
||||||
*
|
*
|
||||||
* In either of these cases, we are definitely processing a system
|
* In either of these cases, we are definitely processing a system index,
|
||||||
* index, so we'd better be ignoring system indexes.
|
* so we'd better be ignoring system indexes.
|
||||||
*/
|
*/
|
||||||
if (iRel->rd_rel->relisshared)
|
if (iRel->rd_rel->relisshared)
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.55 2003/08/01 00:15:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.56 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -1115,8 +1115,8 @@ ConversionIsVisible(Oid conid)
|
|||||||
/*
|
/*
|
||||||
* If it is in the path, it might still not be visible; it could
|
* If it is in the path, it might still not be visible; it could
|
||||||
* be hidden by another conversion of the same name earlier in the
|
* be hidden by another conversion of the same name earlier in the
|
||||||
* path. So we must do a slow check to see if this conversion would
|
* path. So we must do a slow check to see if this conversion
|
||||||
* be found by ConversionGetConid.
|
* would be found by ConversionGetConid.
|
||||||
*/
|
*/
|
||||||
char *conname = NameStr(conform->conname);
|
char *conname = NameStr(conform->conname);
|
||||||
|
|
||||||
@ -1720,8 +1720,8 @@ RemoveTempRelations(Oid tempNamespaceId)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* We want to get rid of everything in the target namespace, but not
|
* We want to get rid of everything in the target namespace, but not
|
||||||
* the namespace itself (deleting it only to recreate it later would be
|
* the namespace itself (deleting it only to recreate it later would
|
||||||
* a waste of cycles). We do this by finding everything that has a
|
* be a waste of cycles). We do this by finding everything that has a
|
||||||
* dependency on the namespace.
|
* dependency on the namespace.
|
||||||
*/
|
*/
|
||||||
object.classId = get_system_catalog_relid(NamespaceRelationName);
|
object.classId = get_system_catalog_relid(NamespaceRelationName);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.61 2003/07/21 01:59:10 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.62 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -99,8 +99,8 @@ AggregateCreate(const char *aggName,
|
|||||||
* enforce_generic_type_consistency, if transtype isn't polymorphic)
|
* enforce_generic_type_consistency, if transtype isn't polymorphic)
|
||||||
* must exactly match declared transtype.
|
* must exactly match declared transtype.
|
||||||
*
|
*
|
||||||
* In the non-polymorphic-transtype case, it might be okay to allow
|
* In the non-polymorphic-transtype case, it might be okay to allow a
|
||||||
* a rettype that's binary-coercible to transtype, but I'm not quite
|
* rettype that's binary-coercible to transtype, but I'm not quite
|
||||||
* convinced that it's either safe or useful. When transtype is
|
* convinced that it's either safe or useful. When transtype is
|
||||||
* polymorphic we *must* demand exact equality.
|
* polymorphic we *must* demand exact equality.
|
||||||
*/
|
*/
|
||||||
@ -151,9 +151,9 @@ AggregateCreate(const char *aggName,
|
|||||||
Assert(OidIsValid(finaltype));
|
Assert(OidIsValid(finaltype));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If finaltype (i.e. aggregate return type) is polymorphic,
|
* If finaltype (i.e. aggregate return type) is polymorphic, basetype
|
||||||
* basetype must be polymorphic also, else parser will fail to deduce
|
* must be polymorphic also, else parser will fail to deduce result
|
||||||
* result type. (Note: given the previous test on transtype and basetype,
|
* type. (Note: given the previous test on transtype and basetype,
|
||||||
* this cannot happen, unless someone has snuck a finalfn definition
|
* this cannot happen, unless someone has snuck a finalfn definition
|
||||||
* into the catalogs that itself violates the rule against polymorphic
|
* into the catalogs that itself violates the rule against polymorphic
|
||||||
* result with no polymorphic input.)
|
* result with no polymorphic input.)
|
||||||
@ -286,9 +286,9 @@ lookup_agg_function(List *fnName,
|
|||||||
func_signature_string(fnName, nargs, input_types))));
|
func_signature_string(fnName, nargs, input_types))));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the given type(s) are all polymorphic, there's nothing we
|
* If the given type(s) are all polymorphic, there's nothing we can
|
||||||
* can check. Otherwise, enforce consistency, and possibly refine
|
* check. Otherwise, enforce consistency, and possibly refine the
|
||||||
* the result type.
|
* result type.
|
||||||
*/
|
*/
|
||||||
if ((input_types[0] == ANYARRAYOID || input_types[0] == ANYELEMENTOID) &&
|
if ((input_types[0] == ANYARRAYOID || input_types[0] == ANYELEMENTOID) &&
|
||||||
(nargs == 1 ||
|
(nargs == 1 ||
|
||||||
@ -305,8 +305,8 @@ lookup_agg_function(List *fnName,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* func_get_detail will find functions requiring run-time argument type
|
* func_get_detail will find functions requiring run-time argument
|
||||||
* coercion, but nodeAgg.c isn't prepared to deal with that
|
* type coercion, but nodeAgg.c isn't prepared to deal with that
|
||||||
*/
|
*/
|
||||||
if (true_oid_array[0] != ANYARRAYOID &&
|
if (true_oid_array[0] != ANYARRAYOID &&
|
||||||
true_oid_array[0] != ANYELEMENTOID &&
|
true_oid_array[0] != ANYELEMENTOID &&
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.14 2003/07/21 01:59:10 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_constraint.c,v 1.15 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -234,8 +234,8 @@ CreateConstraintEntry(const char *constraintName,
|
|||||||
if (OidIsValid(indexRelId))
|
if (OidIsValid(indexRelId))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Register normal dependency on the unique index that supports
|
* Register normal dependency on the unique index that supports a
|
||||||
* a foreign-key constraint.
|
* foreign-key constraint.
|
||||||
*/
|
*/
|
||||||
ObjectAddress relobject;
|
ObjectAddress relobject;
|
||||||
|
|
||||||
@ -438,8 +438,8 @@ RemoveConstraintById(Oid conId)
|
|||||||
Relation rel;
|
Relation rel;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the constraint is for a relation, open and exclusive-lock the
|
* If the constraint is for a relation, open and exclusive-lock
|
||||||
* relation it's for.
|
* the relation it's for.
|
||||||
*/
|
*/
|
||||||
rel = heap_open(con->conrelid, AccessExclusiveLock);
|
rel = heap_open(con->conrelid, AccessExclusiveLock);
|
||||||
|
|
||||||
@ -483,16 +483,15 @@ RemoveConstraintById(Oid conId)
|
|||||||
else if (OidIsValid(con->contypid))
|
else if (OidIsValid(con->contypid))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* XXX for now, do nothing special when dropping a domain constraint
|
* XXX for now, do nothing special when dropping a domain
|
||||||
|
* constraint
|
||||||
*
|
*
|
||||||
* Probably there should be some form of locking on the domain type,
|
* Probably there should be some form of locking on the domain type,
|
||||||
* but we have no such concept at the moment.
|
* but we have no such concept at the moment.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
elog(ERROR, "constraint %u is not of a known type", conId);
|
elog(ERROR, "constraint %u is not of a known type", conId);
|
||||||
}
|
|
||||||
|
|
||||||
/* Fry the constraint itself */
|
/* Fry the constraint itself */
|
||||||
simple_heap_delete(conDesc, &tup->t_self);
|
simple_heap_delete(conDesc, &tup->t_self);
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_conversion.c,v 1.13 2003/08/01 00:15:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_conversion.c,v 1.14 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.81 2003/08/01 00:15:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.82 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* these routines moved here from commands/define.c and somewhat cleaned up.
|
* these routines moved here from commands/define.c and somewhat cleaned up.
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.102 2003/08/01 00:15:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.103 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -696,13 +696,13 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
|
|||||||
prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
|
prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't do full prechecking of the function definition if there are
|
* We can't do full prechecking of the function definition if there
|
||||||
* any polymorphic input types, because actual datatypes of expression
|
* are any polymorphic input types, because actual datatypes of
|
||||||
* results will be unresolvable. The check will be done at runtime
|
* expression results will be unresolvable. The check will be done at
|
||||||
* instead.
|
* runtime instead.
|
||||||
*
|
*
|
||||||
* We can run the text through the raw parser though; this will at
|
* We can run the text through the raw parser though; this will at least
|
||||||
* least catch silly syntactic errors.
|
* catch silly syntactic errors.
|
||||||
*/
|
*/
|
||||||
if (!haspolyarg)
|
if (!haspolyarg)
|
||||||
{
|
{
|
||||||
@ -712,9 +712,7 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
|
|||||||
check_sql_fn_retval(proc->prorettype, functyptype, querytree_list);
|
check_sql_fn_retval(proc->prorettype, functyptype, querytree_list);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
querytree_list = pg_parse_query(prosrc);
|
querytree_list = pg_parse_query(prosrc);
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseSysCache(tuple);
|
ReleaseSysCache(tuple);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.88 2003/07/21 01:59:11 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.89 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -359,7 +359,8 @@ TypeCreate(const char *typeName,
|
|||||||
void
|
void
|
||||||
GenerateTypeDependencies(Oid typeNamespace,
|
GenerateTypeDependencies(Oid typeNamespace,
|
||||||
Oid typeObjectId,
|
Oid typeObjectId,
|
||||||
Oid relationOid, /* only for 'c'atalog types */
|
Oid relationOid, /* only for 'c'atalog
|
||||||
|
* types */
|
||||||
char relationKind, /* ditto */
|
char relationKind, /* ditto */
|
||||||
Oid inputProcedure,
|
Oid inputProcedure,
|
||||||
Oid outputProcedure,
|
Oid outputProcedure,
|
||||||
@ -426,13 +427,13 @@ GenerateTypeDependencies(Oid typeNamespace,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* If the type is a rowtype for a relation, mark it as internally
|
* If the type is a rowtype for a relation, mark it as internally
|
||||||
* dependent on the relation, *unless* it is a stand-alone
|
* dependent on the relation, *unless* it is a stand-alone composite
|
||||||
* composite type relation. For the latter case, we have to
|
* type relation. For the latter case, we have to reverse the
|
||||||
* reverse the dependency.
|
* dependency.
|
||||||
*
|
*
|
||||||
* In the former case, this allows the type to be auto-dropped when
|
* In the former case, this allows the type to be auto-dropped when the
|
||||||
* the relation is, and not otherwise. And in the latter, of
|
* relation is, and not otherwise. And in the latter, of course we get
|
||||||
* course we get the opposite effect.
|
* the opposite effect.
|
||||||
*/
|
*/
|
||||||
if (OidIsValid(relationOid))
|
if (OidIsValid(relationOid))
|
||||||
{
|
{
|
||||||
@ -447,11 +448,11 @@ GenerateTypeDependencies(Oid typeNamespace,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the type is an array type, mark it auto-dependent on the
|
* If the type is an array type, mark it auto-dependent on the base
|
||||||
* base type. (This is a compromise between the typical case
|
* type. (This is a compromise between the typical case where the
|
||||||
* where the array type is automatically generated and the case
|
* array type is automatically generated and the case where it is
|
||||||
* where it is manually created: we'd prefer INTERNAL for the
|
* manually created: we'd prefer INTERNAL for the former case and
|
||||||
* former case and NORMAL for the latter.)
|
* NORMAL for the latter.)
|
||||||
*/
|
*/
|
||||||
if (OidIsValid(elementType))
|
if (OidIsValid(elementType))
|
||||||
{
|
{
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.12 2003/08/01 00:15:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/aggregatecmds.c,v 1.13 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
* DESCRIPTION
|
* DESCRIPTION
|
||||||
* The "DefineFoo" routines take the parse tree and pick out the
|
* The "DefineFoo" routines take the parse tree and pick out the
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/alter.c,v 1.4 2003/08/01 00:15:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/alter.c,v 1.5 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -92,8 +92,8 @@ ExecRenameStmt(RenameStmt *stmt)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* RENAME TABLE requires that we (still) hold
|
* RENAME TABLE requires that we (still) hold
|
||||||
* CREATE rights on the containing namespace, as
|
* CREATE rights on the containing namespace,
|
||||||
* well as ownership of the table.
|
* as well as ownership of the table.
|
||||||
*/
|
*/
|
||||||
Oid namespaceId = get_rel_namespace(relid);
|
Oid namespaceId = get_rel_namespace(relid);
|
||||||
AclResult aclresult;
|
AclResult aclresult;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.56 2003/07/20 21:56:32 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/analyze.c,v 1.57 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -220,9 +220,9 @@ analyze_rel(Oid relid, VacuumStmt *vacstmt)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Silently ignore tables that are temp tables of other backends ---
|
* Silently ignore tables that are temp tables of other backends ---
|
||||||
* trying to analyze these is rather pointless, since their
|
* trying to analyze these is rather pointless, since their contents
|
||||||
* contents are probably not up-to-date on disk. (We don't throw a
|
* are probably not up-to-date on disk. (We don't throw a warning
|
||||||
* warning here; it would just lead to chatter during a database-wide
|
* here; it would just lead to chatter during a database-wide
|
||||||
* ANALYZE.)
|
* ANALYZE.)
|
||||||
*/
|
*/
|
||||||
if (isOtherTempNamespace(RelationGetNamespace(onerel)))
|
if (isOtherTempNamespace(RelationGetNamespace(onerel)))
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.96 2003/07/20 21:56:32 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/async.c,v 1.97 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -603,10 +603,10 @@ Async_NotifyHandler(SIGNAL_ARGS)
|
|||||||
bool save_ImmediateInterruptOK = ImmediateInterruptOK;
|
bool save_ImmediateInterruptOK = ImmediateInterruptOK;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We may be called while ImmediateInterruptOK is true; turn it off
|
* We may be called while ImmediateInterruptOK is true; turn it
|
||||||
* while messing with the NOTIFY state. (We would have to save
|
* off while messing with the NOTIFY state. (We would have to
|
||||||
* and restore it anyway, because PGSemaphore operations inside
|
* save and restore it anyway, because PGSemaphore operations
|
||||||
* ProcessIncomingNotify() might reset it.)
|
* inside ProcessIncomingNotify() might reset it.)
|
||||||
*/
|
*/
|
||||||
ImmediateInterruptOK = false;
|
ImmediateInterruptOK = false;
|
||||||
|
|
||||||
@ -639,7 +639,8 @@ Async_NotifyHandler(SIGNAL_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restore ImmediateInterruptOK, and check for interrupts if needed.
|
* Restore ImmediateInterruptOK, and check for interrupts if
|
||||||
|
* needed.
|
||||||
*/
|
*/
|
||||||
ImmediateInterruptOK = save_ImmediateInterruptOK;
|
ImmediateInterruptOK = save_ImmediateInterruptOK;
|
||||||
if (save_ImmediateInterruptOK)
|
if (save_ImmediateInterruptOK)
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.112 2003/08/01 00:15:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/cluster.c,v 1.113 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -152,7 +152,10 @@ cluster(ClusterStmt *stmt)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* The index is expected to be in the same namespace as the relation. */
|
/*
|
||||||
|
* The index is expected to be in the same namespace as the
|
||||||
|
* relation.
|
||||||
|
*/
|
||||||
indexOid = get_relname_relid(stmt->indexname,
|
indexOid = get_relname_relid(stmt->indexname,
|
||||||
rel->rd_rel->relnamespace);
|
rel->rd_rel->relnamespace);
|
||||||
if (!OidIsValid(indexOid))
|
if (!OidIsValid(indexOid))
|
||||||
@ -175,16 +178,16 @@ cluster(ClusterStmt *stmt)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* This is the "multi relation" case. We need to cluster all tables
|
* This is the "multi relation" case. We need to cluster all
|
||||||
* that have some index with indisclustered set.
|
* tables that have some index with indisclustered set.
|
||||||
*/
|
*/
|
||||||
MemoryContext cluster_context;
|
MemoryContext cluster_context;
|
||||||
List *rv,
|
List *rv,
|
||||||
*rvs;
|
*rvs;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We cannot run this form of CLUSTER inside a user transaction block;
|
* We cannot run this form of CLUSTER inside a user transaction
|
||||||
* we'd be holding locks way too long.
|
* block; we'd be holding locks way too long.
|
||||||
*/
|
*/
|
||||||
PreventTransactionChain((void *) stmt, "CLUSTER");
|
PreventTransactionChain((void *) stmt, "CLUSTER");
|
||||||
|
|
||||||
@ -201,8 +204,8 @@ cluster(ClusterStmt *stmt)
|
|||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build the list of relations to cluster. Note that this lives in
|
* Build the list of relations to cluster. Note that this lives
|
||||||
* cluster_context.
|
* in cluster_context.
|
||||||
*/
|
*/
|
||||||
rvs = get_tables_to_cluster(cluster_context);
|
rvs = get_tables_to_cluster(cluster_context);
|
||||||
|
|
||||||
@ -216,7 +219,8 @@ cluster(ClusterStmt *stmt)
|
|||||||
|
|
||||||
/* Start a new transaction for each relation. */
|
/* Start a new transaction for each relation. */
|
||||||
StartTransactionCommand();
|
StartTransactionCommand();
|
||||||
SetQuerySnapshot(); /* might be needed for functions in indexes */
|
SetQuerySnapshot(); /* might be needed for functions in
|
||||||
|
* indexes */
|
||||||
cluster_rel(rvtc, true);
|
cluster_rel(rvtc, true);
|
||||||
CommitTransactionCommand();
|
CommitTransactionCommand();
|
||||||
}
|
}
|
||||||
@ -256,8 +260,8 @@ cluster_rel(RelToCluster *rvtc, bool recheck)
|
|||||||
* Since we may open a new transaction for each relation, we have to
|
* Since we may open a new transaction for each relation, we have to
|
||||||
* check that the relation still is what we think it is.
|
* check that the relation still is what we think it is.
|
||||||
*
|
*
|
||||||
* If this is a single-transaction CLUSTER, we can skip these tests.
|
* If this is a single-transaction CLUSTER, we can skip these tests. We
|
||||||
* We *must* skip the one on indisclustered since it would reject an
|
* *must* skip the one on indisclustered since it would reject an
|
||||||
* attempt to cluster a not-previously-clustered index.
|
* attempt to cluster a not-previously-clustered index.
|
||||||
*/
|
*/
|
||||||
if (recheck)
|
if (recheck)
|
||||||
@ -319,10 +323,10 @@ cluster_rel(RelToCluster *rvtc, bool recheck)
|
|||||||
RelationGetRelationName(OldHeap))));
|
RelationGetRelationName(OldHeap))));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Disallow clustering on incomplete indexes (those that might not index
|
* Disallow clustering on incomplete indexes (those that might not
|
||||||
* every row of the relation). We could relax this by making a separate
|
* index every row of the relation). We could relax this by making a
|
||||||
* seqscan pass over the table to copy the missing rows, but that seems
|
* separate seqscan pass over the table to copy the missing rows, but
|
||||||
* expensive and tedious.
|
* that seems expensive and tedious.
|
||||||
*/
|
*/
|
||||||
if (!heap_attisnull(OldIndex->rd_indextuple, Anum_pg_index_indpred))
|
if (!heap_attisnull(OldIndex->rd_indextuple, Anum_pg_index_indpred))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -432,6 +436,7 @@ rebuild_relation(Relation OldHeap, Oid indexOid)
|
|||||||
snprintf(NewHeapName, sizeof(NewHeapName), "pg_temp_%u", tableOid);
|
snprintf(NewHeapName, sizeof(NewHeapName), "pg_temp_%u", tableOid);
|
||||||
|
|
||||||
OIDNewHeap = make_new_heap(tableOid, NewHeapName);
|
OIDNewHeap = make_new_heap(tableOid, NewHeapName);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't need CommandCounterIncrement() because make_new_heap did
|
* We don't need CommandCounterIncrement() because make_new_heap did
|
||||||
* it.
|
* it.
|
||||||
@ -868,9 +873,9 @@ get_tables_to_cluster(MemoryContext cluster_context)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Get all indexes that have indisclustered set and are owned by
|
* Get all indexes that have indisclustered set and are owned by
|
||||||
* appropriate user. System relations or nailed-in relations cannot ever
|
* appropriate user. System relations or nailed-in relations cannot
|
||||||
* have indisclustered set, because CLUSTER will refuse to set it when
|
* ever have indisclustered set, because CLUSTER will refuse to set it
|
||||||
* called with one of them as argument.
|
* when called with one of them as argument.
|
||||||
*/
|
*/
|
||||||
indRelation = relation_openr(IndexRelationName, AccessShareLock);
|
indRelation = relation_openr(IndexRelationName, AccessShareLock);
|
||||||
ScanKeyEntryInitialize(&entry, 0,
|
ScanKeyEntryInitialize(&entry, 0,
|
||||||
@ -886,8 +891,8 @@ get_tables_to_cluster(MemoryContext cluster_context)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to build the list in a different memory context so
|
* We have to build the list in a different memory context so it
|
||||||
* it will survive the cross-transaction processing
|
* will survive the cross-transaction processing
|
||||||
*/
|
*/
|
||||||
old_context = MemoryContextSwitchTo(cluster_context);
|
old_context = MemoryContextSwitchTo(cluster_context);
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
* Copyright (c) 1996-2001, PostgreSQL Global Development Group
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.67 2003/08/01 00:15:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/comment.c,v 1.68 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -418,16 +418,17 @@ CommentDatabase(List *qualname, char *comment)
|
|||||||
database = strVal(lfirst(qualname));
|
database = strVal(lfirst(qualname));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We cannot currently support cross-database comments (since other DBs
|
* We cannot currently support cross-database comments (since other
|
||||||
* cannot see pg_description of this database). So, we reject attempts
|
* DBs cannot see pg_description of this database). So, we reject
|
||||||
* to comment on a database other than the current one. Someday this
|
* attempts to comment on a database other than the current one.
|
||||||
* might be improved, but it would take a redesigned infrastructure.
|
* Someday this might be improved, but it would take a redesigned
|
||||||
|
* infrastructure.
|
||||||
*
|
*
|
||||||
* When loading a dump, we may see a COMMENT ON DATABASE for the old name
|
* When loading a dump, we may see a COMMENT ON DATABASE for the old name
|
||||||
* of the database. Erroring out would prevent pg_restore from completing
|
* of the database. Erroring out would prevent pg_restore from
|
||||||
* (which is really pg_restore's fault, but for now we will work around
|
* completing (which is really pg_restore's fault, but for now we will
|
||||||
* the problem here). Consensus is that the best fix is to treat wrong
|
* work around the problem here). Consensus is that the best fix is
|
||||||
* database name as a WARNING not an ERROR.
|
* to treat wrong database name as a WARNING not an ERROR.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* First get the database OID */
|
/* First get the database OID */
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/conversioncmds.c,v 1.9 2003/08/01 00:15:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/conversioncmds.c,v 1.10 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.205 2003/08/01 00:15:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.206 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -136,6 +136,7 @@ static void CopySendChar(char c);
|
|||||||
static void CopySendEndOfRow(bool binary);
|
static void CopySendEndOfRow(bool binary);
|
||||||
static void CopyGetData(void *databuf, int datasize);
|
static void CopyGetData(void *databuf, int datasize);
|
||||||
static int CopyGetChar(void);
|
static int CopyGetChar(void);
|
||||||
|
|
||||||
#define CopyGetEof() (fe_eof)
|
#define CopyGetEof() (fe_eof)
|
||||||
static int CopyPeekChar(void);
|
static int CopyPeekChar(void);
|
||||||
static void CopyDonePeek(int c, bool pickup);
|
static void CopyDonePeek(int c, bool pickup);
|
||||||
@ -537,7 +538,11 @@ CopyDonePeek(int c, bool pickup)
|
|||||||
/* We want to pick it up */
|
/* We want to pick it up */
|
||||||
(void) pq_getbyte();
|
(void) pq_getbyte();
|
||||||
}
|
}
|
||||||
/* If we didn't want to pick it up, just leave it where it sits */
|
|
||||||
|
/*
|
||||||
|
* If we didn't want to pick it up, just leave it where it
|
||||||
|
* sits
|
||||||
|
*/
|
||||||
break;
|
break;
|
||||||
case COPY_NEW_FE:
|
case COPY_NEW_FE:
|
||||||
if (!pickup)
|
if (!pickup)
|
||||||
@ -955,8 +960,8 @@ CopyTo(Relation rel, List *attnumlist, bool binary, bool oids,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a temporary memory context that we can reset once per row
|
* Create a temporary memory context that we can reset once per row to
|
||||||
* to recover palloc'd memory. This avoids any problems with leaks
|
* recover palloc'd memory. This avoids any problems with leaks
|
||||||
* inside datatype output routines, and should be faster than retail
|
* inside datatype output routines, and should be faster than retail
|
||||||
* pfree's anyway. (We don't need a whole econtext as CopyFrom does.)
|
* pfree's anyway. (We don't need a whole econtext as CopyFrom does.)
|
||||||
*/
|
*/
|
||||||
@ -1219,10 +1224,10 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
|||||||
/*
|
/*
|
||||||
* Easiest way to do this is to use parse_coerce.c to set up
|
* Easiest way to do this is to use parse_coerce.c to set up
|
||||||
* an expression that checks the constraints. (At present,
|
* an expression that checks the constraints. (At present,
|
||||||
* the expression might contain a length-coercion-function call
|
* the expression might contain a length-coercion-function
|
||||||
* and/or CoerceToDomain nodes.) The bottom of the expression
|
* call and/or CoerceToDomain nodes.) The bottom of the
|
||||||
* is a Param node so that we can fill in the actual datum during
|
* expression is a Param node so that we can fill in the
|
||||||
* the data input loop.
|
* actual datum during the data input loop.
|
||||||
*/
|
*/
|
||||||
prm = makeNode(Param);
|
prm = makeNode(Param);
|
||||||
prm->paramkind = PARAM_EXEC;
|
prm->paramkind = PARAM_EXEC;
|
||||||
@ -1241,11 +1246,11 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check BEFORE STATEMENT insertion triggers. It's debateable
|
* Check BEFORE STATEMENT insertion triggers. It's debateable whether
|
||||||
* whether we should do this for COPY, since it's not really an
|
* we should do this for COPY, since it's not really an "INSERT"
|
||||||
* "INSERT" statement as such. However, executing these triggers
|
* statement as such. However, executing these triggers maintains
|
||||||
* maintains consistency with the EACH ROW triggers that we already
|
* consistency with the EACH ROW triggers that we already fire on
|
||||||
* fire on COPY.
|
* COPY.
|
||||||
*/
|
*/
|
||||||
ExecBSInsertTriggers(estate, resultRelInfo);
|
ExecBSInsertTriggers(estate, resultRelInfo);
|
||||||
|
|
||||||
@ -1418,9 +1423,9 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
|||||||
/*
|
/*
|
||||||
* Complain if there are more fields on the input line.
|
* Complain if there are more fields on the input line.
|
||||||
*
|
*
|
||||||
* Special case: if we're reading a zero-column table, we
|
* Special case: if we're reading a zero-column table, we won't
|
||||||
* won't yet have called CopyReadAttribute() at all; so do that
|
* yet have called CopyReadAttribute() at all; so do that and
|
||||||
* and check we have an empty line. Fortunately we can keep that
|
* check we have an empty line. Fortunately we can keep that
|
||||||
* silly corner case out of the main line of execution.
|
* silly corner case out of the main line of execution.
|
||||||
*/
|
*/
|
||||||
if (result == NORMAL_ATTR)
|
if (result == NORMAL_ATTR)
|
||||||
@ -1531,9 +1536,9 @@ CopyFrom(Relation rel, List *attnumlist, bool binary, bool oids,
|
|||||||
prmdata->isnull = (nulls[i] == 'n');
|
prmdata->isnull = (nulls[i] == 'n');
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute the constraint expression. Allow the expression
|
* Execute the constraint expression. Allow the
|
||||||
* to replace the value (consider e.g. a timestamp precision
|
* expression to replace the value (consider e.g. a
|
||||||
* restriction).
|
* timestamp precision restriction).
|
||||||
*/
|
*/
|
||||||
values[i] = ExecEvalExpr(exprstate, econtext,
|
values[i] = ExecEvalExpr(exprstate, econtext,
|
||||||
&isnull, NULL);
|
&isnull, NULL);
|
||||||
@ -1679,6 +1684,7 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
|
|||||||
if (copy_lineno == 1 || eol_type == EOL_CRNL)
|
if (copy_lineno == 1 || eol_type == EOL_CRNL)
|
||||||
{
|
{
|
||||||
int c2 = CopyPeekChar();
|
int c2 = CopyPeekChar();
|
||||||
|
|
||||||
if (c2 == '\n')
|
if (c2 == '\n')
|
||||||
{
|
{
|
||||||
CopyDonePeek(c2, true); /* eat newline */
|
CopyDonePeek(c2, true); /* eat newline */
|
||||||
@ -1692,7 +1698,11 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
|
|||||||
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
|
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
|
||||||
errmsg("literal carriage return found in data"),
|
errmsg("literal carriage return found in data"),
|
||||||
errhint("Use \"\\r\" to represent carriage return.")));
|
errhint("Use \"\\r\" to represent carriage return.")));
|
||||||
/* if we got here, it is the first line and we didn't get \n, so put it back */
|
|
||||||
|
/*
|
||||||
|
* if we got here, it is the first line and we didn't
|
||||||
|
* get \n, so put it back
|
||||||
|
*/
|
||||||
CopyDonePeek(c2, false);
|
CopyDonePeek(c2, false);
|
||||||
eol_type = EOL_CR;
|
eol_type = EOL_CR;
|
||||||
}
|
}
|
||||||
@ -1820,18 +1830,17 @@ CopyReadAttribute(const char *delim, CopyReadResult *result)
|
|||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
|
(errcode(ERRCODE_BAD_COPY_FILE_FORMAT),
|
||||||
errmsg("end-of-copy marker does not match previous newline style")));
|
errmsg("end-of-copy marker does not match previous newline style")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In protocol version 3, we should ignore anything after
|
* In protocol version 3, we should ignore anything
|
||||||
* \. up to the protocol end of copy data. (XXX maybe
|
* after \. up to the protocol end of copy data. (XXX
|
||||||
* better not to treat \. as special?)
|
* maybe better not to treat \. as special?)
|
||||||
*/
|
*/
|
||||||
if (copy_dest == COPY_NEW_FE)
|
if (copy_dest == COPY_NEW_FE)
|
||||||
{
|
{
|
||||||
while (c != EOF)
|
while (c != EOF)
|
||||||
{
|
|
||||||
c = CopyGetChar();
|
c = CopyGetChar();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
*result = END_OF_FILE;
|
*result = END_OF_FILE;
|
||||||
goto copy_eof;
|
goto copy_eof;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.119 2003/08/01 00:15:19 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.120 2003/08/04 00:43:16 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -577,10 +577,13 @@ dropdb(const char *dbname)
|
|||||||
void
|
void
|
||||||
RenameDatabase(const char *oldname, const char *newname)
|
RenameDatabase(const char *oldname, const char *newname)
|
||||||
{
|
{
|
||||||
HeapTuple tup, newtup;
|
HeapTuple tup,
|
||||||
|
newtup;
|
||||||
Relation rel;
|
Relation rel;
|
||||||
SysScanDesc scan, scan2;
|
SysScanDesc scan,
|
||||||
ScanKeyData key, key2;
|
scan2;
|
||||||
|
ScanKeyData key,
|
||||||
|
key2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Obtain AccessExclusiveLock so that no new session gets started
|
* Obtain AccessExclusiveLock so that no new session gets started
|
||||||
@ -610,9 +613,8 @@ RenameDatabase(const char *oldname, const char *newname)
|
|||||||
errmsg("current database may not be renamed")));
|
errmsg("current database may not be renamed")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure the database does not have active sessions. Might
|
* Make sure the database does not have active sessions. Might not be
|
||||||
* not be necessary, but it's consistent with other database
|
* necessary, but it's consistent with other database operations.
|
||||||
* operations.
|
|
||||||
*/
|
*/
|
||||||
if (DatabaseHasActiveBackends(HeapTupleGetOid(tup), false))
|
if (DatabaseHasActiveBackends(HeapTupleGetOid(tup), false))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -651,10 +653,10 @@ RenameDatabase(const char *oldname, const char *newname)
|
|||||||
heap_close(rel, NoLock);
|
heap_close(rel, NoLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Force dirty buffers out to disk, so that newly-connecting
|
* Force dirty buffers out to disk, so that newly-connecting backends
|
||||||
* backends will see the renamed database in pg_database right
|
* will see the renamed database in pg_database right away. (They'll
|
||||||
* away. (They'll see an uncommitted tuple, but they don't care;
|
* see an uncommitted tuple, but they don't care; see
|
||||||
* see GetRawDatabaseInfo.)
|
* GetRawDatabaseInfo.)
|
||||||
*/
|
*/
|
||||||
BufferSync();
|
BufferSync();
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user