1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-20 00:42:27 +03:00

pgindent run.

This commit is contained in:
Bruce Momjian 2003-08-04 00:43:34 +00:00
parent 63354a0228
commit 089003fb46
554 changed files with 24888 additions and 21245 deletions

View File

@ -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);

View File

@ -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);
@ -1264,17 +1268,19 @@ cube_f8_f8(double *x1, double *x2)
/* Add a dimension to an existing cube with the same values for the new /* Add a dimension to an existing cube with the same values for the new
coordinate */ coordinate */
NDBOX * NDBOX *
cube_c_f8(NDBOX *c, double *x1) 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];
} }
@ -1285,17 +1291,19 @@ cube_c_f8(NDBOX *c, double *x1)
/* Add a dimension to an existing cube */ /* Add a dimension to an existing cube */
NDBOX * NDBOX *
cube_c_f8_f8(NDBOX *c, double *x1, double *x2) 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];
} }

View File

@ -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

View File

@ -63,7 +63,7 @@ typedef struct remoteConn
{ {
PGconn *con; /* Hold the remote connection */ PGconn *con; /* Hold the remote connection */
bool remoteTrFlag; /* Indicates whether or not a transaction bool remoteTrFlag; /* Indicates whether or not a transaction
* on remote database is in progress*/ * on remote database is in progress */
} remoteConn; } remoteConn;
/* /*
@ -71,7 +71,7 @@ typedef struct remoteConn
*/ */
static remoteConn *getConnectionByName(const char *name); static remoteConn *getConnectionByName(const char *name);
static HTAB *createConnHash(void); static HTAB *createConnHash(void);
static void createNewConnection(const char *name,remoteConn *con); static void createNewConnection(const char *name, remoteConn * con);
static void deleteConnection(const char *name); static void deleteConnection(const char *name);
static char **get_pkey_attnames(Oid relid, int16 *numatts); static char **get_pkey_attnames(Oid relid, int16 *numatts);
static char *get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals); static char *get_sql_insert(Oid relid, int16 *pkattnums, int16 pknumatts, char **src_pkattvals, char **tgt_pkattvals);
@ -89,7 +89,7 @@ static char *generate_relation_name(Oid relid);
List *res_id = NIL; List *res_id = NIL;
int res_id_index = 0; int res_id_index = 0;
PGconn *persistent_conn = NULL; PGconn *persistent_conn = NULL;
static HTAB *remoteConnHash=NULL; static HTAB *remoteConnHash = NULL;
/* /*
Following is list that holds multiple remote connections. Following is list that holds multiple remote connections.
@ -186,18 +186,18 @@ dblink_connect(PG_FUNCTION_ARGS)
PGconn *conn = NULL; PGconn *conn = NULL;
remoteConn *rcon = NULL; remoteConn *rcon = NULL;
if(PG_NARGS()==2) if (PG_NARGS() == 2)
{ {
connstr = GET_STR(PG_GETARG_TEXT_P(1)); connstr = GET_STR(PG_GETARG_TEXT_P(1));
connname = GET_STR(PG_GETARG_TEXT_P(0)); connname = GET_STR(PG_GETARG_TEXT_P(0));
} }
else if(PG_NARGS()==1) else if (PG_NARGS() == 1)
connstr = GET_STR(PG_GETARG_TEXT_P(0)); connstr = GET_STR(PG_GETARG_TEXT_P(0));
oldcontext = MemoryContextSwitchTo(TopMemoryContext); oldcontext = MemoryContextSwitchTo(TopMemoryContext);
if(connname) if (connname)
rcon=(remoteConn *) palloc(sizeof(remoteConn)); rcon = (remoteConn *) palloc(sizeof(remoteConn));
conn = PQconnectdb(connstr); conn = PQconnectdb(connstr);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
@ -206,7 +206,7 @@ dblink_connect(PG_FUNCTION_ARGS)
{ {
msg = pstrdup(PQerrorMessage(conn)); msg = pstrdup(PQerrorMessage(conn));
PQfinish(conn); PQfinish(conn);
if(rcon) if (rcon)
pfree(rcon); pfree(rcon);
ereport(ERROR, ereport(ERROR,
@ -215,7 +215,7 @@ dblink_connect(PG_FUNCTION_ARGS)
errdetail("%s", msg))); errdetail("%s", msg)));
} }
if(connname) if (connname)
{ {
rcon->con = conn; rcon->con = conn;
createNewConnection(connname, rcon); createNewConnection(connname, rcon);
@ -237,7 +237,7 @@ dblink_disconnect(PG_FUNCTION_ARGS)
remoteConn *rcon = NULL; remoteConn *rcon = NULL;
PGconn *conn = NULL; PGconn *conn = NULL;
if (PG_NARGS() ==1 ) if (PG_NARGS() == 1)
{ {
conname = GET_STR(PG_GETARG_TEXT_P(0)); conname = GET_STR(PG_GETARG_TEXT_P(0));
rcon = getConnectionByName(conname); rcon = getConnectionByName(conname);
@ -276,13 +276,13 @@ dblink_open(PG_FUNCTION_ARGS)
StringInfo str = makeStringInfo(); StringInfo str = makeStringInfo();
remoteConn *rcon = NULL; remoteConn *rcon = NULL;
if(PG_NARGS() == 2) if (PG_NARGS() == 2)
{ {
curname = GET_STR(PG_GETARG_TEXT_P(0)); curname = GET_STR(PG_GETARG_TEXT_P(0));
sql = GET_STR(PG_GETARG_TEXT_P(1)); sql = GET_STR(PG_GETARG_TEXT_P(1));
conn = persistent_conn; conn = persistent_conn;
} }
else if(PG_NARGS() == 3) else if (PG_NARGS() == 3)
{ {
conname = GET_STR(PG_GETARG_TEXT_P(0)); conname = GET_STR(PG_GETARG_TEXT_P(0));
curname = GET_STR(PG_GETARG_TEXT_P(1)); curname = GET_STR(PG_GETARG_TEXT_P(1));
@ -333,12 +333,12 @@ dblink_close(PG_FUNCTION_ARGS)
curname = GET_STR(PG_GETARG_TEXT_P(0)); curname = GET_STR(PG_GETARG_TEXT_P(0));
conn = persistent_conn; conn = persistent_conn;
} }
else if (PG_NARGS()==2) else if (PG_NARGS() == 2)
{ {
conname = GET_STR(PG_GETARG_TEXT_P(0)); conname = GET_STR(PG_GETARG_TEXT_P(0));
curname = GET_STR(PG_GETARG_TEXT_P(1)); curname = GET_STR(PG_GETARG_TEXT_P(1));
rcon = getConnectionByName(conname); rcon = getConnectionByName(conname);
if(rcon) if (rcon)
conn = rcon->con; conn = rcon->con;
} }
@ -381,7 +381,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
PGresult *res = NULL; PGresult *res = NULL;
MemoryContext oldcontext; MemoryContext oldcontext;
char *conname = NULL; char *conname = NULL;
remoteConn *rcon=NULL; remoteConn *rcon = NULL;
/* stuff done only on the first call of the function */ /* stuff done only on the first call of the function */
if (SRF_IS_FIRSTCALL()) if (SRF_IS_FIRSTCALL())
@ -401,7 +401,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
howmany = PG_GETARG_INT32(2); howmany = PG_GETARG_INT32(2);
rcon = getConnectionByName(conname); rcon = getConnectionByName(conname);
if(rcon) if (rcon)
conn = rcon->con; conn = rcon->con;
} }
else if (PG_NARGS() == 2) else if (PG_NARGS() == 2)
@ -411,7 +411,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
conn = persistent_conn; conn = persistent_conn;
} }
if(!conn) if (!conn)
DBLINK_CONN_NOT_AVAIL; DBLINK_CONN_NOT_AVAIL;
/* create a function context for cross-call persistence */ /* create a function context for cross-call persistence */
@ -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 */
@ -549,7 +547,7 @@ dblink_record(PG_FUNCTION_ARGS)
char *connstr = NULL; char *connstr = NULL;
char *sql = NULL; char *sql = NULL;
char *conname = NULL; char *conname = NULL;
remoteConn *rcon=NULL; remoteConn *rcon = NULL;
/* create a function context for cross-call persistence */ /* create a function context for cross-call persistence */
funcctx = SRF_FIRSTCALL_INIT(); funcctx = SRF_FIRSTCALL_INIT();
@ -574,7 +572,7 @@ dblink_record(PG_FUNCTION_ARGS)
/* shouldn't happen */ /* shouldn't happen */
elog(ERROR, "wrong number of arguments"); elog(ERROR, "wrong number of arguments");
if(!conn) if (!conn)
DBLINK_CONN_NOT_AVAIL; DBLINK_CONN_NOT_AVAIL;
res = PQexec(conn, sql); res = PQexec(conn, sql);
@ -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;
@ -707,7 +705,7 @@ dblink_exec(PG_FUNCTION_ARGS)
char *connstr = NULL; char *connstr = NULL;
char *sql = NULL; char *sql = NULL;
char *conname = NULL; char *conname = NULL;
remoteConn *rcon=NULL; remoteConn *rcon = NULL;
bool freeconn = true; bool freeconn = true;
if (PG_NARGS() == 2) if (PG_NARGS() == 2)
@ -724,7 +722,7 @@ dblink_exec(PG_FUNCTION_ARGS)
/* shouldn't happen */ /* shouldn't happen */
elog(ERROR, "wrong number of arguments"); elog(ERROR, "wrong number of arguments");
if(!conn) if (!conn)
DBLINK_CONN_NOT_AVAIL; DBLINK_CONN_NOT_AVAIL;
res = PQexec(conn, sql); res = PQexec(conn, sql);
@ -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
@ -1896,18 +1895,18 @@ getConnectionByName(const char *name)
remoteConnHashEnt *hentry; remoteConnHashEnt *hentry;
char key[NAMEDATALEN]; char key[NAMEDATALEN];
if(!remoteConnHash) if (!remoteConnHash)
remoteConnHash=createConnHash(); remoteConnHash = createConnHash();
MemSet(key, 0, NAMEDATALEN); MemSet(key, 0, NAMEDATALEN);
snprintf(key, NAMEDATALEN - 1, "%s", name); snprintf(key, NAMEDATALEN - 1, "%s", name);
hentry = (remoteConnHashEnt*) hash_search(remoteConnHash, hentry = (remoteConnHashEnt *) hash_search(remoteConnHash,
key, HASH_FIND, NULL); key, HASH_FIND, NULL);
if(hentry) if (hentry)
return(hentry->rcon); return (hentry->rcon);
return(NULL); return (NULL);
} }
static HTAB * static HTAB *
@ -1919,24 +1918,24 @@ createConnHash(void)
ctl.keysize = NAMEDATALEN; ctl.keysize = NAMEDATALEN;
ctl.entrysize = sizeof(remoteConnHashEnt); ctl.entrysize = sizeof(remoteConnHashEnt);
ptr=hash_create("Remote Con hash", NUMCONN, &ctl, HASH_ELEM); ptr = hash_create("Remote Con hash", NUMCONN, &ctl, HASH_ELEM);
if(!ptr) if (!ptr)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); errmsg("out of memory")));
return(ptr); return (ptr);
} }
static void static void
createNewConnection(const char *name, remoteConn *con) createNewConnection(const char *name, remoteConn * con)
{ {
remoteConnHashEnt *hentry; remoteConnHashEnt *hentry;
bool found; bool found;
char key[NAMEDATALEN]; char key[NAMEDATALEN];
if(!remoteConnHash) if (!remoteConnHash)
remoteConnHash = createConnHash(); remoteConnHash = createConnHash();
MemSet(key, 0, NAMEDATALEN); MemSet(key, 0, NAMEDATALEN);
@ -1944,12 +1943,12 @@ createNewConnection(const char *name, remoteConn *con)
hentry = (remoteConnHashEnt *) hash_search(remoteConnHash, key, hentry = (remoteConnHashEnt *) hash_search(remoteConnHash, key,
HASH_ENTER, &found); HASH_ENTER, &found);
if(!hentry) if (!hentry)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); errmsg("out of memory")));
if(found) if (found)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT), (errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("duplicate connection name"))); errmsg("duplicate connection name")));
@ -1965,8 +1964,8 @@ deleteConnection(const char *name)
bool found; bool found;
char key[NAMEDATALEN]; char key[NAMEDATALEN];
if(!remoteConnHash) if (!remoteConnHash)
remoteConnHash=createConnHash(); remoteConnHash = createConnHash();
MemSet(key, 0, NAMEDATALEN); MemSet(key, 0, NAMEDATALEN);
snprintf(key, NAMEDATALEN - 1, "%s", name); snprintf(key, NAMEDATALEN - 1, "%s", name);
@ -1974,7 +1973,7 @@ deleteConnection(const char *name)
hentry = (remoteConnHashEnt *) hash_search(remoteConnHash, hentry = (remoteConnHashEnt *) hash_search(remoteConnHash,
key, HASH_REMOVE, &found); key, HASH_REMOVE, &found);
if(!hentry) if (!hentry)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("undefined connection name"))); errmsg("undefined connection name")));

View File

@ -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)
{ {
@ -96,11 +97,11 @@ recordchange(PG_FUNCTION_ARGS)
schemaname = get_namespace_name(RelationGetNamespace(trigdata->tg_relation)); schemaname = get_namespace_name(RelationGetNamespace(trigdata->tg_relation));
fullyqualtblname = SPI_palloc(strlen(tblname) + fullyqualtblname = SPI_palloc(strlen(tblname) +
strlen(schemaname) + 6); strlen(schemaname) + 6);
sprintf(fullyqualtblname,"\"%s\".\"%s\"", sprintf(fullyqualtblname, "\"%s\".\"%s\"",
schemaname,tblname); schemaname, tblname);
#else #else
fullyqualtblname = SPI_palloc(strlen(tblname) + 3); fullyqualtblname = SPI_palloc(strlen(tblname) + 3);
sprintf(fullyqualtblname,"\"%s\"",tblname); sprintf(fullyqualtblname, "\"%s\"", tblname);
#endif #endif
tupdesc = trigdata->tg_relation->rd_att; tupdesc = trigdata->tg_relation->rd_att;
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
@ -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;
@ -460,7 +461,7 @@ packageData(HeapTuple tTupleData, TupleDesc tTupleDesc,
} }
else else
{ {
sprintf(cpFormatedPtr," "); sprintf(cpFormatedPtr, " ");
iUsedDataBlock++; iUsedDataBlock++;
cpFormatedPtr++; cpFormatedPtr++;
continue; continue;
@ -508,7 +509,7 @@ packageData(HeapTuple tTupleData, TupleDesc tTupleDesc,
if (tpPKeys != NULL) if (tpPKeys != NULL)
SPI_pfree(tpPKeys); SPI_pfree(tpPKeys);
#if defined DEBUG_OUTPUT #if defined DEBUG_OUTPUT
elog(NOTICE, "returning DataBlockSize:%d iUsedDataBlock:%d",iDataBlockSize, elog(NOTICE, "returning DataBlockSize:%d iUsedDataBlock:%d", iDataBlockSize,
iUsedDataBlock); iUsedDataBlock);
#endif #endif
memset(cpDataBlock + iUsedDataBlock, 0, iDataBlockSize - iUsedDataBlock); memset(cpDataBlock + iUsedDataBlock, 0, iDataBlockSize - iUsedDataBlock);

View File

@ -66,9 +66,10 @@ geo_distance(Point *pt1, Point *pt2)
if (longdiff > M_PI) if (longdiff > M_PI)
longdiff = TWO_PI - longdiff; longdiff = TWO_PI - longdiff;
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;

View File

@ -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++)

View File

@ -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;

View File

@ -126,8 +126,8 @@ ArrayType *intarray_concat_arrays(ArrayType *a, ArrayType *b);
ArrayType *int_to_intset(int32 elem); ArrayType *int_to_intset(int32 elem);
bool inner_int_overlap(ArrayType *a, ArrayType *b); bool inner_int_overlap(ArrayType *a, ArrayType *b);
bool inner_int_contains(ArrayType *a, ArrayType *b); bool inner_int_contains(ArrayType *a, ArrayType *b);
ArrayType * inner_int_union(ArrayType *a, ArrayType *b); ArrayType *inner_int_union(ArrayType *a, ArrayType *b);
ArrayType * inner_int_inter(ArrayType *a, ArrayType *b); ArrayType *inner_int_inter(ArrayType *a, ArrayType *b);
void rt__int_size(ArrayType *a, float *size); void rt__int_size(ArrayType *a, float *size);
void gensign(BITVEC sign, int *a, int len); void gensign(BITVEC sign, int *a, int len);
@ -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 )

View File

@ -743,4 +743,3 @@ querytree(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(res); PG_RETURN_POINTER(res);
} }

View File

@ -85,26 +85,30 @@ 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));
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) ); {
ptr+=ARRNELEMS( GETENTRY(entryvec,i) ); memcpy(ptr, ARRPTR(GETENTRY(entryvec, i)), ARRNELEMS(GETENTRY(entryvec, i)) * sizeof(int4));
ptr += ARRNELEMS(GETENTRY(entryvec, i));
} }
QSORT(res,1); QSORT(res, 1);
res=_int_unique(res); res = _int_unique(res);
*size = VARSIZE(res); *size = VARSIZE(res);
PG_RETURN_POINTER(res); PG_RETURN_POINTER(res);
} }
@ -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);
@ -254,7 +259,7 @@ g_int_penalty(PG_FUNCTION_ARGS) {
*result = tmp1 - tmp2; *result = tmp1 - tmp2;
pfree(ud); pfree(ud);
PG_RETURN_POINTER (result); PG_RETURN_POINTER(result);
} }
@ -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);
} }

View File

@ -270,7 +270,7 @@ _int_unique(ArrayType *r)
*data; *data;
int num = ARRNELEMS(r); int num = ARRNELEMS(r);
if ( num<2 ) if (num < 2)
return r; return r;
data = tmp = dr = ARRPTR(r); data = tmp = dr = ARRPTR(r);
@ -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;
} }

View File

@ -144,13 +144,15 @@ _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;
} }
num--; num--;
query = (lquery*)NEXTVAL(query); query = (lquery *) NEXTVAL(query);
} }
PG_FREE_IF_COPY(_tree, 0); PG_FREE_IF_COPY(_tree, 0);

View File

@ -45,7 +45,7 @@ getlexem(char *start, char *end, int *len)
} }
bool bool
compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend) compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
{ {
char *endt = t->name + t->len; char *endt = t->name + t->len;
char *endq = qn + len; char *endq = qn + len;
@ -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,13 +206,15 @@ 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 )
memcpy(&tmpptr,ptr,sizeof(FieldNot)); if (ptr)
SomeStack.high_pos = high_pos-cur_tpos; memcpy(&tmpptr, ptr, sizeof(FieldNot));
SomeStack.high_pos = high_pos - cur_tpos;
SomeStack.muse = true; SomeStack.muse = true;
if ( checkCond(prevq, qlen+1, curt, tlen, (ptr) ? &tmpptr : NULL) ) if (checkCond(prevq, qlen + 1, curt, tlen, (ptr) ? &tmpptr : NULL))
return true; return true;
} }
if (!isok && ptr) if (!isok && ptr)
@ -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)
)); ));
} }

View File

@ -331,46 +331,55 @@ 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;
bool found=false; ltree_level *startptr,
*aptr,
*bptr;
bool found = false;
if ( start < 0 ) { if (start < 0)
if ( -start >= a->numlevel ) {
start=0; if (-start >= a->numlevel)
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 ) { {
aptr=startptr; if (i >= start)
bptr=LTREE_FIRST(b); {
for(j=0;j<b->numlevel;j++) { aptr = startptr;
if ( !(aptr->len==bptr->len && strncmp(aptr->name,bptr->name, aptr->len)==0) ) bptr = LTREE_FIRST(b);
for (j = 0; j < b->numlevel; j++)
{
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;
} }
} }
startptr=LEVEL_NEXT(startptr); startptr = LEVEL_NEXT(startptr);
} }
if ( !found ) if (!found)
i=-1; i = -1;
PG_FREE_IF_COPY(a, 0); PG_FREE_IF_COPY(a, 0);
PG_FREE_IF_COPY(b, 1); PG_FREE_IF_COPY(b, 1);
@ -507,7 +516,7 @@ text2ltree(PG_FUNCTION_ARGS)
PointerGetDatum(s) PointerGetDatum(s)
)); ));
pfree(s); pfree(s);
PG_FREE_IF_COPY(in,0); PG_FREE_IF_COPY(in, 0);
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }
@ -521,11 +530,13 @@ ltree2text(PG_FUNCTION_ARGS)
ltree_level *curlevel; ltree_level *curlevel;
text *out; text *out;
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++;
} }
@ -534,12 +545,8 @@ ltree2text(PG_FUNCTION_ARGS)
curlevel = LEVEL_NEXT(curlevel); curlevel = LEVEL_NEXT(curlevel);
} }
VARATT_SIZEP(out) = VARHDRSZ + (ptr-VARDATA(out)); VARATT_SIZEP(out) = VARHDRSZ + (ptr - VARDATA(out));
PG_FREE_IF_COPY(in, 0); PG_FREE_IF_COPY(in, 0);
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }

File diff suppressed because it is too large Load Diff

View File

@ -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,58 +67,73 @@ 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;
/* Functions for dealing with command line arguements */ /* Functions for dealing with command line arguements */
static cmd_args *get_cmd_args (int argc, char *argv[]); static cmd_args *get_cmd_args(int argc, char *argv[]);
static void print_cmd_args (void); static void print_cmd_args(void);
static void free_cmd_args (void); static void free_cmd_args(void);
static void usage (void); static void usage(void);
/* Functions for managing database lists */ /* Functions for managing database lists */
static Dllist *init_db_list (void); static Dllist *init_db_list(void);
static db_info *init_dbinfo (char *dbname, int oid, int age); static db_info *init_dbinfo(char *dbname, int oid, int age);
static void update_db_list (Dllist * db_list); static void update_db_list(Dllist *db_list);
static void remove_db_from_list (Dlelem * db_to_remove); static void remove_db_from_list(Dlelem *db_to_remove);
static void print_db_info (db_info * dbi, int print_table_list); static void print_db_info(db_info * dbi, int print_table_list);
static void print_db_list (Dllist * db_list, int print_table_lists); static void print_db_list(Dllist *db_list, int print_table_lists);
static int xid_wraparound_check (db_info * dbi); static int xid_wraparound_check(db_info * dbi);
static void free_db_list (Dllist * db_list); static void free_db_list(Dllist *db_list);
/* Functions for managing table lists */ /* Functions for managing table lists */
static tbl_info *init_table_info (PGresult * conn, int row, db_info *dbi); static tbl_info *init_table_info(PGresult *conn, int row, db_info * dbi);
static void update_table_list (db_info * dbi); static void update_table_list(db_info * dbi);
static void remove_table_from_list (Dlelem * tbl_to_remove); static void remove_table_from_list(Dlelem *tbl_to_remove);
static void print_table_list (Dllist * tbl_node); static void print_table_list(Dllist *tbl_node);
static void print_table_info (tbl_info * tbl); static void print_table_info(tbl_info * tbl);
static void update_table_thresholds (db_info * dbi, tbl_info * tbl, int vacuum_type); static void update_table_thresholds(db_info * dbi, tbl_info * tbl, int vacuum_type);
static void free_tbl_list (Dllist * tbl_list); static void free_tbl_list(Dllist *tbl_list);
/* A few database helper functions */ /* A few database helper functions */
static int check_stats_enabled (db_info * dbi); static int check_stats_enabled(db_info * dbi);
static PGconn *db_connect (db_info * dbi); static PGconn *db_connect(db_info * dbi);
static void db_disconnect (db_info * dbi); static void db_disconnect(db_info * dbi);
static PGresult *send_query (const char *query, db_info * dbi); static PGresult *send_query(const char *query, db_info * dbi);
static char *query_table_stats (db_info * dbi); static char *query_table_stats(db_info * dbi);
/* Other Generally needed Functions */ /* Other Generally needed Functions */
static void daemonize(void); static void daemonize(void);
static void log_entry (const char *logentry); static void log_entry(const char *logentry);

View File

@ -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
* ------------------------------------------------------------------------- * -------------------------------------------------------------------------

View File

@ -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

View File

@ -26,7 +26,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE. * SUCH DAMAGE.
* *
* $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);
@ -311,8 +312,8 @@ ossl_des_ecb_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
ossldata *od = c->ptr; ossldata *od = c->ptr;
for (i = 0; i < dlen / bs; i++) for (i = 0; i < dlen / bs; i++)
des_ecb_encrypt((des_cblock*)(data + i * bs), des_ecb_encrypt((des_cblock *) (data + i * bs),
(des_cblock*)(res + i * bs), (des_cblock *) (res + i * bs),
od->u.des.key_schedule, 1); od->u.des.key_schedule, 1);
return 0; return 0;
} }
@ -326,8 +327,8 @@ ossl_des_ecb_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
ossldata *od = c->ptr; ossldata *od = c->ptr;
for (i = 0; i < dlen / bs; i++) for (i = 0; i < dlen / bs; i++)
des_ecb_encrypt((des_cblock*)(data + i * bs), des_ecb_encrypt((des_cblock *) (data + i * bs),
(des_cblock*)(res + i * bs), (des_cblock *) (res + i * bs),
od->u.des.key_schedule, 0); od->u.des.key_schedule, 0);
return 0; return 0;
} }
@ -339,7 +340,7 @@ ossl_des_cbc_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
ossldata *od = c->ptr; ossldata *od = c->ptr;
des_ncbc_encrypt(data, res, dlen, od->u.des.key_schedule, des_ncbc_encrypt(data, res, dlen, od->u.des.key_schedule,
(des_cblock*)od->iv, 1); (des_cblock *) od->iv, 1);
return 0; return 0;
} }
@ -350,7 +351,7 @@ ossl_des_cbc_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
ossldata *od = c->ptr; ossldata *od = c->ptr;
des_ncbc_encrypt(data, res, dlen, od->u.des.key_schedule, des_ncbc_encrypt(data, res, dlen, od->u.des.key_schedule,
(des_cblock*)od->iv, 0); (des_cblock *) od->iv, 0);
return 0; return 0;
} }
@ -429,37 +430,37 @@ static PX_Alias ossl_aliases[] = {
static const struct ossl_cipher ossl_bf_cbc = { static const struct ossl_cipher ossl_bf_cbc = {
bf_init, bf_cbc_encrypt, bf_cbc_decrypt, bf_init, bf_cbc_encrypt, bf_cbc_decrypt,
64/8, 448/8, 0 64 / 8, 448 / 8, 0
}; };
static const struct ossl_cipher ossl_bf_ecb = { static const struct ossl_cipher ossl_bf_ecb = {
bf_init, bf_ecb_encrypt, bf_ecb_decrypt, bf_init, bf_ecb_encrypt, bf_ecb_decrypt,
64/8, 448/8, 0 64 / 8, 448 / 8, 0
}; };
static const struct ossl_cipher ossl_bf_cfb = { static const struct ossl_cipher ossl_bf_cfb = {
bf_init, bf_cfb64_encrypt, bf_cfb64_decrypt, bf_init, bf_cfb64_encrypt, bf_cfb64_decrypt,
64/8, 448/8, 1 64 / 8, 448 / 8, 1
}; };
static const struct ossl_cipher ossl_des_ecb = { static const struct ossl_cipher ossl_des_ecb = {
ossl_des_init, ossl_des_ecb_encrypt, ossl_des_ecb_decrypt, ossl_des_init, ossl_des_ecb_encrypt, ossl_des_ecb_decrypt,
64/8, 64/8, 0 64 / 8, 64 / 8, 0
}; };
static const struct ossl_cipher ossl_des_cbc = { static const struct ossl_cipher ossl_des_cbc = {
ossl_des_init, ossl_des_cbc_encrypt, ossl_des_cbc_decrypt, ossl_des_init, ossl_des_cbc_encrypt, ossl_des_cbc_decrypt,
64/8, 64/8, 0 64 / 8, 64 / 8, 0
}; };
static const struct ossl_cipher ossl_cast_ecb = { static const struct ossl_cipher ossl_cast_ecb = {
ossl_cast_init, ossl_cast_ecb_encrypt, ossl_cast_ecb_decrypt, ossl_cast_init, ossl_cast_ecb_encrypt, ossl_cast_ecb_decrypt,
64/8, 128/8, 0 64 / 8, 128 / 8, 0
}; };
static const struct ossl_cipher ossl_cast_cbc = { static const struct ossl_cipher ossl_cast_cbc = {
ossl_cast_init, ossl_cast_cbc_encrypt, ossl_cast_cbc_decrypt, ossl_cast_init, ossl_cast_cbc_encrypt, ossl_cast_cbc_decrypt,
64/8, 128/8, 0 64 / 8, 128 / 8, 0
}; };
/* /*
@ -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;
} }

View File

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

View File

@ -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
* *
@ -221,5 +221,5 @@ pgstattuple_real(Relation rel)
pfree(values[i]); pfree(values[i]);
pfree(values); pfree(values);
return(result); return (result);
} }

View File

@ -32,7 +32,7 @@ typedef struct _TTOffList
char name[1]; char name[1];
} TTOffList; } TTOffList;
static TTOffList TTOff = {NULL,{0}}; static TTOffList TTOff = {NULL, {0}};
static int findTTStatus(char *name); static int findTTStatus(char *name);
static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans); static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
@ -106,22 +106,22 @@ timetravel(PG_FUNCTION_ARGS)
*/ */
/* Called by trigger manager ? */ /* Called by trigger manager ? */
if(!CALLED_AS_TRIGGER(fcinfo)) if (!CALLED_AS_TRIGGER(fcinfo))
elog(ERROR, "timetravel: not fired by trigger manager"); elog(ERROR, "timetravel: not fired by trigger manager");
/* Should be called for ROW trigger */ /* Should be called for ROW trigger */
if(TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event)) if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
elog(ERROR, "timetravel: can't process STATEMENT events"); elog(ERROR, "timetravel: can't process STATEMENT events");
/* Should be called BEFORE */ /* Should be called BEFORE */
if(TRIGGER_FIRED_AFTER(trigdata->tg_event)) if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
elog(ERROR, "timetravel: must be fired before event"); elog(ERROR, "timetravel: must be fired before event");
/* INSERT ? */ /* INSERT ? */
if(TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
isinsert = true; isinsert = true;
if(TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
newtuple = trigdata->tg_newtuple; newtuple = trigdata->tg_newtuple;
trigtuple = trigdata->tg_trigtuple; trigtuple = trigdata->tg_trigtuple;
@ -130,7 +130,7 @@ timetravel(PG_FUNCTION_ARGS)
relname = SPI_getrelname(rel); relname = SPI_getrelname(rel);
/* check if TT is OFF for this relation */ /* check if TT is OFF for this relation */
if(0==findTTStatus(relname)) if (0 == findTTStatus(relname))
{ {
/* OFF - nothing to do */ /* OFF - nothing to do */
pfree(relname); pfree(relname);
@ -140,7 +140,7 @@ timetravel(PG_FUNCTION_ARGS)
trigger = trigdata->tg_trigger; trigger = trigdata->tg_trigger;
argc = trigger->tgnargs; argc = trigger->tgnargs;
if(argc != MinAttrNum && argc != MaxAttrNum) if (argc != MinAttrNum && argc != MaxAttrNum)
elog(ERROR, "timetravel (%s): invalid (!= %d or %d) number of arguments %d", elog(ERROR, "timetravel (%s): invalid (!= %d or %d) number of arguments %d",
relname, MinAttrNum, MaxAttrNum, trigger->tgnargs); relname, MinAttrNum, MaxAttrNum, trigger->tgnargs);
@ -148,21 +148,21 @@ timetravel(PG_FUNCTION_ARGS)
tupdesc = rel->rd_att; tupdesc = rel->rd_att;
natts = tupdesc->natts; natts = tupdesc->natts;
for(i = 0 ; i < MinAttrNum ; i++) for (i = 0; i < MinAttrNum; i++)
{ {
attnum[i] = SPI_fnumber(tupdesc, args[i]); attnum[i] = SPI_fnumber(tupdesc, args[i]);
if(attnum[i] < 0) if (attnum[i] < 0)
elog(ERROR, "timetravel (%s): there is no attribute %s", relname, args[i]); elog(ERROR, "timetravel (%s): there is no attribute %s", relname, args[i]);
if(SPI_gettypeid(tupdesc, attnum[i]) != ABSTIMEOID) if (SPI_gettypeid(tupdesc, attnum[i]) != ABSTIMEOID)
elog(ERROR, "timetravel (%s): attribute %s must be of abstime type", elog(ERROR, "timetravel (%s): attribute %s must be of abstime type",
relname, args[i]); relname, args[i]);
} }
for( ; i < argc ; i++) for (; i < argc; i++)
{ {
attnum[i] = SPI_fnumber(tupdesc, args[i]); attnum[i] = SPI_fnumber(tupdesc, args[i]);
if(attnum[i] < 0) if (attnum[i] < 0)
elog(ERROR, "timetravel (%s): there is no attribute %s", relname, args[i]); elog(ERROR, "timetravel (%s): there is no attribute %s", relname, args[i]);
if(SPI_gettypeid(tupdesc, attnum[i]) != TEXTOID) if (SPI_gettypeid(tupdesc, attnum[i]) != TEXTOID)
elog(ERROR, "timetravel (%s): attribute %s must be of text type", elog(ERROR, "timetravel (%s): attribute %s must be of text type",
relname, args[i]); relname, args[i]);
} }
@ -170,9 +170,9 @@ timetravel(PG_FUNCTION_ARGS)
/* create fields containing name */ /* create fields containing name */
newuser = DirectFunctionCall1(textin, CStringGetDatum(GetUserNameFromId(GetUserId()))); newuser = DirectFunctionCall1(textin, CStringGetDatum(GetUserNameFromId(GetUserId())));
nulltext = (Datum)NULL; nulltext = (Datum) NULL;
if(isinsert) if (isinsert)
{ /* INSERT */ { /* INSERT */
int chnattrs = 0; int chnattrs = 0;
int chattrs[MaxAttrNum]; int chattrs[MaxAttrNum];
@ -180,7 +180,7 @@ timetravel(PG_FUNCTION_ARGS)
char newnulls[MaxAttrNum]; char newnulls[MaxAttrNum];
oldtimeon = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_on], &isnull); oldtimeon = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_on], &isnull);
if(isnull) if (isnull)
{ {
newvals[chnattrs] = GetCurrentAbsoluteTime(); newvals[chnattrs] = GetCurrentAbsoluteTime();
newnulls[chnattrs] = ' '; newnulls[chnattrs] = ' ';
@ -189,9 +189,9 @@ timetravel(PG_FUNCTION_ARGS)
} }
oldtimeoff = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_off], &isnull); oldtimeoff = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_off], &isnull);
if(isnull) if (isnull)
{ {
if((chnattrs == 0 && DatumGetInt32(oldtimeon) >= NOEND_ABSTIME) || if ((chnattrs == 0 && DatumGetInt32(oldtimeon) >= NOEND_ABSTIME) ||
(chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) >= NOEND_ABSTIME)) (chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) >= NOEND_ABSTIME))
elog(ERROR, "timetravel (%s): %s is infinity", relname, args[a_time_on]); elog(ERROR, "timetravel (%s): %s is infinity", relname, args[a_time_on]);
newvals[chnattrs] = NOEND_ABSTIME; newvals[chnattrs] = NOEND_ABSTIME;
@ -201,16 +201,16 @@ timetravel(PG_FUNCTION_ARGS)
} }
else else
{ {
if((chnattrs == 0 && DatumGetInt32(oldtimeon) > DatumGetInt32(oldtimeoff)) || if ((chnattrs == 0 && DatumGetInt32(oldtimeon) > DatumGetInt32(oldtimeoff)) ||
(chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) > DatumGetInt32(oldtimeoff))) (chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) > DatumGetInt32(oldtimeoff)))
elog(ERROR, "timetravel (%s): %s gt %s", relname, args[a_time_on], args[a_time_off]); elog(ERROR, "timetravel (%s): %s gt %s", relname, args[a_time_on], args[a_time_off]);
} }
pfree(relname); pfree(relname);
if(chnattrs <= 0) if (chnattrs <= 0)
return PointerGetDatum(trigtuple); return PointerGetDatum(trigtuple);
if(argc == MaxAttrNum) if (argc == MaxAttrNum)
{ {
/* clear update_user value */ /* clear update_user value */
newvals[chnattrs] = nulltext; newvals[chnattrs] = nulltext;
@ -235,33 +235,34 @@ timetravel(PG_FUNCTION_ARGS)
/* UPDATE/DELETE: */ /* UPDATE/DELETE: */
oldtimeon = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_on], &isnull); oldtimeon = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_on], &isnull);
if(isnull) if (isnull)
elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_on]); elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_on]);
oldtimeoff = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_off], &isnull); oldtimeoff = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_off], &isnull);
if(isnull) if (isnull)
elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_off]); elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_off]);
/* /*
* If DELETE/UPDATE of tuple with stop_date neq INFINITY then say * If DELETE/UPDATE of tuple with stop_date neq INFINITY then say
* upper Executor to skip operation for this tuple * upper Executor to skip operation for this tuple
*/ */
if(newtuple != NULL) if (newtuple != NULL)
{ /* UPDATE */ { /* UPDATE */
newtimeon = SPI_getbinval(newtuple, tupdesc, attnum[a_time_on], &isnull); newtimeon = SPI_getbinval(newtuple, tupdesc, attnum[a_time_on], &isnull);
if(isnull) if (isnull)
elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_on]); elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_on]);
newtimeoff = SPI_getbinval(newtuple, tupdesc, attnum[a_time_off], &isnull); newtimeoff = SPI_getbinval(newtuple, tupdesc, attnum[a_time_off], &isnull);
if(isnull) if (isnull)
elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_off]); elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_off]);
if(oldtimeon != newtimeon || oldtimeoff != newtimeoff) if (oldtimeon != newtimeon || oldtimeoff != newtimeoff)
elog(ERROR, "timetravel (%s): you can't change %s and/or %s columns (use set_timetravel)", elog(ERROR, "timetravel (%s): you can't change %s and/or %s columns (use set_timetravel)",
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);
} }
@ -269,25 +270,26 @@ timetravel(PG_FUNCTION_ARGS)
newtimeoff = GetCurrentAbsoluteTime(); newtimeoff = GetCurrentAbsoluteTime();
/* Connect to SPI manager */ /* Connect to SPI manager */
if((ret = SPI_connect()) < 0) if ((ret = SPI_connect()) < 0)
elog(ERROR, "timetravel (%s): SPI_connect returned %d", relname, ret); elog(ERROR, "timetravel (%s): SPI_connect returned %d", relname, ret);
/* Fetch tuple values and nulls */ /* Fetch tuple values and nulls */
cvals = (Datum *) palloc(natts * sizeof(Datum)); cvals = (Datum *) palloc(natts * sizeof(Datum));
cnulls = (char *) palloc(natts * sizeof(char)); cnulls = (char *) palloc(natts * sizeof(char));
for(i = 0; i < natts; i++) for (i = 0; i < natts; i++)
{ {
cvals[i] = SPI_getbinval(trigtuple, tupdesc, i + 1, &isnull); cvals[i] = SPI_getbinval(trigtuple, tupdesc, i + 1, &isnull);
cnulls[i] = (isnull) ? 'n' : ' '; cnulls[i] = (isnull) ? 'n' : ' ';
} }
/* 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)
{ /* DELETE */ { /* DELETE */
if(argc == MaxAttrNum) if (argc == MaxAttrNum)
{ {
cvals[attnum[a_del_user] - 1] = newuser; /* set delete user */ cvals[attnum[a_del_user] - 1] = newuser; /* set delete user */
cnulls[attnum[a_del_user] - 1] = ' '; cnulls[attnum[a_del_user] - 1] = ' ';
@ -302,7 +304,7 @@ timetravel(PG_FUNCTION_ARGS)
plan = find_plan(ident, &Plans, &nPlans); plan = find_plan(ident, &Plans, &nPlans);
/* if there is no plan ... */ /* if there is no plan ... */
if(plan->splan == NULL) if (plan->splan == NULL)
{ {
void *pplan; void *pplan;
Oid *ctypes; Oid *ctypes;
@ -315,15 +317,15 @@ timetravel(PG_FUNCTION_ARGS)
* Construct query: INSERT INTO _relation_ VALUES ($1, ...) * Construct query: INSERT INTO _relation_ VALUES ($1, ...)
*/ */
snprintf(sql, sizeof(sql), "INSERT INTO %s VALUES (", relname); snprintf(sql, sizeof(sql), "INSERT INTO %s VALUES (", relname);
for(i = 1; i <= natts; i++) for (i = 1; i <= natts; i++)
{ {
ctypes[i - 1] = SPI_gettypeid(tupdesc, i); ctypes[i - 1] = SPI_gettypeid(tupdesc, i);
if(!(tupdesc->attrs[i - 1]->attisdropped)) /* skip dropped columns */ if (!(tupdesc->attrs[i - 1]->attisdropped)) /* skip dropped columns */
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "$%d%s", snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "$%d%s",
i, (i < natts) ? ", " : ")" ); i, (i < natts) ? ", " : ")");
#if 0 #if 0
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "$%d /* %d */ %s", snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "$%d /* %d */ %s",
i, ctypes[i-1], (i < natts) ? ", " : ")" ); i, ctypes[i - 1], (i < natts) ? ", " : ")");
#endif #endif
} }
@ -331,7 +333,7 @@ timetravel(PG_FUNCTION_ARGS)
/* Prepare plan for query */ /* Prepare plan for query */
pplan = SPI_prepare(sql, natts, ctypes); pplan = SPI_prepare(sql, natts, ctypes);
if(pplan == NULL) if (pplan == NULL)
elog(ERROR, "timetravel (%s): SPI_prepare returned %d", relname, SPI_result); elog(ERROR, "timetravel (%s): SPI_prepare returned %d", relname, SPI_result);
/* /*
@ -340,7 +342,7 @@ timetravel(PG_FUNCTION_ARGS)
* use. * use.
*/ */
pplan = SPI_saveplan(pplan); pplan = SPI_saveplan(pplan);
if(pplan == NULL) if (pplan == NULL)
elog(ERROR, "timetravel (%s): SPI_saveplan returned %d", relname, SPI_result); elog(ERROR, "timetravel (%s): SPI_saveplan returned %d", relname, SPI_result);
plan->splan = pplan; plan->splan = pplan;
@ -351,11 +353,11 @@ timetravel(PG_FUNCTION_ARGS)
*/ */
ret = SPI_execp(plan->splan, cvals, cnulls, 0); ret = SPI_execp(plan->splan, cvals, cnulls, 0);
if(ret < 0) if (ret < 0)
elog(ERROR, "timetravel (%s): SPI_execp returned %d", relname, ret); elog(ERROR, "timetravel (%s): SPI_execp returned %d", relname, ret);
/* Tuple to return to upper Executor ... */ /* Tuple to return to upper Executor ... */
if(newtuple) if (newtuple)
{ /* UPDATE */ { /* UPDATE */
int chnattrs = 0; int chnattrs = 0;
int chattrs[MaxAttrNum]; int chattrs[MaxAttrNum];
@ -372,7 +374,7 @@ timetravel(PG_FUNCTION_ARGS)
chattrs[chnattrs] = attnum[a_time_off]; chattrs[chnattrs] = attnum[a_time_off];
chnattrs++; chnattrs++;
if(argc == MaxAttrNum) if (argc == MaxAttrNum)
{ {
/* set update_user value */ /* set update_user value */
newvals[chnattrs] = newuser; newvals[chnattrs] = newuser;
@ -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,17 +426,18 @@ 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)
{ {
if(namestrcmp(relname, pp->name) == 0) if (namestrcmp(relname, pp->name) == 0)
break; break;
} }
if(pp) if (pp)
{ {
/* OFF currently */ /* OFF currently */
if(on != 0) if (on != 0)
{ {
/* turn ON */ /* turn ON */
p->next = pp->next; p->next = pp->next;
@ -444,20 +448,20 @@ set_timetravel(PG_FUNCTION_ARGS)
else else
{ {
/* ON currently */ /* ON currently */
if(on == 0) if (on == 0)
{ {
/* turn OFF */ /* turn OFF */
s = rname = DatumGetCString(DirectFunctionCall1(nameout, NameGetDatum(relname))); s = rname = DatumGetCString(DirectFunctionCall1(nameout, NameGetDatum(relname)));
if(s) if (s)
{ {
pp = malloc(sizeof(TTOffList)+strlen(rname)); pp = malloc(sizeof(TTOffList) + strlen(rname));
if(pp) if (pp)
{ {
pp->next = NULL; pp->next = NULL;
p->next = pp; p->next = pp;
d = pp->name; d = pp->name;
while (*s) while (*s)
*d++ = tolower((unsigned char)*s++); *d++ = tolower((unsigned char) *s++);
*d = '\0'; *d = '\0';
} }
pfree(rname); pfree(rname);
@ -480,9 +484,9 @@ get_timetravel(PG_FUNCTION_ARGS)
Name relname = PG_GETARG_NAME(0); Name relname = PG_GETARG_NAME(0);
TTOffList *pp; TTOffList *pp;
for(pp = TTOff.next; pp; pp = pp->next) for (pp = TTOff.next; pp; pp = pp->next)
{ {
if(namestrcmp(relname, pp->name) == 0) if (namestrcmp(relname, pp->name) == 0)
PG_RETURN_INT32(0); PG_RETURN_INT32(0);
} }
PG_RETURN_INT32(1); PG_RETURN_INT32(1);
@ -491,9 +495,10 @@ get_timetravel(PG_FUNCTION_ARGS)
static int static int
findTTStatus(char *name) findTTStatus(char *name)
{ {
TTOffList* pp; TTOffList *pp;
for(pp = TTOff.next; pp; pp = pp->next)
if(strcasecmp(name, pp->name) == 0) for (pp = TTOff.next; pp; pp = pp->next)
if (strcasecmp(name, pp->name) == 0)
return 0; return 0;
return 1; return 1;
} }
@ -512,14 +517,14 @@ find_plan(char *ident, EPlan ** eplan, int *nplans)
EPlan *newp; EPlan *newp;
int i; int i;
if(*nplans > 0) if (*nplans > 0)
{ {
for(i = 0; i < *nplans; i++) for (i = 0; i < *nplans; i++)
{ {
if(strcmp((*eplan)[i].ident, ident) == 0) if (strcmp((*eplan)[i].ident, ident) == 0)
break; break;
} }
if(i != *nplans) if (i != *nplans)
return (*eplan + i); return (*eplan + i);
*eplan = (EPlan *) realloc(*eplan, (i + 1) * sizeof(EPlan)); *eplan = (EPlan *) realloc(*eplan, (i + 1) * sizeof(EPlan));
newp = *eplan + i; newp = *eplan + i;

View File

@ -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 */
@ -1309,7 +1315,7 @@ build_tuplestore_recursively(char *key_fld,
parent_key_fld, parent_key_fld,
start_with, start_with,
key_fld); key_fld);
serial_column=0; serial_column = 0;
} }
else else
{ {
@ -1321,7 +1327,7 @@ build_tuplestore_recursively(char *key_fld,
start_with, start_with,
key_fld, key_fld,
orderby_fld); orderby_fld);
serial_column=1; serial_column = 1;
} }
/* Retrieve the desired rows */ /* Retrieve the desired rows */
@ -1508,10 +1514,10 @@ build_tuplestore_recursively(char *key_fld,
static void static void
validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial) validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial)
{ {
int serial_column=0; int serial_column = 0;
if (show_serial) if (show_serial)
serial_column=1; serial_column = 1;
/* are there the correct number of columns */ /* are there the correct number of columns */
if (show_branch) if (show_branch)

View File

@ -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

View File

@ -4,54 +4,72 @@
#include "ts_cfg.h" #include "ts_cfg.h"
#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 *
text *out=(text*)palloc(len+VARHDRSZ); charl2text(char *in, int len)
{
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) { *
char *out=palloc( VARSIZE(in) ); text2char(text *in)
memcpy(out, VARDATA(in), VARSIZE(in)-VARHDRSZ); {
out[ VARSIZE(in)-VARHDRSZ ] ='\0'; char *out = palloc(VARSIZE(in));
memcpy(out, VARDATA(in), VARSIZE(in) - VARHDRSZ);
out[VARSIZE(in) - VARHDRSZ] = '\0';
return out; return out;
} }
char char
*pnstrdup(char* in, int len) { *
char *out=palloc( len+1 ); pnstrdup(char *in, int len)
{
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) { *
text *out=(text*)palloc( VARSIZE(in) ); ptextdup(text *in)
memcpy(out,in,VARSIZE(in)); {
text *out = (text *) palloc(VARSIZE(in));
memcpy(out, in, VARSIZE(in));
return out; return out;
} }
text text
*mtextdup(text* in) { *
text *out=(text*)malloc( VARSIZE(in) ); mtextdup(text *in)
if ( !out ) {
text *out = (text *) malloc(VARSIZE(in));
if (!out)
ts_error(ERROR, "No memory"); ts_error(ERROR, "No memory");
memcpy(out,in,VARSIZE(in)); memcpy(out, in, VARSIZE(in));
return out; return out;
} }
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();
@ -60,11 +78,12 @@ 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; {
buf = repalloc( buf, tlen ); tlen = len + 1;
vsnprintf(buf, tlen-1, format, args); buf = repalloc(buf, tlen);
vsnprintf(buf, tlen - 1, format, args);
} }
va_end(args); va_end(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) ) {
return strncmp( VARDATA(a), VARDATA(b), VARSIZE(a)-VARHDRSZ ); if (VARSIZE(a) == VARSIZE(b))
return (int)VARSIZE(a) - (int)VARSIZE(b); return strncmp(VARDATA(a), VARDATA(b), VARSIZE(a) - VARHDRSZ);
return (int) VARSIZE(a) - (int) VARSIZE(b);
} }

View File

@ -7,18 +7,18 @@
#define PG_NARGS() (fcinfo->nargs) #define PG_NARGS() (fcinfo->nargs)
#endif #endif
text* char2text(char* in); text *char2text(char *in);
text* charl2text(char* in, int len); text *charl2text(char *in, int len);
char *text2char(text* in); char *text2char(text *in);
char *pnstrdup(char* in, int len); char *pnstrdup(char *in, int len);
text *ptextdup(text* in); text *ptextdup(text *in);
text *mtextdup(text* in); text *mtextdup(text *in);
int text_cmp(text *a, text *b); int text_cmp(text *a, text *b);
#define NEXTVAL(x) ( (text*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) ) #define NEXTVAL(x) ( (text*)( (char*)(x) + INTALIGN( VARSIZE(x) ) ) )
#define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x)) #define ARRNELEMS(x) ArrayGetNItems( ARR_NDIM(x), ARR_DIMS(x))
void ts_error(int state, const char *format, ...); void ts_error(int state, const char *format,...);
#endif #endif

View File

@ -19,45 +19,52 @@
/*********top interface**********/ /*********top interface**********/
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)};
int stat; int stat;
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 ) ); {
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));
if (!plan_getdict)
ts_error(ERROR, "SPI_prepare() failed"); ts_error(ERROR, "SPI_prepare() failed");
} }
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) );
if ( !(isnull || oid==InvalidOid) ) { oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
opt=SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull); if (!(isnull || oid == InvalidOid))
dict->dictionary=(void*)DatumGetPointer(OidFunctionCall1(oid, opt)); {
opt = SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull);
dict->dictionary = (void *) DatumGetPointer(OidFunctionCall1(oid, opt));
} }
oid=DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3, &isnull) ); oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3, &isnull));
if ( isnull || oid==InvalidOid ) if (isnull || oid == InvalidOid)
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;
@ -65,86 +72,95 @@ typedef struct {
SNMap name2id_map; SNMap name2id_map;
} DictList; } DictList;
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)
free(DList.list); free(DList.list);
memset(&DList,0,sizeof(DictList)); memset(&DList, 0, sizeof(DictList));
} }
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)
return DList.last_dict; return DList.last_dict;
} }
/* 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);
if ( !tmp ) tmp = (DictInfo *) realloc(DList.list, sizeof(DictInfo) * reallen);
ts_error(ERROR,"No memory"); if (!tmp)
DList.reallen=reallen; ts_error(ERROR, "No memory");
DList.list=tmp; DList.reallen = reallen;
DList.list = tmp;
} }
DList.last_dict=&(DList.list[DList.len]); DList.last_dict = &(DList.list[DList.len]);
init_dict(id, DList.last_dict); init_dict(id, DList.last_dict);
DList.len++; DList.len++;
qsort(DList.list, DList.len, sizeof(DictInfo), comparedict); qsort(DList.list, DList.len, sizeof(DictInfo), comparedict);
return finddict(id); /* qsort changed order!! */; return finddict(id); /* qsort changed order!! */ ;
} }
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)};
int stat; int stat;
Oid id=findSNMap_t( &(DList.name2id_map), name ); Oid id = findSNMap_t(&(DList.name2id_map), name);
if ( id ) if (id)
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 ) ); {
if ( !plan_name2id ) plan_name2id = SPI_saveplan(SPI_prepare("select oid from pg_ts_dict where dict_name = $1", 1, arg));
if (!plan_name2id)
ts_error(ERROR, "SPI_prepare() failed"); ts_error(ERROR, "SPI_prepare() failed");
} }
stat = SPI_execp(plan_name2id, pars, " ", 1); stat = SPI_execp(plan_name2id, 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)
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));
else else
ts_error(ERROR, "No dictionary with name '%s'", text2char(name)); ts_error(ERROR, "No dictionary with name '%s'", text2char(name));
SPI_finish(); SPI_finish();
addSNMap_t( &(DList.name2id_map), name, id ); addSNMap_t(&(DList.name2id_map), name, id);
return id; return id;
} }
@ -154,50 +170,56 @@ 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); {
DictInfo *dict = finddict( PG_GETARG_OID(0) ); text *in = PG_GETARG_TEXT_P(1);
char **res, **ptr; DictInfo *dict = finddict(PG_GETARG_OID(0));
char **res,
**ptr;
Datum *da; Datum *da;
ArrayType *a; ArrayType *a;
ptr = res = (char**)DatumGetPointer( ptr = res = (char **) DatumGetPointer(
FunctionCall3(&(dict->lexize_info), FunctionCall3(&(dict->lexize_info),
PointerGetDatum(dict->dictionary), PointerGetDatum(dict->dictionary),
PointerGetDatum(VARDATA(in)), PointerGetDatum(VARDATA(in)),
Int32GetDatum(VARSIZE(in)-VARHDRSZ) Int32GetDatum(VARSIZE(in) - VARHDRSZ)
) )
); );
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)
da = (Datum*)palloc(sizeof(Datum)*(ptr-res+1)); ptr++;
ptr=res; da = (Datum *) palloc(sizeof(Datum) * (ptr - res + 1));
while(*ptr) { ptr = res;
da[ ptr-res ] = PointerGetDatum( char2text(*ptr) ); while (*ptr)
{
da[ptr - res] = PointerGetDatum(char2text(*ptr));
ptr++; ptr++;
} }
a = construct_array( a = construct_array(
da, da,
ptr-res, ptr - res,
TEXTOID, TEXTOID,
-1, -1,
false, false,
'i' 'i'
); );
ptr=res; ptr = res;
while(*ptr) { while (*ptr)
pfree( DatumGetPointer(da[ ptr-res ]) ); {
pfree( *ptr ); pfree(DatumGetPointer(da[ptr - res]));
pfree(*ptr);
ptr++; ptr++;
} }
pfree(res); pfree(res);
@ -209,16 +231,17 @@ 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;
strdup("simple"); strdup("simple");
res=DirectFunctionCall3( res = DirectFunctionCall3(
lexize, lexize,
ObjectIdGetDatum(name2id_dict(dictname)), ObjectIdGetDatum(name2id_dict(dictname)),
PG_GETARG_DATUM(1), PG_GETARG_DATUM(1),
(Datum)0 (Datum) 0
); );
PG_FREE_IF_COPY(dictname, 0); PG_FREE_IF_COPY(dictname, 0);
if (res) if (res)
@ -227,26 +250,28 @@ lexize_byname(PG_FUNCTION_ARGS) {
PG_RETURN_NULL(); PG_RETURN_NULL();
} }
static Oid currect_dictionary_id=0; 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();
} }
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(
set_curdict, set_curdict,
ObjectIdGetDatum( name2id_dict(dictname) ) ObjectIdGetDatum(name2id_dict(dictname))
); );
PG_FREE_IF_COPY(dictname, 0); PG_FREE_IF_COPY(dictname, 0);
PG_RETURN_VOID(); PG_RETURN_VOID();
@ -255,9 +280,11 @@ 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),
errmsg("no currect dictionary"), errmsg("no currect dictionary"),
@ -267,12 +294,10 @@ lexize_bycurrent(PG_FUNCTION_ARGS) {
lexize, lexize,
ObjectIdGetDatum(currect_dictionary_id), ObjectIdGetDatum(currect_dictionary_id),
PG_GETARG_DATUM(0), PG_GETARG_DATUM(0),
(Datum)0 (Datum) 0
); );
if (res) if (res)
PG_RETURN_DATUM(res); PG_RETURN_DATUM(res);
else else
PG_RETURN_NULL(); PG_RETURN_NULL();
} }

View File

@ -3,36 +3,39 @@
#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 *);
} StopList; } StopList;
void sortstoplist(StopList *s); void sortstoplist(StopList * s);
void freestoplist(StopList *s); void freestoplist(StopList * s);
void readstoplist(text *in, StopList *s); 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;
} DictInfo; } DictInfo;
void init_dict(Oid id, DictInfo *dict); void init_dict(Oid id, DictInfo * dict);
DictInfo* finddict(Oid id); DictInfo *finddict(Oid id);
Oid name2id_dict(text *name); Oid name2id_dict(text *name);
void reset_dict(void); 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;
void parse_cfgdict(text *in, Map **m); void parse_cfgdict(text *in, Map ** m);
#endif #endif

View File

@ -11,30 +11,35 @@
#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)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); errmsg("out of memory")));
memset(d,0,sizeof(DictExample)); memset(d, 0, sizeof(DictExample));
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,18 +49,21 @@ dex_init(PG_FUNCTION_ARGS) {
} }
Datum Datum
dex_lexize(PG_FUNCTION_ARGS) { dex_lexize(PG_FUNCTION_ARGS)
DictExample *d = (DictExample*)PG_GETARG_POINTER(0); {
char *in = (char*)PG_GETARG_POINTER(1); DictExample *d = (DictExample *) PG_GETARG_POINTER(0);
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 }
res[0]=txt; else
res[1]=NULL; res[0] = txt;
res[1] = NULL;
PG_RETURN_POINTER(res); PG_RETURN_POINTER(res);
} }

View File

@ -12,81 +12,100 @@
#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,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
errmsg("ISpell confguration error"))); errmsg("ISpell confguration error")));
d = (DictISpell*)malloc( sizeof(DictISpell) ); d = (DictISpell *) malloc(sizeof(DictISpell));
if ( !d ) if (!d)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); errmsg("out of memory")));
memset(d,0,sizeof(DictISpell)); memset(d, 0, sizeof(DictISpell));
d->stoplist.wordop=lowerstr; d->stoplist.wordop = lowerstr;
in = PG_GETARG_TEXT_P(0); in = PG_GETARG_TEXT_P(0);
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),
errmsg("could not load dictionary file \"%s\"", errmsg("could not load dictionary file \"%s\"",
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),
errmsg("could not load affix file \"%s\"", errmsg("could not load affix file \"%s\"",
pcfg->value))); pcfg->value)));
} }
affloaded=true; affloaded = true;
} else if ( strcasecmp("StopFile", pcfg->key) == 0 ) { }
text *tmp=char2text(pcfg->value); else if (strcasecmp("StopFile", pcfg->key) == 0)
if ( stoploaded ) { {
text *tmp = char2text(pcfg->value);
if (stoploaded)
{
freeDictISpell(d); freeDictISpell(d);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
@ -95,8 +114,10 @@ spell_init(PG_FUNCTION_ARGS) {
readstoplist(tmp, &(d->stoplist)); readstoplist(tmp, &(d->stoplist));
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,37 +154,43 @@ spell_init(PG_FUNCTION_ARGS) {
} }
Datum Datum
spell_lexize(PG_FUNCTION_ARGS) { spell_lexize(PG_FUNCTION_ARGS)
DictISpell *d = (DictISpell*)PG_GETARG_POINTER(0); {
char *in = (char*)PG_GETARG_POINTER(1); DictISpell *d = (DictISpell *) PG_GETARG_POINTER(0);
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);
res=palloc(sizeof(char*)*2); res = palloc(sizeof(char *) * 2);
txt = pnstrdup(in, PG_GETARG_INT32(2)); txt = pnstrdup(in, PG_GETARG_INT32(2));
res=NormalizeWord(&(d->obj), txt); res = NormalizeWord(&(d->obj), txt);
pfree(txt); pfree(txt);
if ( res==NULL ) if (res == NULL)
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++;
}
else
{
*cptr = *ptr;
cptr++;
ptr++; ptr++;
} else {
*cptr=*ptr;
cptr++; ptr++;
} }
} }
*cptr=NULL; *cptr = NULL;
PG_RETURN_POINTER(res); PG_RETURN_POINTER(res);
} }

View File

@ -14,103 +14,118 @@
#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);
} DictSnowball; } DictSnowball;
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)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); errmsg("out of memory")));
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),
errmsg("out of memory"))); errmsg("out of memory")));
} }
d->stem=english_stem; d->stem = english_stem;
PG_RETURN_POINTER(d); PG_RETURN_POINTER(d);
} }
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)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); errmsg("out of memory")));
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),
errmsg("out of memory"))); errmsg("out of memory")));
} }
d->stem=russian_stem; d->stem = russian_stem;
PG_RETURN_POINTER(d); PG_RETURN_POINTER(d);
} }
Datum Datum
snb_lexize(PG_FUNCTION_ARGS) { snb_lexize(PG_FUNCTION_ARGS)
DictSnowball *d = (DictSnowball*)PG_GETARG_POINTER(0); {
char *in = (char*)PG_GETARG_POINTER(1); DictSnowball *d = (DictSnowball *) PG_GETARG_POINTER(0);
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); {
memcpy( txt, d->z->p, d->z->l); txt = repalloc(txt, d->z->l + 1);
txt[d->z->l]='\0'; memcpy(txt, d->z->p, d->z->l);
txt[d->z->l] = '\0';
} }
res[0]=txt; res[0] = txt;
} }
res[1]=NULL; res[1] = NULL;
PG_RETURN_POINTER(res); PG_RETURN_POINTER(res);
} }

View File

@ -13,93 +13,106 @@
#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;
while(*in && isspace(*in)) while (*in && isspace(*in))
in++; in++;
if ( !in ) if (!in)
return NULL; return NULL;
start=in; start = in;
while(*in && !isspace(*in)) while (*in && !isspace(*in))
in++; in++;
*end=in; *end = in;
return start; return start;
} }
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)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("NULL config"))); errmsg("NULL config")));
in = PG_GETARG_TEXT_P(0); in = PG_GETARG_TEXT_P(0);
if ( VARSIZE(in) - VARHDRSZ == 0 ) if (VARSIZE(in) - VARHDRSZ == 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("VOID config"))); errmsg("VOID config")));
filename=text2char(in); filename = text2char(in);
PG_FREE_IF_COPY(in, 0); PG_FREE_IF_COPY(in, 0);
if ( (fin=fopen(filename,"r")) == NULL ) if ((fin = fopen(filename, "r")) == NULL)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open file \"%s\": %m", errmsg("could not open file \"%s\": %m",
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),
errmsg("out of memory"))); errmsg("out of memory")));
} }
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;
d->len = (d->len) ? 2*d->len : 16; if (cur == d->len)
d->syn=(Syn*)realloc( d->syn, sizeof(Syn)*d->len ); {
if ( !d->syn ) { d->len = (d->len) ? 2 * d->len : 16;
d->syn = (Syn *) realloc(d->syn, sizeof(Syn) * d->len);
if (!d->syn)
{
fclose(fin); fclose(fin);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
@ -107,21 +120,22 @@ syn_init(PG_FUNCTION_ARGS) {
} }
} }
starti=findwrd(buf,&end); starti = findwrd(buf, &end);
if ( !starti ) if (!starti)
continue; continue;
*end='\0'; *end = '\0';
if ( end >= buf+slen ) if (end >= buf + slen)
continue; continue;
starto= findwrd(end+1, &end); starto = findwrd(end + 1, &end);
if ( !starto ) if (!starto)
continue; continue;
*end='\0'; *end = '\0';
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),
@ -133,8 +147,8 @@ syn_init(PG_FUNCTION_ARGS) {
fclose(fin); fclose(fin);
d->len=cur; d->len = cur;
if ( cur>1 ) if (cur > 1)
qsort(d->syn, d->len, sizeof(Syn), compareSyn); qsort(d->syn, d->len, sizeof(Syn), compareSyn);
pfree(filename); pfree(filename);
@ -142,29 +156,30 @@ syn_init(PG_FUNCTION_ARGS) {
} }
Datum Datum
syn_lexize(PG_FUNCTION_ARGS) { syn_lexize(PG_FUNCTION_ARGS)
DictSyn *d = (DictSyn*)PG_GETARG_POINTER(0); {
char *in = (char*)PG_GETARG_POINTER(1); DictSyn *d = (DictSyn *) PG_GETARG_POINTER(0);
Syn key,*found; char *in = (char *) PG_GETARG_POINTER(1);
char **res=NULL; Syn key,
*found;
char **res = NULL;
if ( !PG_GETARG_INT32(2) ) if (!PG_GETARG_INT32(2))
PG_RETURN_POINTER(NULL); PG_RETURN_POINTER(NULL);
key.out=NULL; key.out = NULL;
key.in=lowerstr(pnstrdup(in, PG_GETARG_INT32(2))); key.in = lowerstr(pnstrdup(in, PG_GETARG_INT32(2)));
found=(Syn*)bsearch(&key, d->syn, d->len, sizeof(Syn), compareSyn); found = (Syn *) bsearch(&key, d->syn, d->len, sizeof(Syn), compareSyn);
pfree(key.in); pfree(key.in);
if ( !found ) if (!found)
PG_RETURN_POINTER(NULL); PG_RETURN_POINTER(NULL);
res=palloc(sizeof(char*)*2); res = palloc(sizeof(char *) * 2);
res[0]=pstrdup(found->out); res[0] = pstrdup(found->out);
res[1]=NULL; res[1] = NULL;
PG_RETURN_POINTER(res); PG_RETURN_POINTER(res);
} }

View File

@ -11,291 +11,371 @@
#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
return(strcmp(((const SPELL*)s1)->word,((const SPELL*)s2)->word)); cmpspell(const void *s1, const void *s2)
{
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; {
while ( *ptr ) { unsigned char *ptr = (unsigned char *) str;
*ptr = tolower( *ptr );
while (*ptr)
{
*ptr = tolower(*ptr);
ptr++; ptr++;
} }
} }
/* 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)
if (((const AFFIX*)s1)->type == 'p') return -1;
return(strcmp(((const AFFIX*)s1)->repl,((const AFFIX*)s2)->repl)); if (((const AFFIX *) s1)->type > ((const AFFIX *) s2)->type)
return 1;
if (((const AFFIX *) s1)->type == 'p')
return (strcmp(((const AFFIX *) s1)->repl, ((const AFFIX *) s2)->repl));
else else
return(strbcmp(((const AFFIX*)s1)->repl,((const AFFIX*)s2)->repl)); return (strbcmp(((const AFFIX *) s1)->repl, ((const AFFIX *) s2)->repl));
} }
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)
Conf->mspell+=1024*20; {
Conf->Spell=(SPELL *)realloc(Conf->Spell,Conf->mspell*sizeof(SPELL)); if (Conf->mspell)
}else{ {
Conf->mspell=1024*20; Conf->mspell += 1024 * 20;
Conf->Spell=(SPELL *)malloc(Conf->mspell*sizeof(SPELL)); Conf->Spell = (SPELL *) realloc(Conf->Spell, Conf->mspell * sizeof(SPELL));
} }
if ( Conf->Spell == NULL ) else
{
Conf->mspell = 1024 * 20;
Conf->Spell = (SPELL *) malloc(Conf->mspell * sizeof(SPELL));
}
if (Conf->Spell == NULL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); errmsg("out of memory")));
} }
Conf->Spell[Conf->nspell].word=strdup(word); Conf->Spell[Conf->nspell].word = strdup(word);
if ( !Conf->Spell[Conf->nspell].word ) if (!Conf->Spell[Conf->nspell].word)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); errmsg("out of memory")));
strncpy(Conf->Spell[Conf->nspell].flag,flag,10); strncpy(Conf->Spell[Conf->nspell].flag, flag, 10);
Conf->nspell++; Conf->nspell++;
return(0); return (0);
} }
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++;flag=s; *s = 0;
while(*s){
if (((*s>='A')&&(*s<='Z'))||((*s>='a')&&(*s<='z')))
s++; s++;
else { flag = s;
*s=0; while (*s)
{
if (((*s >= 'A') && (*s <= 'Z')) || ((*s >= 'a') && (*s <= 'z')))
s++;
else
{
*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);
} }
fclose(dict); fclose(dict);
return(0); return (0);
} }
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--;
} }
} }
return(NULL); return (NULL);
} }
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)
Conf->maffixes+=16; {
Conf->Affix = (AFFIX*)realloc((void*)Conf->Affix,Conf->maffixes*sizeof(AFFIX)); if (Conf->maffixes)
}else{ {
Conf->maffixes=16; Conf->maffixes += 16;
Conf->Affix = (AFFIX*)malloc(Conf->maffixes * sizeof(AFFIX)); Conf->Affix = (AFFIX *) realloc((void *) Conf->Affix, Conf->maffixes * sizeof(AFFIX));
} }
if ( Conf->Affix == NULL ) else
{
Conf->maffixes = 16;
Conf->Affix = (AFFIX *) malloc(Conf->maffixes * sizeof(AFFIX));
}
if (Conf->Affix == NULL)
ereport(ERROR, ereport(ERROR,
(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;
strcpy(Conf->Affix[Conf->naffixes].find,find); strcpy(Conf->Affix[Conf->naffixes].find, find);
strcpy(Conf->Affix[Conf->naffixes].repl,repl); strcpy(Conf->Affix[Conf->naffixes].repl, repl);
Conf->Affix[Conf->naffixes].replen=strlen(repl); Conf->Affix[Conf->naffixes].replen = strlen(repl);
Conf->naffixes++; Conf->naffixes++;
return(0); return (0);
} }
static char * static char *
remove_spaces(char *dist,char *src){ remove_spaces(char *dist, char *src)
char *d,*s; {
d=dist; char *d,
s=src; *s;
while(*s){
if(*s!=' '&&*s!='-'&&*s!='\t'){ d = dist;
*d=*s; s = src;
while (*s)
{
if (*s != ' ' && *s != '-' && *s != '\t')
{
*d = *s;
d++; d++;
} }
s++; s++;
} }
*d=0; *d = 0;
return(dist); return (dist);
} }
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] = "";
unsigned char find[BUFSIZ]=""; unsigned char find[BUFSIZ] = "";
unsigned char repl[BUFSIZ]=""; unsigned char repl[BUFSIZ] = "";
unsigned char *s; unsigned char *s;
int i; int i;
int suffixes=0; int suffixes = 0;
int prefixes=0; int prefixes = 0;
FILE *affix; FILE *affix;
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")){ {
suffixes=1; if (!STRNCASECMP(str, "suffixes"))
prefixes=0; {
suffixes = 1;
prefixes = 0;
continue; continue;
} }
if(!STRNCASECMP(str,"prefixes")){ if (!STRNCASECMP(str, "prefixes"))
suffixes=0; {
prefixes=1; suffixes = 0;
prefixes = 1;
continue; continue;
} }
if(!STRNCASECMP(str,"flag ")){ if (!STRNCASECMP(str, "flag "))
s=str+5; {
while(strchr("* ",*s)) s = str + 5;
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(find,""); strcpy(repl, find);
strcpy(find, "");
} }
break; break;
default: default:
continue; continue;
} }
AddAffix(Conf,(int)flag,mask,find,repl,suffixes?'s':'p'); AddAffix(Conf, (int) flag, mask, find, repl, suffixes ? 's' : 'p');
} }
fclose(affix); fclose(affix);
return(0); return (0);
} }
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; {
if (CurLet != Let) { Let = (int) (*(Conf->Spell[i].word)) & 255;
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]); {
if(Affix->type == 'p') { Affix = &(((AFFIX *) Conf->Affix)[i]);
Let = (int)(*(Affix->repl)) & 255; if (Affix->type == 'p')
if (CurLetP != Let) { {
Let = (int) (*(Affix->repl)) & 255;
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 { }
Let = (Affix->replen) ? (int)(Affix->repl[Affix->replen-1]) & 255 : 0; else
if (CurLetS != Let) { {
Let = (Affix->replen) ? (int) (Affix->repl[Affix->replen - 1]) & 255 : 0;
if (CurLetS != Let)
{
Conf->SuffixTree.Left[Let] = i; Conf->SuffixTree.Left[Let] = i;
CurLetS = Let; CurLetS = Let;
} }
@ -336,32 +427,34 @@ 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); {
if(err){ err = regcomp(&(Affix->reg), Affix->mask, REG_EXTENDED | REG_ICASE | REG_NOSUB);
/*regerror(err, &(Affix->reg), regerrstr, ERRSTRSIZE);*/ if (err)
{
/* 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);
} }
return NULL; return NULL;
@ -370,45 +463,57 @@ CheckSuffix(const char *word, size_t len, AFFIX *Affix, int *res, IspellDict *Co
#define NS 1 #define NS 1
#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]; {
char newword[2*MAXNORMLEN] = ""; regmatch_t subs[NS * 2];
int err, ls, res, lres; char newword[2 * MAXNORMLEN] = "";
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); {
if(err){ err = regcomp(&(Affix->reg), Affix->mask, REG_EXTENDED | REG_ICASE | REG_NOSUB);
/*regerror(err, &(Affix->reg), regerrstr, ERRSTRSIZE);*/ if (err)
{
/* 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,61 +522,78 @@ 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);
if (len > MAXNORMLEN) if (len > MAXNORMLEN)
return(NULL); return (NULL);
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++;*cur=NULL; *cur = pstrdup(word);
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,28 +628,29 @@ int lres, rres, cres = 0;
} /* for ipi */ } /* for ipi */
if(cur==forms){ if (cur == forms)
{
pfree(forms); pfree(forms);
return(NULL); return (NULL);
} }
return(forms); return (forms);
} }
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));
return; return;
} }

View File

@ -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,14 +22,17 @@ 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;
int nspell; int nspell;
int mspell; int mspell;
@ -38,14 +43,14 @@ typedef struct {
} IspellDict; } IspellDict;
char ** NormalizeWord(IspellDict * Conf,char *word); char **NormalizeWord(IspellDict * Conf, char *word);
int ImportAffixes(IspellDict * Conf, const char *filename); int ImportAffixes(IspellDict * Conf, const char *filename);
int ImportDictionary(IspellDict * Conf,const char *filename); int ImportDictionary(IspellDict * Conf, const char *filename);
int AddSpell(IspellDict * Conf,const char * word,const char *flag); int AddSpell(IspellDict * Conf, const char *word, const char *flag);
int AddAffix(IspellDict * Conf,int flag,const char *mask,const char *find,const char *repl,int type); int AddAffix(IspellDict * Conf, int flag, const char *mask, const char *find, const char *repl, int type);
void SortDictionary(IspellDict * Conf); void SortDictionary(IspellDict * Conf);
void SortAffixes(IspellDict * Conf); void SortAffixes(IspellDict * Conf);
void FreeIspell (IspellDict *Conf); void FreeIspell(IspellDict * Conf);
#endif #endif

View File

@ -22,120 +22,158 @@
#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; {
memcpy(res,ptr,len); char *res = palloc(len + 1),
res[len]='\0'; *cptr;
memcpy(res, ptr, len);
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';
return res; return res;
} }
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),
char num=0; *begin = NULL;
int state=CS_WAITKEY; char num = 0;
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)
begin=ptr; {
state=CS_INKEY; if (isalpha(*ptr))
} else if ( !isspace(*ptr) ) {
ereport(ERROR, begin = ptr;
(errcode(ERRCODE_SYNTAX_ERROR), state = CS_INKEY;
errmsg("syntax error"),
errdetail("Syntax error in position %d near \"%c\"",
(int) (ptr-VARDATA(in)), *ptr)));
} else if (state==CS_INKEY) {
if ( isspace(*ptr) ) {
mptr->key=nstrdup(begin, ptr-begin);
state=CS_WAITEQ;
} else if ( *ptr=='=' ) {
mptr->key=nstrdup(begin, ptr-begin);
state=CS_WAITVALUE;
} else if ( !isalpha(*ptr) )
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error"),
errdetail("Syntax error in position %d near \"%c\"",
(int) (ptr-VARDATA(in)), *ptr)));
} else if ( state==CS_WAITEQ ) {
if ( *ptr=='=' )
state=CS_WAITVALUE;
else if ( !isspace(*ptr) )
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error"),
errdetail("Syntax error in position %d near \"%c\"",
(int) (ptr-VARDATA(in)), *ptr)));
} else if ( state==CS_WAITVALUE ) {
if ( *ptr=='"' ) {
begin=ptr+1;
state=CS_INVALUE;
} else if ( !isspace(*ptr) ) {
begin=ptr;
state=CS_IN2VALUE;
} }
} else if ( state==CS_INVALUE ) { else if (!isspace(*ptr))
if ( *ptr=='"' ) {
mptr->value = nstrdup(begin, ptr-begin);
mptr++;
state=CS_WAITDELIM;
} else if ( *ptr=='\\' )
state=CS_INESC;
} else if ( state==CS_IN2VALUE ) {
if ( isspace(*ptr) || *ptr==',' ) {
mptr->value = nstrdup(begin, ptr-begin);
mptr++;
state=( *ptr==',' ) ? CS_WAITKEY : CS_WAITDELIM;
} else if ( *ptr=='\\' )
state=CS_INESC;
} else if ( state==CS_WAITDELIM ) {
if ( *ptr==',' )
state=CS_WAITKEY;
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_INESC ) { }
state=CS_INVALUE; else if (state == CS_INKEY)
} else if ( state == CS_IN2ESC ) { {
state=CS_IN2VALUE; if (isspace(*ptr))
} else {
mptr->key = nstrdup(begin, ptr - begin);
state = CS_WAITEQ;
}
else if (*ptr == '=')
{
mptr->key = nstrdup(begin, ptr - begin);
state = CS_WAITVALUE;
}
else if (!isalpha(*ptr))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error"),
errdetail("Syntax error in position %d near \"%c\"",
(int) (ptr - VARDATA(in)), *ptr)));
}
else if (state == CS_WAITEQ)
{
if (*ptr == '=')
state = CS_WAITVALUE;
else if (!isspace(*ptr))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error"),
errdetail("Syntax error in position %d near \"%c\"",
(int) (ptr - VARDATA(in)), *ptr)));
}
else if (state == CS_WAITVALUE)
{
if (*ptr == '"')
{
begin = ptr + 1;
state = CS_INVALUE;
}
else if (!isspace(*ptr))
{
begin = ptr;
state = CS_IN2VALUE;
}
}
else if (state == CS_INVALUE)
{
if (*ptr == '"')
{
mptr->value = nstrdup(begin, ptr - begin);
mptr++;
state = CS_WAITDELIM;
}
else if (*ptr == '\\')
state = CS_INESC;
}
else if (state == CS_IN2VALUE)
{
if (isspace(*ptr) || *ptr == ',')
{
mptr->value = nstrdup(begin, ptr - begin);
mptr++;
state = (*ptr == ',') ? CS_WAITKEY : CS_WAITDELIM;
}
else if (*ptr == '\\')
state = CS_INESC;
}
else if (state == CS_WAITDELIM)
{
if (*ptr == ',')
state = CS_WAITKEY;
else if (!isspace(*ptr))
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error"),
errdetail("Syntax error in position %d near \"%c\"",
(int) (ptr - VARDATA(in)), *ptr)));
}
else if (state == CS_INESC)
state = CS_INVALUE;
else if (state == CS_IN2ESC)
state = CS_IN2VALUE;
else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("bad parser state"), errmsg("bad parser state"),
errdetail("%d at position %d near \"%c\"", errdetail("%d at position %d near \"%c\"",
state, (int) (ptr-VARDATA(in)), *ptr))); state, (int) (ptr - VARDATA(in)), *ptr)));
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")));
} }

View File

@ -102,21 +102,33 @@ typedef struct
int cfg_id; int cfg_id;
} 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,16 +282,17 @@ 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)
pushquery(state, OPR, (int4) '&', 0, 0, 0 ); pushquery(state, OPR, (int4) '&', 0, 0, 0);
} }
pfree(prs.words); pfree(prs.words);
/* XXX */ /* XXX */
if ( prs.curwords==0 ) if (prs.curwords == 0)
pushval_asis(state, VALTRUE, 0, 0, 0); pushval_asis(state, VALTRUE, 0, 0, 0);
} }
@ -381,11 +398,14 @@ 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)); {
uint16 len = *( (uint16*) (chkval->values+val->pos+SHORTALIGN(val->len)) ); WordEntryPos *ptr = (WordEntryPos *) (chkval->values + val->pos + SHORTALIGN(val->len) + sizeof(uint16));
while (len--) { uint16 len = *((uint16 *) (chkval->values + val->pos + SHORTALIGN(val->len)));
if ( item->weight & ( 1<<ptr->weight ) )
while (len--)
{
if (item->weight & (1 << ptr->weight))
return true; return true;
ptr++; ptr++;
} }
@ -410,8 +430,8 @@ checkcondition_str(void *checkval, ITEM * val)
StopMiddle = StopLow + (StopHigh - StopLow) / 2; StopMiddle = StopLow + (StopHigh - StopLow) / 2;
difference = ValCompare((CHKVAL *) checkval, StopMiddle, val); difference = ValCompare((CHKVAL *) checkval, StopMiddle, val);
if (difference == 0) if (difference == 0)
return ( val->weight && StopMiddle->haspos ) ? return (val->weight && StopMiddle->haspos) ?
checkclass_str((CHKVAL *) checkval,StopMiddle, val) : true; checkclass_str((CHKVAL *) checkval, StopMiddle, val) : true;
else if (difference < 0) else if (difference < 0)
StopLow = StopMiddle + 1; StopLow = StopMiddle + 1;
else else
@ -534,7 +554,7 @@ findoprnd(ITEM * ptr, int4 *pos)
* input * input
*/ */
static QUERYTYPE * static QUERYTYPE *
queryin(char *buf, void (*pushval) (QPRS_STATE *, int, char *, int, int2), int cfg_id) queryin(char *buf, void (*pushval) (QPRS_STATE *, int, char *, int, int2), int cfg_id)
{ {
QPRS_STATE state; QPRS_STATE state;
int4 i; int4 i;
@ -555,7 +575,7 @@ queryin(char *buf, void (*pushval) (QPRS_STATE *, int, char *, int, int2), int c
state.count = 0; state.count = 0;
state.num = 0; state.num = 0;
state.str = NULL; state.str = NULL;
state.cfg_id=cfg_id; state.cfg_id = cfg_id;
/* init value parser's state */ /* init value parser's state */
state.valstate.oprisdelim = true; state.valstate.oprisdelim = true;
@ -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,15 +865,16 @@ 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;
ITEM *res; ITEM *res;
int4 len; int4 len;
str=text2char(in); str = text2char(in);
PG_FREE_IF_COPY(in,1); PG_FREE_IF_COPY(in, 1);
query = queryin(str, pushval_morph, PG_GETARG_INT32(0)); query = queryin(str, pushval_morph, PG_GETARG_INT32(0));
res = clean_fakeval_v2(GETQUERY(query), &len); res = clean_fakeval_v2(GETQUERY(query), &len);
@ -851,25 +890,25 @@ 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); {
Datum res= DirectFunctionCall2( text *name = PG_GETARG_TEXT_P(0);
Datum res = DirectFunctionCall2(
to_tsquery, to_tsquery,
Int32GetDatum( name2id_cfg(name) ), Int32GetDatum(name2id_cfg(name)),
PG_GETARG_DATUM(1) PG_GETARG_DATUM(1)
); );
PG_FREE_IF_COPY(name,1); PG_FREE_IF_COPY(name, 1);
PG_RETURN_DATUM(res); PG_RETURN_DATUM(res);
} }
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)
)); ));
} }

View File

@ -37,7 +37,7 @@ Datum rank_cd_def(PG_FUNCTION_ARGS);
PG_FUNCTION_INFO_V1(get_covers); PG_FUNCTION_INFO_V1(get_covers);
Datum get_covers(PG_FUNCTION_ARGS); Datum get_covers(PG_FUNCTION_ARGS);
static float weights[]={0.1, 0.2, 0.4, 1.0}; static float weights[] = {0.1, 0.2, 0.4, 1.0};
#define wpos(wep) ( w[ ((WordEntryPos*)(wep))->weight ] ) #define wpos(wep) ( w[ ((WordEntryPos*)(wep))->weight ] )
@ -46,20 +46,26 @@ 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
if ( w>100 ) word_distance(int4 w)
{
if (w > 100)
return 1e-30; return 1e-30;
return 1.0/(1.005+0.05*exp( ((float4)w)/1.5-2) ); return 1.0 / (1.005 + 0.05 * exp(((float4) w) / 1.5 - 2));
} }
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
len += clen; len += clen;
@ -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,
@ -80,10 +87,11 @@ WordECompareITEM(char *eval, char *qval, WordEntry * ptr, ITEM * item) {
return (ptr->len > item->length) ? 1 : -1; return (ptr->len > item->length) ? 1 : -1;
} }
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;
int difference; int difference;
@ -104,53 +112,68 @@ find_wordentry(tsvector *t, QUERYTYPE *q, ITEM *item) {
return NULL; return NULL;
} }
static WordEntryPos POSNULL[]={ static WordEntryPos POSNULL[] = {
{0,0}, {0, 0},
{0,MAXENTRYPOS-1} {0, MAXENTRYPOS - 1}
}; };
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); {
int i,k,l,p; uint16 **pos = (uint16 **) palloc(sizeof(uint16 *) * q->size);
int i,
k,
l,
p;
WordEntry *entry; WordEntry *entry;
WordEntryPos *post,*ct; WordEntryPos *post,
int4 dimt,lenct,dist; *ct;
float res=-1.0; int4 dimt,
ITEM *item=GETQUERY(q); lenct,
dist;
float res = -1.0;
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;
entry=find_wordentry(t,q,&(item[i])); entry = find_wordentry(t, q, &(item[i]));
if ( !entry ) if (!entry)
continue; continue;
if ( entry->haspos ) if (entry->haspos)
pos[i] = (uint16*)_POSDATAPTR(t,entry); pos[i] = (uint16 *) _POSDATAPTR(t, entry);
else else
pos[i] = (uint16*)POSNULL; pos[i] = (uint16 *) POSNULL;
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; {
lenct = *(uint16*)(pos[k]); if (!pos[k])
ct = (WordEntryPos*)(pos[k]+1); continue;
for(l=0; l<dimt; l++) { lenct = *(uint16 *) (pos[k]);
for(p=0; p<lenct; p++) { ct = (WordEntryPos *) (pos[k] + 1);
dist = abs( post[l].pos - ct[p].pos ); for (l = 0; l < dimt; l++)
if ( dist || (dist==0 && (pos[i]==(uint16*)POSNULL || pos[k]==(uint16*)POSNULL) ) ) { {
for (p = 0; p < lenct; p++)
{
dist = abs(post[l].pos - ct[p].pos);
if (dist || (dist == 0 && (pos[i] == (uint16 *) POSNULL || pos[k] == (uint16 *) POSNULL)))
{
float curw; float curw;
if ( !dist ) dist=MAXENTRYPOS;
curw= sqrt( wpos(&(post[l])) * wpos( &(ct[p]) ) * word_distance(dist) ); if (!dist)
res = ( res < 0 ) ? curw : 1.0 - ( 1.0 - res ) * ( 1.0 - curw ); dist = MAXENTRYPOS;
curw = sqrt(wpos(&(post[l])) * wpos(&(ct[p])) * word_distance(dist));
res = (res < 0) ? curw : 1.0 - (1.0 - res) * (1.0 - curw);
} }
} }
} }
@ -161,99 +184,116 @@ 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,
float res=-1.0; j,
ITEM *item=GETQUERY(q); i;
float res = -1.0;
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;
entry=find_wordentry(t,q,&(item[i])); entry = find_wordentry(t, q, &(item[i]));
if ( !entry ) if (!entry)
continue; continue;
if ( entry->haspos ) { if (entry->haspos)
dimt = POSDATALEN(t,entry); {
post = POSDATAPTR(t,entry); dimt = POSDATALEN(t, entry);
} else { post = POSDATAPTR(t, entry);
dimt = *(uint16*)POSNULL; }
post = POSNULL+1; else
{
dimt = *(uint16 *) POSNULL;
post = POSNULL + 1;
} }
for(j=0;j<dimt;j++) { for (j = 0; j < dimt; j++)
if ( res < 0 ) {
res = wpos( &(post[j]) ); if (res < 0)
res = wpos(&(post[j]));
else else
res = 1.0 - ( 1.0-res ) * ( 1.0-wpos( &(post[j]) ) ); res = 1.0 - (1.0 - res) * (1.0 - wpos(&(post[j])));
} }
} }
return res; return res;
} }
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;
if (!t->size || !q->size) if (!t->size || !q->size)
return 0.0; return 0.0;
res = ( item->type != VAL && item->val == (int4) '&' ) ? res = (item->type != VAL && item->val == (int4) '&') ?
calc_rank_and(w,t,q) : calc_rank_or(w,t,q); calc_rank_and(w, t, q) : calc_rank_or(w, t, q);
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);
} }
return res; return res;
} }
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));
int method=DEF_NORM_METHOD; int method = DEF_NORM_METHOD;
float res=0.0; float res = 0.0;
float ws[ lengthof(weights) ]; float ws[lengthof(weights)];
int i; int i;
if ( ARR_NDIM(win) != 1 ) if (ARR_NDIM(win) != 1)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("array of weight must be one-dimensional"))); errmsg("array of weight must be one-dimensional")));
if ( ARRNELEMS(win) < lengthof(weights) ) if (ARRNELEMS(win) < lengthof(weights))
ereport(ERROR, ereport(ERROR,
(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]; {
if ( ws[ i ] > 1.0 ) ws[i] = (((float4 *) ARR_DATA_PTR(win))[i] >= 0) ? ((float4 *) ARR_DATA_PTR(win))[i] : weights[i];
if (ws[i] > 1.0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("weight out of range"))); errmsg("weight out of range")));
} }
if ( PG_NARGS() == 4 ) if (PG_NARGS() == 4)
method=PG_GETARG_INT32(3); method = PG_GETARG_INT32(3);
res=calc_rank(ws, txt, query, method); res = calc_rank(ws, txt, query, method);
PG_FREE_IF_COPY(win, 0); PG_FREE_IF_COPY(win, 0);
PG_FREE_IF_COPY(txt, 1); PG_FREE_IF_COPY(txt, 1);
@ -262,16 +302,17 @@ 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;
int method=DEF_NORM_METHOD; int method = DEF_NORM_METHOD;
if ( PG_NARGS() == 3 ) if (PG_NARGS() == 3)
method=PG_GETARG_INT32(2); method = PG_GETARG_INT32(2);
res=calc_rank(weights, txt, query, method); res = calc_rank(weights, txt, query, method);
PG_FREE_IF_COPY(txt, 0); PG_FREE_IF_COPY(txt, 0);
PG_FREE_IF_COPY(query, 1); PG_FREE_IF_COPY(query, 1);
@ -279,30 +320,35 @@ 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,28 +358,35 @@ 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,
ITEM *item=GETQUERY(query); *f = (DocRepresentation *) 0xffffffff;
int lastpos=*pos; ITEM *item = GETQUERY(query);
int oldq=*q; int lastpos = *pos;
int oldq = *q;
*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;
} }
break; break;
} }
@ -343,27 +396,33 @@ Cover(DocRepresentation *doc, int len, QUERYTYPE *query, int *pos, int *p, int *
item++; item++;
} }
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;
} }
break; break;
} }
@ -372,62 +431,80 @@ 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 }; {
*pos = f-doc+1; ChkDocR ch = {f, (doc + lastpos) - f + 1};
if ( TS_execute(GETQUERY(query), &ch, false, checkcondition_DR) ) {
/*elog(NOTICE,"OP:%d NP:%d P:%d Q:%d", *pos, lastpos, *p, *q);*/ *pos = f - doc + 1;
if (TS_execute(GETQUERY(query), &ch, false, checkcondition_DR))
{
/*
* elog(NOTICE,"OP:%d NP:%d P:%d Q:%d", *pos, lastpos, *p,
* *q);
*/
return true; return true;
} else }
return Cover(doc, len, query, pos,p,q); else
return Cover(doc, len, query, pos, p, q);
} }
return false; return false;
} }
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;
entry=find_wordentry(txt,query,&(item[i])); entry = find_wordentry(txt, query, &(item[i]));
if ( !entry ) if (!entry)
continue; continue;
if ( entry->haspos ) { if (entry->haspos)
dimt = POSDATALEN(txt,entry); {
post = POSDATAPTR(txt,entry); dimt = POSDATALEN(txt, entry);
} else { post = POSDATAPTR(txt, entry);
dimt = *(uint16*)POSNULL; }
post = POSNULL+1; else
{
dimt = *(uint16 *) POSNULL;
post = POSNULL + 1;
} }
while( cur+dimt >= len ) { while (cur + dimt >= len)
len*=2; {
doc = (DocRepresentation*)repalloc(doc,sizeof(DocRepresentation)*len); len *= 2;
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].pos=post[j].pos; doc[cur].item = &(item[i]);
doc[cur].pos = post[j].pos;
cur++; cur++;
} }
} }
*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,38 +515,49 @@ 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);
} }
cur=0; cur = 0;
if (K<=0) if (K <= 0)
K=4; K = 4;
while( Cover(doc, len, query, &cur, &p, &q) ) while (Cover(doc, len, query, &cur, &p, &q))
res += ( q-p+1 > K ) ? ((float)K)/((float)(q-p+1)) : 1.0; res += (q - p + 1 > K) ? ((float) K) / ((float) (q - p + 1)) : 1.0;
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);
} }
pfree(doc); pfree(doc);
@ -481,19 +569,21 @@ 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),
PG_GETARG_DATUM(0), PG_GETARG_DATUM(0),
PG_GETARG_DATUM(1), PG_GETARG_DATUM(1),
( PG_NARGS() == 3 ) ? PG_GETARG_DATUM(2) : Int32GetDatum(DEF_NORM_METHOD) (PG_NARGS() == 3) ? PG_GETARG_DATUM(2) : Int32GetDatum(DEF_NORM_METHOD)
)); ));
} }
/**************debug*************/ /**************debug*************/
typedef struct { typedef struct
{
char *w; char *w;
int2 len; int2 len;
int2 pos; int2 pos;
@ -502,99 +592,118 @@ 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;
} }
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,
int ncover=1; p,
q,
olddwpos = 0;
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);
PG_FREE_IF_COPY(query,1); PG_FREE_IF_COPY(query, 1);
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),
errmsg("no pos info"))); errmsg("no pos info")));
dlen += POSDATALEN(txt,&(pptr[i])); dlen += POSDATALEN(txt, &(pptr[i]));
} }
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])); {
for(j=0;j<POSDATALEN(txt,&(pptr[i]));j++) { WordEntryPos *posdata = POSDATAPTR(txt, &(pptr[i]));
dw[cur].w=STRPTR(txt)+pptr[i].pos;
dw[cur].len=pptr[i].len; for (j = 0; j < POSDATALEN(txt, &(pptr[i])); j++)
dw[cur].pos=posdata[j].pos; {
dw[cur].w = STRPTR(txt) + pptr[i].pos;
dw[cur].len = pptr[i].len;
dw[cur].pos = posdata[j].pos;
cur++; cur++;
} }
len+=(pptr[i].len + 1) * (int)POSDATALEN(txt,&(pptr[i])); len += (pptr[i].len + 1) * (int) POSDATALEN(txt, &(pptr[i]));
} }
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; {
while(dwptr->pos < p && dwptr-dw<dlen) dwptr = dw + olddwpos;
while (dwptr->pos < p && dwptr - dw < dlen)
dwptr++; dwptr++;
olddwpos=dwptr-dw; olddwpos = dwptr - dw;
dwptr->start=ncover; dwptr->start = ncover;
while(dwptr->pos < q+1 && dwptr-dw<dlen) while (dwptr->pos < q + 1 && dwptr - dw < dlen)
dwptr++; dwptr++;
(dwptr-1)->finish=ncover; (dwptr - 1)->finish = ncover;
len+= 4 /* {}+two spaces */ + 2*16 /*numbers*/; len += 4 /* {}+two spaces */ + 2 * 16 /* numbers */ ;
ncover++; ncover++;
} }
out=palloc(VARHDRSZ+len); out = palloc(VARHDRSZ + len);
cptr=((char*)out)+VARHDRSZ; cptr = ((char *) out) + VARHDRSZ;
dwptr=dw; dwptr = dw;
while( dwptr-dw < dlen) { while (dwptr - dw < dlen)
if ( dwptr->start ) { {
sprintf(cptr,"{%d ",dwptr->start); if (dwptr->start)
cptr=strchr(cptr,'\0'); {
sprintf(cptr, "{%d ", dwptr->start);
cptr = strchr(cptr, '\0');
} }
memcpy(cptr,dwptr->w,dwptr->len); memcpy(cptr, dwptr->w, dwptr->len);
cptr+=dwptr->len; cptr += dwptr->len;
*cptr=' '; *cptr = ' ';
cptr++; cptr++;
if ( dwptr->finish ) { if (dwptr->finish)
sprintf(cptr,"}%d ",dwptr->finish); {
cptr=strchr(cptr,'\0'); sprintf(cptr, "}%d ", dwptr->finish);
cptr = strchr(cptr, '\0');
} }
dwptr++; dwptr++;
} }
VARATT_SIZEP(out) = cptr - ((char*)out); VARATT_SIZEP(out) = cptr - ((char *) out);
pfree(dw); pfree(dw);
pfree(doc); pfree(doc);
PG_FREE_IF_COPY(txt,0); PG_FREE_IF_COPY(txt, 0);
PG_FREE_IF_COPY(query,1); PG_FREE_IF_COPY(query, 1);
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }

View File

@ -11,69 +11,85 @@
#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);
if ( !tmp ) tmp = (SNMapEntry *) realloc(map->list, sizeof(SNMapEntry) * len);
if (!tmp)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); errmsg("out of memory")));
map->reallen=len; map->reallen = len;
map->list=tmp; map->list = tmp;
} }
map->list[ map->len ].key = strdup(key); map->list[map->len].key = strdup(key);
if ( ! map->list[ map->len ].key ) if (!map->list[map->len].key)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
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);
return (ptr) ? ptr->value : 0; return (ptr) ? ptr->value : 0;
} }
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
SNMapEntry *entry=map->list; freeSNMap(SNMap * map)
if ( map->list ) { {
while( map->len ) { SNMapEntry *entry = map->list;
if ( entry->key ) free(entry->key);
entry++; map->len--; if (map->list)
{
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));
} }

View File

@ -3,21 +3,23 @@
#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;
} SNMap; } SNMap;
void addSNMap( SNMap *map, char *key, Oid value ); void addSNMap(SNMap * map, char *key, Oid value);
void addSNMap_t( SNMap *map, text *key, Oid value ); void addSNMap_t(SNMap * map, text *key, Oid value);
Oid findSNMap( SNMap *map, char *key ); Oid findSNMap(SNMap * map, char *key);
Oid findSNMap_t( SNMap *map, text *key ); Oid findSNMap_t(SNMap * map, text *key);
void freeSNMap( SNMap *map ); void freeSNMap(SNMap * map);
#endif #endif

View File

@ -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;
} }

View File

@ -11,17 +11,24 @@ typedef unsigned char symbol;
*/ */
struct SN_env { struct SN_env
symbol * p; {
int c; int a; int l; int lb; int bra; int ket; symbol *p;
int S_size; int I_size; int B_size; int c;
symbol * * S; int a;
int * I; int l;
symbol * B; int lb;
int bra;
int ket;
int S_size;
int I_size;
int B_size;
symbol **S;
int *I;
symbol *B;
}; };
extern struct SN_env * SN_create_env(int S_size, int I_size, int B_size); 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);

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,7 @@
/* This file was generated automatically by the Snowball to ANSI C compiler */ /* This file was generated automatically by the Snowball to ANSI C compiler */
extern struct SN_env * english_create_env(void); 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);

View File

@ -7,20 +7,21 @@
#define CAPACITY(p) ((int *)(p))[-2] #define CAPACITY(p) ((int *)(p))[-2]
struct among struct among
{ int s_size; /* number of chars in string */ {
symbol * s; /* search string */ int s_size; /* number of chars in string */
int substring_i;/* index to longest matching substring */ symbol *s; /* search string */
int substring_i; /* index to longest matching substring */
int result; /* result of the lookup */ int result; /* result of the lookup */
int (* function)(struct SN_env *); int (*function) (struct SN_env *);
}; };
extern symbol * create_s(void); extern symbol *create_s(void);
extern void lose_s(symbol * p); extern void lose_s(symbol * p);
extern int in_grouping(struct SN_env * z, unsigned char * s, int min, int max); extern int in_grouping(struct SN_env * z, unsigned char *s, int min, int max);
extern int in_grouping_b(struct SN_env * z, unsigned char * s, int min, int max); extern int in_grouping_b(struct SN_env * z, unsigned char *s, int min, int max);
extern int out_grouping(struct SN_env * z, unsigned char * s, int min, int max); extern int out_grouping(struct SN_env * z, unsigned char *s, int min, int max);
extern int out_grouping_b(struct SN_env * z, unsigned char * s, int min, int max); extern int out_grouping_b(struct SN_env * z, unsigned char *s, int min, int max);
extern int in_range(struct SN_env * z, int min, int max); extern int in_range(struct SN_env * z, int min, int max);
extern int in_range_b(struct SN_env * z, int min, int max); extern int in_range_b(struct SN_env * z, int min, int max);
@ -35,7 +36,7 @@ extern int eq_v_b(struct SN_env * z, symbol * 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);
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);
extern symbol * increase_size(symbol * p, int n); extern symbol *increase_size(symbol * p, int n);
extern int replace_s(struct SN_env * z, int c_bra, int c_ket, int s_size, const symbol * s); extern int replace_s(struct SN_env * z, int c_bra, int c_ket, int s_size, const symbol * s);
extern void slice_from_s(struct SN_env * z, int s_size, symbol * s); extern void slice_from_s(struct SN_env * z, int s_size, symbol * s);
extern void slice_from_v(struct SN_env * z, symbol * p); extern void slice_from_v(struct SN_env * z, symbol * p);
@ -44,8 +45,7 @@ extern void slice_del(struct SN_env * z);
extern void insert_s(struct SN_env * z, int bra, int ket, int s_size, symbol * s); extern void insert_s(struct SN_env * z, int bra, int ket, int s_size, symbol * s);
extern void insert_v(struct SN_env * z, int bra, int ket, symbol * p); extern void insert_v(struct SN_env * z, int bra, int ket, symbol * p);
extern symbol * slice_to(struct SN_env * z, symbol * p); 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);

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,7 @@
/* This file was generated automatically by the Snowball to ANSI C compiler */ /* This file was generated automatically by the Snowball to ANSI C compiler */
extern struct SN_env * russian_create_env(void); 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);

View File

@ -9,249 +9,398 @@
#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)
{
extern int in_grouping(struct SN_env * z, unsigned char * s, int min, int max) free((char *) p - HEAD);
{ if (z->c >= z->l) return 0;
{ int ch = z->p[z->c];
if
(ch > max || (ch -= min) < 0 ||
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
}
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(struct SN_env * z, unsigned char *s, int min, int max)
{ int ch = z->p[z->c - 1]; {
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 out_grouping(struct SN_env * z, unsigned char * s, int min, int max) extern int
{ if (z->c >= z->l) return 0; in_grouping_b(struct SN_env * z, unsigned char *s, int min, int max)
{ int ch = z->p[z->c]; {
if (z->c <= z->lb)
return 0;
{
int ch = z->p[z->c - 1];
if
(ch > max || (ch -= min) < 0 ||
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
return 0;
}
z->c--;
return 1;
}
extern int
out_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];
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;
symbol * q = z->p + c; int l = z->l;
symbol *q = z->p + c;
struct among * w; struct among *w;
int common_i = 0; int common_i = 0;
int common_j = 0; int common_j = 0;
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;
symbol * q = z->p + c - 1; int lb = z->lb;
symbol *q = z->p + c - 1;
struct among * w; struct among *w;
int common_i = 0; int common_i = 0;
int common_j = 0; int common_j = 0;
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;
diff = q[- common] - w->s[i];
if (diff != 0) break; for (i = w->s_size - 1 - common; i >= 0; i--)
{
if (c - common == lb)
{
diff = -1;
break;
}
diff = q[-common] - w->s[i];
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)
symbol * q = (symbol *) (HEAD + (char *) malloc(HEAD + (new_size + 1) * sizeof(symbol))); {
int new_size = n + 20;
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): [%d]'", number, line_count,limit); /* if (number >= 0) printf("%3d (line %4d): '", number, line_count); */
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);
} }
} }

View File

@ -13,97 +13,114 @@
#define STOPBUFLEN 4096 #define STOPBUFLEN 4096
char* char *
lowerstr(char *str) { lowerstr(char *str)
char *ptr=str; {
while(*ptr) { char *ptr = str;
*ptr = tolower(*(unsigned char*)ptr);
while (*ptr)
{
*ptr = tolower(*(unsigned char *) ptr);
ptr++; ptr++;
} }
return str; return str;
} }
void void
freestoplist(StopList *s) { freestoplist(StopList * s)
char **ptr=s->stop; {
if ( ptr ) char **ptr = s->stop;
while( *ptr && s->len >0 ) {
if (ptr)
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; {
s->len=0; char **stop = NULL;
if ( in && VARSIZE(in) - VARHDRSZ > 0 ) {
char *filename=text2char(in);
FILE *hin=NULL;
char buf[STOPBUFLEN];
int reallen=0;
if ( (hin=fopen(filename,"r")) == NULL ) s->len = 0;
if (in && VARSIZE(in) - VARHDRSZ > 0)
{
char *filename = text2char(in);
FILE *hin = NULL;
char buf[STOPBUFLEN];
int reallen = 0;
if ((hin = fopen(filename, "r")) == NULL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
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'; {
if ( *buf=='\0' ) continue; buf[strlen(buf) - 1] = '\0';
if (*buf == '\0')
continue;
if ( s->len>= reallen ) { if (s->len >= reallen)
{
char **tmp; char **tmp;
reallen=(reallen) ? reallen*2 : 16;
tmp=(char**)realloc((void*)stop, sizeof(char*)*reallen); reallen = (reallen) ? reallen * 2 : 16;
if (!tmp) { tmp = (char **) realloc((void *) stop, sizeof(char *) * reallen);
if (!tmp)
{
freestoplist(s); freestoplist(s);
fclose(hin); fclose(hin);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); errmsg("out of memory")));
} }
stop=tmp; stop = tmp;
} }
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,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); errmsg("out of memory")));
} }
if ( s->wordop ) if (s->wordop)
stop[s->len]=(s->wordop)(stop[s->len]); stop[s->len] = (s->wordop) (stop[s->len]);
(s->len)++; (s->len)++;
} }
fclose(hin); fclose(hin);
pfree(filename); pfree(filename);
} }
s->stop=stop; s->stop = stop;
} }
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) {
qsort(s->stop, s->len, sizeof(char*), comparestr); if (s->stop && s->len > 0)
qsort(s->stop, s->len, sizeof(char *), comparestr);
} }
bool bool
searchstoplist(StopList *s, char *key) { searchstoplist(StopList * s, char *key)
if ( s->wordop ) {
key=(*(s->wordop))(key); if (s->wordop)
return ( s->stop && s->len>0 && bsearch(&key, s->stop, s->len, sizeof(char*), comparestr) ) ? true : false; key = (*(s->wordop)) (key);
return (s->stop && s->len > 0 && bsearch(&key, s->stop, s->len, sizeof(char *), comparestr)) ? true : false;
} }

View File

@ -23,112 +23,125 @@
/*********top interface**********/ /*********top interface**********/
static void *plan_getcfg_bylocale=NULL; static void *plan_getcfg_bylocale = NULL;
static void *plan_getcfg=NULL; static void *plan_getcfg = NULL;
static void *plan_getmap=NULL; static void *plan_getmap = NULL;
static void *plan_name2id=NULL; 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 ) ); {
if ( !plan_getcfg ) plan_getcfg = SPI_saveplan(SPI_prepare("select prs_name from pg_ts_cfg where oid = $1", 1, arg));
if (!plan_getcfg)
ts_error(ERROR, "SPI_prepare() failed"); ts_error(ERROR, "SPI_prepare() failed");
} }
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)
); );
oldcontext = MemoryContextSwitchTo(TopMemoryContext); oldcontext = MemoryContextSwitchTo(TopMemoryContext);
prsname = ptextdup( prsname ); prsname = ptextdup(prsname);
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 ) ); {
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));
if (!plan_getmap)
ts_error(ERROR, "SPI_prepare() failed"); ts_error(ERROR, "SPI_prepare() failed");
} }
pars[0]=PointerGetDatum( prsname ); pars[0] = PointerGetDatum(prsname);
stat = SPI_execp(plan_getmap, pars, " ", 0); stat = SPI_execp(plan_getmap, pars, " ", 0);
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)
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->map = (ListDictionary*)malloc( sizeof(ListDictionary)*cfg->len ); cfg->len = lexid + 1;
if ( !cfg->map ) cfg->map = (ListDictionary *) malloc(sizeof(ListDictionary) * cfg->len);
if (!cfg->map)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OUT_OF_MEMORY), (errcode(ERRCODE_OUT_OF_MEMORY),
errmsg("out of memory"))); errmsg("out of memory")));
memset( cfg->map, 0, sizeof(ListDictionary)*cfg->len ); memset(cfg->map, 0, sizeof(ListDictionary) * cfg->len);
} }
if (isnull) if (isnull)
continue; continue;
a=(ArrayType*)PointerGetDatum( PG_DETOAST_DATUM( DatumGetPointer(toasted_a) ) ); a = (ArrayType *) PointerGetDatum(PG_DETOAST_DATUM(DatumGetPointer(toasted_a)));
if ( ARR_NDIM(a) != 1 ) if (ARR_NDIM(a) != 1)
ts_error(ERROR,"Wrong dimension"); ts_error(ERROR, "Wrong dimension");
if ( ARRNELEMS(a) < 1 ) if (ARRNELEMS(a) < 1)
continue; continue;
cfg->map[lexid].len=ARRNELEMS(a); cfg->map[lexid].len = ARRNELEMS(a);
cfg->map[lexid].dict_id=(Datum*)malloc( sizeof(Datum)*cfg->map[lexid].len ); cfg->map[lexid].dict_id = (Datum *) malloc(sizeof(Datum) * cfg->map[lexid].len);
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);
} }
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
if ( a != toasted_a ) if (a != toasted_a)
pfree(a); pfree(a);
} }
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++) { {
ptr = (text*)DatumGetPointer( cfg->map[i].dict_id[j] ); for (j = 0; j < cfg->map[i].len; j++)
cfg->map[i].dict_id[j] = ObjectIdGetDatum( name2id_dict(ptr) ); {
ptr = (text *) DatumGetPointer(cfg->map[i].dict_id[j]);
cfg->map[i].dict_id[j] = ObjectIdGetDatum(name2id_dict(ptr));
pfree(ptr); pfree(ptr);
} }
} }
} }
typedef struct { typedef struct
{
TSCfgInfo *last_cfg; TSCfgInfo *last_cfg;
int len; int len;
int reallen; int reallen;
@ -136,110 +149,128 @@ typedef struct {
SNMap name2id_map; SNMap name2id_map;
} CFGList; } CFGList;
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) ); {
if ( CList.list ) { freeSNMap(&(CList.name2id_map));
int i,j; if (CList.list)
for(i=0;i<CList.len;i++) {
if ( CList.list[i].map ) { int i,
for(j=0;j<CList.list[i].len;j++) j;
if ( CList.list[i].map[j].dict_id )
for (i = 0; i < CList.len; i++)
if (CList.list[i].map)
{
for (j = 0; j < CList.list[i].len; j++)
if (CList.list[i].map[j].dict_id)
free(CList.list[i].map[j].dict_id); free(CList.list[i].map[j].dict_id);
free( CList.list[i].map ); free(CList.list[i].map);
} }
free(CList.list); free(CList.list);
} }
memset(&CList,0,sizeof(CFGList)); memset(&CList, 0, sizeof(CFGList));
} }
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)
return CList.last_cfg; return CList.last_cfg;
} }
/* 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);
if ( !tmp ) tmp = (TSCfgInfo *) realloc(CList.list, sizeof(TSCfgInfo) * reallen);
ts_error(ERROR,"No memory"); if (!tmp)
CList.reallen=reallen; ts_error(ERROR, "No memory");
CList.list=tmp; CList.reallen = reallen;
CList.list = tmp;
} }
CList.last_cfg=&(CList.list[CList.len]); CList.last_cfg = &(CList.list[CList.len]);
init_cfg(id, CList.last_cfg); init_cfg(id, CList.last_cfg);
CList.len++; CList.len++;
qsort(CList.list, CList.len, sizeof(TSCfgInfo), comparecfg); qsort(CList.list, CList.len, sizeof(TSCfgInfo), comparecfg);
return findcfg(id); /* qsort changed order!! */; return findcfg(id); /* qsort changed order!! */ ;
} }
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)};
int stat; int stat;
Oid id=findSNMap_t( &(CList.name2id_map), name ); Oid id = findSNMap_t(&(CList.name2id_map), name);
if ( id ) if (id)
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 ) ); {
if ( !plan_name2id ) plan_name2id = SPI_saveplan(SPI_prepare("select oid from pg_ts_cfg where ts_name = $1", 1, arg));
if (!plan_name2id)
/* internal error */ /* internal error */
elog(ERROR, "SPI_prepare() failed"); elog(ERROR, "SPI_prepare() failed");
} }
stat = SPI_execp(plan_name2id, pars, " ", 1); stat = SPI_execp(plan_name2id, pars, " ", 1);
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) ); {
if ( isnull ) id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &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")));
SPI_finish(); SPI_finish();
addSNMap_t( &(CList.name2id_map), name, id ); addSNMap_t(&(CList.name2id_map), name, id);
return id; return id;
} }
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; {
char *lemm=NULL; int type,
lenlemm,
i;
char *lemm = NULL;
WParserInfo *prsobj = findprs(cfg->prs_id); WParserInfo *prsobj = findprs(cfg->prs_id);
prsobj->prs=(void*)DatumGetPointer( prsobj->prs = (void *) DatumGetPointer(
FunctionCall2( FunctionCall2(
&(prsobj->start_info), &(prsobj->start_info),
PointerGetDatum(buf), PointerGetDatum(buf),
@ -247,25 +278,28 @@ parsetext_v2(TSCfgInfo *cfg, PRSTEXT * prs, char *buf, int4 buflen) {
) )
); );
while( ( type=DatumGetInt32(FunctionCall3( while ((type = DatumGetInt32(FunctionCall3(
&(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,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("word is too long"))); errmsg("word is too long")));
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]) ); {
char **norms, **ptr; DictInfo *dict = finddict(DatumGetObjectId(cfg->map[type].dict_id[i]));
char **norms,
**ptr;
norms = ptr = (char**)DatumGetPointer( norms = ptr = (char **) DatumGetPointer(
FunctionCall3( FunctionCall3(
&(dict->lexize_info), &(dict->lexize_info),
PointerGetDatum(dict->dictionary), PointerGetDatum(dict->dictionary),
@ -273,13 +307,15 @@ parsetext_v2(TSCfgInfo *cfg, PRSTEXT * prs, char *buf, int4 buflen) {
PointerGetDatum(lenlemm) PointerGetDatum(lenlemm)
) )
); );
if ( !norms ) /* dictionary doesn't know this lexem */ if (!norms) /* dictionary doesn't know this lexem */
continue; continue;
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,13 +340,15 @@ 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));
} }
memset( &(prs->words[prs->curwords]), 0, sizeof(HLWORD) ); memset(&(prs->words[prs->curwords]), 0, sizeof(HLWORD));
prs->words[prs->curwords].type = (uint8)type; prs->words[prs->curwords].type = (uint8) type;
prs->words[prs->curwords].len = buflen; prs->words[prs->curwords].len = buflen;
prs->words[prs->curwords].word = palloc(buflen); prs->words[prs->curwords].word = palloc(buflen);
memcpy(prs->words[prs->curwords].word, buf, buflen); memcpy(prs->words[prs->curwords].word, buf, buflen);
@ -317,37 +356,46 @@ 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)
memcpy( &(prs->words[prs->curwords]), word, sizeof(HLWORD) ); {
prs->words[prs->curwords].item=item; if (word->item)
prs->words[prs->curwords].repeated=1; {
memcpy(&(prs->words[prs->curwords]), word, sizeof(HLWORD));
prs->words[prs->curwords].item = item;
prs->words[prs->curwords].repeated = 1;
prs->curwords++; prs->curwords++;
} else }
word->item=item; else
word->item = item;
} }
item++; item++;
} }
} }
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; {
char *lemm=NULL; int type,
lenlemm,
i;
char *lemm = NULL;
WParserInfo *prsobj = findprs(cfg->prs_id); WParserInfo *prsobj = findprs(cfg->prs_id);
prsobj->prs=(void*)DatumGetPointer( prsobj->prs = (void *) DatumGetPointer(
FunctionCall2( FunctionCall2(
&(prsobj->start_info), &(prsobj->start_info),
PointerGetDatum(buf), PointerGetDatum(buf),
@ -355,27 +403,30 @@ hlparsetext(TSCfgInfo *cfg, HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int4 b
) )
); );
while( ( type=DatumGetInt32(FunctionCall3( while ((type = DatumGetInt32(FunctionCall3(
&(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,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("word is too long"))); errmsg("word is too long")));
hladdword(prs,lemm,lenlemm,type); hladdword(prs, lemm, lenlemm, type);
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]) ); {
char **norms, **ptr; DictInfo *dict = finddict(DatumGetObjectId(cfg->map[type].dict_id[i]));
char **norms,
**ptr;
norms = ptr = (char**)DatumGetPointer( norms = ptr = (char **) DatumGetPointer(
FunctionCall3( FunctionCall3(
&(dict->lexize_info), &(dict->lexize_info),
PointerGetDatum(dict->dictionary), PointerGetDatum(dict->dictionary),
@ -383,16 +434,18 @@ hlparsetext(TSCfgInfo *cfg, HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int4 b
PointerGetDatum(lenlemm) PointerGetDatum(lenlemm)
) )
); );
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 */
} }
} }
@ -402,80 +455,92 @@ 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;
HLWORD *wrd=prs->words; HLWORD *wrd = prs->words;
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 ) { {
int dist = ptr - ((char*)out); while (wrd->len + prs->stopsellen + prs->startsellen + (ptr - ((char *) out)) >= len)
len*= 2; {
int dist = ptr - ((char *) out);
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 ) { {
*ptr=' '; if (wrd->replace)
{
*ptr = ' ';
ptr++; ptr++;
} else {
if (wrd->selected) {
memcpy(ptr,prs->startsel,prs->startsellen);
ptr+=prs->startsellen;
} }
memcpy(ptr,wrd->word,wrd->len); else
ptr+=wrd->len; {
if (wrd->selected) { if (wrd->selected)
memcpy(ptr,prs->stopsel,prs->stopsellen); {
ptr+=prs->stopsellen; memcpy(ptr, prs->startsel, prs->startsellen);
ptr += prs->startsellen;
}
memcpy(ptr, wrd->word, wrd->len);
ptr += wrd->len;
if (wrd->selected)
{
memcpy(ptr, prs->stopsel, prs->stopsellen);
ptr += prs->stopsellen;
} }
} }
} }
if ( !wrd->repeated ) if (!wrd->repeated)
pfree(wrd->word); pfree(wrd->word);
wrd++; wrd++;
} }
VARATT_SIZEP(out)=ptr - ((char*)out); VARATT_SIZEP(out) = ptr - ((char *) out);
return out; return out;
} }
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];
bool isnull; bool isnull;
int stat; int stat;
if ( current_cfg_id > 0 ) if (current_cfg_id > 0)
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 ) ); {
if ( !plan_getcfg_bylocale ) plan_getcfg_bylocale = SPI_saveplan(SPI_prepare("select oid from pg_ts_cfg where locale = $1 ", 1, arg));
if (!plan_getcfg_bylocale)
/* internal error */ /* internal error */
elog(ERROR, "SPI_prepare() failed"); elog(ERROR, "SPI_prepare() failed");
} }
curlocale = setlocale(LC_CTYPE, NULL); curlocale = setlocale(LC_CTYPE, NULL);
pars[0] = PointerGetDatum( char2text((char*)curlocale) ); pars[0] = PointerGetDatum(char2text((char *) curlocale));
stat = SPI_execp(plan_getcfg_bylocale, pars, " ", 1); stat = SPI_execp(plan_getcfg_bylocale, pars, " ", 1);
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)
current_cfg_id = DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) ); current_cfg_id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
else else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_CONFIG_FILE_ERROR), (errcode(ERRCODE_CONFIG_FILE_ERROR),
@ -489,21 +554,23 @@ 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();
} }
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(
set_curcfg, set_curcfg,
ObjectIdGetDatum( name2id_cfg(name) ) ObjectIdGetDatum(name2id_cfg(name))
); );
PG_FREE_IF_COPY(name, 0); PG_FREE_IF_COPY(name, 0);
PG_RETURN_VOID(); PG_RETURN_VOID();
@ -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();
} }

View File

@ -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;
@ -16,13 +18,15 @@ typedef struct {
} TSCfgInfo; } TSCfgInfo;
Oid name2id_cfg(text *name); Oid name2id_cfg(text *name);
TSCfgInfo * findcfg(Oid id); 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;
@ -59,10 +66,10 @@ typedef struct {
int2 stopsellen; int2 stopsellen;
} HLPRSTEXT; } HLPRSTEXT;
void hlparsetext(TSCfgInfo *cfg, HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int4 buflen); void hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4 buflen);
text* genhl(HLPRSTEXT * prs); text *genhl(HLPRSTEXT * prs);
void parsetext_v2(TSCfgInfo *cfg, PRSTEXT * prs, char *buf, int4 buflen); void parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen);
int get_currcfg(void); int get_currcfg(void);
#endif #endif

View File

@ -12,106 +12,126 @@
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); {
stat->len=STATHDRSIZE; tsstat *stat = palloc(STATHDRSIZE);
stat->size=0;
stat->len = STATHDRSIZE;
stat->size = 0;
PG_RETURN_POINTER(stat); PG_RETURN_POINTER(stat);
} }
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")));
PG_RETURN_NULL(); PG_RETURN_NULL();
} }
static WordEntry** static WordEntry **
SEI_realloc( WordEntry** in, uint32 *len ) { SEI_realloc(WordEntry ** in, uint32 *len)
if ( *len==0 || in==NULL ) { {
*len=8; if (*len == 0 || in == NULL)
in=palloc( sizeof(WordEntry*)* (*len) ); {
} else { *len = 8;
in = palloc(sizeof(WordEntry *) * (*len));
}
else
{
*len *= 2; *len *= 2;
in=repalloc( in, sizeof(WordEntry*)* (*len) ); in = repalloc(in, sizeof(WordEntry *) * (*len));
} }
return in; return in;
} }
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,
STRPTR(txt) + b->pos, STRPTR(txt) + b->pos,
a->len a->len
); );
return ( a->len > b->len ) ? 1 : -1; return (a->len > b->len) ? 1 : -1;
} }
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,
uint32 slen=0; nentry;
WordEntry **ptr=entry; uint32 slen = 0;
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++;
} }
nentry=stat->size + len; nentry = stat->size + len;
slen+=STATSTRSIZE(stat); slen += STATSTRSIZE(stat);
totallen=CALCSTATSIZE(nentry,slen); totallen = CALCSTATSIZE(nentry, slen);
newstat=palloc(totallen); newstat = palloc(totallen);
newstat->len=totallen; newstat->len = totallen;
newstat->size=nentry; newstat->size = nentry;
memcpy(STATSTRPTR(newstat), STATSTRPTR(stat), STATSTRSIZE(stat)); memcpy(STATSTRPTR(newstat), STATSTRPTR(stat), STATSTRSIZE(stat));
curptr=STATSTRPTR(newstat) + STATSTRSIZE(stat); curptr = STATSTRPTR(newstat) + STATSTRSIZE(stat);
ptr=entry; ptr = entry;
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; {
if ( compareStatWord(sptr,*ptr,stat,txt) < 0 ) sptr = StopLow + (StopHigh - StopLow) / 2;
if (compareStatWord(sptr, *ptr, stat, txt) < 0)
StopLow = sptr + 1; StopLow = sptr + 1;
else else
StopHigh = sptr; StopHigh = sptr;
} }
nptr =STATPTR(newstat) + (StopLow-STATPTR(stat)); nptr = STATPTR(newstat) + (StopLow - STATPTR(stat));
memcpy( STATPTR(newstat), STATPTR(stat), sizeof(StatEntry) * (StopLow-STATPTR(stat)) ); memcpy(STATPTR(newstat), STATPTR(stat), sizeof(StatEntry) * (StopLow - STATPTR(stat)));
nptr->nentry=POSDATALEN(txt,*ptr); nptr->nentry = POSDATALEN(txt, *ptr);
if ( nptr->nentry==0 ) if (nptr->nentry == 0)
nptr->nentry=1; nptr->nentry = 1;
nptr->ndoc=1; nptr->ndoc = 1;
nptr->len=(*ptr)->len; nptr->len = (*ptr)->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 { }
nptr->nentry=POSDATALEN(txt,*ptr); else
if ( nptr->nentry==0 ) {
nptr->nentry=1; nptr->nentry = POSDATALEN(txt, *ptr);
nptr->ndoc=1; if (nptr->nentry == 0)
nptr->len=(*ptr)->len; nptr->nentry = 1;
nptr->ndoc = 1;
nptr->len = (*ptr)->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;
@ -120,18 +140,20 @@ formstat(tsstat *stat, tsvector *txt, WordEntry** entry, uint32 len) {
nptr++; nptr++;
} }
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); {
if ( nptr->nentry==0 ) nptr->nentry = POSDATALEN(txt, *ptr);
nptr->nentry=1; if (nptr->nentry == 0)
nptr->ndoc=1; nptr->nentry = 1;
nptr->len=(*ptr)->len; nptr->ndoc = 1;
nptr->len = (*ptr)->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,80 +163,105 @@ 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))
stat=palloc(STATHDRSIZE); { /* Init in first */
stat->len=STATHDRSIZE; stat = palloc(STATHDRSIZE);
stat->size=0; stat->len = STATHDRSIZE;
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);
} }
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 */
int cmp = compareStatWord(sptr,wptr,stat,txt); while (sptr - STATPTR(stat) < stat->size && wptr - ARRPTR(txt) < txt->size)
if ( cmp<0 ) { {
int cmp = compareStatWord(sptr, wptr, stat, txt);
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++;
if ( cur==len ) }
newentry=SEI_realloc(newentry, &len); else
newentry[cur]=wptr; {
wptr++; cur++; if (cur == len)
newentry = SEI_realloc(newentry, &len);
newentry[cur] = wptr;
wptr++;
cur++;
} }
} }
while( wptr-ARRPTR(txt) < txt->size ) { while (wptr - ARRPTR(txt) < txt->size)
if ( cur==len ) {
newentry=SEI_realloc(newentry, &len); if (cur == len)
newentry[cur]=wptr; newentry = SEI_realloc(newentry, &len);
wptr++; cur++; newentry[cur] = wptr;
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; {
cmp = compareStatWord(sptr,wptr,stat,txt); sptr = StopLow + (StopHigh - StopLow) / 2;
if (cmp==0) { cmp = compareStatWord(sptr, wptr, stat, txt);
int n=POSDATALEN(txt,wptr); if (cmp == 0)
if (n==0) n=1; {
int n = POSDATALEN(txt, wptr);
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)
if ( cur==len ) { /* not found */
newentry=SEI_realloc(newentry, &len); if (cur == len)
newentry[cur]=wptr; newentry = SEI_realloc(newentry, &len);
newentry[cur] = wptr;
cur++; cur++;
} }
wptr++; wptr++;
@ -222,36 +269,39 @@ ts_accum(PG_FUNCTION_ARGS) {
} }
if ( cur==0 ) { /* no new words */ if (cur == 0)
PG_FREE_IF_COPY(txt,1); { /* no new words */
PG_FREE_IF_COPY(txt, 1);
PG_RETURN_POINTER(stat); PG_RETURN_POINTER(stat);
} }
newstat = formstat(stat, txt, newentry, cur); newstat = formstat(stat, txt, newentry, cur);
pfree(newentry); pfree(newentry);
PG_FREE_IF_COPY(txt,1); PG_FREE_IF_COPY(txt, 1);
/* pfree(stat); */ /* pfree(stat); */
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;
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
st=palloc( sizeof(StatStorage) ); st = palloc(sizeof(StatStorage));
st->cur=0; st->cur = 0;
st->stat=palloc( stat->len ); st->stat = palloc(stat->len);
memcpy(st->stat, stat, stat->len); memcpy(st->stat, stat, stat->len);
funcctx->user_fctx = (void*)st; funcctx->user_fctx = (void *) st;
tupdesc = RelationNameGetTupleDesc("statinfo"); tupdesc = RelationNameGetTupleDesc("statinfo");
funcctx->slot = TupleDescGetSlot(tupdesc); funcctx->slot = TupleDescGetSlot(tupdesc);
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
@ -260,25 +310,28 @@ 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;
if ( st->cur < st->stat->size ) { st = (StatStorage *) funcctx->user_fctx;
if (st->cur < st->stat->size)
{
Datum result; Datum result;
char* values[3]; char *values[3];
char ndoc[16]; char ndoc[16];
char nentry[16]; char nentry[16];
StatEntry *entry=STATPTR(st->stat) + st->cur; StatEntry *entry = STATPTR(st->stat) + st->cur;
HeapTuple tuple; HeapTuple tuple;
values[1]=ndoc; values[1] = ndoc;
sprintf(ndoc,"%d",entry->ndoc); sprintf(ndoc, "%d", entry->ndoc);
values[2]=nentry; values[2] = nentry;
sprintf(nentry,"%d",entry->nentry); sprintf(nentry, "%d", entry->nentry);
values[0]=palloc( entry->len+1 ); values[0] = palloc(entry->len + 1);
memcpy( values[0], STATSTRPTR(st->stat)+entry->pos, entry->len); memcpy(values[0], STATSTRPTR(st->stat) + entry->pos, entry->len);
(values[0])[entry->len]='\0'; (values[0])[entry->len] = '\0';
tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
result = TupleGetDatum(funcctx->slot, tuple); result = TupleGetDatum(funcctx->slot, tuple);
@ -286,98 +339,108 @@ 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);
} }
return (Datum)0; return (Datum) 0;
} }
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));
} }
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
if ( (result=ts_process_call(funcctx)) != (Datum)0 ) if ((result = ts_process_call(funcctx)) != (Datum) 0)
SRF_RETURN_NEXT(funcctx, result); SRF_RETURN_NEXT(funcctx, result);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }
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;
if ( (ret = SPI_exec("select oid from pg_type where typname='tsvector'",1)) < 0 ) if ((ret = SPI_exec("select oid from pg_type where typname='tsvector'", 1)) < 0)
/* internal error */ /* internal error */
elog(ERROR, "SPI_exec to get tsvector oid returns %d", ret); elog(ERROR, "SPI_exec to get tsvector oid returns %d", ret);
if ( SPI_processed<0 ) if (SPI_processed < 0)
/* internal error */ /* internal error */
elog(ERROR, "There is no tsvector type"); elog(ERROR, "There is no tsvector type");
tiOid = DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) ); tiOid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
if ( tiOid==InvalidOid ) if (tiOid == InvalidOid)
/* internal error */ /* internal error */
elog(ERROR, "tsvector type has InvalidOid"); elog(ERROR, "tsvector type has InvalidOid");
} }
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;
if ( tiOid==InvalidOid ) if (tiOid == InvalidOid)
get_ti_Oid(); get_ti_Oid();
if ( (plan = SPI_prepare(query,0,NULL))==NULL ) if ((plan = SPI_prepare(query, 0, NULL)) == NULL)
/* internal error */ /* internal error */
elog(ERROR, "SPI_prepare('%s') returns NULL",query); elog(ERROR, "SPI_prepare('%s') returns NULL", query);
if ( (portal = SPI_cursor_open(NULL, plan, NULL, NULL)) == NULL ) if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL)) == NULL)
/* internal error */ /* internal error */
elog(ERROR, "SPI_cursor_open('%s') returns NULL",query); elog(ERROR, "SPI_cursor_open('%s') returns NULL", query);
SPI_cursor_fetch(portal, true, 100); SPI_cursor_fetch(portal, true, 100);
if ( SPI_tuptable->tupdesc->natts != 1 ) if (SPI_tuptable->tupdesc->natts != 1)
/* internal error */ /* internal error */
elog(ERROR, "number of fields doesn't equal to 1"); elog(ERROR, "number of fields doesn't equal to 1");
if ( SPI_gettypeid(SPI_tuptable->tupdesc, 1) != tiOid ) if (SPI_gettypeid(SPI_tuptable->tupdesc, 1) != tiOid)
/* internal error */ /* internal error */
elog(ERROR, "column isn't of tsvector type"); elog(ERROR, "column isn't of tsvector type");
stat=palloc(STATHDRSIZE); stat = palloc(STATHDRSIZE);
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++) { {
Datum data=SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull); for (i = 0; i < SPI_processed; i++)
{
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),
data data
)); ));
if ( stat!=newstat && stat ) if (stat != newstat && stat)
pfree(stat); pfree(stat);
stat=newstat; stat = newstat;
} }
} }
@ -396,26 +459,26 @@ 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);
funcctx = SRF_FIRSTCALL_INIT(); funcctx = SRF_FIRSTCALL_INIT();
SPI_connect(); SPI_connect();
stat = ts_stat_sql(txt); stat = ts_stat_sql(txt);
PG_FREE_IF_COPY(txt,0); PG_FREE_IF_COPY(txt, 0);
ts_setup_firstcall(funcctx, stat ); ts_setup_firstcall(funcctx, stat);
SPI_finish(); SPI_finish();
} }
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
if ( (result=ts_process_call(funcctx)) != (Datum)0 ) if ((result = ts_process_call(funcctx)) != (Datum) 0)
SRF_RETURN_NEXT(funcctx, result); SRF_RETURN_NEXT(funcctx, result);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }

View File

@ -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];

View File

@ -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,31 +48,37 @@ 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)
return l; return 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++;
} }
@ -81,14 +89,14 @@ static char *BufferStr;
static int static int
compareentry(const void *a, const void *b) compareentry(const void *a, const void *b)
{ {
if ( ((WordEntryIN *) a)->entry.len == ((WordEntryIN *) b)->entry.len) if (((WordEntryIN *) a)->entry.len == ((WordEntryIN *) b)->entry.len)
{ {
return strncmp( return strncmp(
&BufferStr[((WordEntryIN *) a)->entry.pos], &BufferStr[((WordEntryIN *) a)->entry.pos],
&BufferStr[((WordEntryIN *) b)->entry.pos], &BufferStr[((WordEntryIN *) b)->entry.pos],
((WordEntryIN *) a)->entry.len); ((WordEntryIN *) a)->entry.len);
} }
return ( ((WordEntryIN *) a)->entry.len > ((WordEntryIN *) b)->entry.len ) ? 1 : -1; return (((WordEntryIN *) a)->entry.len > ((WordEntryIN *) b)->entry.len) ? 1 : -1;
} }
static int static int
@ -98,10 +106,12 @@ 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 ) { {
*(uint16*)(a->pos) = uniquePos( &(a->pos[1]), *(uint16*)(a->pos)); if (a->entry.haspos)
*outbuflen = SHORTALIGN(res->entry.len) + (*(uint16*)(a->pos) +1 )*sizeof(WordEntryPos); {
*(uint16 *) (a->pos) = uniquePos(&(a->pos[1]), *(uint16 *) (a->pos));
*outbuflen = SHORTALIGN(res->entry.len) + (*(uint16 *) (a->pos) + 1) * sizeof(WordEntryPos);
} }
return l; return l;
} }
@ -115,31 +125,39 @@ 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)); {
*outbuflen += *(uint16*)(res->pos) * sizeof(WordEntryPos); *(uint16 *) (res->pos) = uniquePos(&(res->pos[1]), *(uint16 *) (res->pos));
*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)
int4 len=*(uint16*)(ptr->pos) + 1 + *(uint16*)(res->pos); {
res->pos=(WordEntryPos*)repalloc( res->pos, len*sizeof(WordEntryPos)); if (res->entry.haspos)
memcpy( &(res->pos[ *(uint16*)(res->pos) + 1 ]), {
&(ptr->pos[1]), *(uint16*)(ptr->pos) * sizeof(WordEntryPos)); int4 len = *(uint16 *) (ptr->pos) + 1 + *(uint16 *) (res->pos);
*(uint16*)(res->pos) += *(uint16*)(ptr->pos);
pfree( ptr->pos ); res->pos = (WordEntryPos *) repalloc(res->pos, len * sizeof(WordEntryPos));
} else { memcpy(&(res->pos[*(uint16 *) (res->pos) + 1]),
res->entry.haspos=1; &(ptr->pos[1]), *(uint16 *) (ptr->pos) * sizeof(WordEntryPos));
*(uint16 *) (res->pos) += *(uint16 *) (ptr->pos);
pfree(ptr->pos);
}
else
{
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)); {
*outbuflen += *(uint16*)(res->pos) * sizeof(WordEntryPos); *(uint16 *) (res->pos) = uniquePos(&(res->pos[1]), *(uint16 *) (res->pos));
*outbuflen += *(uint16 *) (res->pos) * sizeof(WordEntryPos);
} }
*outbuflen += SHORTALIGN(res->entry.len); *outbuflen += SHORTALIGN(res->entry.len);
@ -172,7 +190,7 @@ gettoken_tsvector(TI_IN_STATE * state)
state->curpos = state->word; state->curpos = state->word;
state->state = WAITWORD; state->state = WAITWORD;
state->alen=0; state->alen = 0;
while (1) while (1)
{ {
@ -229,13 +247,15 @@ 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),
errmsg("syntax error"))); errmsg("syntax error")));
*(state->curpos) = '\0'; *(state->curpos) = '\0';
if ( state->oprisdelim ) if (state->oprisdelim)
return 1; return 1;
else else
state->state = INPOSINFO; state->state = INPOSINFO;
@ -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,67 +300,87 @@ gettoken_tsvector(TI_IN_STATE * state)
*(state->curpos) = *(state->prsbuf); *(state->curpos) = *(state->prsbuf);
state->curpos++; state->curpos++;
} }
} else if (state->state == WAITPOSINFO) { }
if ( *(state->prsbuf) == ':' ) else if (state->state == WAITPOSINFO)
state->state=INPOSINFO; {
if (*(state->prsbuf) == ':')
state->state = INPOSINFO;
else else
return 1; return 1;
} else if (state->state == INPOSINFO) {
if ( isdigit(*(state->prsbuf)) ) {
if ( state->alen==0 ) {
state->alen=4;
state->pos = (WordEntryPos*)palloc( sizeof(WordEntryPos)*state->alen );
*(uint16*)(state->pos)=0;
} else if ( *(uint16*)(state->pos) +1 >= state->alen ) {
state->alen *= 2;
state->pos = (WordEntryPos*)repalloc( state->pos, sizeof(WordEntryPos)*state->alen );
} }
( *(uint16*)(state->pos) )++; else if (state->state == INPOSINFO)
state->pos[ *(uint16*)(state->pos) ].pos = LIMITPOS(atoi(state->prsbuf)); {
if ( state->pos[ *(uint16*)(state->pos) ].pos == 0 ) if (isdigit(*(state->prsbuf)))
{
if (state->alen == 0)
{
state->alen = 4;
state->pos = (WordEntryPos *) palloc(sizeof(WordEntryPos) * state->alen);
*(uint16 *) (state->pos) = 0;
}
else if (*(uint16 *) (state->pos) + 1 >= state->alen)
{
state->alen *= 2;
state->pos = (WordEntryPos *) repalloc(state->pos, sizeof(WordEntryPos) * state->alen);
}
(*(uint16 *) (state->pos))++;
state->pos[*(uint16 *) (state->pos)].pos = LIMITPOS(atoi(state->prsbuf));
if (state->pos[*(uint16 *) (state->pos)].pos == 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
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' ) { }
if ( state->pos[ *(uint16*)(state->pos) ].weight ) else if (tolower(*(state->prsbuf)) == 'b')
{
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' ) { }
if ( state->pos[ *(uint16*)(state->pos) ].weight ) else if (tolower(*(state->prsbuf)) == 'c')
{
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' ) { }
if ( state->pos[ *(uint16*)(state->pos) ].weight ) else if (tolower(*(state->prsbuf)) == 'd')
{
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++;
@ -388,28 +430,30 @@ tsvector_in(PG_FUNCTION_ARGS)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("word is too long"))); errmsg("word is too long")));
arr[len].entry.len= state.curpos - state.word; arr[len].entry.len = state.curpos - state.word;
if (cur - tmpbuf > MAXSTRPOS) if (cur - tmpbuf > MAXSTRPOS)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("too long value"))); errmsg("too long value")));
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 }
arr[len].entry.haspos=0; else
arr[len].entry.haspos = 0;
len++; len++;
} }
pfree(state.word); pfree(state.word);
if ( len > 0 ) if (len > 0)
len = uniqueentry(arr, len, tmpbuf, &buflen); len = uniqueentry(arr, len, tmpbuf, &buflen);
totallen = CALCDATASIZE(len, buflen); totallen = CALCDATASIZE(len, buflen);
in = (tsvector *) palloc(totallen); in = (tsvector *) palloc(totallen);
memset(in,0,totallen); memset(in, 0, totallen);
in->len = totallen; in->len = totallen;
in->size = len; in->size = len;
cur = STRPTR(in); cur = STRPTR(in);
@ -417,14 +461,15 @@ tsvector_in(PG_FUNCTION_ARGS)
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
{ {
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)); {
cur += (*(uint16*)arr[i].pos + 1) * sizeof(WordEntryPos); memcpy(cur, arr[i].pos, (*(uint16 *) arr[i].pos + 1) * sizeof(WordEntryPos));
pfree( arr[i].pos ); cur += (*(uint16 *) arr[i].pos + 1) * sizeof(WordEntryPos);
pfree(arr[i].pos);
} }
memcpy( &(inarr[i]), &(arr[i].entry), sizeof(WordEntry) ); memcpy(&(inarr[i]), &(arr[i].entry), sizeof(WordEntry));
} }
pfree(tmpbuf); pfree(tmpbuf);
pfree(arr); pfree(arr);
@ -448,22 +493,24 @@ 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 */; {
if ( ptr[i].haspos ) lenbuf += ptr[i].len * 2 /* for escape */ ;
lenbuf += 7*POSDATALEN(out, &(ptr[i])); if (ptr[i].haspos)
lenbuf += 7 * POSDATALEN(out, &(ptr[i]));
} }
curout = outbuf = (char *) palloc(lenbuf); curout = outbuf = (char *) palloc(lenbuf);
for (i = 0; i < out->size; i++) for (i = 0; i < out->size; i++)
{ {
curin = STRPTR(out)+ptr->pos; curin = STRPTR(out) + ptr->pos;
if (i != 0) if (i != 0)
*curout++ = ' '; *curout++ = ' ';
*curout++ = '\''; *curout++ = '\'';
@ -481,27 +528,40 @@ 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); {
curout=strchr(curout,'\0'); sprintf(curout, "%d", wptr->pos);
switch( wptr->weight ) { curout = strchr(curout, '\0');
case 3: *curout++ = 'A'; break; switch (wptr->weight)
case 2: *curout++ = 'B'; break; {
case 1: *curout++ = 'C'; break; case 3:
*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++;
} }
*curout='\0'; *curout = '\0';
outbuf[lenbuf - 1] = '\0'; outbuf[lenbuf - 1] = '\0';
PG_FREE_IF_COPY(out, 0); PG_FREE_IF_COPY(out, 0);
PG_RETURN_POINTER(outbuf); PG_RETURN_POINTER(outbuf);
@ -510,13 +570,15 @@ 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 )
return ( ((WORD *) a)->pos.pos > ((WORD *) b)->pos.pos ) ? 1 : -1; if (res == 0)
return (((WORD *) a)->pos.pos > ((WORD *) b)->pos.pos) ? 1 : -1;
return res; return res;
} }
return (((WORD *) a)->len > ((WORD *) b)->len) ? 1 : -1; return (((WORD *) a)->len > ((WORD *) b)->len) ? 1 : -1;
@ -529,12 +591,13 @@ uniqueWORD(WORD * a, int4 l)
*res; *res;
int tmppos; int tmppos;
if (l == 1) { if (l == 1)
tmppos=LIMITPOS(a->pos.pos); {
a->alen=2; tmppos = LIMITPOS(a->pos.pos);
a->pos.apos=(uint16*)palloc( sizeof(uint16)*a->alen ); a->alen = 2;
a->pos.apos[0]=1; a->pos.apos = (uint16 *) palloc(sizeof(uint16) * a->alen);
a->pos.apos[1]=tmppos; a->pos.apos[0] = 1;
a->pos.apos[1] = tmppos;
return l; return l;
} }
@ -542,11 +605,11 @@ uniqueWORD(WORD * a, int4 l)
ptr = a + 1; ptr = a + 1;
qsort((void *) a, l, sizeof(WORD), compareWORD); qsort((void *) a, l, sizeof(WORD), compareWORD);
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);
a->pos.apos[0]=1; a->pos.apos[0] = 1;
a->pos.apos[1]=tmppos; a->pos.apos[1] = tmppos;
while (ptr - a < l) while (ptr - a < l)
{ {
@ -556,19 +619,23 @@ uniqueWORD(WORD * a, int4 l)
res++; res++;
res->len = ptr->len; res->len = ptr->len;
res->word = ptr->word; res->word = ptr->word;
tmppos=LIMITPOS(ptr->pos.pos); tmppos = LIMITPOS(ptr->pos.pos);
res->alen=2; res->alen = 2;
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 {
pfree(ptr->word);
if ( res->pos.apos[0] < MAXNUMPOS-1 && res->pos.apos[ res->pos.apos[0] ] != MAXENTRYPOS-1 ) {
if ( res->pos.apos[0]+1 >= res->alen ) {
res->alen*=2;
res->pos.apos=(uint16*)repalloc( res->pos.apos, sizeof(uint16)*res->alen );
} }
res->pos.apos[ res->pos.apos[0]+1 ] = LIMITPOS(ptr->pos.pos); else
{
pfree(ptr->word);
if (res->pos.apos[0] < MAXNUMPOS - 1 && res->pos.apos[res->pos.apos[0]] != MAXENTRYPOS - 1)
{
if (res->pos.apos[0] + 1 >= res->alen)
{
res->alen *= 2;
res->pos.apos = (uint16 *) repalloc(res->pos.apos, sizeof(uint16) * res->alen);
}
res->pos.apos[res->pos.apos[0] + 1] = LIMITPOS(ptr->pos.pos);
res->pos.apos[0]++; res->pos.apos[0]++;
} }
} }
@ -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,16 +661,17 @@ 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)
lenstr += sizeof(uint16) + prs->words[i].pos.apos[0] * sizeof(WordEntryPos); lenstr += sizeof(uint16) + prs->words[i].pos.apos[0] * sizeof(WordEntryPos);
} }
totallen = CALCDATASIZE(prs->curwords, lenstr); totallen = CALCDATASIZE(prs->curwords, lenstr);
in = (tsvector *) palloc(totallen); in = (tsvector *) palloc(totallen);
memset(in,0,totallen); memset(in, 0, totallen);
in->len = totallen; in->len = totallen;
in->size = prs->curwords; in->size = prs->curwords;
@ -615,24 +684,27 @@ makevalue(PRSTEXT * prs)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("value is too big"))); errmsg("value is too big")));
ptr->pos= cur - str; ptr->pos = cur - str;
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].pos=prs->words[i].pos.apos[j+1]; wptr[j].weight = 0;
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 }
ptr->haspos=0; else
ptr->haspos = 0;
ptr++; ptr++;
} }
pfree(prs->words); pfree(prs->words);
@ -646,7 +718,7 @@ to_tsvector(PG_FUNCTION_ARGS)
text *in = PG_GETARG_TEXT_P(1); text *in = PG_GETARG_TEXT_P(1);
PRSTEXT prs; PRSTEXT prs;
tsvector *out = NULL; tsvector *out = NULL;
TSCfgInfo *cfg=findcfg(PG_GETARG_INT32(0)); TSCfgInfo *cfg = findcfg(PG_GETARG_INT32(0));
prs.lenwords = 32; prs.lenwords = 32;
prs.curwords = 0; prs.curwords = 0;
@ -658,57 +730,65 @@ 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);
out->size = 0; out->size = 0;
} }
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }
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,
Int32GetDatum( name2id_cfg( cfg ) ), Int32GetDatum(name2id_cfg(cfg)),
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));
ptr = clist = FuncnameGetCandidates(names, 1); ptr = clist = FuncnameGetCandidates(names, 1);
freeList(names); freeList(names);
if ( !ptr ) if (!ptr)
return funcid; return funcid;
while(ptr) { while (ptr)
if ( ptr->args[0] == TEXTOID && funcid == InvalidOid ) {
funcid=ptr->oid; if (ptr->args[0] == TEXTOID && funcid == InvalidOid)
clist=ptr->next; funcid = ptr->oid;
clist = ptr->next;
pfree(ptr); pfree(ptr);
ptr=clist; ptr = clist;
} }
return funcid; return funcid;
@ -724,7 +804,7 @@ tsearch2(PG_FUNCTION_ARGS)
Trigger *trigger; Trigger *trigger;
Relation rel; Relation rel;
HeapTuple rettuple = NULL; HeapTuple rettuple = NULL;
TSCfgInfo *cfg=findcfg(get_currcfg()); TSCfgInfo *cfg = findcfg(get_currcfg());
int numidxattr, int numidxattr,
i; i;
PRSTEXT prs; PRSTEXT prs;
@ -782,8 +862,8 @@ tsearch2(PG_FUNCTION_ARGS)
numattr = SPI_fnumber(rel->rd_att, trigger->tgargs[i]); numattr = SPI_fnumber(rel->rd_att, trigger->tgargs[i]);
if (numattr == SPI_ERROR_NOATTRIBUTE) if (numattr == SPI_ERROR_NOATTRIBUTE)
{ {
funcoid=findFunc(trigger->tgargs[i]); funcoid = findFunc(trigger->tgargs[i]);
if ( funcoid==InvalidOid ) if (funcoid == InvalidOid)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN), (errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("could not find function or field \"%s\"", errmsg("could not find function or field \"%s\"",
@ -805,19 +885,22 @@ 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);
if (txt != (text*)DatumGetPointer(txt_toasted) ) if (txt != (text *) DatumGetPointer(txt_toasted))
pfree(txt); pfree(txt);
} }
@ -831,8 +914,9 @@ 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);
pfree(prs.words); pfree(prs.words);

View File

@ -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;

View File

@ -35,26 +35,29 @@ 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++)
len += SHORTALIGN( arrin[i].len ); len += SHORTALIGN(arrin[i].len);
len = CALCDATASIZE(in->size, len); len = CALCDATASIZE(in->size, len);
out=(tsvector*)palloc(len); out = (tsvector *) palloc(len);
memset(out,0,len); memset(out, 0, len);
out->len=len; out->len = len;
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;
arrout[i].pos = cur - STRPTR(out); arrout[i].pos = cur - STRPTR(out);
cur += SHORTALIGN( arrout[i].len ); cur += SHORTALIGN(arrout[i].len);
} }
PG_FREE_IF_COPY(in, 0); PG_FREE_IF_COPY(in, 0);
@ -67,29 +70,43 @@ 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 ) { {
p=POSDATAPTR(out,entry); if ((j = POSDATALEN(out, entry)) != 0)
while(j--) { {
p->weight=w; p = POSDATAPTR(out, entry);
while (j--)
{
p->weight = w;
p++; p++;
} }
} }
@ -101,60 +118,75 @@ setweight(PG_FUNCTION_ARGS)
} }
static int static int
compareEntry(char *ptra, WordEntry* a, char *ptrb, WordEntry* b) compareEntry(char *ptra, WordEntry * a, char *ptrb, WordEntry * b)
{ {
if ( a->len == b->len) if (a->len == b->len)
{ {
return strncmp( return strncmp(
ptra + a->pos, ptra + a->pos,
ptrb + b->pos, ptrb + b->pos,
a->len); a->len);
} }
return ( a->len > b->len ) ? 1 : -1; return (a->len > b->len) ? 1 : -1;
} }
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 ].pos = LIMITPOS(spos[i].pos + maxpos); dpos[*clen].weight = spos[i].weight;
dpos[*clen].pos = LIMITPOS(spos[i].pos + maxpos);
(*clen)++; (*clen)++;
} }
if ( *clen != startlen ) if (*clen != startlen)
destptr->haspos=1; destptr->haspos = 1;
return *clen - startlen; return *clen - startlen;
} }
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 ) { {
p=POSDATAPTR(in1,ptr); if ((j = POSDATALEN(in1, ptr)) != 0)
while(j--) { {
if ( p->pos > maxpos ) p = POSDATAPTR(in1, ptr);
while (j--)
{
if (p->pos > maxpos)
maxpos = p->pos; maxpos = p->pos;
p++; p++;
} }
@ -162,102 +194,136 @@ 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);
out=(tsvector*)palloc( in1->len + in2->len ); data2 = STRPTR(in2);
memset(out,0,in1->len + in2->len); i1 = in1->size;
i2 = in2->size;
out = (tsvector *) palloc(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); {
if ( cmp < 0 ) { /* in1 first */ int cmp = compareEntry(data1, ptr1, data2, ptr2);
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)); {
cur+=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);
} }
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 ); {
if ( addlen == 0 ) int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
ptr->haspos=0;
if (addlen == 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 ) { {
memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1)*sizeof(WordEntryPos) + sizeof(uint16)); if (ptr1->haspos)
cur+=POSDATALEN(in1, ptr1)*sizeof(WordEntryPos) + sizeof(uint16); {
if ( ptr2->haspos ) memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
cur += add_pos(in2, ptr2, out, ptr, maxpos )*sizeof(WordEntryPos); cur += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
} else if ( ptr2->haspos ) { if (ptr2->haspos)
int addlen = add_pos(in2, ptr2, out, ptr, maxpos ); cur += add_pos(in2, ptr2, out, ptr, maxpos) * sizeof(WordEntryPos);
if ( addlen == 0 ) }
ptr->haspos=0; else if (ptr2->haspos)
{
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
if (addlen == 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)); {
cur+=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);
} }
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 ); {
if ( addlen == 0 ) int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
ptr->haspos=0;
if (addlen == 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);
out->len = CALCDATASIZE( out->size, cur-data ); out->len = CALCDATASIZE(out->size, cur - data);
if ( data != STRPTR(out) ) if (data != STRPTR(out))
memmove( STRPTR(out), data, cur-data ); memmove(STRPTR(out), data, cur - data);
PG_FREE_IF_COPY(in1, 0); PG_FREE_IF_COPY(in1, 0);
PG_FREE_IF_COPY(in2, 1); PG_FREE_IF_COPY(in2, 1);
PG_RETURN_POINTER(out); PG_RETURN_POINTER(out);
} }

View File

@ -1,6 +1,6 @@
#include "deflex.h" #include "deflex.h"
const char *lex_descr[]={ const char *lex_descr[] = {
"", "",
"Latin word", "Latin word",
"Non-latin word", "Non-latin word",
@ -27,7 +27,7 @@ const char *lex_descr[]={
"HTML Entity" "HTML Entity"
}; };
const char *tok_alias[]={ const char *tok_alias[] = {
"", "",
"lword", "lword",
"nlword", "nlword",
@ -53,4 +53,3 @@ const char *tok_alias[]={
"uint", "uint",
"entity" "entity"
}; };

View File

@ -21,45 +21,51 @@
/*********top interface**********/ /*********top interface**********/
static void *plan_getparser=NULL; 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)};
int stat; int stat;
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 ) ); {
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));
if (!plan_getparser)
ts_error(ERROR, "SPI_prepare() failed"); ts_error(ERROR, "SPI_prepare() failed");
} }
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=DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) ); Oid oid = InvalidOid;
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));
fmgr_info_cxt(oid, &(prs->getlexeme_info), TopMemoryContext); fmgr_info_cxt(oid, &(prs->getlexeme_info), TopMemoryContext);
oid=DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3, &isnull) ); oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3, &isnull));
fmgr_info_cxt(oid, &(prs->end_info), TopMemoryContext); fmgr_info_cxt(oid, &(prs->end_info), TopMemoryContext);
prs->lextype=DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 4, &isnull) ); prs->lextype = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 4, &isnull));
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;
@ -67,95 +73,106 @@ typedef struct {
SNMap name2id_map; SNMap name2id_map;
} PrsList; } PrsList;
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) ); {
if ( PList.list ) freeSNMap(&(PList.name2id_map));
if (PList.list)
free(PList.list); free(PList.list);
memset(&PList,0,sizeof(PrsList)); memset(&PList, 0, sizeof(PrsList));
} }
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)
return PList.last_prs; return PList.last_prs;
} }
/* 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);
if ( !tmp ) tmp = (WParserInfo *) realloc(PList.list, sizeof(WParserInfo) * reallen);
ts_error(ERROR,"No memory"); if (!tmp)
PList.reallen=reallen; ts_error(ERROR, "No memory");
PList.list=tmp; PList.reallen = reallen;
PList.list = tmp;
} }
PList.last_prs=&(PList.list[PList.len]); PList.last_prs = &(PList.list[PList.len]);
init_prs(id, PList.last_prs); init_prs(id, PList.last_prs);
PList.len++; PList.len++;
qsort(PList.list, PList.len, sizeof(WParserInfo), compareprs); qsort(PList.list, PList.len, sizeof(WParserInfo), compareprs);
return findprs(id); /* qsort changed order!! */; return findprs(id); /* qsort changed order!! */ ;
} }
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)};
int stat; int stat;
Oid id=findSNMap_t( &(PList.name2id_map), name ); Oid id = findSNMap_t(&(PList.name2id_map), name);
if ( id ) if (id)
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_parser where prs_name = $1" , 1, arg ) ); {
if ( !plan_name2id ) plan_name2id = SPI_saveplan(SPI_prepare("select oid from pg_ts_parser where prs_name = $1", 1, arg));
if (!plan_name2id)
ts_error(ERROR, "SPI_prepare() failed"); ts_error(ERROR, "SPI_prepare() failed");
} }
stat = SPI_execp(plan_name2id, pars, " ", 1); stat = SPI_execp(plan_name2id, 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)
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));
else else
ts_error(ERROR, "No parser '%s'", text2char(name)); ts_error(ERROR, "No parser '%s'", text2char(name));
SPI_finish(); SPI_finish();
addSNMap_t( &(PList.name2id_map), name, id ); addSNMap_t(&(PList.name2id_map), name, id);
return id; return id;
} }
/******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;
@ -163,12 +180,12 @@ setup_firstcall(FuncCallContext *funcctx, Oid prsid) {
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
st=(TypeStorage*)palloc( sizeof(TypeStorage) ); st = (TypeStorage *) palloc(sizeof(TypeStorage));
st->cur=0; st->cur = 0;
st->list = (LexDescr*)DatumGetPointer( st->list = (LexDescr *) DatumGetPointer(
OidFunctionCall1( prs->lextype, PointerGetDatum(prs->prs) ) OidFunctionCall1(prs->lextype, PointerGetDatum(prs->prs))
); );
funcctx->user_fctx = (void*)st; funcctx->user_fctx = (void *) st;
tupdesc = RelationNameGetTupleDesc("tokentype"); tupdesc = RelationNameGetTupleDesc("tokentype");
funcctx->slot = TupleDescGetSlot(tupdesc); funcctx->slot = TupleDescGetSlot(tupdesc);
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
@ -176,20 +193,22 @@ 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];
HeapTuple tuple; HeapTuple tuple;
values[0]=txtid; values[0] = txtid;
sprintf(txtid,"%d",st->list[st->cur].lexid); sprintf(txtid, "%d", st->list[st->cur].lexid);
values[1]=st->list[st->cur].alias; values[1] = st->list[st->cur].alias;
values[2]=st->list[st->cur].descr; values[2] = st->list[st->cur].descr;
tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
result = TupleGetDatum(funcctx->slot, tuple); result = TupleGetDatum(funcctx->slot, tuple);
@ -198,29 +217,34 @@ 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;
} }
PG_FUNCTION_INFO_V1(token_type); 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));
} }
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
if ( (result=process_call(funcctx)) != (Datum)0 ) if ((result = process_call(funcctx)) != (Datum) 0)
SRF_RETURN_NEXT(funcctx, result); SRF_RETURN_NEXT(funcctx, result);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }
@ -228,20 +252,23 @@ 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);
} }
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
if ( (result=process_call(funcctx)) != (Datum)0 ) if ((result = process_call(funcctx)) != (Datum) 0)
SRF_RETURN_NEXT(funcctx, result); SRF_RETURN_NEXT(funcctx, result);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }
@ -249,20 +276,22 @@ 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"));
setup_firstcall(funcctx, current_parser_id ); setup_firstcall(funcctx, current_parser_id);
} }
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
if ( (result=process_call(funcctx)) != (Datum)0 ) if ((result = process_call(funcctx)) != (Datum) 0)
SRF_RETURN_NEXT(funcctx, result); SRF_RETURN_NEXT(funcctx, result);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }
@ -271,32 +300,36 @@ 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();
} }
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(
set_curprs, set_curprs,
ObjectIdGetDatum( name2id_prs(name) ) ObjectIdGetDatum(name2id_prs(name))
); );
PG_FREE_IF_COPY(name, 0); PG_FREE_IF_COPY(name, 0);
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,43 +337,47 @@ 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);
st=(PrsStorage*)palloc( sizeof(PrsStorage) ); st = (PrsStorage *) palloc(sizeof(PrsStorage));
st->cur=0; st->cur = 0;
st->len=16; st->len = 16;
st->list=(LexemEntry*)palloc( sizeof(LexemEntry)*st->len ); st->list = (LexemEntry *) palloc(sizeof(LexemEntry) * st->len);
prs->prs = (void*)DatumGetPointer( prs->prs = (void *) DatumGetPointer(
FunctionCall2( FunctionCall2(
&(prs->start_info), &(prs->start_info),
PointerGetDatum(VARDATA(txt)), PointerGetDatum(VARDATA(txt)),
Int32GetDatum(VARSIZE(txt)-VARHDRSZ) Int32GetDatum(VARSIZE(txt) - VARHDRSZ)
) )
); );
while( ( type=DatumGetInt32(FunctionCall3( while ((type = DatumGetInt32(FunctionCall3(
&(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->list=(LexemEntry*)repalloc(st->list, sizeof(LexemEntry)*st->len); st->len = 2 * st->len;
st->list = (LexemEntry *) repalloc(st->list, sizeof(LexemEntry) * st->len);
} }
st->list[st->cur].lexem = palloc(llen+1); st->list[st->cur].lexem = palloc(llen + 1);
memcpy( st->list[st->cur].lexem, lex, llen); memcpy(st->list[st->cur].lexem, lex, llen);
st->list[st->cur].lexem[llen]='\0'; st->list[st->cur].lexem[llen] = '\0';
st->list[st->cur].type=type; st->list[st->cur].type = type;
st->cur++; st->cur++;
} }
@ -349,10 +386,10 @@ prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt) {
PointerGetDatum(prs->prs) PointerGetDatum(prs->prs)
); );
st->len=st->cur; st->len = st->cur;
st->cur=0; st->cur = 0;
funcctx->user_fctx = (void*)st; funcctx->user_fctx = (void *) st;
tupdesc = RelationNameGetTupleDesc("tokenout"); tupdesc = RelationNameGetTupleDesc("tokenout");
funcctx->slot = TupleDescGetSlot(tupdesc); funcctx->slot = TupleDescGetSlot(tupdesc);
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc); funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
@ -360,30 +397,35 @@ 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];
HeapTuple tuple; HeapTuple tuple;
values[0]=tid; values[0] = tid;
sprintf(tid,"%d",st->list[st->cur].type); sprintf(tid, "%d", st->list[st->cur].type);
values[1]=st->list[st->cur].lexem; values[1] = st->list[st->cur].lexem;
tuple = BuildTupleFromCStrings(funcctx->attinmeta, values); tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
result = TupleGetDatum(funcctx->slot, tuple); result = TupleGetDatum(funcctx->slot, tuple);
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,20 +433,23 @@ 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);
} }
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
if ( (result=prs_process_call(funcctx)) != (Datum)0 ) if ((result = prs_process_call(funcctx)) != (Datum) 0)
SRF_RETURN_NEXT(funcctx, result); SRF_RETURN_NEXT(funcctx, result);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }
@ -412,22 +457,25 @@ 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);
PG_FREE_IF_COPY(txt,1); PG_FREE_IF_COPY(txt, 1);
} }
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
if ( (result=prs_process_call(funcctx)) != (Datum)0 ) if ((result = prs_process_call(funcctx)) != (Datum) 0)
SRF_RETURN_NEXT(funcctx, result); SRF_RETURN_NEXT(funcctx, result);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }
@ -436,22 +484,25 @@ 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"));
prs_setup_firstcall(funcctx, current_parser_id,txt ); prs_setup_firstcall(funcctx, current_parser_id, txt);
PG_FREE_IF_COPY(txt,0); PG_FREE_IF_COPY(txt, 0);
} }
funcctx = SRF_PERCALL_SETUP(); funcctx = SRF_PERCALL_SETUP();
if ( (result=prs_process_call(funcctx)) != (Datum)0 ) if ((result = prs_process_call(funcctx)) != (Datum) 0)
SRF_RETURN_NEXT(funcctx, result); SRF_RETURN_NEXT(funcctx, result);
SRF_RETURN_DONE(funcctx); SRF_RETURN_DONE(funcctx);
} }
@ -459,16 +510,17 @@ 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)));
text *opt=( PG_NARGS()>3 && PG_GETARG_POINTER(3) ) ? PG_GETARG_TEXT_P(3) : NULL; text *opt = (PG_NARGS() > 3 && PG_GETARG_POINTER(3)) ? PG_GETARG_TEXT_P(3) : NULL;
HLPRSTEXT prs; HLPRSTEXT prs;
text *out; text *out;
WParserInfo *prsobj = findprs(cfg->prs_id); WParserInfo *prsobj = findprs(cfg->prs_id);
memset(&prs,0,sizeof(HLPRSTEXT)); memset(&prs, 0, sizeof(HLPRSTEXT));
prs.lenwords = 32; prs.lenwords = 32;
prs.words = (HLWORD *) palloc(sizeof(HLWORD) * prs.lenwords); prs.words = (HLWORD *) palloc(sizeof(HLWORD) * prs.lenwords);
hlparsetext(cfg, &prs, query, VARDATA(in), VARSIZE(in) - VARHDRSZ); hlparsetext(cfg, &prs, query, VARDATA(in), VARSIZE(in) - VARHDRSZ);
@ -483,9 +535,10 @@ headline(PG_FUNCTION_ARGS) {
out = genhl(&prs); out = genhl(&prs);
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,33 +550,32 @@ 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(
headline, headline,
ObjectIdGetDatum(name2id_cfg( cfg ) ), ObjectIdGetDatum(name2id_cfg(cfg)),
PG_GETARG_DATUM(1), PG_GETARG_DATUM(1),
PG_GETARG_DATUM(2), PG_GETARG_DATUM(2),
( PG_NARGS()>3 ) ? PG_GETARG_DATUM(3) : PointerGetDatum(NULL) (PG_NARGS() > 3) ? PG_GETARG_DATUM(3) : PointerGetDatum(NULL)
); );
PG_FREE_IF_COPY(cfg,0); PG_FREE_IF_COPY(cfg, 0);
PG_RETURN_DATUM(out); PG_RETURN_DATUM(out);
} }
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()),
PG_GETARG_DATUM(0), PG_GETARG_DATUM(0),
PG_GETARG_DATUM(1), PG_GETARG_DATUM(1),
( PG_NARGS()>2 ) ? PG_GETARG_DATUM(2) : PointerGetDatum(NULL) (PG_NARGS() > 2) ? PG_GETARG_DATUM(2) : PointerGetDatum(NULL)
)); ));
} }

View File

@ -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;
@ -13,13 +14,14 @@ typedef struct {
void *prs; void *prs;
} WParserInfo; } WParserInfo;
void init_prs(Oid id, WParserInfo *prs); void init_prs(Oid id, WParserInfo * prs);
WParserInfo* findprs(Oid id); WParserInfo *findprs(Oid id);
Oid name2id_prs(text *name); 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;

View File

@ -20,17 +20,19 @@ 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].alias = pstrdup(tok_alias[i]); descr[i - 1].lexid = i;
descr[i-1].descr = pstrdup(lex_descr[i]); descr[i - 1].alias = pstrdup(tok_alias[i]);
descr[i - 1].descr = pstrdup(lex_descr[i]);
} }
descr[LASTNUM].lexid=0; descr[LASTNUM].lexid = 0;
PG_RETURN_POINTER(descr); PG_RETURN_POINTER(descr);
} }
@ -38,19 +40,21 @@ 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);
} }
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);
int type=tsearch2_yylex(); int type = tsearch2_yylex();
*t = token; *t = token;
*tlen = tokenlen; *tlen = tokenlen;
@ -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,16 +81,20 @@ 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++) {
if ( ((hlCheck*)checkval)->words[i].item==val ) for (i = 0; i < ((hlCheck *) checkval)->len; i++)
{
if (((hlCheck *) checkval)->words[i].item == val)
return true; return true;
} }
return false; return false;
@ -93,21 +102,28 @@ 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; {
ITEM *item=GETQUERY(query); int i,
int pos=*p; j;
*q=0; ITEM *item = GETQUERY(query);
*p=0x7fffffff; int pos = *p;
for(j=0;j<query->size;j++) { *q = 0;
if ( item->type != VAL ) { *p = 0x7fffffff;
for (j = 0; j < query->size; j++)
{
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 ( i>*q) if (prs->words[i].item == item)
{
if (i > *q)
*q = i; *q = i;
break; break;
} }
@ -115,32 +131,39 @@ hlCover(HLPRSTEXT *prs, QUERYTYPE *query, int *p, int *q) {
item++; item++;
} }
if ( *q==0 ) if (*q == 0)
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 ( i<*p ) if (prs->words[i].item == item)
*p=i; {
if (i < *p)
*p = i;
break; break;
} }
} }
item++; item++;
} }
if ( *p<=*q ) { if (*p <= *q)
hlCheck ch={ &(prs->words[*p]), *q-*p+1 }; {
if ( TS_execute(GETQUERY(query), &ch, false, checkcondition_HL) ) { hlCheck ch = {&(prs->words[*p]), *q - *p + 1};
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,42 +173,51 @@ 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); {
text *opt=(text*)PG_GETARG_POINTER(1); /* can't be toasted */ HLPRSTEXT *prs = (HLPRSTEXT *) PG_GETARG_POINTER(0);
QUERYTYPE *query=(QUERYTYPE*)PG_GETARG_POINTER(2); /* can't be toasted */ text *opt = (text *) PG_GETARG_POINTER(1); /* can't be toasted */
/* from opt + start and and tag */ QUERYTYPE *query = (QUERYTYPE *) PG_GETARG_POINTER(2); /* can't be toasted */
int min_words=15;
int max_words=35;
int shortword=3;
int p=0,q=0; /* from opt + start and and tag */
int bestb=-1,beste=-1; int min_words = 15;
int bestlen=-1; int max_words = 35;
int pose=0, poslen, curlen; int shortword = 3;
int p = 0,
q = 0;
int bestb = -1,
beste = -1;
int bestlen = -1;
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 ) {
max_words=pg_atoi(mptr->value,4,1); if (strcasecmp(mptr->key, "MaxWords") == 0)
else if ( strcasecmp(mptr->key,"MinWords")==0 ) max_words = pg_atoi(mptr->value, 4, 1);
min_words=pg_atoi(mptr->value,4,1); else if (strcasecmp(mptr->key, "MinWords") == 0)
else if ( strcasecmp(mptr->key,"ShortWord")==0 ) min_words = pg_atoi(mptr->value, 4, 1);
shortword=pg_atoi(mptr->value,4,1); else if (strcasecmp(mptr->key, "ShortWord") == 0)
else if ( strcasecmp(mptr->key,"StartSel")==0 ) shortword = pg_atoi(mptr->value, 4, 1);
prs->startsel=pstrdup(mptr->value); else if (strcasecmp(mptr->key, "StartSel") == 0)
else if ( strcasecmp(mptr->key,"StopSel")==0 ) prs->startsel = pstrdup(mptr->value);
prs->stopsel=pstrdup(mptr->value); else if (strcasecmp(mptr->key, "StopSel") == 0)
prs->stopsel = pstrdup(mptr->value);
pfree(mptr->key); pfree(mptr->key);
pfree(mptr->value); pfree(mptr->value);
@ -194,104 +226,118 @@ prsd_headline(PG_FUNCTION_ARGS) {
} }
pfree(map); pfree(map);
if ( min_words >= max_words ) if (min_words >= max_words)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("must be MinWords < MaxWords"))); errmsg("must be MinWords < MaxWords")));
if ( min_words<=0 ) if (min_words <= 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("must be MinWords > 0"))); errmsg("must be MinWords > 0")));
if ( shortword<0 ) if (shortword < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
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)
poslen++; poslen++;
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 ( !NONWORDTOKEN(prs->words[i].type) ) {
if (i != q)
{
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)
poslen++; poslen++;
} }
pose=i; pose = i;
if ( NOENDTOKEN(prs->words[i].type) || prs->words[i].len <= shortword ) if (NOENDTOKEN(prs->words[i].type) || prs->words[i].len <= shortword)
continue; continue;
if ( curlen>=min_words ) if (curlen >= min_words)
break; break;
} }
} else { /* shorter cover :((( */ }
for(;curlen>min_words;i--) { else
if ( !NONWORDTOKEN(prs->words[i].type) ) { /* shorter cover :((( */
for (; curlen > min_words; i--)
{
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)
poslen--; poslen--;
pose=i; pose = i;
if ( NOENDTOKEN(prs->words[i].type) || prs->words[i].len <= shortword ) if (NOENDTOKEN(prs->words[i].type) || prs->words[i].len <= shortword)
continue; continue;
break; break;
} }
} }
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; {
bestlen=poslen; bestb = p;
beste = pose;
bestlen = poslen;
} }
p++; p++;
} }
if ( bestlen<0 ) { if (bestlen < 0)
curlen=0; {
poslen=0; curlen = 0;
for(i=0;i<prs->curwords && curlen<min_words ; i++) { poslen = 0;
if ( !NONWORDTOKEN(prs->words[i].type) ) for (i = 0; i < prs->curwords && curlen < min_words; i++)
{
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 ) {
prs->words[i].selected=1; if (prs->words[i].item)
if ( prs->words[i].repeated ) prs->words[i].selected = 1;
prs->words[i].skip=1; if (prs->words[i].repeated)
if ( HLIDIGNORE(prs->words[i].type) ) prs->words[i].skip = 1;
prs->words[i].replace=1; if (HLIDIGNORE(prs->words[i].type))
prs->words[i].replace = 1;
prs->words[i].in=1; prs->words[i].in = 1;
} }
if (!prs->startsel) if (!prs->startsel)
prs->startsel=pstrdup("<b>"); prs->startsel = pstrdup("<b>");
if (!prs->stopsel) if (!prs->stopsel)
prs->stopsel=pstrdup("</b>"); prs->stopsel = pstrdup("</b>");
prs->startsellen=strlen(prs->startsel); prs->startsellen = strlen(prs->startsel);
prs->stopsellen=strlen(prs->stopsel); prs->stopsellen = strlen(prs->stopsel);
PG_RETURN_POINTER(prs); PG_RETURN_POINTER(prs);
} }

View File

@ -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

View File

@ -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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */

View File

@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $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));

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $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++)
{ {

View File

@ -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);

View File

@ -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.

View File

@ -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;

View File

@ -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,22 +459,23 @@ 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;
index_rescan(scan, NULL /* no change to key */); index_rescan(scan, NULL /* no change to key */ );
scan->keys_are_unique = true; scan->keys_are_unique = true;
scan->got_tuple = true; scan->got_tuple = true;
@ -631,7 +632,7 @@ index_bulk_delete(Relation indexRelation,
*/ */
IndexBulkDeleteResult * IndexBulkDeleteResult *
index_vacuum_cleanup(Relation indexRelation, index_vacuum_cleanup(Relation indexRelation,
IndexVacuumCleanupInfo *info, IndexVacuumCleanupInfo * info,
IndexBulkDeleteResult *stats) IndexBulkDeleteResult *stats)
{ {
RegProcedure procedure; RegProcedure procedure;

View File

@ -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;

View File

@ -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,12 +927,13 @@ _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)
{ {
/* no update wanted */ /* no update wanted */
_bt_relbuf(rel, metabuf); _bt_relbuf(rel, metabuf);
@ -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)
{ {

View File

@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $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;
@ -728,7 +730,7 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
* after we start the scan will not be examined; this should be fine, * after we start the scan will not be examined; this should be fine,
* since they can't possibly be empty.) * since they can't possibly be empty.)
*/ */
for (blkno = BTREE_METAPAGE+1; blkno < num_pages; blkno++) for (blkno = BTREE_METAPAGE + 1; blkno < num_pages; blkno++)
{ {
Buffer buf; Buffer buf;
Page page; Page page;
@ -787,16 +789,16 @@ 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)
{ {
BlockNumber new_pages = num_pages; BlockNumber new_pages = num_pages;
while (nFreePages > 0 && freePages[nFreePages-1] == new_pages-1) while (nFreePages > 0 && freePages[nFreePages - 1] == new_pages - 1)
{ {
new_pages--; new_pages--;
pages_deleted--; pages_deleted--;
@ -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\"",

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $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)))

View File

@ -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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $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);

View File

@ -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++)
{ {

View File

@ -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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */

View File

@ -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"
@ -19,7 +19,7 @@
#include "commands/sequence.h" #include "commands/sequence.h"
RmgrData RmgrTable[RM_MAX_ID+1] = { RmgrData RmgrTable[RM_MAX_ID + 1] = {
{"XLOG", xlog_redo, xlog_undo, xlog_desc, NULL, NULL}, {"XLOG", xlog_redo, xlog_undo, xlog_desc, NULL, NULL},
{"Transaction", xact_redo, xact_undo, xact_desc, NULL, NULL}, {"Transaction", xact_redo, xact_undo, xact_desc, NULL, NULL},
{"Storage", smgr_redo, smgr_undo, smgr_desc, NULL, NULL}, {"Storage", smgr_redo, smgr_undo, smgr_desc, NULL, NULL},

View File

@ -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
*/ */
@ -210,7 +212,7 @@ SimpleLruInit(SlruCtl ctl, const char *name, const char *subdir)
memset(shared, 0, sizeof(SlruSharedData)); memset(shared, 0, sizeof(SlruSharedData));
bufptr = (char *)shared + MAXALIGN(sizeof(SlruSharedData)); bufptr = (char *) shared + MAXALIGN(sizeof(SlruSharedData));
for (slotno = 0; slotno < NUM_CLOG_BUFFERS; slotno++) for (slotno = 0; slotno < NUM_CLOG_BUFFERS; slotno++)
{ {
@ -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);

View File

@ -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.

View File

@ -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 */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -238,7 +238,7 @@ BootstrapMain(int argc, char *argv[])
* *
* If we are running under the postmaster, this is done already. * If we are running under the postmaster, this is done already.
*/ */
if (!IsUnderPostmaster /* when exec || ExecBackend */) if (!IsUnderPostmaster /* when exec || ExecBackend */ )
MemoryContextInit(); MemoryContextInit();
/* /*
@ -247,7 +247,7 @@ BootstrapMain(int argc, char *argv[])
/* Set defaults, to be overriden by explicit options below */ /* Set defaults, to be overriden by explicit options below */
dbname = NULL; dbname = NULL;
if (!IsUnderPostmaster /* when exec || ExecBackend*/) if (!IsUnderPostmaster /* when exec || ExecBackend */ )
{ {
InitializeGUCOptions(); InitializeGUCOptions();
potential_DataDir = getenv("PGDATA"); /* Null if no PGDATA potential_DataDir = getenv("PGDATA"); /* Null if no PGDATA
@ -293,9 +293,9 @@ BootstrapMain(int argc, char *argv[])
sscanf(optarg, "%d,%p,", &UsedShmemSegID, &UsedShmemSegAddr); sscanf(optarg, "%d,%p,", &UsedShmemSegID, &UsedShmemSegAddr);
p = strchr(optarg, ','); p = strchr(optarg, ',');
if (p) if (p)
p = strchr(p+1, ','); p = strchr(p + 1, ',');
if (p) if (p)
dbname = strdup(p+1); dbname = strdup(p + 1);
#else #else
dbname = strdup(optarg); dbname = strdup(optarg);
#endif #endif
@ -346,12 +346,10 @@ BootstrapMain(int argc, char *argv[])
usage(); usage();
if (IsUnderPostmaster && ExecBackend && MyProc /* ordinary backend */) if (IsUnderPostmaster && ExecBackend && MyProc /* ordinary backend */ )
{
AttachSharedMemoryAndSemaphores(); AttachSharedMemoryAndSemaphores();
}
if (!IsUnderPostmaster /* when exec || ExecBackend*/) if (!IsUnderPostmaster /* when exec || ExecBackend */ )
{ {
if (!potential_DataDir) if (!potential_DataDir)
{ {
@ -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);

View File

@ -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.
@ -97,33 +97,36 @@ 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,
(errcode(ERRCODE_INVALID_GRANT_OPERATION), (errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("grant options can only be granted to individual users"))); errmsg("grant options can only be granted to individual users")));
aclitem.ai_grantor = GetUserId(); aclitem. ai_grantor = GetUserId();
ACLITEM_SET_PRIVS_IDTYPE(aclitem, ACLITEM_SET_PRIVS_IDTYPE(aclitem,
(is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS, (is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
@ -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
@ -856,7 +859,7 @@ aclcheck(Acl *acl, AclId userid, AclMode mode)
* supply strings that might be already quoted. * supply strings that might be already quoted.
*/ */
static const char * const no_priv_msg[MAX_ACL_KIND] = static const char *const no_priv_msg[MAX_ACL_KIND] =
{ {
/* ACL_KIND_CLASS */ /* ACL_KIND_CLASS */
gettext_noop("permission denied for relation %s"), gettext_noop("permission denied for relation %s"),
@ -878,7 +881,7 @@ static const char * const no_priv_msg[MAX_ACL_KIND] =
gettext_noop("permission denied for conversion %s") gettext_noop("permission denied for conversion %s")
}; };
static const char * const not_owner_msg[MAX_ACL_KIND] = static const char *const not_owner_msg[MAX_ACL_KIND] =
{ {
/* ACL_KIND_CLASS */ /* ACL_KIND_CLASS */
gettext_noop("must be owner of relation %s"), gettext_noop("must be owner of relation %s"),

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $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)
{ {

View File

@ -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))
{ {

View File

@ -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)
{ {

View File

@ -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);

View File

@ -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 &&

View File

@ -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);

View File

@ -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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */

View File

@ -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.

View File

@ -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);

View File

@ -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))
{ {

View File

@ -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

View File

@ -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;
@ -121,7 +121,7 @@ ExecRenameStmt(RenameStmt *stmt)
stmt->newname); /* new att name */ stmt->newname); /* new att name */
break; break;
default: default:
/*can't happen*/; /* can't happen */ ;
} }
break; break;
} }

View File

@ -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)))

View File

@ -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)

View File

@ -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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -63,7 +63,7 @@ typedef struct
} RelToCluster; } RelToCluster;
static void cluster_rel(RelToCluster *rv, bool recheck); static void cluster_rel(RelToCluster * rv, bool recheck);
static Oid make_new_heap(Oid OIDOldHeap, const char *NewName); static Oid make_new_heap(Oid OIDOldHeap, const char *NewName);
static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex); static void copy_heap_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex);
static List *get_indexattr_list(Relation OldHeap, Oid OldIndex); static List *get_indexattr_list(Relation OldHeap, Oid OldIndex);
@ -123,7 +123,7 @@ cluster(ClusterStmt *stmt)
List *index; List *index;
/* We need to find the index that has indisclustered set. */ /* We need to find the index that has indisclustered set. */
foreach (index, RelationGetIndexList(rel)) foreach(index, RelationGetIndexList(rel))
{ {
HeapTuple idxtuple; HeapTuple idxtuple;
Form_pg_index indexForm; Form_pg_index indexForm;
@ -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);
@ -210,13 +213,14 @@ cluster(ClusterStmt *stmt)
CommitTransactionCommand(); CommitTransactionCommand();
/* Ok, now that we've got them all, cluster them one by one */ /* Ok, now that we've got them all, cluster them one by one */
foreach (rv, rvs) foreach(rv, rvs)
{ {
RelToCluster *rvtc = (RelToCluster *) lfirst(rv); RelToCluster *rvtc = (RelToCluster *) lfirst(rv);
/* 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();
} }
@ -244,7 +248,7 @@ cluster(ClusterStmt *stmt)
* them incrementally while we load the table. * them incrementally while we load the table.
*/ */
static void static void
cluster_rel(RelToCluster *rvtc, bool recheck) cluster_rel(RelToCluster * rvtc, bool recheck)
{ {
Relation OldHeap, Relation OldHeap,
OldIndex; OldIndex;
@ -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);

View File

@ -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 */

View File

@ -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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */

View File

@ -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);
@ -421,7 +422,7 @@ CopyGetData(void *databuf, int datasize)
avail = datasize; avail = datasize;
pq_copymsgbytes(copy_msgbuf, databuf, avail); pq_copymsgbytes(copy_msgbuf, databuf, avail);
databuf = (void *) ((char *) databuf + avail); databuf = (void *) ((char *) databuf + avail);
datasize =- avail; datasize = -avail;
} }
break; break;
} }
@ -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;
} }

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