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

@ -1,7 +1,7 @@
#include "btree_gist.h" #include "btree_gist.h"
PG_FUNCTION_INFO_V1(btree_decompress); PG_FUNCTION_INFO_V1(btree_decompress);
Datum btree_decompress(PG_FUNCTION_ARGS); Datum btree_decompress(PG_FUNCTION_ARGS);
/* /*
** GiST DeCompress methods ** GiST DeCompress methods

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

@ -28,11 +28,11 @@ extern int cube_yyparse();
NDBOX *cube_in(char *str); NDBOX *cube_in(char *str);
NDBOX *cube(text *str); NDBOX *cube(text *str);
char *cube_out(NDBOX * cube); char *cube_out(NDBOX * cube);
NDBOX *cube_f8(double *); NDBOX *cube_f8(double *);
NDBOX *cube_f8_f8(double *, double *); NDBOX *cube_f8_f8(double *, double *);
NDBOX *cube_c_f8(NDBOX *, double *); NDBOX *cube_c_f8(NDBOX *, double *);
NDBOX *cube_c_f8_f8(NDBOX *, double *, double *); NDBOX *cube_c_f8_f8(NDBOX *, double *, double *);
int4 cube_dim(NDBOX * a); int4 cube_dim(NDBOX * a);
double *cube_ll_coord(NDBOX * a, int4 n); double *cube_ll_coord(NDBOX * a, int4 n);
double *cube_ur_coord(NDBOX * a, int4 n); double *cube_ur_coord(NDBOX * a, int4 n);
@ -123,7 +123,7 @@ cube_out(NDBOX * cube)
bool equal = true; bool equal = true;
int dim = cube->dim; int dim = cube->dim;
int i; int i;
int ndig; int ndig;
initStringInfo(&buf); initStringInfo(&buf);
@ -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)
@ -1234,14 +1236,15 @@ NDBOX *
cube_f8(double *x1) 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);
result->size = size; result->size = size;
result->dim = 1; result->dim = 1;
result->x[0] = *x1; result->x[0] = *x1;
result->x[1] = *x1; result->x[1] = *x1;
return result; return result;
} }
@ -1250,56 +1253,61 @@ NDBOX *
cube_f8_f8(double *x1, double *x2) 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);
result->size = size; result->size = size;
result->dim = 1; result->dim = 1;
result->x[0] = *x1; result->x[0] = *x1;
result->x[1] = *x2; result->x[1] = *x2;
return result; return result;
} }
/* Add a dimension to an existing cube with the same values for the new /* Add a dimension to an existing cube with the same values for the new
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[result->dim + i] = c->x[c->dim + i]; result->x[i] = c->x[i];
} result->x[result->dim + i] = c->x[c->dim + i];
result->x[result->dim - 1] = *x1; }
result->x[2 * result->dim - 1] = *x1; result->x[result->dim - 1] = *x1;
result->x[2 * result->dim - 1] = *x1;
return result; return result;
} }
/* 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[result->dim + i] = c->x[c->dim + i]; result->x[i] = c->x[i];
} result->x[result->dim + i] = c->x[c->dim + i];
result->x[result->dim - 1] = *x1; }
result->x[2 * result->dim - 1] = *x2; result->x[result->dim - 1] = *x1;
result->x[2 * result->dim - 1] = *x2;
return result; return result;
} }

View File

@ -443,17 +443,15 @@ do_inserts(PGconn *conn, char *table, dbhead * dbh)
if (result == DBF_VALID) if (result == DBF_VALID)
{ {
query[0] = '\0'; query[0] = '\0';
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

@ -61,17 +61,17 @@
typedef struct remoteConn 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;
/* /*
* Internal declarations * Internal declarations
*/ */
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);
@ -86,10 +86,10 @@ static TupleDesc pgresultGetTupleDesc(PGresult *res);
static char *generate_relation_name(Oid relid); static char *generate_relation_name(Oid relid);
/* Global */ /* Global */
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.
@ -102,7 +102,7 @@ typedef struct remoteConnHashEnt
{ {
char name[NAMEDATALEN]; char name[NAMEDATALEN];
remoteConn *rcon; remoteConn *rcon;
} remoteConnHashEnt; } remoteConnHashEnt;
/* initial number of connection hashes */ /* initial number of connection hashes */
#define NUMCONN 16 #define NUMCONN 16
@ -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,16 +206,16 @@ 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,
(errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION), (errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION),
errmsg("could not establish connection"), errmsg("could not establish connection"),
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,15 +739,15 @@ 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));
} }
else else
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED), (errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
errmsg("statement returning results not allowed"))); errmsg("statement returning results not allowed")));
PQclear(res); PQclear(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
@ -980,8 +979,8 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
if (src_nitems != pknumatts) if (src_nitems != pknumatts)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("source key array length must match number of key " \ errmsg("source key array length must match number of key " \
"attributes"))); "attributes")));
/* /*
* get array of pointers to c-strings from the input source array * get array of pointers to c-strings from the input source array
@ -1013,8 +1012,8 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
if (tgt_nitems != pknumatts) if (tgt_nitems != pknumatts)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("target key array length must match number of key " \ errmsg("target key array length must match number of key " \
"attributes"))); "attributes")));
/* /*
* get array of pointers to c-strings from the input target array * get array of pointers to c-strings from the input target array
@ -1126,8 +1125,8 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS)
if (tgt_nitems != pknumatts) if (tgt_nitems != pknumatts)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("target key array length must match number of key " \ errmsg("target key array length must match number of key " \
"attributes"))); "attributes")));
/* /*
* get array of pointers to c-strings from the input target array * get array of pointers to c-strings from the input target array
@ -1249,8 +1248,8 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
if (src_nitems != pknumatts) if (src_nitems != pknumatts)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("source key array length must match number of key " \ errmsg("source key array length must match number of key " \
"attributes"))); "attributes")));
/* /*
* get array of pointers to c-strings from the input source array * get array of pointers to c-strings from the input source array
@ -1282,8 +1281,8 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
if (tgt_nitems != pknumatts) if (tgt_nitems != pknumatts)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("target key array length must match number of key " \ errmsg("target key array length must match number of key " \
"attributes"))); "attributes")));
/* /*
* get array of pointers to c-strings from the input target array * get array of pointers to c-strings from the input target array
@ -1839,10 +1838,10 @@ pgresultGetTupleDesc(PGresult *res)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH), (errcode(ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH),
errmsg("field size mismatch"), errmsg("field size mismatch"),
errdetail("Size of remote field \"%s\" does not match " \ errdetail("Size of remote field \"%s\" does not match " \
"size of local type \"%s\".", attname, "size of local type \"%s\".", attname,
format_type_with_typemod(atttypid, format_type_with_typemod(atttypid,
atttypmod)))); atttypmod))));
attdim = 0; attdim = 0;
attisset = false; attisset = false;
@ -1893,50 +1892,50 @@ generate_relation_name(Oid relid)
static remoteConn * static remoteConn *
getConnectionByName(const char *name) 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 *
createConnHash(void) createConnHash(void)
{ {
HASHCTL ctl; HASHCTL ctl;
HTAB *ptr; HTAB *ptr;
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")));
@ -1961,12 +1960,12 @@ createNewConnection(const char *name, remoteConn *con)
static void static void
deleteConnection(const char *name) deleteConnection(const char *name)
{ {
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);
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.
@ -8,7 +8,7 @@
* *
* Written by Steven Singer (ssinger@navtechinc.com) * Written by Steven Singer (ssinger@navtechinc.com)
* (c) 2001-2002 Navtech Systems Support Inc. * (c) 2001-2002 Navtech Systems Support Inc.
* ALL RIGHTS RESERVED * ALL RIGHTS RESERVED
* *
* Permission to use, copy, modify, and distribute this software and its * Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose, without fee, and without a written agreement * documentation for any purpose, without fee, and without a written agreement
@ -79,8 +79,9 @@ recordchange(PG_FUNCTION_ARGS)
HeapTuple retTuple = NULL; HeapTuple retTuple = NULL;
char *tblname; char *tblname;
char op = 0; char op = 0;
char *schemaname; char *schemaname;
char *fullyqualtblname; char *fullyqualtblname;
if (fcinfo->context != NULL) if (fcinfo->context != NULL)
{ {
@ -95,12 +96,12 @@ recordchange(PG_FUNCTION_ARGS)
#ifndef NOSCHEMAS #ifndef NOSCHEMAS
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,8 +167,8 @@ 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;
@ -253,7 +254,7 @@ storeKeyInfo(char *cpTableName, HeapTuple tTupleData,
if (cpKeyData == NULL) if (cpKeyData == NULL)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
/* cpTableName already contains quotes... */ /* cpTableName already contains quotes... */
errmsg("there is no PRIMARY KEY for table %s", errmsg("there is no PRIMARY KEY for table %s",
cpTableName))); cpTableName)));
@ -460,7 +461,7 @@ packageData(HeapTuple tTupleData, TupleDesc tTupleDesc,
} }
else else
{ {
sprintf(cpFormatedPtr," "); sprintf(cpFormatedPtr, " ");
iUsedDataBlock++; iUsedDataBlock++;
cpFormatedPtr++; cpFormatedPtr++;
continue; continue;
@ -508,8 +509,8 @@ 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

@ -54,7 +54,7 @@ database_size(PG_FUNCTION_ARGS)
if (!OidIsValid(dbid)) if (!OidIsValid(dbid))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE), (errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", NameStr(*dbname)))); errmsg("database \"%s\" does not exist", NameStr(*dbname))));
dbpath = GetDatabasePath(dbid); dbpath = GetDatabasePath(dbid);

View File

@ -6,8 +6,8 @@
/* Earth's radius is in statute miles. */ /* Earth's radius is in statute miles. */
const double EARTH_RADIUS = 3958.747716; const double EARTH_RADIUS = 3958.747716;
const double TWO_PI = 2.0 * M_PI; const double TWO_PI = 2.0 * M_PI;
double *geo_distance(Point *pt1, Point *pt2); double *geo_distance(Point *pt1, Point *pt2);
@ -66,10 +66,11 @@ 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.)
*resultp = 2. * EARTH_RADIUS * asin(sino); sino = 1.;
*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"
@ -14,17 +14,18 @@
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
PGconn *conn; PGconn *conn;
PQExpBufferData sql; PQExpBufferData sql;
PGresult *res; PGresult *res;
PGresult *pkrel_res; PGresult *pkrel_res;
PGresult *fkrel_res; PGresult *fkrel_res;
char *fk_relname; char *fk_relname;
char *fk_nspname; char *fk_nspname;
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)
{ {
@ -48,13 +49,13 @@ main(int argc, char **argv)
resetPQExpBuffer(&sql); resetPQExpBuffer(&sql);
appendPQExpBuffer(&sql, "%s", appendPQExpBuffer(&sql, "%s",
"SET search_path = public;" "SET search_path = public;"
"SELECT c.relname, (SELECT nspname FROM " "SELECT c.relname, (SELECT nspname FROM "
"pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname " "pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname "
"FROM pg_catalog.pg_class c " "FROM pg_catalog.pg_class c "
"WHERE c.relkind = 'r' " "WHERE c.relkind = 'r' "
"AND c.relhasoids " "AND c.relhasoids "
"ORDER BY nspname, c.relname" "ORDER BY nspname, c.relname"
); );
res = PQexec(conn, sql.data); res = PQexec(conn, sql.data);
@ -70,20 +71,20 @@ main(int argc, char **argv)
resetPQExpBuffer(&sql); resetPQExpBuffer(&sql);
appendPQExpBuffer(&sql, "%s", appendPQExpBuffer(&sql, "%s",
"SELECT c.relname, " "SELECT c.relname, "
"(SELECT nspname FROM pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname, " "(SELECT nspname FROM pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname, "
"a.attname " "a.attname "
"FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a " "FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
"WHERE a.attnum > 0 AND c.relkind = 'r' " "WHERE a.attnum > 0 AND c.relkind = 'r' "
"AND a.attrelid = c.oid " "AND a.attrelid = c.oid "
"AND a.atttypid IN ('pg_catalog.oid'::regtype, " "AND a.atttypid IN ('pg_catalog.oid'::regtype, "
" 'pg_catalog.regclass'::regtype, " " 'pg_catalog.regclass'::regtype, "
" 'pg_catalog.regoper'::regtype, " " 'pg_catalog.regoper'::regtype, "
" 'pg_catalog.regoperator'::regtype, " " 'pg_catalog.regoperator'::regtype, "
" 'pg_catalog.regproc'::regtype, " " 'pg_catalog.regproc'::regtype, "
" 'pg_catalog.regprocedure'::regtype, " " 'pg_catalog.regprocedure'::regtype, "
" 'pg_catalog.regtype'::regtype) " " 'pg_catalog.regtype'::regtype) "
"ORDER BY nspname, c.relname, a.attnum" "ORDER BY nspname, c.relname, a.attnum"
); );
res = PQexec(conn, sql.data); res = PQexec(conn, sql.data);
@ -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++)
@ -113,12 +114,12 @@ main(int argc, char **argv)
resetPQExpBuffer(&sql); resetPQExpBuffer(&sql);
appendPQExpBuffer(&sql, appendPQExpBuffer(&sql,
"SELECT 1 " "SELECT 1 "
"FROM \"%s\".\"%s\" t1, " "FROM \"%s\".\"%s\" t1, "
"\"%s\".\"%s\" t2 " "\"%s\".\"%s\" t2 "
"WHERE t1.\"%s\"::pg_catalog.oid = t2.oid " "WHERE t1.\"%s\"::pg_catalog.oid = t2.oid "
"LIMIT 1", "LIMIT 1",
fk_nspname, fk_relname, pk_nspname, pk_relname, fk_attname); fk_nspname, fk_relname, pk_nspname, pk_relname, fk_attname);
res = PQexec(conn, sql.data); res = PQexec(conn, sql.data);
if (!res || PQresultStatus(res) != PGRES_TUPLES_OK) if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)

View File

@ -304,7 +304,7 @@ fti(PG_FUNCTION_ARGS)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN), (errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" of \"%s\" does not exist", errmsg("column \"%s\" of \"%s\" does not exist",
args[i + 1], indexname))); args[i + 1], indexname)));
/* Get the char* representation of the column */ /* Get the char* representation of the column */
column = SPI_getvalue(rettuple, tupdesc, colnum); column = SPI_getvalue(rettuple, tupdesc, colnum);
@ -339,8 +339,8 @@ fti(PG_FUNCTION_ARGS)
ret = SPI_execp(*(plan->splan), values, NULL, 0); ret = SPI_execp(*(plan->splan), values, NULL, 0);
if (ret != SPI_OK_INSERT) if (ret != SPI_OK_INSERT)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
errmsg("error executing insert"))); errmsg("error executing insert")));
} }
pfree(buff); pfree(buff);
pfree(data); pfree(data);

View File

@ -87,7 +87,7 @@ levenshtein(PG_FUNCTION_ARGS)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument exceeds max length: %d", errmsg("argument exceeds max length: %d",
MAX_LEVENSHTEIN_STRLEN))); MAX_LEVENSHTEIN_STRLEN)));
/* /*
* If either rows or cols is 0, the answer is the other value. This * If either rows or cols is 0, the answer is the other value. This
@ -220,7 +220,7 @@ metaphone(PG_FUNCTION_ARGS)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument exceeds max length: %d", errmsg("argument exceeds max length: %d",
MAX_METAPHONE_STRLEN))); MAX_METAPHONE_STRLEN)));
if (!(str_i_len > 0)) if (!(str_i_len > 0))
ereport(ERROR, ereport(ERROR,
@ -232,7 +232,7 @@ metaphone(PG_FUNCTION_ARGS)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("output length exceeds max length: %d", errmsg("output length exceeds max length: %d",
MAX_METAPHONE_STRLEN))); MAX_METAPHONE_STRLEN)));
if (!(reqlen > 0)) if (!(reqlen > 0))
ereport(ERROR, ereport(ERROR,

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;
@ -194,7 +194,7 @@ int_enum(PG_FUNCTION_ARGS)
if (!rsi || !IsA(rsi, ReturnSetInfo)) if (!rsi || !IsA(rsi, ReturnSetInfo))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("int_enum called in context that cannot accept a set"))); errmsg("int_enum called in context that cannot accept a set")));
if (!p) if (!p)
{ {

View File

@ -91,19 +91,19 @@ typedef char *BITVECP;
*/ */
typedef struct typedef struct
{ {
int4 len; int4 len;
int4 flag; int4 flag;
char data[1]; char data[1];
} GISTTYPE; } GISTTYPE;
#define ALLISTRUE 0x04 #define ALLISTRUE 0x04
#define ISALLTRUE(x) ( ((GISTTYPE*)x)->flag & ALLISTRUE ) #define ISALLTRUE(x) ( ((GISTTYPE*)x)->flag & ALLISTRUE )
#define GTHDRSIZE ( sizeof(int4)*2 ) #define GTHDRSIZE ( sizeof(int4)*2 )
#define CALCGTSIZE(flag) ( GTHDRSIZE+(((flag) & ALLISTRUE) ? 0 : SIGLEN) ) #define CALCGTSIZE(flag) ( GTHDRSIZE+(((flag) & ALLISTRUE) ? 0 : SIGLEN) )
#define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) ) #define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) )
/* /*
** types for functions ** types for functions
@ -114,22 +114,22 @@ typedef void (*formfloat) (ArrayType *, float *);
/* /*
** useful function ** useful function
*/ */
bool isort(int4 *a, const int len); bool isort(int4 *a, const int len);
ArrayType *new_intArrayType(int num); ArrayType *new_intArrayType(int num);
ArrayType *copy_intArrayType(ArrayType *a); ArrayType *copy_intArrayType(ArrayType *a);
ArrayType *resize_intArrayType(ArrayType *a, int num); ArrayType *resize_intArrayType(ArrayType *a, int num);
int internal_size(int *a, int len); int internal_size(int *a, int len);
ArrayType *_int_unique(ArrayType *a); ArrayType *_int_unique(ArrayType *a);
int32 intarray_match_first(ArrayType *a, int32 elem); int32 intarray_match_first(ArrayType *a, int32 elem);
ArrayType *intarray_add_elem(ArrayType *a, int32 elem); ArrayType *intarray_add_elem(ArrayType *a, int32 elem);
ArrayType *intarray_concat_arrays(ArrayType *a, ArrayType *b); 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);
/***************************************************************************** /*****************************************************************************
@ -160,18 +160,16 @@ typedef struct
#define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) ) #define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) )
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT ) #define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
bool signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot); bool signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot);
bool execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot); bool execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot);
int compASC(const void *a, const void *b); int compASC(const void *a, const void *b);
int compDESC(const void *a, const void *b);
#define QSORT(a, direction) \
if (ARRNELEMS(a) > 1) \
qsort((void*)ARRPTR(a), ARRNELEMS(a),sizeof(int4), \
(direction) ? compASC : compDESC )
int compDESC(const void *a, const void *b);
#define QSORT(a, direction) \
if (ARRNELEMS(a) > 1) \
qsort((void*)ARRPTR(a), ARRNELEMS(a),sizeof(int4), \
(direction) ? compASC : compDESC )

View File

@ -299,7 +299,7 @@ signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot)
GETQUERY(query) + query->size - 1, GETQUERY(query) + query->size - 1,
(void *) sign, calcnot, (void *) sign, calcnot,
checkcondition_bit checkcondition_bit
); );
} }
bool bool
@ -326,7 +326,7 @@ rboolop(PG_FUNCTION_ARGS)
boolop, boolop,
PG_GETARG_DATUM(1), PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0) PG_GETARG_DATUM(0)
); );
} }
Datum Datum
@ -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); {
int *size = (int *) PG_GETARG_POINTER(1); bytea *entryvec = (bytea *) PG_GETARG_POINTER(0);
int4 i,len = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY); int *size = (int *) PG_GETARG_POINTER(1);
ArrayType *res; int4 i,
int totlen=0,*ptr; len = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
ArrayType *res;
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,22 +243,23 @@ 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 *newentry = (GISTENTRY *) PG_GETARG_POINTER(1); GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
float *result = (float *) PG_GETARG_POINTER(2); GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
float *result = (float *) PG_GETARG_POINTER(2);
ArrayType *ud; ArrayType *ud;
float tmp1, float tmp1,
tmp2; tmp2;
ud = inner_int_union((ArrayType *) DatumGetPointer(origentry->key), ud = inner_int_union((ArrayType *) DatumGetPointer(origentry->key),
(ArrayType *) DatumGetPointer(newentry->key)); (ArrayType *) DatumGetPointer(newentry->key));
rt__int_size(ud, &tmp1); rt__int_size(ud, &tmp1);
rt__int_size((ArrayType *) DatumGetPointer(origentry->key), &tmp2); rt__int_size((ArrayType *) DatumGetPointer(origentry->key), &tmp2);
*result = tmp1 - tmp2; *result = tmp1 - tmp2;
pfree(ud); pfree(ud);
PG_RETURN_POINTER (result); PG_RETURN_POINTER(result);
} }
@ -311,8 +316,9 @@ 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,
j; j;
@ -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

@ -45,8 +45,8 @@ array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree ** found)
if (ARR_NDIM(la) != 1) if (ARR_NDIM(la) != 1)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR), (errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
errmsg("array must be one-dimensional"))); errmsg("array must be one-dimensional")));
if (found) if (found)
*found = NULL; *found = NULL;
@ -133,38 +133,40 @@ _ltq_rregex(PG_FUNCTION_ARGS)
Datum Datum
_lt_q_regex(PG_FUNCTION_ARGS) _lt_q_regex(PG_FUNCTION_ARGS)
{ {
ArrayType *_tree = PG_GETARG_ARRAYTYPE_P(0); ArrayType *_tree = PG_GETARG_ARRAYTYPE_P(0);
ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1); ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
lquery *query = (lquery *) ARR_DATA_PTR(_query); lquery *query = (lquery *) ARR_DATA_PTR(_query);
bool res = false; bool res = false;
int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query)); int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
if (ARR_NDIM(_query) != 1) if (ARR_NDIM(_query) != 1)
ereport(ERROR, ereport(ERROR,
(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) ) { {
res = true; if (array_iterator(_tree, ltq_regex, (void *) query, NULL))
break; {
} res = true;
num--; break;
query = (lquery*)NEXTVAL(query); }
} num--;
query = (lquery *) NEXTVAL(query);
}
PG_FREE_IF_COPY(_tree, 0); PG_FREE_IF_COPY(_tree, 0);
PG_FREE_IF_COPY(_query, 1); PG_FREE_IF_COPY(_query, 1);
PG_RETURN_BOOL(res); PG_RETURN_BOOL(res);
} }
Datum Datum
_lt_q_rregex(PG_FUNCTION_ARGS) _lt_q_rregex(PG_FUNCTION_ARGS)
{ {
PG_RETURN_DATUM(DirectFunctionCall2(_lt_q_regex, PG_RETURN_DATUM(DirectFunctionCall2(_lt_q_regex,
PG_GETARG_DATUM(1), PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0) PG_GETARG_DATUM(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; {
uint32 high_pos; bool muse;
} SomeStack = {false,0,}; uint32 high_pos;
} 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; {
if ( ptr ) FieldNot tmpptr;
memcpy(&tmpptr,ptr,sizeof(FieldNot));
SomeStack.high_pos = high_pos-cur_tpos; if (ptr)
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)
@ -311,19 +319,21 @@ Datum
lt_q_regex(PG_FUNCTION_ARGS) lt_q_regex(PG_FUNCTION_ARGS)
{ {
ltree *tree = PG_GETARG_LTREE(0); ltree *tree = PG_GETARG_LTREE(0);
ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1); ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
lquery *query = (lquery *) ARR_DATA_PTR(_query); lquery *query = (lquery *) ARR_DATA_PTR(_query);
bool res = false; bool res = false;
int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query)); int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
if (ARR_NDIM(_query) != 1) if (ARR_NDIM(_query) != 1)
ereport(ERROR, ereport(ERROR,
(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

@ -22,7 +22,7 @@ Datum lquery_out(PG_FUNCTION_ARGS);
#define UNCHAR ereport(ERROR, \ #define UNCHAR ereport(ERROR, \
(errcode(ERRCODE_SYNTAX_ERROR), \ (errcode(ERRCODE_SYNTAX_ERROR), \
errmsg("syntax error at position %d near \"%c\"", \ errmsg("syntax error at position %d near \"%c\"", \
(int)(ptr-buf), *ptr))); (int)(ptr-buf), *ptr)));
@ -81,8 +81,8 @@ ltree_in(PG_FUNCTION_ARGS)
(errcode(ERRCODE_NAME_TOO_LONG), (errcode(ERRCODE_NAME_TOO_LONG),
errmsg("name of level is too long"), errmsg("name of level is too long"),
errdetail("name length is %d, must " \ errdetail("name length is %d, must " \
"be < 256, in position %d", "be < 256, in position %d",
lptr->len, (int) (lptr->start - buf)))); lptr->len, (int) (lptr->start - buf))));
totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE); totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
lptr++; lptr++;
@ -105,8 +105,8 @@ ltree_in(PG_FUNCTION_ARGS)
(errcode(ERRCODE_NAME_TOO_LONG), (errcode(ERRCODE_NAME_TOO_LONG),
errmsg("name of level is too long"), errmsg("name of level is too long"),
errdetail("name length is %d, must " \ errdetail("name length is %d, must " \
"be < 256, in position %d", "be < 256, in position %d",
lptr->len, (int) (lptr->start - buf)))); lptr->len, (int) (lptr->start - buf))));
totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE); totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
lptr++; lptr++;
@ -283,8 +283,8 @@ lquery_in(PG_FUNCTION_ARGS)
(errcode(ERRCODE_NAME_TOO_LONG), (errcode(ERRCODE_NAME_TOO_LONG),
errmsg("name of level is too long"), errmsg("name of level is too long"),
errdetail("name length is %d, must " \ errdetail("name length is %d, must " \
"be < 256, in position %d", "be < 256, in position %d",
lptr->len, (int) (lptr->start - buf)))); lptr->len, (int) (lptr->start - buf))));
state = LQPRS_WAITVAR; state = LQPRS_WAITVAR;
} }
@ -299,8 +299,8 @@ lquery_in(PG_FUNCTION_ARGS)
(errcode(ERRCODE_NAME_TOO_LONG), (errcode(ERRCODE_NAME_TOO_LONG),
errmsg("name of level is too long"), errmsg("name of level is too long"),
errdetail("name length is %d, must " \ errdetail("name length is %d, must " \
"be < 256, in position %d", "be < 256, in position %d",
lptr->len, (int) (lptr->start - buf)))); lptr->len, (int) (lptr->start - buf))));
state = LQPRS_WAITLEVEL; state = LQPRS_WAITLEVEL;
curqlevel = NEXTLEV(curqlevel); curqlevel = NEXTLEV(curqlevel);
@ -412,8 +412,8 @@ lquery_in(PG_FUNCTION_ARGS)
(errcode(ERRCODE_NAME_TOO_LONG), (errcode(ERRCODE_NAME_TOO_LONG),
errmsg("name of level is too long"), errmsg("name of level is too long"),
errdetail("name length is %d, must " \ errdetail("name length is %d, must " \
"be < 256, in position %d", "be < 256, in position %d",
lptr->len, (int) (lptr->start - buf)))); lptr->len, (int) (lptr->start - buf))));
} }
else if (state == LQPRS_WAITOPEN) else if (state == LQPRS_WAITOPEN)
curqlevel->high = 0xffff; curqlevel->high = 0xffff;
@ -442,7 +442,7 @@ lquery_in(PG_FUNCTION_ARGS)
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("syntax error"), errmsg("syntax error"),
errdetail("Low limit(%d) is greater than upper(%d).", errdetail("Low limit(%d) is greater than upper(%d).",
curqlevel->low, curqlevel->high))); curqlevel->low, curqlevel->high)));
curqlevel = NEXTLEV(curqlevel); curqlevel = NEXTLEV(curqlevel);
} }

View File

@ -83,49 +83,49 @@ Datum
ltree_cmp(PG_FUNCTION_ARGS) ltree_cmp(PG_FUNCTION_ARGS)
{ {
RUNCMP RUNCMP
PG_RETURN_INT32(res); PG_RETURN_INT32(res);
} }
Datum Datum
ltree_lt(PG_FUNCTION_ARGS) ltree_lt(PG_FUNCTION_ARGS)
{ {
RUNCMP RUNCMP
PG_RETURN_BOOL((res < 0) ? true : false); PG_RETURN_BOOL((res < 0) ? true : false);
} }
Datum Datum
ltree_le(PG_FUNCTION_ARGS) ltree_le(PG_FUNCTION_ARGS)
{ {
RUNCMP RUNCMP
PG_RETURN_BOOL((res <= 0) ? true : false); PG_RETURN_BOOL((res <= 0) ? true : false);
} }
Datum Datum
ltree_eq(PG_FUNCTION_ARGS) ltree_eq(PG_FUNCTION_ARGS)
{ {
RUNCMP RUNCMP
PG_RETURN_BOOL((res == 0) ? true : false); PG_RETURN_BOOL((res == 0) ? true : false);
} }
Datum Datum
ltree_ge(PG_FUNCTION_ARGS) ltree_ge(PG_FUNCTION_ARGS)
{ {
RUNCMP RUNCMP
PG_RETURN_BOOL((res >= 0) ? true : false); PG_RETURN_BOOL((res >= 0) ? true : false);
} }
Datum Datum
ltree_gt(PG_FUNCTION_ARGS) ltree_gt(PG_FUNCTION_ARGS)
{ {
RUNCMP RUNCMP
PG_RETURN_BOOL((res > 0) ? true : false); PG_RETURN_BOOL((res > 0) ? true : false);
} }
Datum Datum
ltree_ne(PG_FUNCTION_ARGS) ltree_ne(PG_FUNCTION_ARGS)
{ {
RUNCMP RUNCMP
PG_RETURN_BOOL((res != 0) ? true : false); PG_RETURN_BOOL((res != 0) ? true : false);
} }
Datum Datum
@ -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);
@ -496,18 +505,18 @@ Datum
text2ltree(PG_FUNCTION_ARGS) text2ltree(PG_FUNCTION_ARGS)
{ {
text *in = PG_GETARG_TEXT_P(0); text *in = PG_GETARG_TEXT_P(0);
char *s = (char *) palloc(VARSIZE(in) - VARHDRSZ + 1); char *s = (char *) palloc(VARSIZE(in) - VARHDRSZ + 1);
ltree *out; ltree *out;
memcpy(s, VARDATA(in), VARSIZE(in) - VARHDRSZ); memcpy(s, VARDATA(in), VARSIZE(in) - VARHDRSZ);
s[VARSIZE(in) - VARHDRSZ] = '\0'; s[VARSIZE(in) - VARHDRSZ] = '\0';
out = (ltree *) DatumGetPointer(DirectFunctionCall1( out = (ltree *) DatumGetPointer(DirectFunctionCall1(
ltree_in, ltree_in,
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);
} }
@ -516,16 +525,18 @@ Datum
ltree2text(PG_FUNCTION_ARGS) ltree2text(PG_FUNCTION_ARGS)
{ {
ltree *in = PG_GETARG_LTREE(0); ltree *in = PG_GETARG_LTREE(0);
char *ptr; char *ptr;
int i; int i;
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);
} }

View File

@ -356,8 +356,8 @@ sql_exec_dumptable(PGconn *conn, int systables)
snprintf(todo, 1024, "select relfilenode,relname from pg_class order by relname"); snprintf(todo, 1024, "select relfilenode,relname from pg_class order by relname");
else else
snprintf(todo, 1024, "select relfilenode,relname from pg_class " snprintf(todo, 1024, "select relfilenode,relname from pg_class "
"where relkind not in ('v','s', 'c') and " "where relkind not in ('v','s', 'c') and "
"relname not like 'pg_%%' order by relname"); "relname not like 'pg_%%' order by relname");
sql_exec(conn, todo, 0); sql_exec(conn, todo, 0);
} }

File diff suppressed because it is too large Load Diff

View File

@ -23,19 +23,19 @@
#include "/usr/include/pgsql/server/lib/dllist.h" #include "/usr/include/pgsql/server/lib/dllist.h"
*/ */
#define AUTOVACUUM_DEBUG 1 #define AUTOVACUUM_DEBUG 1
#define VACBASETHRESHOLD 1000 #define VACBASETHRESHOLD 1000
#define VACSCALINGFACTOR 2 #define VACSCALINGFACTOR 2
#define SLEEPBASEVALUE 300 #define SLEEPBASEVALUE 300
#define SLEEPSCALINGFACTOR 2 #define SLEEPSCALINGFACTOR 2
#define UPDATE_INTERVAL 2 #define UPDATE_INTERVAL 2
/* these two constants are used to tell update_table_stats what operation we just perfomred */ /* these two constants are used to tell update_table_stats what operation we just perfomred */
#define VACUUM_ANALYZE 0 #define VACUUM_ANALYZE 0
#define ANALYZE_ONLY 1 #define ANALYZE_ONLY 1
#define TABLE_STATS_ALL "select a.relfilenode,a.relname,a.relnamespace,a.relpages,a.reltuples,b.schemaname,b.n_tup_ins,b.n_tup_upd,b.n_tup_del from pg_class a, pg_stat_all_tables b where a.relfilenode=b.relid" #define TABLE_STATS_ALL "select a.relfilenode,a.relname,a.relnamespace,a.relpages,a.reltuples,b.schemaname,b.n_tup_ins,b.n_tup_upd,b.n_tup_del from pg_class a, pg_stat_all_tables b where a.relfilenode=b.relid"
#define TABLE_STATS_USER "select a.relfilenode,a.relname,a.relnamespace,a.relpages,a.reltuples,b.schemaname,b.n_tup_ins,b.n_tup_upd,b.n_tup_del from pg_class a, pg_stat_user_tables b where a.relfilenode=b.relid" #define TABLE_STATS_USER "select a.relfilenode,a.relname,a.relnamespace,a.relpages,a.reltuples,b.schemaname,b.n_tup_ins,b.n_tup_upd,b.n_tup_del from pg_class a, pg_stat_user_tables b where a.relfilenode=b.relid"
#define FRONTEND #define FRONTEND
#define PAGES_QUERY "select relfilenode,reltuples,relpages from pg_class where relfilenode=%i" #define PAGES_QUERY "select relfilenode,reltuples,relpages from pg_class where relfilenode=%i"
#define FROZENOID_QUERY "select oid,age(datfrozenxid) from pg_database where datname = 'template1'" #define FROZENOID_QUERY "select oid,age(datfrozenxid) from pg_database where datname = 'template1'"
@ -44,71 +44,96 @@
/* 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;
/* define cmd_args as global so we can get to them everywhere */ /* define cmd_args as global so we can get to them everywhere */
cmd_args *args; cmd_args *args;
/* Might need to add a time value for last time the whold database was vacuumed. /* Might need to add a time value for last time the whold database was vacuumed.
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;
PGconn *conn; int analyze_threshold,
char *dbname, *username, *password; vacuum_threshold; /* Use these as defaults for table
Dllist *table_list; * thresholds */
PGconn *conn;
char *dbname,
*username,
*password;
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
* ------------------------------------------------------------------------- * -------------------------------------------------------------------------
@ -26,7 +26,7 @@
#ifndef HAVE_GETOPT_LONG #ifndef HAVE_GETOPT_LONG
#include "getopt_long.h" #include "getopt_long.h"
int optreset; int optreset;
#endif #endif
char *progname = NULL; char *progname = NULL;

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,14 +134,15 @@ 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 (*encrypt) (PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res); int (*init) (PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv);
int (*decrypt) (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 block_size; int block_size;
int max_key_size; int max_key_size;
int stream_cipher; int stream_cipher;
}; };
typedef struct typedef struct
@ -224,7 +225,7 @@ static int
bf_ecb_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res) bf_ecb_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res)
{ {
unsigned bs = gen_ossl_block_size(c); unsigned bs = gen_ossl_block_size(c);
unsigned i; unsigned i;
ossldata *od = c->ptr; ossldata *od = c->ptr;
for (i = 0; i < dlen / bs; i++) for (i = 0; i < dlen / bs; i++)
@ -288,7 +289,7 @@ static int
ossl_des_init(PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv) ossl_des_init(PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv)
{ {
ossldata *od = c->ptr; ossldata *od = c->ptr;
des_cblock xkey; des_cblock xkey;
memset(&xkey, 0, sizeof(xkey)); memset(&xkey, 0, sizeof(xkey));
memcpy(&xkey, key, klen > 8 ? 8 : klen); memcpy(&xkey, key, klen > 8 ? 8 : klen);
@ -304,53 +305,53 @@ ossl_des_init(PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv)
static int static int
ossl_des_ecb_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, ossl_des_ecb_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
uint8 *res) uint8 *res)
{ {
unsigned bs = gen_ossl_block_size(c); unsigned bs = gen_ossl_block_size(c);
unsigned i; unsigned i;
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;
} }
static int static int
ossl_des_ecb_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, ossl_des_ecb_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
uint8 *res) uint8 *res)
{ {
unsigned bs = gen_ossl_block_size(c); unsigned bs = gen_ossl_block_size(c);
unsigned i; unsigned i;
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;
} }
static int static int
ossl_des_cbc_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, ossl_des_cbc_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
uint8 *res) uint8 *res)
{ {
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;
} }
static int static int
ossl_des_cbc_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, ossl_des_cbc_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
uint8 *res) uint8 *res)
{ {
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;
} }
@ -375,7 +376,7 @@ ossl_cast_ecb_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *re
{ {
unsigned bs = gen_ossl_block_size(c); unsigned bs = gen_ossl_block_size(c);
ossldata *od = c->ptr; ossldata *od = c->ptr;
const uint8 *end = data + dlen - bs; const uint8 *end = data + dlen - bs;
for (; data <= end; data += bs, res += bs) for (; data <= end; data += bs, res += bs)
CAST_ecb_encrypt(data, res, &od->u.cast_key, CAST_ENCRYPT); CAST_ecb_encrypt(data, res, &od->u.cast_key, CAST_ENCRYPT);
@ -387,7 +388,7 @@ ossl_cast_ecb_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *re
{ {
unsigned bs = gen_ossl_block_size(c); unsigned bs = gen_ossl_block_size(c);
ossldata *od = c->ptr; ossldata *od = c->ptr;
const uint8 *end = data + dlen - bs; const uint8 *end = data + dlen - bs;
for (; data <= end; data += bs, res += bs) for (; data <= end; data += bs, res += bs)
CAST_ecb_encrypt(data, res, &od->u.cast_key, CAST_DECRYPT); CAST_ecb_encrypt(data, res, &od->u.cast_key, CAST_DECRYPT);
@ -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
}; };
/* /*
@ -467,7 +468,7 @@ static const struct ossl_cipher ossl_cast_cbc = {
*/ */
static const struct static const struct
{ {
const char *name; const char *name;
const struct ossl_cipher *ciph; const struct ossl_cipher *ciph;
} ossl_cipher_types[] = } ossl_cipher_types[] =
@ -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>
@ -241,7 +241,7 @@ pg_gen_salt_rounds(PG_FUNCTION_ARGS)
if (len == 0) if (len == 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("no such crypt algorithm or bad number of rounds"))); errmsg("no such crypt algorithm or bad number of rounds")));
res = (text *) palloc(len + VARHDRSZ); res = (text *) palloc(len + VARHDRSZ);
VARATT_SIZEP(res) = len + VARHDRSZ; VARATT_SIZEP(res) = len + VARHDRSZ;

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

@ -73,8 +73,8 @@ autoinc(PG_FUNCTION_ARGS)
if (SPI_gettypeid(tupdesc, attnum) != INT4OID) if (SPI_gettypeid(tupdesc, attnum) != INT4OID)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
errmsg("attribute \"%s\" of \"%s\" must be type INT4", errmsg("attribute \"%s\" of \"%s\" must be type INT4",
args[i], relname))); args[i], relname)));
val = DatumGetInt32(SPI_getbinval(rettuple, tupdesc, attnum, &isnull)); val = DatumGetInt32(SPI_getbinval(rettuple, tupdesc, attnum, &isnull));

View File

@ -65,17 +65,17 @@ insert_username(PG_FUNCTION_ARGS)
if (attnum < 0) if (attnum < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
errmsg("\"%s\" has no attribute \"%s\"", relname, args[0]))); errmsg("\"%s\" has no attribute \"%s\"", relname, args[0])));
if (SPI_gettypeid(tupdesc, attnum) != TEXTOID) if (SPI_gettypeid(tupdesc, attnum) != TEXTOID)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
errmsg("attribute \"%s\" of \"%s\" must be type TEXT", errmsg("attribute \"%s\" of \"%s\" must be type TEXT",
args[0], relname))); args[0], relname)));
/* create fields containing name */ /* create fields containing name */
newval = DirectFunctionCall1(textin, newval = DirectFunctionCall1(textin,
CStringGetDatum(GetUserNameFromId(GetUserId()))); CStringGetDatum(GetUserNameFromId(GetUserId())));
/* construct new tuple */ /* construct new tuple */
rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newval, NULL); rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newval, NULL);

View File

@ -100,8 +100,8 @@ moddatetime(PG_FUNCTION_ARGS)
if (SPI_gettypeid(tupdesc, attnum) != TIMESTAMPOID) if (SPI_gettypeid(tupdesc, attnum) != TIMESTAMPOID)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
errmsg("attribute \"%s\" of \"%s\" must be type TIMESTAMP", errmsg("attribute \"%s\" of \"%s\" must be type TIMESTAMP",
args[0], relname))); args[0], relname)));
/* 1 is the number of items in the arrays attnum and newdt. /* 1 is the number of items in the arrays attnum and newdt.
attnum is the positional number of the field to be updated. attnum is the positional number of the field to be updated.

View File

@ -134,8 +134,8 @@ check_primary_key(PG_FUNCTION_ARGS)
if (fnumber < 0) if (fnumber < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN), (errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("there is no attribute \"%s\" in relation \"%s\"", errmsg("there is no attribute \"%s\" in relation \"%s\"",
args[i], SPI_getrelname(rel)))); args[i], SPI_getrelname(rel))));
/* Well, get binary (in internal format) value of column */ /* Well, get binary (in internal format) value of column */
kvals[i] = SPI_getbinval(tuple, tupdesc, fnumber, &isnull); kvals[i] = SPI_getbinval(tuple, tupdesc, fnumber, &isnull);
@ -365,8 +365,8 @@ check_foreign_key(PG_FUNCTION_ARGS)
if (fnumber < 0) if (fnumber < 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN), (errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("there is no attribute \"%s\" in relation \"%s\"", errmsg("there is no attribute \"%s\" in relation \"%s\"",
args[i], SPI_getrelname(rel)))); args[i], SPI_getrelname(rel))));
/* Well, get binary (in internal format) value of column */ /* Well, get binary (in internal format) value of column */
kvals[i] = SPI_getbinval(trigtuple, tupdesc, fnumber, &isnull); kvals[i] = SPI_getbinval(trigtuple, tupdesc, fnumber, &isnull);
@ -591,7 +591,7 @@ check_foreign_key(PG_FUNCTION_ARGS)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION), (errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
errmsg("\"%s\": tuple is referenced in \"%s\"", errmsg("\"%s\": tuple is referenced in \"%s\"",
trigger->tgname, relname))); trigger->tgname, relname)));
} }
else else
{ {

View File

@ -6,11 +6,11 @@
/* Modified by BÖJTHE Zoltán, Hungary, mailto:urdesobt@axelero.hu */ /* Modified by BÖJTHE Zoltán, Hungary, mailto:urdesobt@axelero.hu */
#include "executor/spi.h" /* this is what you need to work with SPI */ #include "executor/spi.h" /* this is what you need to work with SPI */
#include "commands/trigger.h" /* -"- and triggers */ #include "commands/trigger.h" /* -"- and triggers */
#include "miscadmin.h" /* for GetPgUserName() */ #include "miscadmin.h" /* for GetPgUserName() */
#include <ctype.h> /* tolower () */ #include <ctype.h> /* tolower () */
#define ABSTIMEOID 702 /* it should be in pg_type.h */ #define ABSTIMEOID 702 /* it should be in pg_type.h */
/* AbsoluteTime currabstime(void); */ /* AbsoluteTime currabstime(void); */
Datum timetravel(PG_FUNCTION_ARGS); Datum timetravel(PG_FUNCTION_ARGS);
@ -28,13 +28,13 @@ static int nPlans = 0;
typedef struct _TTOffList typedef struct _TTOffList
{ {
struct _TTOffList *next; struct _TTOffList *next;
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);
/* /*
@ -71,57 +71,57 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
PG_FUNCTION_INFO_V1(timetravel); PG_FUNCTION_INFO_V1(timetravel);
Datum /* have to return HeapTuple to Executor */ Datum /* have to return HeapTuple to Executor */
timetravel(PG_FUNCTION_ARGS) timetravel(PG_FUNCTION_ARGS)
{ {
TriggerData *trigdata = (TriggerData *) fcinfo->context; TriggerData *trigdata = (TriggerData *) fcinfo->context;
Trigger *trigger; /* to get trigger name */ Trigger *trigger; /* to get trigger name */
int argc; int argc;
char **args; /* arguments */ char **args; /* arguments */
int attnum[MaxAttrNum]; /* fnumbers of start/stop columns */ int attnum[MaxAttrNum]; /* fnumbers of start/stop columns */
Datum oldtimeon, Datum oldtimeon,
oldtimeoff; oldtimeoff;
Datum newtimeon, Datum newtimeon,
newtimeoff, newtimeoff,
newuser, newuser,
nulltext; nulltext;
Datum *cvals; /* column values */ Datum *cvals; /* column values */
char *cnulls; /* column nulls */ char *cnulls; /* column nulls */
char *relname; /* triggered relation name */ char *relname; /* triggered relation name */
Relation rel; /* triggered relation */ Relation rel; /* triggered relation */
HeapTuple trigtuple; HeapTuple trigtuple;
HeapTuple newtuple = NULL; HeapTuple newtuple = NULL;
HeapTuple rettuple; HeapTuple rettuple;
TupleDesc tupdesc; /* tuple description */ TupleDesc tupdesc; /* tuple description */
int natts; /* # of attributes */ int natts; /* # of attributes */
EPlan *plan; /* prepared plan */ EPlan *plan; /* prepared plan */
char ident[2 * NAMEDATALEN]; char ident[2 * NAMEDATALEN];
bool isnull; /* to know is some column NULL or not */ bool isnull; /* to know is some column NULL or not */
bool isinsert = false; bool isinsert = false;
int ret; int ret;
int i; int i;
/* /*
* Some checks first... * Some checks first...
*/ */
/* 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,39 +148,39 @@ 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]);
} }
/* 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];
Datum newvals[MaxAttrNum]; Datum newvals[MaxAttrNum];
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,10 +189,10 @@ 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;
newnulls[chnattrs] = ' '; newnulls[chnattrs] = ' ';
@ -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,27 +270,28 @@ 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,11 +304,11 @@ 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;
char sql[8192]; char sql[8192];
/* allocate ctypes for preparation */ /* allocate ctypes for preparation */
ctypes = (Oid *) palloc(natts * sizeof(Oid)); ctypes = (Oid *) palloc(natts * sizeof(Oid));
@ -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,14 +353,14 @@ 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];
Datum newvals[MaxAttrNum]; Datum newvals[MaxAttrNum];
char newnulls[MaxAttrNum]; char newnulls[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 */
@ -417,23 +420,24 @@ PG_FUNCTION_INFO_V1(set_timetravel);
Datum Datum
set_timetravel(PG_FUNCTION_ARGS) set_timetravel(PG_FUNCTION_ARGS)
{ {
Name relname = PG_GETARG_NAME(0); Name relname = PG_GETARG_NAME(0);
int32 on = PG_GETARG_INT32(1); int32 on = PG_GETARG_INT32(1);
char *rname; char *rname;
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);
@ -470,7 +474,7 @@ set_timetravel(PG_FUNCTION_ARGS)
/* /*
* get_timetravel (relname) -- * get_timetravel (relname) --
* get timetravel status for specified relation (ON/OFF) * get timetravel status for specified relation (ON/OFF)
*/ */
PG_FUNCTION_INFO_V1(get_timetravel); PG_FUNCTION_INFO_V1(get_timetravel);
@ -478,11 +482,11 @@ Datum
get_timetravel(PG_FUNCTION_ARGS) 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;
} }
@ -509,17 +514,17 @@ currabstime()
static EPlan * static EPlan *
find_plan(char *ident, EPlan ** eplan, int *nplans) 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

@ -42,11 +42,11 @@
#include "tablefunc.h" #include "tablefunc.h"
static int load_categories_hash(char *cats_sql, MemoryContext per_query_ctx); static int load_categories_hash(char *cats_sql, MemoryContext per_query_ctx);
static Tuplestorestate *get_crosstab_tuplestore(char *sql, static Tuplestorestate *get_crosstab_tuplestore(char *sql,
int num_categories, int num_categories,
TupleDesc tupdesc, TupleDesc tupdesc,
MemoryContext per_query_ctx); MemoryContext per_query_ctx);
static void validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial); static void validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial);
static bool compatCrosstabTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2); static bool compatCrosstabTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
static bool compatConnectbyTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2); static bool compatConnectbyTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2);
@ -56,7 +56,7 @@ static TupleDesc make_crosstab_tupledesc(TupleDesc spi_tupdesc,
static Tuplestorestate *connectby(char *relname, static Tuplestorestate *connectby(char *relname,
char *key_fld, char *key_fld,
char *parent_key_fld, char *parent_key_fld,
char *orderby_fld, char *orderby_fld,
char *branch_delim, char *branch_delim,
char *start_with, char *start_with,
int max_depth, int max_depth,
@ -115,7 +115,7 @@ static HTAB *crosstab_HashTable;
typedef struct crosstab_cat_desc typedef struct crosstab_cat_desc
{ {
char *catname; char *catname;
int attidx; /* zero based */ int attidx; /* zero based */
} crosstab_cat_desc; } crosstab_cat_desc;
#define MAX_CATNAME_LEN NAMEDATALEN #define MAX_CATNAME_LEN NAMEDATALEN
@ -157,9 +157,9 @@ do { \
/* hash table */ /* hash table */
typedef struct crosstab_hashent typedef struct crosstab_hashent
{ {
char internal_catname[MAX_CATNAME_LEN]; char internal_catname[MAX_CATNAME_LEN];
crosstab_cat_desc *catdesc; crosstab_cat_desc *catdesc;
} crosstab_HashEnt; } crosstab_HashEnt;
/* /*
* normal_rand - return requested number of random values * normal_rand - return requested number of random values
@ -414,7 +414,7 @@ crosstab(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid source data SQL statement"), errmsg("invalid source data SQL statement"),
errdetail("The provided SQL must return 3 " \ errdetail("The provided SQL must return 3 " \
" columns; rowid, category, and values."))); " columns; rowid, category, and values.")));
} }
else else
{ {
@ -705,13 +705,13 @@ PG_FUNCTION_INFO_V1(crosstab_hash);
Datum Datum
crosstab_hash(PG_FUNCTION_ARGS) crosstab_hash(PG_FUNCTION_ARGS)
{ {
char *sql = GET_STR(PG_GETARG_TEXT_P(0)); char *sql = GET_STR(PG_GETARG_TEXT_P(0));
char *cats_sql = GET_STR(PG_GETARG_TEXT_P(1)); char *cats_sql = GET_STR(PG_GETARG_TEXT_P(1));
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
TupleDesc tupdesc; TupleDesc tupdesc;
MemoryContext per_query_ctx; MemoryContext per_query_ctx;
MemoryContext oldcontext; MemoryContext oldcontext;
int num_categories; int num_categories;
/* check to see if caller supports us returning a tuplestore */ /* check to see if caller supports us returning a tuplestore */
if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize)) if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
@ -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,
@ -770,19 +770,19 @@ crosstab_hash(PG_FUNCTION_ARGS)
static int static int
load_categories_hash(char *cats_sql, MemoryContext per_query_ctx) load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
{ {
HASHCTL ctl; HASHCTL ctl;
int ret; int ret;
int proc; int proc;
MemoryContext SPIcontext; MemoryContext SPIcontext;
int num_categories = 0; int num_categories = 0;
/* initialize the category hash table */ /* initialize the category hash table */
ctl.keysize = MAX_CATNAME_LEN; ctl.keysize = MAX_CATNAME_LEN;
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);
@ -798,13 +798,13 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
/* Check for qualifying tuples */ /* Check for qualifying tuples */
if ((ret == SPI_OK_SELECT) && (proc > 0)) if ((ret == SPI_OK_SELECT) && (proc > 0))
{ {
SPITupleTable *spi_tuptable = SPI_tuptable; SPITupleTable *spi_tuptable = SPI_tuptable;
TupleDesc spi_tupdesc = spi_tuptable->tupdesc; TupleDesc spi_tupdesc = spi_tuptable->tupdesc;
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,
@ -814,9 +814,9 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
for (i = 0; i < proc; i++) for (i = 0; i < proc; i++)
{ {
crosstab_cat_desc *catdesc; crosstab_cat_desc *catdesc;
char *catname; char *catname;
HeapTuple spi_tuple; HeapTuple spi_tuple;
/* get the next sql result tuple */ /* get the next sql result tuple */
spi_tuple = spi_tuptable->vals[i]; spi_tuple = spi_tuptable->vals[i];
@ -862,13 +862,13 @@ get_crosstab_tuplestore(char *sql,
TupleDesc tupdesc, TupleDesc tupdesc,
MemoryContext per_query_ctx) MemoryContext per_query_ctx)
{ {
Tuplestorestate *tupstore; Tuplestorestate *tupstore;
AttInMetadata *attinmeta = TupleDescGetAttInMetadata(tupdesc); AttInMetadata *attinmeta = TupleDescGetAttInMetadata(tupdesc);
char **values; char **values;
HeapTuple tuple; HeapTuple tuple;
int ret; int ret;
int proc; int proc;
MemoryContext SPIcontext; MemoryContext SPIcontext;
/* initialize our tuplestore */ /* initialize our tuplestore */
tupstore = tuplestore_begin_heap(true, false, SortMem); tupstore = tuplestore_begin_heap(true, false, SortMem);
@ -885,33 +885,36 @@ get_crosstab_tuplestore(char *sql,
/* Check for qualifying tuples */ /* Check for qualifying tuples */
if ((ret == SPI_OK_SELECT) && (proc > 0)) if ((ret == SPI_OK_SELECT) && (proc > 0))
{ {
SPITupleTable *spi_tuptable = SPI_tuptable; SPITupleTable *spi_tuptable = SPI_tuptable;
TupleDesc spi_tupdesc = spi_tuptable->tupdesc; TupleDesc spi_tupdesc = spi_tuptable->tupdesc;
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,
int result_ncols; j;
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,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid source data SQL statement"), errmsg("invalid source data SQL statement"),
errdetail("The provided SQL must return 3 " \ errdetail("The provided SQL must return 3 " \
" columns; rowid, category, and values."))); " columns; rowid, category, and values.")));
result_ncols = (ncols - 2) + num_categories; result_ncols = (ncols - 2) + num_categories;
@ -922,7 +925,7 @@ get_crosstab_tuplestore(char *sql,
errmsg("invalid return type"), errmsg("invalid return type"),
errdetail("query-specified return " \ errdetail("query-specified return " \
"tuple has %d columns but crosstab " \ "tuple has %d columns but crosstab " \
"returns %d", tupdesc->natts, result_ncols))); "returns %d", tupdesc->natts, result_ncols)));
/* allocate space */ /* allocate space */
values = (char **) palloc(result_ncols * sizeof(char *)); values = (char **) palloc(result_ncols * sizeof(char *));
@ -932,9 +935,9 @@ get_crosstab_tuplestore(char *sql,
for (i = 0; i < proc; i++) for (i = 0; i < proc; i++)
{ {
HeapTuple spi_tuple; HeapTuple spi_tuple;
crosstab_cat_desc *catdesc; crosstab_cat_desc *catdesc;
char *catname; char *catname;
/* get the next sql result tuple */ /* get the next sql result tuple */
spi_tuple = spi_tuptable->vals[i]; spi_tuple = spi_tuptable->vals[i];
@ -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 */
@ -1026,29 +1032,29 @@ get_crosstab_tuplestore(char *sql,
* *
* keyid parent_keyid pos * keyid parent_keyid pos
* ------+------------+-- * ------+------------+--
* row1 NULL 0 * row1 NULL 0
* row2 row1 0 * row2 row1 0
* row3 row1 0 * row3 row1 0
* row4 row2 1 * row4 row2 1
* row5 row2 0 * row5 row2 0
* row6 row4 0 * row6 row4 0
* row7 row3 0 * row7 row3 0
* row8 row6 0 * row8 row6 0
* row9 row5 0 * row9 row5 0
* *
* *
* connectby(text relname, text keyid_fld, text parent_keyid_fld * connectby(text relname, text keyid_fld, text parent_keyid_fld
* [, text orderby_fld], text start_with, int max_depth * [, text orderby_fld], text start_with, int max_depth
* [, text branch_delim]) * [, text branch_delim])
* connectby('foo', 'keyid', 'parent_keyid', 'pos', 'row2', 0, '~') returns: * connectby('foo', 'keyid', 'parent_keyid', 'pos', 'row2', 0, '~') returns:
* *
* keyid parent_id level branch serial * keyid parent_id level branch serial
* ------+-----------+--------+----------------------- * ------+-----------+--------+-----------------------
* row2 NULL 0 row2 1 * row2 NULL 0 row2 1
* row5 row2 1 row2~row5 2 * row5 row2 1 row2~row5 2
* row9 row5 2 row2~row5~row9 3 * row9 row5 2 row2~row5~row9 3
* row4 row2 1 row2~row4 4 * row4 row2 1 row2~row4 4
* row6 row4 2 row2~row4~row6 5 * row6 row4 2 row2~row4~row6 5
* row8 row6 3 row2~row4~row6~row8 6 * row8 row6 3 row2~row4~row6~row8 6
* *
*/ */
@ -1114,7 +1120,7 @@ connectby_text(PG_FUNCTION_ARGS)
rsinfo->setResult = connectby(relname, rsinfo->setResult = connectby(relname,
key_fld, key_fld,
parent_key_fld, parent_key_fld,
NULL, NULL,
branch_delim, branch_delim,
start_with, start_with,
max_depth, max_depth,
@ -1192,7 +1198,7 @@ connectby_text_serial(PG_FUNCTION_ARGS)
rsinfo->setResult = connectby(relname, rsinfo->setResult = connectby(relname,
key_fld, key_fld,
parent_key_fld, parent_key_fld,
orderby_fld, orderby_fld,
branch_delim, branch_delim,
start_with, start_with,
max_depth, max_depth,
@ -1222,12 +1228,12 @@ static Tuplestorestate *
connectby(char *relname, connectby(char *relname,
char *key_fld, char *key_fld,
char *parent_key_fld, char *parent_key_fld,
char *orderby_fld, char *orderby_fld,
char *branch_delim, char *branch_delim,
char *start_with, char *start_with,
int max_depth, int max_depth,
bool show_branch, bool show_branch,
bool show_serial, bool show_serial,
MemoryContext per_query_ctx, MemoryContext per_query_ctx,
AttInMetadata *attinmeta) AttInMetadata *attinmeta)
{ {
@ -1235,7 +1241,7 @@ connectby(char *relname,
int ret; int ret;
MemoryContext oldcontext; MemoryContext oldcontext;
int serial = 1; int serial = 1;
/* Connect to SPI manager */ /* Connect to SPI manager */
if ((ret = SPI_connect()) < 0) if ((ret = SPI_connect()) < 0)
@ -1303,25 +1309,25 @@ build_tuplestore_recursively(char *key_fld,
if (!show_serial) if (!show_serial)
{ {
appendStringInfo(sql, "SELECT %s, %s FROM %s WHERE %s = '%s' AND %s IS NOT NULL", appendStringInfo(sql, "SELECT %s, %s FROM %s WHERE %s = '%s' AND %s IS NOT NULL",
key_fld, key_fld,
parent_key_fld, parent_key_fld,
relname, relname,
parent_key_fld, parent_key_fld,
start_with, start_with,
key_fld); key_fld);
serial_column=0; serial_column = 0;
} }
else else
{ {
appendStringInfo(sql, "SELECT %s, %s FROM %s WHERE %s = '%s' AND %s IS NOT NULL ORDER BY %s", appendStringInfo(sql, "SELECT %s, %s FROM %s WHERE %s = '%s' AND %s IS NOT NULL ORDER BY %s",
key_fld, key_fld,
parent_key_fld, parent_key_fld,
relname, relname,
parent_key_fld, parent_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 */
@ -1371,8 +1377,8 @@ build_tuplestore_recursively(char *key_fld,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid return type"), errmsg("invalid return type"),
errdetail("Return and SQL tuple descriptions are " \ errdetail("Return and SQL tuple descriptions are " \
"incompatible."))); "incompatible.")));
/* root value is the one we initially start with */ /* root value is the one we initially start with */
values[0] = start_with; values[0] = start_with;
@ -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)
@ -1546,7 +1552,7 @@ validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid return type"), errmsg("invalid return type"),
errdetail("Third column must be type %s.", errdetail("Third column must be type %s.",
format_type_be(INT4OID)))); format_type_be(INT4OID))));
/* check that the type of the fourth column is TEXT if applicable */ /* check that the type of the fourth column is TEXT if applicable */
if (show_branch && tupdesc->attrs[3]->atttypid != TEXTOID) if (show_branch && tupdesc->attrs[3]->atttypid != TEXTOID)
@ -1554,7 +1560,7 @@ validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid return type"), errmsg("invalid return type"),
errdetail("Fourth column must be type %s.", errdetail("Fourth column must be type %s.",
format_type_be(TEXTOID)))); format_type_be(TEXTOID))));
/* check that the type of the fifth column is INT4 */ /* check that the type of the fifth column is INT4 */
if (show_branch && show_serial && tupdesc->attrs[4]->atttypid != INT4OID) if (show_branch && show_serial && tupdesc->attrs[4]->atttypid != INT4OID)
@ -1596,7 +1602,7 @@ compatConnectbyTupleDescs(TupleDesc ret_tupdesc, TupleDesc sql_tupdesc)
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid return type"), errmsg("invalid return type"),
errdetail("SQL parent key field datatype does " \ errdetail("SQL parent key field datatype does " \
"not match return parent key field datatype."))); "not match return parent key field datatype.")));
/* OK, the two tupdescs are compatible for our purposes */ /* OK, the two tupdescs are compatible for our purposes */
return true; return true;

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
@ -175,7 +176,7 @@ lemmatize(char *word, int *len, int type)
} }
else if (nd == BYLOCALE) else if (nd == BYLOCALE)
{ {
continue; /* no dict for current locale */ continue; /* no dict for current locale */
} }
else else
{ {

View File

@ -4,55 +4,73 @@
#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; {
int tlen = 128, len=0; va_list args;
char *buf; int tlen = 128,
len = 0;
char *buf;
reset_cfg(); reset_cfg();
reset_dict(); reset_dict();
@ -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,185 +19,207 @@
/*********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 }; {
bool isnull; Oid arg[1] = {OIDOID};
Datum pars[1]={ ObjectIdGetDatum(id) }; bool isnull;
int stat; Datum pars[1] = {ObjectIdGetDatum(id)};
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; {
Oid oid=InvalidOid; Datum opt;
oid=DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) ); Oid oid = InvalidOid;
if ( !(isnull || oid==InvalidOid) ) {
opt=SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull); oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
dict->dictionary=(void*)DatumGetPointer(OidFunctionCall1(oid, opt)); if (!(isnull || oid == InvalidOid))
{
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; {
int len; DictInfo *last_dict;
int reallen; int len;
DictInfo *list; int reallen;
DictInfo *list;
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; {
key.dict_id=id; DictInfo key;
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; {
int reallen = ( DList.reallen ) ? 2*DList.reallen : 16; DictInfo *tmp;
tmp=(DictInfo*)realloc(DList.list,sizeof(DictInfo)*reallen); int reallen = (DList.reallen) ? 2 * DList.reallen : 16;
if ( !tmp )
ts_error(ERROR,"No memory"); tmp = (DictInfo *) realloc(DList.list, sizeof(DictInfo) * reallen);
DList.reallen=reallen; if (!tmp)
DList.list=tmp; ts_error(ERROR, "No memory");
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 }; {
bool isnull; Oid arg[1] = {TEXTOID};
Datum pars[1]={ PointerGetDatum(name) }; bool isnull;
int stat; Datum pars[1] = {PointerGetDatum(name)};
Oid id=findSNMap_t( &(DList.name2id_map), name ); int stat;
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;
} }
/******sql-level interface******/ /******sql-level interface******/
PG_FUNCTION_INFO_V1(lexize); 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));
Datum *da; char **res,
ArrayType *a; **ptr;
Datum *da;
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);
@ -207,19 +229,20 @@ 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); {
Datum res; text *dictname = PG_GETARG_TEXT_P(0);
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)
PG_RETURN_DATUM(res); PG_RETURN_DATUM(res);
@ -227,52 +250,54 @@ 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();
} }
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; {
if ( currect_dictionary_id == 0 ) Datum res;
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"),
errhint("Execute select set_curdict()."))); errhint("Execute select set_curdict().")));
res = DirectFunctionCall3( res = DirectFunctionCall3(
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; {
char **stop; int len;
char* (*wordop)(char*); char **stop;
} StopList; char *(*wordop) (char *);
} 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; {
FmgrInfo lexize_info; Oid dict_id;
void *dictionary; FmgrInfo lexize_info;
} DictInfo; void *dictionary;
} 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 *value; char *key;
} Map; char *value;
} 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)
{
text *in = PG_GETARG_TEXT_P(0);
if ( !PG_ARGISNULL(0) && PG_GETARG_POINTER(0)!=NULL ) {
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 *txt = pnstrdup(in, PG_GETARG_INT32(2)); char *in = (char *) PG_GETARG_POINTER(1);
char **res=palloc(sizeof(char*)*2); char *txt = pnstrdup(in, PG_GETARG_INT32(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,96 +12,117 @@
#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; {
Map *cfg, *pcfg; DictISpell *d;
text *in; Map *cfg,
bool affloaded=false, dictloaded=false, stoploaded=false; *pcfg;
text *in;
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),
errmsg("stop words already loaded"))); errmsg("stop words already loaded")));
} }
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),
errmsg("unrecognized option: %s => %s", errmsg("unrecognized option: %s => %s",
pcfg->key, pcfg->value))); pcfg->key, pcfg->value)));
} }
pfree(pcfg->key); pfree(pcfg->key);
pfree(pcfg->value); pfree(pcfg->value);
@ -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 *txt; char *in = (char *) PG_GETARG_POINTER(1);
char **res; char *txt;
char **ptr, **cptr; char **res;
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)
{
text *in = PG_GETARG_TEXT_P(0);
if ( !PG_ARGISNULL(0) && PG_GETARG_POINTER(0)!=NULL ) {
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)
{
text *in = PG_GETARG_TEXT_P(0);
if ( !PG_ARGISNULL(0) && PG_GETARG_POINTER(0)!=NULL ) {
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 *txt = pnstrdup(in, PG_GETARG_INT32(2)); char *in = (char *) PG_GETARG_POINTER(1);
char **res=palloc(sizeof(char*)*2); char *txt = pnstrdup(in, PG_GETARG_INT32(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 {
SN_set_current(d->z, strlen(txt), txt);
(d->stem)(d->z);
if ( d->z->p && d->z->l ) {
txt=repalloc(txt, d->z->l+1);
memcpy( txt, d->z->p, d->z->l);
txt[d->z->l]='\0';
}
res[0]=txt;
} }
res[1]=NULL; else
{
SN_set_current(d->z, strlen(txt), txt);
(d->stem) (d->z);
if (d->z->p && d->z->l)
{
txt = repalloc(txt, d->z->l + 1);
memcpy(txt, d->z->p, d->z->l);
txt[d->z->l] = '\0';
}
res[0] = txt;
}
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 *out; char *in;
} Syn; char *out;
} Syn;
typedef struct { typedef struct
int len; {
Syn *syn; int len;
} DictSyn; Syn *syn;
} 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; {
DictSyn *d; text *in;
int cur=0; DictSyn *d;
FILE *fin; int cur = 0;
char *filename; FILE *fin;
char buf[SYNBUFLEN]; char *filename;
char *starti,*starto,*end=NULL; char buf[SYNBUFLEN];
int slen; char *starti,
*starto,
*end = NULL;
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,38 +147,39 @@ 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);
PG_RETURN_POINTER(d); PG_RETURN_POINTER(d);
} }
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

@ -9,518 +9,648 @@
#define MAXNORMLEN 56 #define MAXNORMLEN 56
#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){ s++;
if (((*s>='A')&&(*s<='Z'))||((*s>='a')&&(*s<='z'))) flag = s;
while (*s)
{
if (((*s >= 'A') && (*s <= 'Z')) || ((*s >= 'a') && (*s <= 'z')))
s++; s++;
else { else
*s=0; {
*s = 0;
break; break;
} }
} }
}else{
flag="";
} }
else
flag = "";
strlower(str); strlower(str);
/* Dont load words if first letter is not required */ /* Dont load words if first letter is not required */
/* It allows to optimize loading at search time */ /* It allows to optimize loading at search time */
s=str; s = str;
while(*s){ while (*s)
if(*s=='\r')*s=0; {
if(*s=='\n')*s=0; if (*s == '\r')
*s = 0;
if (*s == '\n')
*s = 0;
s++; s++;
} }
AddSpell(Conf,str,flag); AddSpell(Conf, str, flag);
} }
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;
Conf->SpellTree.Left[Let] = i; if (CurLet != Let)
CurLet = Let; {
} Conf->SpellTree.Left[Let] = i;
Conf->SpellTree.Right[Let] = i; CurLet = Let;
}
Conf->SpellTree.Right[Let] = i;
} }
} }
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->SuffixTree.Left[i] = Conf->SuffixTree.Right[i] = -1; Conf->PrefixTree.Left[i] = Conf->PrefixTree.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) { {
Conf->PrefixTree.Left[Let] = i; Let = (int) (*(Affix->repl)) & 255;
CurLetP = Let; if (CurLetP != Let)
} {
Conf->PrefixTree.Right[Let] = i; Conf->PrefixTree.Left[Let] = i;
} else { CurLetP = Let;
Let = (Affix->replen) ? (int)(Affix->repl[Affix->replen-1]) & 255 : 0; }
if (CurLetS != Let) { Conf->PrefixTree.Right[Let] = i;
Conf->SuffixTree.Left[Let] = i; }
CurLetS = Let; else
} {
Conf->SuffixTree.Right[Let] = i; Let = (Affix->replen) ? (int) (Affix->repl[Affix->replen - 1]) & 255 : 0;
} if (CurLetS != Let)
} {
Conf->SuffixTree.Left[Let] = i;
CurLetS = Let;
}
Conf->SuffixTree.Right[Let] = i;
}
}
} }
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 */ {
char newword[2*MAXNORMLEN] = ""; regmatch_t subs[2]; /* workaround for apache&linux */
int err; char newword[2 * MAXNORMLEN] = "";
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 + len - Affix->replen, Affix->find);
strcpy(newword, word);
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)
regfree(&(Affix->reg)); {
return(NULL); /* regerror(err, &(Affix->reg), regerrstr, ERRSTRSIZE); */
} regfree(&(Affix->reg));
Affix->compile = 0; return (NULL);
} }
if(!(err=regexec(&(Affix->reg),newword,1,subs,0))){ Affix->compile = 0;
if(FindWord(Conf, newword, Affix->flag)) }
return pstrdup(newword); if (!(err = regexec(&(Affix->reg), newword, 1, subs, 0)))
} {
return NULL; if (FindWord(Conf, newword, Affix->flag))
return pstrdup(newword);
}
return NULL;
} }
#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] = "";
size_t newlen; int err,
AFFIX *CAffix = Conf->Affix; ls,
res,
lres;
size_t newlen;
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)
regfree(&(Affix->reg)); {
return (0); /* regerror(err, &(Affix->reg), regerrstr, ERRSTRSIZE); */
} regfree(&(Affix->reg));
Affix->compile = 0; return (0);
} }
if(!(err=regexec(&(Affix->reg),newword,1,subs,0))){ Affix->compile = 0;
SPELL * curspell;
if((curspell=FindWord(Conf, newword, Affix->flag))){
if ((*cur - forms) < (MAX_NORM-1)) {
**cur = pstrdup(newword);
(*cur)++; **cur = NULL;
}
}
newlen = strlen(newword);
ls = Conf->SuffixTree.Left[pi];
if ( ls>=0 && ((*cur - forms) < (MAX_NORM-1)) ) {
**cur = CheckSuffix(newword, newlen, &CAffix[ls], &lres, Conf);
if (**cur) {
(*cur)++; **cur = NULL;
} }
} if (!(err = regexec(&(Affix->reg), newword, 1, subs, 0)))
} {
return 0; SPELL *curspell;
if ((curspell = FindWord(Conf, newword, Affix->flag)))
{
if ((*cur - forms) < (MAX_NORM - 1))
{
**cur = pstrdup(newword);
(*cur)++;
**cur = NULL;
}
}
newlen = strlen(newword);
ls = Conf->SuffixTree.Left[pi];
if (ls >= 0 && ((*cur - forms) < (MAX_NORM - 1)))
{
**cur = CheckSuffix(newword, newlen, &CAffix[ls], &lres, Conf);
if (**cur)
{
(*cur)++;
**cur = NULL;
}
}
}
return 0;
} }
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,
SPELL *spell; ipi,
lp,
rp,
cp,
ls,
rs;
int lres,
rres,
cres = 0;
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; {
cres = 0; cp = (lp + rp) >> 1;
if ((cur - forms) < (MAX_NORM-1)) { cres = 0;
cres = CheckPrefix(word, len, &Affix[cp], Conf, ipi, forms, &cur); if ((cur - forms) < (MAX_NORM - 1))
} 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; {
rp--; lp = cp + 1;
} else { rp--;
lp++; }
rp--; else
} {
} lp++;
rp--;
/* check suffix */ }
ls = Conf->SuffixTree.Left[ipi];
rs = Conf->SuffixTree.Right[ipi];
while (ls >= 0 && ls <= rs) {
if ( ((cur - forms) < (MAX_NORM-1)) ) {
*cur = CheckSuffix(word, len, &Affix[ls], &lres, Conf);
if (*cur) {
cur++; *cur = NULL;
} }
}
if ( (rs > ls) && ((cur - forms) < (MAX_NORM-1)) ) {
*cur = CheckSuffix(word, len, &Affix[rs], &rres, Conf);
if (*cur) {
cur++; *cur = NULL;
}
}
ls++;
rs--;
} /* end while */
} /* for ipi */ /* check suffix */
ls = Conf->SuffixTree.Left[ipi];
rs = Conf->SuffixTree.Right[ipi];
while (ls >= 0 && ls <= rs)
{
if (((cur - forms) < (MAX_NORM - 1)))
{
*cur = CheckSuffix(word, len, &Affix[ls], &lres, Conf);
if (*cur)
{
cur++;
*cur = NULL;
}
}
if ((rs > ls) && ((cur - forms) < (MAX_NORM - 1)))
{
*cur = CheckSuffix(word, len, &Affix[rs], &rres, Conf);
if (*cur)
{
cur++;
*cur = NULL;
}
}
ls++;
rs--;
} /* end while */
if(cur==forms){ } /* for ipi */
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; {
AFFIX *Affix = (AFFIX *)Conf->Affix; int i;
AFFIX *Affix = (AFFIX *) Conf->Affix;
for (i = 0; i < Conf->naffixes; i++) { for (i = 0; i < Conf->naffixes; i++)
if (Affix[i].compile == 0) { {
regfree(&(Affix[i].reg)); if (Affix[i].compile == 0)
} 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,48 +4,53 @@
#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 flag[10]; char *word;
} SPELL; char flag[10];
} SPELL;
typedef struct aff_struct { typedef struct aff_struct
char flag; {
char type; char flag;
char mask[33]; char type;
char find[16]; char mask[33];
char repl[16]; char find[16];
regex_t reg; char repl[16];
size_t replen; regex_t reg;
char compile; size_t replen;
} AFFIX; char compile;
} AFFIX;
typedef struct Tree_struct { typedef struct Tree_struct
int Left[256], Right[256]; {
} Tree_struct; int Left[256],
Right[256];
} Tree_struct;
typedef struct { typedef struct
int maffixes; {
int naffixes; int maffixes;
AFFIX * Affix; int naffixes;
AFFIX *Affix;
int nspell; int nspell;
int mspell; int mspell;
SPELL *Spell; SPELL *Spell;
Tree_struct SpellTree; Tree_struct SpellTree;
Tree_struct PrefixTree; Tree_struct PrefixTree;
Tree_struct SuffixTree; Tree_struct SuffixTree;
} 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

@ -16,126 +16,164 @@
#define CS_WAITEQ 2 #define CS_WAITEQ 2
#define CS_WAITVALUE 3 #define CS_WAITVALUE 3
#define CS_INVALUE 4 #define CS_INVALUE 4
#define CS_IN2VALUE 5 #define CS_IN2VALUE 5
#define CS_WAITDELIM 6 #define CS_WAITDELIM 6
#define CS_INESC 7 #define CS_INESC 7
#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; {
char *ptr=VARDATA(in), *begin=NULL; Map *mptr;
char num=0; char *ptr = VARDATA(in),
int state=CS_WAITKEY; *begin = NULL;
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

@ -99,24 +99,36 @@ typedef struct
TI_IN_STATE valstate; TI_IN_STATE valstate;
/* tscfg */ /* tscfg */
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)))
@ -257,7 +273,7 @@ static void
pushval_morph(QPRS_STATE * state, int typeval, char *strval, int lenval, int2 weight) pushval_morph(QPRS_STATE * state, int typeval, char *strval, int lenval, int2 weight)
{ {
int4 count = 0; int4 count = 0;
PRSTEXT prs; PRSTEXT prs;
prs.lenwords = 32; prs.lenwords = 32;
prs.curwords = 0; prs.curwords = 0;
@ -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
@ -468,7 +488,7 @@ rexectsq(PG_FUNCTION_ARGS)
Datum Datum
exectsq(PG_FUNCTION_ARGS) exectsq(PG_FUNCTION_ARGS)
{ {
tsvector *val = (tsvector *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); tsvector *val = (tsvector *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1))); QUERYTYPE *query = (QUERYTYPE *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
CHKVAL chkval; CHKVAL chkval;
bool result; bool result;
@ -485,10 +505,10 @@ exectsq(PG_FUNCTION_ARGS)
chkval.values = STRPTR(val); chkval.values = STRPTR(val);
chkval.operand = GETOPERAND(query); chkval.operand = GETOPERAND(query);
result = TS_execute( result = TS_execute(
GETQUERY(query), GETQUERY(query),
&chkval, &chkval,
true, true,
checkcondition_str checkcondition_str
); );
PG_FREE_IF_COPY(val, 0); PG_FREE_IF_COPY(val, 0);
@ -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); {
char *str; text *in = PG_GETARG_TEXT_P(1);
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);
to_tsquery, Datum res = DirectFunctionCall2(
Int32GetDatum( name2id_cfg(name) ), to_tsquery,
PG_GETARG_DATUM(1) Int32GetDatum(name2id_cfg(name)),
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( {
to_tsquery, PG_RETURN_DATUM(DirectFunctionCall2(
Int32GetDatum( get_currcfg() ), to_tsquery,
PG_GETARG_DATUM(0) Int32GetDatum(get_currcfg()),
)); PG_GETARG_DATUM(0)
));
} }

View File

@ -17,9 +17,9 @@ typedef struct ITEM
int4 val; int4 val;
/* user-friendly value, must correlate with WordEntry */ /* user-friendly value, must correlate with WordEntry */
uint32 uint32
unused:1, unused:1,
length:11, length:11,
distance:20; distance:20;
} ITEM; } ITEM;
/* /*
@ -50,6 +50,6 @@ typedef struct
#define VALFALSE 7 #define VALFALSE 7
bool TS_execute(ITEM * curitem, void *checkval, bool TS_execute(ITEM * curitem, void *checkval,
bool calcnot, bool (*chkcond) (void *checkval, ITEM * val)); bool calcnot, bool (*chkcond) (void *checkval, ITEM * val));
#endif #endif

View File

@ -37,29 +37,35 @@ 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 ] )
#define DEF_NORM_METHOD 0 #define DEF_NORM_METHOD 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)
return 1e-30; {
if (w > 100)
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,87 +76,104 @@ 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) {
return strncmp( if (ptr->len == item->length)
eval + ptr->pos, return strncmp(
qval + item->distance, eval + ptr->pos,
item->length); qval + item->distance,
item->length);
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 *StopHigh = (WordEntry*)STRPTR(t); WordEntry *StopLow = ARRPTR(t);
WordEntry *StopMiddle; WordEntry *StopHigh = (WordEntry *) STRPTR(t);
int difference; WordEntry *StopMiddle;
int difference;
/* Loop invariant: StopLow <= item < StopHigh */ /* Loop invariant: StopLow <= item < StopHigh */
while (StopLow < StopHigh) while (StopLow < StopHigh)
{ {
StopMiddle = StopLow + (StopHigh - StopLow) / 2; StopMiddle = StopLow + (StopHigh - StopLow) / 2;
difference = WordECompareITEM(STRPTR(t), GETOPERAND(q), StopMiddle, item); difference = WordECompareITEM(STRPTR(t), GETOPERAND(q), StopMiddle, item);
if (difference == 0) if (difference == 0)
return StopMiddle; return StopMiddle;
else if (difference < 0) else if (difference < 0)
StopLow = StopMiddle + 1; StopLow = StopMiddle + 1;
else else
StopHigh = StopMiddle; StopHigh = StopMiddle;
} }
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);
WordEntry *entry; int i,
WordEntryPos *post,*ct; k,
int4 dimt,lenct,dist; l,
float res=-1.0; p;
ITEM *item=GETQUERY(q); WordEntry *entry;
WordEntryPos *post,
*ct;
int4 dimt,
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) ) ) { {
float curw; for (p = 0; p < lenct; p++)
if ( !dist ) dist=MAXENTRYPOS; {
curw= sqrt( wpos(&(post[l])) * wpos( &(ct[p]) ) * word_distance(dist) ); dist = abs(post[l].pos - ct[p].pos);
res = ( res < 0 ) ? curw : 1.0 - ( 1.0 - res ) * ( 1.0 - curw ); if (dist || (dist == 0 && (pos[i] == (uint16 *) POSNULL || pos[k] == (uint16 *) POSNULL)))
{
float curw;
if (!dist)
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; {
WordEntryPos *post; WordEntry *entry;
int4 dimt,j,i; WordEntryPos *post;
float res=-1.0; int4 dimt,
ITEM *item=GETQUERY(q); j,
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); {
float res=0.0; ITEM *item = GETQUERY(q);
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; {
int32 pos; ITEM *item;
} DocRepresentation; int32 pos;
} 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; {
DocRepresentation *ptr,*f=(DocRepresentation*)0xffffffff; int i;
ITEM *item=GETQUERY(query); DocRepresentation *ptr,
int lastpos=*pos; *f = (DocRepresentation *) 0xffffffff;
int oldq=*q; ITEM *item = GETQUERY(query);
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); {
WordEntry *entry; ITEM *item = GETQUERY(query);
WordEntryPos *post; WordEntry *entry;
int4 dimt,j,i; WordEntryPos *post;
int len=query->size*4,cur=0; int4 dimt,
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,39 +515,50 @@ 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); {
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); int K = PG_GETARG_INT32(0);
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);
PG_FREE_IF_COPY(txt, 1); PG_FREE_IF_COPY(txt, 1);
@ -481,120 +569,141 @@ rank_cd(PG_FUNCTION_ARGS) {
Datum Datum
rank_cd_def(PG_FUNCTION_ARGS) { rank_cd_def(PG_FUNCTION_ARGS)
PG_RETURN_DATUM( DirectFunctionCall4( {
rank_cd, PG_RETURN_DATUM(DirectFunctionCall4(
Int32GetDatum(-1), rank_cd,
PG_GETARG_DATUM(0), Int32GetDatum(-1),
PG_GETARG_DATUM(1), PG_GETARG_DATUM(0),
( PG_NARGS() == 3 ) ? PG_GETARG_DATUM(2) : Int32GetDatum(DEF_NORM_METHOD) PG_GETARG_DATUM(1),
)); (PG_NARGS() == 3) ? PG_GETARG_DATUM(2) : Int32GetDatum(DEF_NORM_METHOD)
));
} }
/**************debug*************/ /**************debug*************/
typedef struct { typedef struct
char *w; {
int2 len; char *w;
int2 pos; int2 len;
int2 start; int2 pos;
int2 finish; int2 start;
} DocWord; int2 finish;
} 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,
text *out; j,
char *cptr; cur = 0,
len = 0,
rlen;
DocWord *dw,
*dwptr;
text *out;
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); {
int res; char *k = text2char(key);
res= findSNMap(map, k); int res;
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; {
Oid value; char *key;
} SNMapEntry; Oid value;
} SNMapEntry;
typedef struct { typedef struct
int len; {
int reallen; int len;
SNMapEntry *list; int reallen;
} SNMap; SNMapEntry *list;
} 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)
z->p = create_s();
if (S_size)
{ z->S = (symbol * *) calloc(S_size, sizeof(symbol *));
{ int i;
for (i = 0; i < S_size; i++) z->S[i] = create_s();
}
z->S_size = S_size;
}
if (I_size)
{ z->I = (int *) calloc(I_size, sizeof(int));
z->I_size = I_size;
}
if (B_size)
{ z->B = (symbol *) calloc(B_size, sizeof(symbol));
z->B_size = B_size;
}
return z;
}
extern void SN_close_env(struct SN_env * z)
{ {
if (z->S_size) struct SN_env *z = (struct SN_env *) calloc(1, sizeof(struct SN_env));
{
{ int i; z->p = create_s();
for (i = 0; i < z->S_size; i++) lose_s(z->S[i]); if (S_size)
} {
free(z->S); z->S = (symbol * *) calloc(S_size, sizeof(symbol *));
} {
if (z->I_size) free(z->I); int i;
if (z->B_size) free(z->B);
if (z->p) lose_s(z->p); for (i = 0; i < S_size; i++)
free(z); z->S[i] = create_s();
}
z->S_size = S_size;
}
if (I_size)
{
z->I = (int *) calloc(I_size, sizeof(int));
z->I_size = I_size;
}
if (B_size)
{
z->B = (symbol *) calloc(B_size, sizeof(symbol));
z->B_size = B_size;
}
return z;
} }
extern void SN_set_current(struct SN_env * z, int size, const symbol * s) extern void
SN_close_env(struct SN_env * z)
{ {
replace_s(z, 0, z->l, size, s); if (z->S_size)
z->c = 0; {
{
int i;
for (i = 0; i < z->S_size; i++)
lose_s(z->S[i]);
}
free(z->S);
}
if (z->I_size)
free(z->I);
if (z->B_size)
free(z->B);
if (z->p)
lose_s(z->p);
free(z);
} }
extern void
SN_set_current(struct SN_env * z, int size, const symbol * s)
{
replace_s(z, 0, z->l, size, s);
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

@ -2,41 +2,42 @@
#define HEAD 2*sizeof(int) #define HEAD 2*sizeof(int)
#define SIZE(p) ((int *)(p))[-1] #define SIZE(p) ((int *)(p))[-1]
#define SET_SIZE(p, n) ((int *)(p))[-1] = n #define SET_SIZE(p, n) ((int *)(p))[-1] = n
#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 result; /* result of the lookup */ int substring_i; /* index to longest matching substring */
int (* function)(struct SN_env *); int result; /* result of the lookup */
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);
extern int out_range(struct SN_env * z, int min, int max); extern int out_range(struct SN_env * z, int min, int max);
extern int out_range_b(struct SN_env * z, int min, int max); extern int out_range_b(struct SN_env * z, int min, int max);
extern int eq_s(struct SN_env * z, int s_size, symbol * s); extern int eq_s(struct SN_env * z, int s_size, symbol * s);
extern int eq_s_b(struct SN_env * z, int s_size, symbol * s); extern int eq_s_b(struct SN_env * z, int s_size, symbol * s);
extern int eq_v(struct SN_env * z, symbol * p); extern int eq_v(struct SN_env * z, symbol * p);
extern int eq_v_b(struct SN_env * z, symbol * p); 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);
extern void slice_del(struct SN_env * z); extern void slice_del(struct SN_env * z);
@ -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,320 +9,507 @@
#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)
CAPACITY(p) = CREATE_SIZE;
SET_SIZE(p, CREATE_SIZE);
return p;
}
extern void lose_s(symbol * p) { free((char *) p - HEAD); }
extern int in_grouping(struct SN_env * z, unsigned char * s, int min, int max)
{ if (z->c >= z->l) return 0;
{ int ch = z->p[z->c];
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)
{ 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
(ch > max || (ch -= min) < 0 ||
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
}
z->c++; return 1;
}
extern int out_grouping_b(struct SN_env * z, unsigned char * s, int min, int max)
{ if (z->c <= z->lb) return 0;
{ int ch = z->p[z->c - 1];
unless
(ch > max || (ch -= min) < 0 ||
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
}
z->c--; return 1;
}
extern int in_range(struct SN_env * z, int min, int max)
{ if (z->c >= z->l) return 0;
{ int ch = z->p[z->c];
if
(ch > max || ch < min) return 0;
}
z->c++; return 1;
}
extern int in_range_b(struct SN_env * z, int min, int max)
{ if (z->c <= z->lb) return 0;
{ int ch = z->p[z->c - 1];
if
(ch > max || ch < min) return 0;
}
z->c--; return 1;
}
extern int out_range(struct SN_env * z, int min, int max)
{ if (z->c >= z->l) return 0;
{ int ch = z->p[z->c];
unless
(ch > max || ch < min) return 0;
}
z->c++; return 1;
}
extern int out_range_b(struct SN_env * z, int min, int max)
{ if (z->c <= z->lb) return 0;
{ int ch = z->p[z->c - 1];
unless
(ch > max || ch < min) return 0;
}
z->c--; return 1;
}
extern int eq_s(struct SN_env * z, int s_size, symbol * s)
{ 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)
{ 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)
{ return eq_s(z, SIZE(p), p);
}
extern int 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)
{ {
int i = 0; symbol *p = (symbol *) (HEAD + (char *) malloc(HEAD + (CREATE_SIZE + 1) * sizeof(symbol)));
int j = v_size;
int c = z->c; int l = z->l; CAPACITY(p) = CREATE_SIZE;
symbol * q = z->p + c; SET_SIZE(p, CREATE_SIZE);
return p;
}
struct among * w; extern void lose_s(symbol * p)
{
free((char *) p - HEAD);
}
int common_i = 0; extern int
int common_j = 0; in_grouping(struct SN_env * z, unsigned char *s, int min, int max)
{
if (z->c >= z->l)
return 0;
{
int ch = z->p[z->c];
int first_key_inspected = 0; if
(ch > max || (ch -= min) < 0 ||
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
return 0;
}
z->c++;
return 1;
}
while(1) extern int
{ int k = i + ((j - i) >> 1); in_grouping_b(struct SN_env * z, unsigned char *s, int min, int max)
int diff = 0; {
int common = common_i < common_j ? common_i : common_j; /* smaller */ if (z->c <= z->lb)
w = v + k; return 0;
{ int i; for (i = common; i < w->s_size; i++) {
{ if (c + common == l) { diff = -1; break; } int ch = z->p[z->c - 1];
diff = q[common] - w->s[i];
if (diff != 0) break;
common++;
}
}
if (diff < 0) { j = k; common_j = common; }
else { i = k; common_i = common; }
if (j - i <= 1)
{ 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 if
v->s inspected. This looks messy, but is actually (ch > max || (ch -= min) < 0 ||
the optimal approach. */ (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
return 0;
}
z->c--;
return 1;
}
if (first_key_inspected) break; extern int
first_key_inspected = 1; out_grouping(struct SN_env * z, unsigned char *s, int min, int max)
} {
} if (z->c >= z->l)
while(1) return 0;
{ w = v + i; {
if (common_i >= w->s_size) int ch = z->p[z->c];
{ z->c = c + w->s_size;
if (w->function == 0) return w->result; unless
{ int res = w->function(z); (ch > max || (ch -= min) < 0 ||
z->c = c + w->s_size; (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
if (res) return w->result; }
} z->c++;
} return 1;
i = w->substring_i; }
if (i < 0) return 0;
} extern int
out_grouping_b(struct SN_env * z, unsigned char *s, int min, int max)
{
if (z->c <= z->lb)
return 0;
{
int ch = z->p[z->c - 1];
unless
(ch > max || (ch -= min) < 0 ||
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
}
z->c--;
return 1;
}
extern int
in_range(struct SN_env * z, int min, int max)
{
if (z->c >= z->l)
return 0;
{
int ch = z->p[z->c];
if
(ch > max || ch < min)
return 0;
}
z->c++;
return 1;
}
extern int
in_range_b(struct SN_env * z, int min, int max)
{
if (z->c <= z->lb)
return 0;
{
int ch = z->p[z->c - 1];
if
(ch > max || ch < min)
return 0;
}
z->c--;
return 1;
}
extern int
out_range(struct SN_env * z, int min, int max)
{
if (z->c >= z->l)
return 0;
{
int ch = z->p[z->c];
unless
(ch > max || ch < min) return 0;
}
z->c++;
return 1;
}
extern int
out_range_b(struct SN_env * z, int min, int max)
{
if (z->c <= z->lb)
return 0;
{
int ch = z->p[z->c - 1];
unless
(ch > max || ch < min) return 0;
}
z->c--;
return 1;
}
extern int
eq_s(struct SN_env * z, int s_size, symbol * s)
{
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)
{
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)
{
return eq_s(z, SIZE(p), p);
}
extern int
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)
{
int i = 0;
int j = v_size;
int c = z->c;
int l = z->l;
symbol *q = z->p + c;
struct among *w;
int common_i = 0;
int common_j = 0;
int first_key_inspected = 0;
while (1)
{
int k = i + ((j - i) >> 1);
int diff = 0;
int common = common_i < common_j ? common_i : common_j; /* smaller */
w = v + k;
{
int i;
for (i = common; i < w->s_size; i++)
{
if (c + common == l)
{
diff = -1;
break;
}
diff = q[common] - w->s[i];
if (diff != 0)
break;
common++;
}
}
if (diff < 0)
{
j = k;
common_j = common;
}
else
{
i = k;
common_i = common;
}
if (j - i <= 1)
{
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 the optimal
* approach.
*/
if (first_key_inspected)
break;
first_key_inspected = 1;
}
}
while (1)
{
w = v + i;
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;
if (res)
return w->result;
}
}
i = w->substring_i;
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 diff = 0; int k = i + ((j - i) >> 1);
int common = common_i < common_j ? common_i : common_j; int diff = 0;
w = v + k; int common = common_i < common_j ? common_i : common_j;
{ int i; for (i = w->s_size - 1 - common; i >= 0; i--)
{ if (c - common == lb) { diff = -1; break; } w = v + k;
diff = q[- common] - w->s[i]; {
if (diff != 0) break; int i;
common++;
} for (i = w->s_size - 1 - common; i >= 0; i--)
} {
if (diff < 0) { j = k; common_j = common; } if (c - common == lb)
else { i = k; common_i = common; } {
if (j - i <= 1) diff = -1;
{ if (i > 0) break; break;
if (j == i) break; }
if (first_key_inspected) break; diff = q[-common] - w->s[i];
first_key_inspected = 1; if (diff != 0)
} break;
} common++;
while(1) }
{ w = v + i; }
if (common_i >= w->s_size) if (diff < 0)
{ z->c = c - w->s_size; {
if (w->function == 0) return w->result; j = k;
{ int res = w->function(z); common_j = common;
z->c = c - w->s_size; }
if (res) return w->result; else
} {
} i = k;
i = w->substring_i; common_i = common;
if (i < 0) return 0; }
} if (j - i <= 1)
{
if (i > 0)
break;
if (j == i)
break;
if (first_key_inspected)
break;
first_key_inspected = 1;
}
}
while (1)
{
w = v + i;
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;
if (res)
return w->result;
}
}
i = w->substring_i;
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))); {
CAPACITY(q) = new_size; int new_size = n + 20;
memmove(q, p, CAPACITY(p) * sizeof(symbol)); lose_s(p); return q; symbol *q = (symbol *) (HEAD + (char *) malloc(HEAD + (new_size + 1) * sizeof(symbol)));
CAPACITY(q) = new_size;
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 len = SIZE(z->p);
if (adjustment != 0)
{ 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));
SET_SIZE(z->p, adjustment + len);
z->l += adjustment;
if (z->c >= c_ket) 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));
return adjustment;
}
static void slice_check(struct SN_env * z)
{ {
if (!(0 <= z->bra && int adjustment = s_size - (c_ket - c_bra);
z->bra <= z->ket && int len = SIZE(z->p);
z->ket <= z->l &&
z->l <= SIZE(z->p))) /* this line could be removed */ if (adjustment != 0)
{ {
fprintf(stderr, "faulty slice operation:\n"); if (adjustment + len > CAPACITY(z->p))
debug(z, -1, 0); z->p = increase_size(z->p, adjustment + len);
exit(1); memmove(z->p + c_ket + adjustment, z->p + c_ket, (len - c_ket) * sizeof(symbol));
} SET_SIZE(z->p, adjustment + len);
z->l += adjustment;
if (z->c >= c_ket)
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));
return adjustment;
} }
extern void slice_from_s(struct SN_env * z, int s_size, symbol * s) static void
{ slice_check(z); slice_check(struct SN_env * z)
replace_s(z, z->bra, z->ket, s_size, s); {
if (!(0 <= z->bra &&
z->bra <= z->ket &&
z->ket <= z->l &&
z->l <= SIZE(z->p))) /* this line could be removed */
{
fprintf(stderr, "faulty slice operation:\n");
debug(z, -1, 0);
exit(1);
}
} }
extern void slice_from_v(struct SN_env * z, symbol * p) extern void
{ slice_from_s(z, SIZE(p), p); 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);
} }
extern void slice_del(struct SN_env * z) extern void
{ slice_from_s(z, 0, 0); slice_from_v(struct SN_env * z, symbol * p)
{
slice_from_s(z, SIZE(p), p);
} }
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); slice_del(struct SN_env * z)
if (bra <= z->bra) z->bra += adjustment; {
if (bra <= z->ket) z->ket += adjustment; slice_from_s(z, 0, 0);
} }
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_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 symbol * slice_to(struct SN_env * z, symbol * p) extern void
{ slice_check(z); insert_v(struct SN_env * z, int bra, int ket, symbol * p)
{ int len = z->ket - z->bra; {
if (CAPACITY(p) < len) p = increase_size(p, len); int adjustment = replace_s(z, bra, ket, SIZE(p), p);
memmove(p, z->p + z->bra, len * sizeof(symbol));
SET_SIZE(p, len); if (bra <= z->bra)
} z->bra += adjustment;
return p; if (bra <= z->ket)
z->ket += adjustment;
} }
extern symbol * assign_to(struct SN_env * z, symbol * p) extern symbol *
{ int len = z->l; slice_to(struct SN_env * z, symbol * p)
if (CAPACITY(p) < len) p = increase_size(p, len); {
memmove(p, z->p, len * sizeof(symbol)); slice_check(z);
SET_SIZE(p, len); {
return p; int len = z->ket - z->bra;
if (CAPACITY(p) < len)
p = increase_size(p, len);
memmove(p, z->p + z->bra, len * sizeof(symbol));
SET_SIZE(p, len);
}
return p;
} }
extern void debug(struct SN_env * z, int number, int line_count) extern symbol *
{ int i; assign_to(struct SN_env * z, symbol * p)
int limit = SIZE(z->p); {
/*if (number >= 0) printf("%3d (line %4d): '", number, line_count);*/ int len = z->l;
if (number >= 0) printf("%3d (line %4d): [%d]'", number, line_count,limit);
for (i = 0; i <= limit; i++) if (CAPACITY(p) < len)
{ if (z->lb == i) printf("{"); p = increase_size(p, len);
if (z->bra == i) printf("["); memmove(p, z->p, len * sizeof(symbol));
if (z->c == i) printf("|"); SET_SIZE(p, len);
if (z->ket == i) printf("]"); return p;
if (z->l == i) printf("}"); }
if (i < limit)
{ int ch = z->p[i]; extern void
if (ch == 0) ch = '#'; debug(struct SN_env * z, int number, int line_count)
printf("%c", ch); {
} int i;
} int limit = SIZE(z->p);
printf("'\n");
/* 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++)
{
if (z->lb == i)
printf("{");
if (z->bra == i)
printf("[");
if (z->c == i)
printf("|");
if (z->ket == i)
printf("]");
if (z->l == i)
printf("}");
if (i < limit)
{
int ch = z->p[i];
if (ch == 0)
ch = '#';
printf("%c", ch);
}
}
printf("'\n");
} }

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++;
free(s->stop); s->len--;
} 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; {
reallen=(reallen) ? reallen*2 : 16; char **tmp;
tmp=(char**)realloc((void*)stop, sizeof(char*)*reallen);
if (!tmp) { reallen = (reallen) ? reallen * 2 : 16;
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,263 +23,299 @@
/*********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 }; {
bool isnull; Oid arg[2] = {OIDOID, OIDOID};
Datum pars[2]={ ObjectIdGetDatum(id), ObjectIdGetDatum(id) } ; bool isnull;
int stat,i,j; Datum pars[2] = {ObjectIdGetDatum(id), ObjectIdGetDatum(id)};
text *ptr; int stat,
text *prsname=NULL; i,
MemoryContext oldcontext; j;
text *ptr;
text *prsname = NULL;
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( {
SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) prsname = (text *) DatumGetPointer(
); 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)); {
ArrayType *toasted_a = (ArrayType*)PointerGetDatum(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull)); int lexid = DatumGetInt32(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull));
ArrayType *a; ArrayType *toasted_a = (ArrayType *) PointerGetDatum(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 2, &isnull));
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; {
int len; TSCfgInfo *last_cfg;
int reallen; int len;
TSCfgInfo *list; int reallen;
TSCfgInfo *list;
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; {
key.id=id; TSCfgInfo key;
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; {
int reallen = ( CList.reallen ) ? 2*CList.reallen : 16; TSCfgInfo *tmp;
tmp=(TSCfgInfo*)realloc(CList.list,sizeof(TSCfgInfo)*reallen); int reallen = (CList.reallen) ? 2 * CList.reallen : 16;
if ( !tmp )
ts_error(ERROR,"No memory"); tmp = (TSCfgInfo *) realloc(CList.list, sizeof(TSCfgInfo) * reallen);
CList.reallen=reallen; if (!tmp)
CList.list=tmp; ts_error(ERROR, "No memory");
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 }; {
bool isnull; Oid arg[1] = {TEXTOID};
Datum pars[1]={ PointerGetDatum(name) }; bool isnull;
int stat; Datum pars[1] = {PointerGetDatum(name)};
Oid id=findSNMap_t( &(CList.name2id_map), name ); int stat;
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),
Int32GetDatum(buflen) Int32GetDatum(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),
PointerGetDatum(lemm), PointerGetDatum(lemm),
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,24 +328,27 @@ 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 */
} }
} }
FunctionCall1( FunctionCall1(
&(prsobj->end_info), &(prsobj->end_info),
PointerGetDatum(prsobj->prs) PointerGetDatum(prsobj->prs)
); );
} }
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,165 +356,191 @@ 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; {
ITEM *item=GETQUERY(query); int i;
HLWORD *word=&( prs->words[prs->curwords-1] ); ITEM *item = GETQUERY(query);
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),
Int32GetDatum(buflen) Int32GetDatum(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")));
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),
PointerGetDatum(lemm), PointerGetDatum(lemm),
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 */
} }
} }
FunctionCall1( FunctionCall1(
&(prsobj->end_info), &(prsobj->end_info),
PointerGetDatum(prsobj->prs) PointerGetDatum(prsobj->prs)
); );
} }
text* text *
genhl(HLPRSTEXT * prs) { genhl(HLPRSTEXT * prs)
text *out; {
int len=128; text *out;
char *ptr; int len = 128;
HLWORD *wrd=prs->words; char *ptr;
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) { else
memcpy(ptr,prs->startsel,prs->startsellen); {
ptr+=prs->startsellen; if (wrd->selected)
{
memcpy(ptr, prs->startsel, prs->startsellen);
ptr += prs->startsellen;
} }
memcpy(ptr,wrd->word,wrd->len); memcpy(ptr, wrd->word, wrd->len);
ptr+=wrd->len; ptr += wrd->len;
if (wrd->selected) { if (wrd->selected)
memcpy(ptr,prs->stopsel,prs->stopsellen); {
ptr+=prs->stopsellen; 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),
@ -487,39 +552,43 @@ 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)); {
current_cfg_id=PG_GETARG_OID(0); findcfg(PG_GETARG_OID(0));
PG_RETURN_VOID(); current_cfg_id = PG_GETARG_OID(0);
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();
} }
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,66 +3,73 @@
#include "postgres.h" #include "postgres.h"
#include "query.h" #include "query.h"
typedef struct { typedef struct
int len; {
Datum *dict_id; int len;
} ListDictionary; Datum *dict_id;
} ListDictionary;
typedef struct { typedef struct
Oid id; {
Oid prs_id; Oid id;
int len; Oid prs_id;
ListDictionary *map; int len;
ListDictionary *map;
} 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; {
union { uint16 len;
union
{
uint16 pos; uint16 pos;
uint16 *apos; uint16 *apos;
} pos; } pos;
char *word; char *word;
uint32 alen; uint32 alen;
} WORD; } WORD;
typedef struct { typedef struct
WORD *words; {
int4 lenwords; WORD *words;
int4 curwords; int4 lenwords;
int4 curwords;
int4 pos; int4 pos;
} PRSTEXT; } PRSTEXT;
typedef struct { typedef struct
uint16 len; {
uint8 selected:1, uint16 len;
in:1, uint8 selected:1,
skip:1, in:1,
replace:1, skip:1,
repeated:1; replace:1,
uint8 type; repeated:1;
char *word; uint8 type;
ITEM *item; char *word;
} HLWORD; ITEM *item;
} HLWORD;
typedef struct { typedef struct
HLWORD *words; {
int4 lenwords; HLWORD *words;
int4 curwords; int4 lenwords;
char *startsel; int4 curwords;
char *stopsel; char *startsel;
int2 startsellen; char *stopsel;
int2 stopsellen; int2 startsellen;
} HLPRSTEXT; int2 stopsellen;
} 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

@ -10,108 +10,128 @@
#include "common.h" #include "common.h"
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; {
uint32 totallen, nentry; tsstat *newstat;
uint32 slen=0; uint32 totallen,
WordEntry **ptr=entry; nentry;
char *curptr; uint32 slen = 0;
StatEntry *sptr,*nptr; WordEntry **ptr = entry;
char *curptr;
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 *StopHigh = (StatEntry*)STATSTRPTR(stat); StatEntry *StopLow = STATPTR(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++;
} }
} }
@ -139,82 +161,107 @@ 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); {
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); tsstat *newstat,
WordEntry **newentry=NULL; *stat = (tsstat *) PG_GETARG_POINTER(0);
uint32 len=0, cur=0; tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
StatEntry *sptr; WordEntry **newentry = NULL;
WordEntry *wptr; uint32 len = 0,
cur = 0;
StatEntry *sptr;
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
StatEntry *StopLow = STATPTR(stat); { /* search */
StatEntry *StopHigh = (StatEntry*)STATSTRPTR(stat); while (wptr - ARRPTR(txt) < txt->size)
int cmp; {
StatEntry *StopLow = STATPTR(stat);
StatEntry *StopHigh = (StatEntry *) STATSTRPTR(stat);
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; {
tsvector *stat; uint32 cur;
} StatStorage; tsvector *stat;
} StatStorage;
static void static void
ts_setup_firstcall(FuncCallContext *funcctx, tsstat *stat) { ts_setup_firstcall(FuncCallContext *funcctx, tsstat * stat)
TupleDesc tupdesc; {
MemoryContext oldcontext; TupleDesc tupdesc;
StatStorage *st; MemoryContext oldcontext;
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; {
st=(StatStorage*)funcctx->user_fctx; StatStorage *st;
if ( st->cur < st->stat->size ) { st = (StatStorage *) funcctx->user_fctx;
Datum result;
char* values[3];
char ndoc[16];
char nentry[16];
StatEntry *entry=STATPTR(st->stat) + st->cur;
HeapTuple tuple;
values[1]=ndoc; if (st->cur < st->stat->size)
sprintf(ndoc,"%d",entry->ndoc); {
values[2]=nentry; Datum result;
sprintf(nentry,"%d",entry->nentry); char *values[3];
values[0]=palloc( entry->len+1 ); char ndoc[16];
memcpy( values[0], STATSTRPTR(st->stat)+entry->pos, entry->len); char nentry[16];
(values[0])[entry->len]='\0'; StatEntry *entry = STATPTR(st->stat) + st->cur;
HeapTuple tuple;
values[1] = ndoc;
sprintf(ndoc, "%d", entry->ndoc);
values[2] = nentry;
sprintf(nentry, "%d", entry->nentry);
values[0] = palloc(entry->len + 1);
memcpy(values[0], STATSTRPTR(st->stat) + entry->pos, entry->len);
(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; {
Datum result; FuncCallContext *funcctx;
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; {
bool isnull; int ret;
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); {
int i; char *query = text2char(txt);
tsstat *newstat,*stat; int i;
bool isnull; tsstat *newstat,
Portal portal; *stat;
void *plan; bool isnull;
Portal portal;
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( {
ts_accum, newstat = (tsstat *) DatumGetPointer(DirectFunctionCall2(
PointerGetDatum(stat), ts_accum,
data PointerGetDatum(stat),
)); data
if ( stat!=newstat && stat ) ));
if (stat != newstat && stat)
pfree(stat); pfree(stat);
stat=newstat; stat = newstat;
} }
} }
@ -394,28 +457,28 @@ 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; {
Datum result; FuncCallContext *funcctx;
Datum result;
if (SRF_IS_FIRSTCALL()) { if (SRF_IS_FIRSTCALL())
tsstat *stat; {
text *txt=PG_GETARG_TEXT_P(0); tsstat *stat;
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 pos; uint32 len;
uint32 ndoc; uint32 pos;
uint32 nentry; uint32 ndoc;
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,27 +89,29 @@ 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
uniqueentry(WordEntryIN * a, int4 l, char *buf, int4 *outbuflen) uniqueentry(WordEntryIN * a, int4 l, char *buf, int4 *outbuflen)
{ {
WordEntryIN *ptr, WordEntryIN *ptr,
*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);
@ -150,7 +168,7 @@ uniqueentry(WordEntryIN * a, int4 l, char *buf, int4 *outbuflen)
#define WAITENDWORD 2 #define WAITENDWORD 2
#define WAITNEXTCHAR 3 #define WAITNEXTCHAR 3
#define WAITENDCMPLX 4 #define WAITENDCMPLX 4
#define WAITPOSINFO 5 #define WAITPOSINFO 5
#define INPOSINFO 6 #define INPOSINFO 6
#define WAITPOSDELIM 7 #define WAITPOSDELIM 7
@ -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)) ) { else if (state->state == INPOSINFO)
if ( state->alen==0 ) { {
state->alen=4; if (isdigit(*(state->prsbuf)))
state->pos = (WordEntryPos*)palloc( sizeof(WordEntryPos)*state->alen ); {
*(uint16*)(state->pos)=0; if (state->alen == 0)
} else if ( *(uint16*)(state->pos) +1 >= state->alen ) { {
state->alen *= 2; state->alen = 4;
state->pos = (WordEntryPos*)repalloc( state->pos, sizeof(WordEntryPos)*state->alen ); state->pos = (WordEntryPos *) palloc(sizeof(WordEntryPos) * state->alen);
*(uint16 *) (state->pos) = 0;
} }
( *(uint16*)(state->pos) )++; else if (*(uint16 *) (state->pos) + 1 >= state->alen)
state->pos[ *(uint16*)(state->pos) ].pos = LIMITPOS(atoi(state->prsbuf)); {
if ( state->pos[ *(uint16*)(state->pos) ].pos == 0 ) 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++;
@ -352,11 +394,11 @@ tsvector_in(PG_FUNCTION_ARGS)
{ {
char *buf = PG_GETARG_CSTRING(0); char *buf = PG_GETARG_CSTRING(0);
TI_IN_STATE state; TI_IN_STATE state;
WordEntryIN *arr; WordEntryIN *arr;
WordEntry *inarr; WordEntry *inarr;
int4 len = 0, int4 len = 0,
totallen = 64; totallen = 64;
tsvector *in; tsvector *in;
char *tmpbuf, char *tmpbuf,
*cur; *cur;
int4 i, int4 i,
@ -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);
@ -434,7 +479,7 @@ tsvector_in(PG_FUNCTION_ARGS)
Datum Datum
tsvector_length(PG_FUNCTION_ARGS) tsvector_length(PG_FUNCTION_ARGS)
{ {
tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
int4 ret = in->size; int4 ret = in->size;
PG_FREE_IF_COPY(in, 0); PG_FREE_IF_COPY(in, 0);
@ -444,26 +489,28 @@ tsvector_length(PG_FUNCTION_ARGS)
Datum Datum
tsvector_out(PG_FUNCTION_ARGS) tsvector_out(PG_FUNCTION_ARGS)
{ {
tsvector *out = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0)); tsvector *out = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
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( {
((WORD *) a)->word, int res = strncmp(
((WORD *) b)->word, ((WORD *) a)->word,
((WORD *) b)->len); ((WORD *) b)->word,
if ( res==0 ) ((WORD *) b)->len);
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;
@ -527,14 +589,15 @@ uniqueWORD(WORD * a, int4 l)
{ {
WORD *ptr, WORD *ptr,
*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 { }
else
{
pfree(ptr->word); pfree(ptr->word);
if ( res->pos.apos[0] < MAXNUMPOS-1 && res->pos.apos[ res->pos.apos[0] ] != MAXENTRYPOS-1 ) { if (res->pos.apos[0] < MAXNUMPOS - 1 && res->pos.apos[res->pos.apos[0]] != MAXENTRYPOS - 1)
if ( res->pos.apos[0]+1 >= res->alen ) { {
res->alen*=2; if (res->pos.apos[0] + 1 >= res->alen)
res->pos.apos=(uint16*)repalloc( res->pos.apos, sizeof(uint16)*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[res->pos.apos[0] + 1] = LIMITPOS(ptr->pos.pos);
res->pos.apos[0]++; res->pos.apos[0]++;
} }
} }
@ -584,25 +651,27 @@ 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;
WordEntry *ptr; WordEntry *ptr;
char *str, char *str,
*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);
@ -645,8 +717,8 @@ 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); {
Datum res = DirectFunctionCall3( text *cfg = PG_GETARG_TEXT_P(0);
to_tsvector, Datum res = DirectFunctionCall3(
Int32GetDatum( name2id_cfg( cfg ) ), to_tsvector,
PG_GETARG_DATUM(1), Int32GetDatum(name2id_cfg(cfg)),
(Datum)0 PG_GETARG_DATUM(1),
(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( {
to_tsvector, Datum res = DirectFunctionCall3(
Int32GetDatum( get_currcfg() ), to_tsvector,
PG_GETARG_DATUM(0), Int32GetDatum(get_currcfg()),
(Datum)0 PG_GETARG_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; {
Oid funcid = InvalidOid; FuncCandidateList clist,
List *names=makeList1(makeString(fname)); ptr;
Oid funcid = InvalidOid;
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,12 +804,12 @@ 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;
Datum datum = (Datum) 0; Datum datum = (Datum) 0;
Oid funcoid = InvalidOid; Oid funcoid = InvalidOid;
if (!CALLED_AS_TRIGGER(fcinfo)) if (!CALLED_AS_TRIGGER(fcinfo))
/* internal error */ /* internal error */
@ -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( {
funcoid, text *txttmp = (text *) DatumGetPointer(OidFunctionCall1(
PointerGetDatum(txt_toasted) funcoid,
)); 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 }
txt = (text *) DatumGetPointer(PG_DETOAST_DATUM(PointerGetDatum(txt_toasted))); else
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,23 +12,27 @@
#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) )
typedef struct typedef struct
{ {
@ -44,12 +48,13 @@ typedef struct
#define STRSIZE(x) ( ((tsvector*)x)->len - DATAHDRSIZE - ( sizeof(WordEntry) * ((tsvector*)x)->size ) ) #define STRSIZE(x) ( ((tsvector*)x)->len - DATAHDRSIZE - ( sizeof(WordEntry) * ((tsvector*)x)->size ) )
#define _POSDATAPTR(x,e) (STRPTR(x)+((WordEntry*)(e))->pos+SHORTALIGN(((WordEntry*)(e))->len)) #define _POSDATAPTR(x,e) (STRPTR(x)+((WordEntry*)(e))->pos+SHORTALIGN(((WordEntry*)(e))->len))
#define POSDATALEN(x,e) ( ( ((WordEntry*)(e))->haspos ) ? (*(uint16*)_POSDATAPTR(x,e)) : 0 ) #define POSDATALEN(x,e) ( ( ((WordEntry*)(e))->haspos ) ? (*(uint16*)_POSDATAPTR(x,e)) : 0 )
#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; {
WordEntryPos *pos; WordEntry entry;
WordEntryPos *pos;
} WordEntryIN; } WordEntryIN;
typedef struct typedef struct
@ -60,7 +65,7 @@ typedef struct
int4 len; int4 len;
int4 state; int4 state;
int4 alen; int4 alen;
WordEntryPos *pos; WordEntryPos *pos;
bool oprisdelim; bool oprisdelim;
} TI_IN_STATE; } TI_IN_STATE;

View File

@ -33,28 +33,31 @@ Datum concat(PG_FUNCTION_ARGS);
Datum Datum
strip(PG_FUNCTION_ARGS) 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;
char *cur; WordEntry *arrin = ARRPTR(in),
*arrout;
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);
@ -64,32 +67,46 @@ strip(PG_FUNCTION_ARGS)
Datum Datum
setweight(PG_FUNCTION_ARGS) 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,
WordEntry *entry; j;
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;
/* internal error */ case 'b':
default: elog(ERROR,"unrecognized weight"); w = 2;
break;
case 'c':
w = 1;
break;
case 'd':
w = 0;
break;
/* internal error */
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); {
int i; uint16 *clen = (uint16 *) _POSDATAPTR(dest, destptr);
uint16 slen = POSDATALEN(src, srcptr), startlen; int i;
WordEntryPos *spos=POSDATAPTR(src, srcptr), *dpos=POSDATAPTR(dest,destptr); uint16 slen = POSDATALEN(src, srcptr),
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 *in2 = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1)); tsvector *in1 = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
tsvector *out; tsvector *in2 = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
WordEntry *ptr; tsvector *out;
WordEntry *ptr1,*ptr2; WordEntry *ptr;
WordEntry *ptr1,
*ptr2;
WordEntryPos *p; WordEntryPos *p;
int maxpos=0,i,j,i1,i2; int maxpos = 0,
char *cur; i,
char *data,*data1,*data2; j,
i1,
i2;
char *cur;
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,154 +21,171 @@
/*********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 }; {
bool isnull; Oid arg[1] = {OIDOID};
Datum pars[1]={ ObjectIdGetDatum(id) }; bool isnull;
int stat; Datum pars[1] = {ObjectIdGetDatum(id)};
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; {
int len; WParserInfo *last_prs;
int reallen; int len;
WParserInfo *list; int reallen;
WParserInfo *list;
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 }; {
bool isnull; Oid arg[1] = {TEXTOID};
Datum pars[1]={ PointerGetDatum(name) }; bool isnull;
int stat; Datum pars[1] = {PointerGetDatum(name)};
Oid id=findSNMap_t( &(PList.name2id_map), name ); int stat;
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; {
LexDescr *list; int cur;
} TypeStorage; LexDescr *list;
} TypeStorage;
static void static void
setup_firstcall(FuncCallContext *funcctx, Oid prsid) { setup_firstcall(FuncCallContext *funcctx, Oid prsid)
TupleDesc tupdesc; {
MemoryContext oldcontext; TupleDesc tupdesc;
TypeStorage *st; MemoryContext oldcontext;
TypeStorage *st;
WParserInfo *prs = findprs(prsid); WParserInfo *prs = findprs(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; {
char* values[3]; Datum result;
char txtid[16]; char *values[3];
HeapTuple tuple; char txtid[16];
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,161 +217,179 @@ 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; {
Datum result; FuncCallContext *funcctx;
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);
} }
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; {
Datum result; FuncCallContext *funcctx;
Datum result;
if (SRF_IS_FIRSTCALL())
{
text *name = PG_GETARG_TEXT_P(0);
if (SRF_IS_FIRSTCALL()) {
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);
} }
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; {
Datum result; FuncCallContext *funcctx;
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);
} }
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)); {
current_parser_id=PG_GETARG_OID(0); findprs(PG_GETARG_OID(0));
PG_RETURN_VOID(); current_parser_id = PG_GETARG_OID(0);
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; {
char *lexem; int type;
} LexemEntry; char *lexem;
} LexemEntry;
typedef struct { typedef struct
int cur; {
int len; int cur;
LexemEntry *list; int len;
} PrsStorage; LexemEntry *list;
} PrsStorage;
static void static void
prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt) { prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt)
TupleDesc tupdesc; {
MemoryContext oldcontext; TupleDesc tupdesc;
PrsStorage *st; MemoryContext oldcontext;
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++;
} }
FunctionCall1( FunctionCall1(
&(prs->end_info), &(prs->end_info),
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,132 +397,148 @@ 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; {
char* values[2]; Datum result;
char tid[16]; char *values[2];
HeapTuple tuple; char tid[16];
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;
} }
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; {
Datum result; FuncCallContext *funcctx;
Datum result;
if (SRF_IS_FIRSTCALL())
{
text *txt = PG_GETARG_TEXT_P(1);
if (SRF_IS_FIRSTCALL()) {
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);
} }
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; {
Datum result; FuncCallContext *funcctx;
Datum result;
if (SRF_IS_FIRSTCALL())
{
text *name = PG_GETARG_TEXT_P(0);
text *txt = PG_GETARG_TEXT_P(1);
if (SRF_IS_FIRSTCALL()) {
text *name = PG_GETARG_TEXT_P(0);
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);
} }
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; {
Datum result; FuncCallContext *funcctx;
Datum result;
if (SRF_IS_FIRSTCALL())
{
text *txt = PG_GETARG_TEXT_P(0);
if (SRF_IS_FIRSTCALL()) {
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);
} }
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)); {
text *in = PG_GETARG_TEXT_P(1); TSCfgInfo *cfg = findcfg(PG_GETARG_OID(0));
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);
FunctionCall3( FunctionCall3(
&(prsobj->headline_info), &(prsobj->headline_info),
PointerGetDatum(&prs), PointerGetDatum(&prs),
PointerGetDatum(opt), PointerGetDatum(opt),
PointerGetDatum(query) PointerGetDatum(query)
); );
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);
@ -495,35 +548,34 @@ 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,26 +3,28 @@
#include "postgres.h" #include "postgres.h"
#include "fmgr.h" #include "fmgr.h"
typedef struct { typedef struct
Oid prs_id; {
FmgrInfo start_info; Oid prs_id;
FmgrInfo getlexeme_info; FmgrInfo start_info;
FmgrInfo end_info; FmgrInfo getlexeme_info;
FmgrInfo headline_info; FmgrInfo end_info;
Oid lextype; FmgrInfo headline_info;
void *prs; Oid lextype;
} WParserInfo; void *prs;
} 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; {
char *alias; int lexid;
char *descr; char *alias;
} LexDescr; char *descr;
} LexDescr;
#endif #endif

View File

@ -17,40 +17,44 @@
#include "wordparser/deflex.h" #include "wordparser/deflex.h"
PG_FUNCTION_INFO_V1(prsd_lextype); 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)); {
int i; LexDescr *descr = (LexDescr *) palloc(sizeof(LexDescr) * (LASTNUM + 1));
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);
} }
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;
@ -58,34 +62,39 @@ 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();
} }
#define LEAVETOKEN(x) ( (x)==12 ) #define LEAVETOKEN(x) ( (x)==12 )
#define COMPLEXTOKEN(x) ( (x)==5 || (x)==15 || (x)==16 || (x)==17 ) #define COMPLEXTOKEN(x) ( (x)==5 || (x)==15 || (x)==16 || (x)==17 )
#define ENDPUNCTOKEN(x) ( (x)==12 ) #define ENDPUNCTOKEN(x) ( (x)==12 )
#define IDIGNORE(x) ( (x)==13 || (x)==14 || (x)==12 || (x)==23 ) #define IDIGNORE(x) ( (x)==13 || (x)==14 || (x)==12 || (x)==23 )
#define HLIDIGNORE(x) ( (x)==5 || (x)==13 || (x)==15 || (x)==16 || (x)==17 ) #define HLIDIGNORE(x) ( (x)==5 || (x)==13 || (x)==15 || (x)==16 || (x)==17 )
#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; {
int len; HLWORD *words;
} hlCheck; int len;
} hlCheck;
static bool static bool
checkcondition_HL(void *checkval, ITEM *val) { checkcondition_HL(void *checkval, ITEM * val)
int i; {
for(i=0;i<((hlCheck*)checkval)->len;i++) { int 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);
} }
} }
@ -148,44 +171,53 @@ 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 */
QUERYTYPE *query = (QUERYTYPE *) PG_GETARG_POINTER(2); /* can't be toasted */
/* from opt + start and and tag */ /* from opt + start and and tag */
int min_words=15; int min_words = 15;
int max_words=35; int max_words = 35;
int shortword=3; int shortword = 3;
int p=0,q=0; int p = 0,
int bestb=-1,beste=-1; q = 0;
int bestlen=-1; int bestb = -1,
int pose=0, poslen, curlen; 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

@ -87,7 +87,7 @@ pgxml_parse(PG_FUNCTION_ARGS)
doctree = xmlParseMemory((char *) VARDATA(t), docsize); doctree = xmlParseMemory((char *) VARDATA(t), docsize);
if (doctree == NULL) if (doctree == NULL)
{ {
xmlCleanupParser(); xmlCleanupParser();
PG_RETURN_BOOL(false); /* i.e. not well-formed */ PG_RETURN_BOOL(false); /* i.e. not well-formed */
} }
xmlCleanupParser(); xmlCleanupParser();
@ -202,8 +202,8 @@ pgxml_xpath(PG_FUNCTION_ARGS)
doctree = xmlParseMemory((char *) VARDATA(t), docsize); doctree = xmlParseMemory((char *) VARDATA(t), docsize);
if (doctree == NULL) if (doctree == NULL)
{ /* not well-formed */ { /* not well-formed */
xmlCleanupParser(); xmlCleanupParser();
PG_RETURN_NULL(); PG_RETURN_NULL();
} }

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
@ -617,7 +617,7 @@ heap_formtuple(TupleDesc tupleDescriptor,
td->t_natts = numberOfAttributes; td->t_natts = numberOfAttributes;
td->t_hoff = hoff; td->t_hoff = hoff;
if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
td->t_infomask = HEAP_HASOID; td->t_infomask = HEAP_HASOID;
DataFill((char *) td + hoff, DataFill((char *) td + hoff,

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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -162,9 +162,9 @@ index_formtuple(TupleDesc tupleDescriptor,
if ((size & INDEX_SIZE_MASK) != size) if ((size & INDEX_SIZE_MASK) != size)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("index tuple requires %lu bytes, maximum size is %lu", errmsg("index tuple requires %lu bytes, maximum size is %lu",
(unsigned long) size, (unsigned long) size,
(unsigned long) INDEX_SIZE_MASK))); (unsigned long) INDEX_SIZE_MASK)));
infomask |= size; infomask |= size;

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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -24,13 +24,13 @@
static void printtup_startup(DestReceiver *self, int operation, static void printtup_startup(DestReceiver *self, int operation,
TupleDesc typeinfo); TupleDesc typeinfo);
static void printtup(HeapTuple tuple, TupleDesc typeinfo, static void printtup(HeapTuple tuple, TupleDesc typeinfo,
DestReceiver *self); DestReceiver *self);
static void printtup_20(HeapTuple tuple, TupleDesc typeinfo, static void printtup_20(HeapTuple tuple, TupleDesc typeinfo,
DestReceiver *self); DestReceiver *self);
static void printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, static void printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo,
DestReceiver *self); DestReceiver *self);
static void printtup_shutdown(DestReceiver *self); static void printtup_shutdown(DestReceiver *self);
static void printtup_destroy(DestReceiver *self); static void printtup_destroy(DestReceiver *self);
@ -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)
@ -111,12 +111,13 @@ static void
printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo) printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
{ {
DR_printtup *myState = (DR_printtup *) self; DR_printtup *myState = (DR_printtup *) self;
Portal portal = myState->portal; Portal portal = myState->portal;
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)
{ {
@ -163,7 +164,7 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
* or some similar function; it does not contain a full set of fields. * or some similar function; it does not contain a full set of fields.
* The targetlist will be NIL when executing a utility function that does * The targetlist will be NIL when executing a utility function that does
* not have a plan. If the targetlist isn't NIL then it is a Query node's * not have a plan. If the targetlist isn't NIL then it is a Query node's
* targetlist; it is up to us to ignore resjunk columns in it. The formats[] * targetlist; it is up to us to ignore resjunk columns in it. The formats[]
* array pointer might be NULL (if we are doing Describe on a prepared stmt); * array pointer might be NULL (if we are doing Describe on a prepared stmt);
* send zeroes for the format codes in that case. * send zeroes for the format codes in that case.
*/ */
@ -176,14 +177,14 @@ SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist, int16 *formats)
int i; int i;
StringInfoData buf; StringInfoData buf;
pq_beginmessage(&buf, 'T'); /* tuple descriptor message type */ pq_beginmessage(&buf, 'T'); /* tuple descriptor message type */
pq_sendint(&buf, natts, 2); /* # of attrs in tuples */ pq_sendint(&buf, natts, 2); /* # of attrs in tuples */
for (i = 0; i < natts; ++i) for (i = 0; i < natts; ++i)
{ {
Oid atttypid = attrs[i]->atttypid; Oid atttypid = attrs[i]->atttypid;
int32 atttypmod = attrs[i]->atttypmod; int32 atttypmod = attrs[i]->atttypmod;
Oid basetype; Oid basetype;
pq_sendstring(&buf, NameStr(attrs[i]->attname)); pq_sendstring(&buf, NameStr(attrs[i]->attname));
/* column ID info appears in protocol 3.0 and up */ /* column ID info appears in protocol 3.0 and up */
@ -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));
@ -347,7 +348,7 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
outputbytes = DatumGetByteaP(FunctionCall2(&thisState->finfo, outputbytes = DatumGetByteaP(FunctionCall2(&thisState->finfo,
attr, attr,
ObjectIdGetDatum(thisState->typelem))); ObjectIdGetDatum(thisState->typelem)));
/* We assume the result will not have been toasted */ /* We assume the result will not have been toasted */
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4); pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes), pq_sendbytes(&buf, VARDATA(outputbytes),
@ -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));
@ -547,7 +549,7 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
value = DatumGetCString(OidFunctionCall3(typoutput, value = DatumGetCString(OidFunctionCall3(typoutput,
attr, attr,
ObjectIdGetDatum(typelem), ObjectIdGetDatum(typelem),
Int32GetDatum(typeinfo->attrs[i]->atttypmod))); Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
printatt((unsigned) i + 1, typeinfo->attrs[i], value); printatt((unsigned) i + 1, typeinfo->attrs[i], value);
@ -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));
@ -637,7 +639,7 @@ printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
outputbytes = DatumGetByteaP(FunctionCall2(&thisState->finfo, outputbytes = DatumGetByteaP(FunctionCall2(&thisState->finfo,
attr, attr,
ObjectIdGetDatum(thisState->typelem))); ObjectIdGetDatum(thisState->typelem)));
/* We assume the result will not have been toasted */ /* We assume the result will not have been toasted */
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4); pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
pq_sendbytes(&buf, VARDATA(outputbytes), pq_sendbytes(&buf, VARDATA(outputbytes),

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.
@ -205,8 +205,8 @@ _hash_getovfladdr(Relation rel, Buffer *metabufp)
if (++splitnum >= NCACHED) if (++splitnum >= NCACHED)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("out of overflow pages in hash index \"%s\"", errmsg("out of overflow pages in hash index \"%s\"",
RelationGetRelationName(rel)))); RelationGetRelationName(rel))));
metap->hashm_ovflpoint = splitnum; metap->hashm_ovflpoint = splitnum;
metap->hashm_spares[splitnum] = metap->hashm_spares[splitnum - 1]; metap->hashm_spares[splitnum] = metap->hashm_spares[splitnum - 1];
metap->hashm_spares[splitnum - 1]--; metap->hashm_spares[splitnum - 1]--;

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)
@ -1912,7 +1913,7 @@ log_heap_clean(Relation reln, Buffer buffer, OffsetNumber *unused, int uncnt)
/* /*
* The unused-offsets array is not actually in the buffer, but pretend * The unused-offsets array is not actually in the buffer, but pretend
* that it is. When XLogInsert stores the whole buffer, the offsets * that 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 = buffer; rdata[1].buffer = buffer;
@ -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
@ -300,7 +300,7 @@ index_beginscan(Relation heapRelation,
* index_rescan - (re)start a scan of an index * index_rescan - (re)start a scan of an index
* *
* The caller may specify a new set of scankeys (but the number of keys * The caller may specify a new set of scankeys (but the number of keys
* cannot change). To restart the scan without changing keys, pass NULL * cannot change). To restart the scan without changing keys, pass NULL
* for the key array. * for the key array.
* *
* Note that this is also called when first starting an indexscan; * Note that this is also called when first starting an indexscan;
@ -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,24 +427,24 @@ 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)
{ {
int new_tuple_pos = scan->unique_tuple_pos; int new_tuple_pos = scan->unique_tuple_pos;
if (ScanDirectionIsForward(direction)) if (ScanDirectionIsForward(direction))
{ {
@ -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;
@ -649,7 +650,7 @@ index_vacuum_cleanup(Relation indexRelation,
DatumGetPointer(OidFunctionCall3(procedure, DatumGetPointer(OidFunctionCall3(procedure,
PointerGetDatum(indexRelation), PointerGetDatum(indexRelation),
PointerGetDatum((Pointer) info), PointerGetDatum((Pointer) info),
PointerGetDatum((Pointer) stats))); PointerGetDatum((Pointer) stats)));
return result; return result;
} }

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)
{ {
@ -1135,7 +1136,7 @@ _bt_checksplitloc(FindSplitData *state, OffsetNumber firstright,
* *
* On entry, buf and rbuf are the left and right split pages, which we * On entry, buf and rbuf are the left and right split pages, which we
* still hold write locks on per the L&Y algorithm. We release the * still hold write locks on per the L&Y algorithm. We release the
* write locks once we have write lock on the parent page. (Any sooner, * write locks once we have write lock on the parent page. (Any sooner,
* and it'd be possible for some other process to try to split or delete * and it'd be possible for some other process to try to split or delete
* one of these pages, and get confused because it cannot find the downlink.) * one of these pages, and get confused because it cannot find the downlink.)
* *
@ -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);
@ -240,7 +240,7 @@ _bt_getroot(Relation rel, int access)
_bt_wrtnorelbuf(rel, rootbuf); _bt_wrtnorelbuf(rel, rootbuf);
/* /*
* swap root write lock for read lock. There is no danger of * swap root write lock for read lock. There is no danger of
* anyone else accessing the new root page while it's unlocked, * anyone else accessing the new root page while it's unlocked,
* since no one else knows where it is yet. * since no one else knows where it is yet.
*/ */
@ -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;
} }
@ -299,7 +299,7 @@ _bt_getroot(Relation rel, int access)
* By the time we acquire lock on the root page, it might have been split and * By the time we acquire lock on the root page, it might have been split and
* not be the true root anymore. This is okay for the present uses of this * not be the true root anymore. This is okay for the present uses of this
* routine; we only really need to be able to move up at least one tree level * routine; we only really need to be able to move up at least one tree level
* from whatever non-root page we were at. If we ever do need to lock the * from whatever non-root page we were at. If we ever do need to lock the
* one true root page, we could loop here, re-reading the metapage on each * one true root page, we could loop here, re-reading the metapage on each
* failure. (Note that it wouldn't do to hold the lock on the metapage while * failure. (Note that it wouldn't do to hold the lock on the metapage while
* moving to the root --- that'd deadlock against any concurrent root split.) * moving to the root --- that'd deadlock against any concurrent root split.)
@ -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);
@ -484,7 +484,7 @@ _bt_relbuf(Relation rel, Buffer buf)
* and a pin on the buffer. * and a pin on the buffer.
* *
* NOTE: actually, the buffer manager just marks the shared buffer page * NOTE: actually, the buffer manager just marks the shared buffer page
* dirty here; the real I/O happens later. This is okay since we are not * dirty here; the real I/O happens later. This is okay since we are not
* relying on write ordering anyway. The WAL mechanism is responsible for * relying on write ordering anyway. The WAL mechanism is responsible for
* guaranteeing correctness after a crash. * guaranteeing correctness after a crash.
*/ */
@ -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.
@ -565,7 +566,7 @@ _bt_page_recyclable(Page page)
* mistake. On exit, metapage data is correct and we no longer have * mistake. On exit, metapage data is correct and we no longer have
* a pin or lock on the metapage. * a pin or lock on the metapage.
* *
* Actually this is not used for splitting on-the-fly anymore. It's only used * Actually this is not used for splitting on-the-fly anymore. It's only used
* in nbtsort.c at the completion of btree building, where we know we have * in nbtsort.c at the completion of btree building, where we know we have
* sole access to the index anyway. * sole access to the index anyway.
*/ */
@ -623,7 +624,7 @@ _bt_metaproot(Relation rel, BlockNumber rootbknum, uint32 level)
/* /*
* Delete item(s) from a btree page. * Delete item(s) from a btree page.
* *
* This must only be used for deleting leaf items. Deleting an item on a * This must only be used for deleting leaf items. Deleting an item on a
* non-leaf page has to be done as part of an atomic action that includes * non-leaf page has to be done as part of an atomic action that includes
* deleting the page it points to. * deleting the page it points to.
* *
@ -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;
@ -701,7 +700,7 @@ _bt_delitems(Relation rel, Buffer buf,
* may currently be trying to follow links leading to the page; they have to * may currently be trying to follow links leading to the page; they have to
* be allowed to use its right-link to recover. See nbtree/README. * be allowed to use its right-link to recover. See nbtree/README.
* *
* On entry, the target buffer must be pinned and read-locked. This lock and * On entry, the target buffer must be pinned and read-locked. This lock and
* pin will be dropped before exiting. * pin will be dropped before exiting.
* *
* Returns the number of pages successfully deleted (zero on failure; could * Returns the number of pages successfully deleted (zero on failure; could
@ -714,7 +713,7 @@ _bt_delitems(Relation rel, Buffer buf,
int int
_bt_pagedel(Relation rel, Buffer buf, bool vacuum_full) _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
{ {
BlockNumber target, BlockNumber target,
leftsib, leftsib,
rightsib, rightsib,
parent; parent;
@ -740,17 +739,18 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
BTPageOpaque opaque; BTPageOpaque opaque;
/* /*
* We can never delete rightmost pages nor root pages. While at it, * We can never delete rightmost pages nor root pages. While at it,
* check that page is not already deleted and is empty. * check that page is not already deleted and is empty.
*/ */
page = BufferGetPage(buf); page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page); opaque = (BTPageOpaque) PageGetSpecialPointer(page);
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))
{ {
_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,21 +828,24 @@ _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))
{ {
_bt_relbuf(rel, buf); _bt_relbuf(rel, buf);
if (BufferIsValid(lbuf)) if (BufferIsValid(lbuf))
@ -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);
@ -950,7 +964,7 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
} }
else else
{ {
OffsetNumber nextoffset; OffsetNumber nextoffset;
itemid = PageGetItemId(page, poffset); itemid = PageGetItemId(page, poffset);
btitem = (BTItem) PageGetItem(page, itemid); btitem = (BTItem) PageGetItem(page, itemid);
@ -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 */
@ -604,7 +605,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
OffsetNumber offnum, OffsetNumber offnum,
minoff, minoff,
maxoff; maxoff;
BlockNumber nextpage; BlockNumber nextpage;
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
@ -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.
@ -640,7 +643,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
ItemPointer htup; ItemPointer htup;
btitem = (BTItem) PageGetItem(page, btitem = (BTItem) PageGetItem(page,
PageGetItemId(page, offnum)); PageGetItemId(page, offnum));
htup = &(btitem->bti_itup.t_tid); htup = &(btitem->bti_itup.t_tid);
if (callback(htup, callback_state)) if (callback(htup, callback_state))
{ {
@ -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;
@ -712,7 +714,7 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
/* No point in remembering more than MaxFSMPages pages */ /* No point in remembering more than MaxFSMPages pages */
maxFreePages = MaxFSMPages; maxFreePages = MaxFSMPages;
if ((BlockNumber) maxFreePages > num_pages) if ((BlockNumber) maxFreePages > num_pages)
maxFreePages = (int) num_pages + 1; /* +1 to avoid palloc(0) */ maxFreePages = (int) num_pages + 1; /* +1 to avoid palloc(0) */
freePages = (BlockNumber *) palloc(maxFreePages * sizeof(BlockNumber)); freePages = (BlockNumber *) palloc(maxFreePages * sizeof(BlockNumber));
nFreePages = 0; nFreePages = 0;
@ -728,10 +730,10 @@ 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;
BTPageOpaque opaque; BTPageOpaque opaque;
buf = _bt_getbuf(rel, blkno, BT_READ); buf = _bt_getbuf(rel, blkno, BT_READ);
@ -753,7 +755,7 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
P_FIRSTDATAKEY(opaque) > PageGetMaxOffsetNumber(page)) P_FIRSTDATAKEY(opaque) > PageGetMaxOffsetNumber(page))
{ {
/* Empty, try to delete */ /* Empty, try to delete */
int ndel; int ndel;
/* Run pagedel in a temp context to avoid memory leakage */ /* Run pagedel in a temp context to avoid memory leakage */
MemoryContextReset(mycontext); MemoryContextReset(mycontext);
@ -768,7 +770,7 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
/* /*
* During VACUUM FULL it's okay to recycle deleted pages * During VACUUM FULL it's okay to recycle deleted pages
* immediately, since there can be no other transactions * immediately, since there can be no other transactions
* scanning the index. Note that we will only recycle the * scanning the index. Note that we will only recycle the
* current page and not any parent pages that _bt_pagedel * current page and not any parent pages that _bt_pagedel
* might have recursed to; this seems reasonable in the name * might have recursed to; this seems reasonable in the name
* of simplicity. (Trying to do otherwise would mean we'd * of simplicity. (Trying to do otherwise would mean we'd
@ -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;
} }
@ -856,7 +860,7 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
* and so no deletion can have occurred on that page. * and so no deletion can have occurred on that page.
* *
* On entry, we have a pin but no read lock on the buffer that contained * On entry, we have a pin but no read lock on the buffer that contained
* the index tuple we stopped the scan on. On exit, we have pin and read * the index tuple we stopped the scan on. On exit, we have pin and read
* lock on the buffer that now contains that index tuple, and the scandesc's * lock on the buffer that now contains that index tuple, and the scandesc's
* current position is updated to point at it. * current position is updated to point at it.
*/ */
@ -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);
@ -921,11 +925,11 @@ _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\"",
@ -1028,7 +1031,7 @@ _bt_walk_left(Relation rel, Buffer buf)
* _bt_get_endpoint() -- Find the first or last page on a given tree level * _bt_get_endpoint() -- Find the first or last page on a given tree level
* *
* If the index is empty, we will return InvalidBuffer; any other failure * If the index is empty, we will return InvalidBuffer; any other failure
* condition causes ereport(). We will not return a dead page. * condition causes ereport(). We will not return a dead page.
* *
* The returned buffer is pinned and read-locked. * The returned buffer is pinned and read-locked.
*/ */
@ -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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -93,7 +93,7 @@ typedef struct BTPageState
static void _bt_blnewpage(Relation index, Buffer *buf, Page *page, static void _bt_blnewpage(Relation index, Buffer *buf, Page *page,
uint32 level); uint32 level);
static BTPageState *_bt_pagestate(Relation index, uint32 level); static BTPageState *_bt_pagestate(Relation index, uint32 level);
static void _bt_slideleft(Relation index, Buffer buf, Page page); static void _bt_slideleft(Relation index, Buffer buf, Page page);
static void _bt_sortaddtup(Page page, Size itemsize, static void _bt_sortaddtup(Page page, Size itemsize,
@ -469,7 +469,7 @@ _bt_buildadd(Relation index, BTPageState *state, BTItem bti)
oopaque->btpo_next = BufferGetBlockNumber(nbuf); oopaque->btpo_next = BufferGetBlockNumber(nbuf);
nopaque->btpo_prev = BufferGetBlockNumber(obuf); nopaque->btpo_prev = BufferGetBlockNumber(obuf);
nopaque->btpo_next = P_NONE; /* redundant */ nopaque->btpo_next = P_NONE; /* redundant */
} }
/* /*

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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -29,10 +29,10 @@
typedef struct bt_incomplete_split typedef struct bt_incomplete_split
{ {
RelFileNode node; /* the index */ RelFileNode node; /* the index */
BlockNumber leftblk; /* left half of split */ BlockNumber leftblk; /* left half of split */
BlockNumber rightblk; /* right half of split */ BlockNumber rightblk; /* right half of split */
bool is_root; /* we split the root */ bool is_root; /* we split the root */
} bt_incomplete_split; } bt_incomplete_split;
static List *incomplete_splits; static List *incomplete_splits;
@ -172,7 +172,7 @@ btree_xlog_insert(bool redo, bool isleaf, bool ismeta,
if (!redo || !(record->xl_info & XLR_BKP_BLOCK_1)) if (!redo || !(record->xl_info & XLR_BKP_BLOCK_1))
{ {
buffer = XLogReadBuffer(false, reln, buffer = XLogReadBuffer(false, reln,
ItemPointerGetBlockNumber(&(xlrec->target.tid))); ItemPointerGetBlockNumber(&(xlrec->target.tid)));
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
elog(PANIC, "btree_insert_%sdo: block unfound", (redo) ? "re" : "un"); elog(PANIC, "btree_insert_%sdo: block unfound", (redo) ? "re" : "un");
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
@ -183,13 +183,11 @@ 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,
ItemPointerGetOffsetNumber(&(xlrec->target.tid)), ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
LP_USED) == InvalidOffsetNumber) LP_USED) == InvalidOffsetNumber)
elog(PANIC, "btree_insert_redo: failed to add item"); elog(PANIC, "btree_insert_redo: failed to add item");
@ -204,13 +202,9 @@ 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");
}
} }
} }
@ -226,8 +220,8 @@ btree_xlog_insert(bool redo, bool isleaf, bool ismeta,
if (redo && !isleaf && incomplete_splits != NIL) if (redo && !isleaf && incomplete_splits != NIL)
{ {
forget_matching_split(reln, xlrec->target.node, forget_matching_split(reln, xlrec->target.node,
ItemPointerGetBlockNumber(&(xlrec->target.tid)), ItemPointerGetBlockNumber(&(xlrec->target.tid)),
ItemPointerGetOffsetNumber(&(xlrec->target.tid)), ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
false); false);
} }
} }
@ -238,9 +232,9 @@ btree_xlog_split(bool redo, bool onleft, bool isroot,
{ {
xl_btree_split *xlrec = (xl_btree_split *) XLogRecGetData(record); xl_btree_split *xlrec = (xl_btree_split *) XLogRecGetData(record);
Relation reln; Relation reln;
BlockNumber targetblk; BlockNumber targetblk;
BlockNumber leftsib; BlockNumber leftsib;
BlockNumber rightsib; BlockNumber rightsib;
Buffer buffer; Buffer buffer;
Page page; Page page;
BTPageOpaque pageop; BTPageOpaque pageop;
@ -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);
@ -357,8 +349,8 @@ btree_xlog_split(bool redo, bool onleft, bool isroot,
if (redo && xlrec->level > 0 && incomplete_splits != NIL) if (redo && xlrec->level > 0 && incomplete_splits != NIL)
{ {
forget_matching_split(reln, xlrec->target.node, forget_matching_split(reln, xlrec->target.node,
ItemPointerGetBlockNumber(&(xlrec->target.tid)), ItemPointerGetBlockNumber(&(xlrec->target.tid)),
ItemPointerGetOffsetNumber(&(xlrec->target.tid)), ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
false); false);
} }
@ -422,10 +414,10 @@ btree_xlog_delete_page(bool redo, bool ismeta,
{ {
xl_btree_delete_page *xlrec = (xl_btree_delete_page *) XLogRecGetData(record); xl_btree_delete_page *xlrec = (xl_btree_delete_page *) XLogRecGetData(record);
Relation reln; Relation reln;
BlockNumber parent; BlockNumber parent;
BlockNumber target; BlockNumber target;
BlockNumber leftsib; BlockNumber leftsib;
BlockNumber rightsib; BlockNumber rightsib;
Buffer buffer; Buffer buffer;
Page page; Page page;
BTPageOpaque pageop; BTPageOpaque pageop;
@ -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;
@ -469,7 +459,7 @@ btree_xlog_delete_page(bool redo, bool ismeta,
{ {
ItemId itemid; ItemId itemid;
BTItem btitem; BTItem btitem;
OffsetNumber nextoffset; OffsetNumber nextoffset;
itemid = PageGetItemId(page, poffset); itemid = PageGetItemId(page, poffset);
btitem = (BTItem) PageGetItem(page, itemid); btitem = (BTItem) PageGetItem(page, itemid);
@ -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);
@ -799,116 +785,116 @@ btree_desc(char *buf, uint8 xl_info, char *rec)
switch (info) switch (info)
{ {
case XLOG_BTREE_INSERT_LEAF: case XLOG_BTREE_INSERT_LEAF:
{ {
xl_btree_insert *xlrec = (xl_btree_insert *) rec; xl_btree_insert *xlrec = (xl_btree_insert *) rec;
strcat(buf, "insert: "); strcat(buf, "insert: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
break; break;
} }
case XLOG_BTREE_INSERT_UPPER: case XLOG_BTREE_INSERT_UPPER:
{ {
xl_btree_insert *xlrec = (xl_btree_insert *) rec; xl_btree_insert *xlrec = (xl_btree_insert *) rec;
strcat(buf, "insert_upper: "); strcat(buf, "insert_upper: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
break; break;
} }
case XLOG_BTREE_INSERT_META: case XLOG_BTREE_INSERT_META:
{ {
xl_btree_insert *xlrec = (xl_btree_insert *) rec; xl_btree_insert *xlrec = (xl_btree_insert *) rec;
strcat(buf, "insert_meta: "); strcat(buf, "insert_meta: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
break; break;
} }
case XLOG_BTREE_SPLIT_L: case XLOG_BTREE_SPLIT_L:
{ {
xl_btree_split *xlrec = (xl_btree_split *) rec; xl_btree_split *xlrec = (xl_btree_split *) rec;
strcat(buf, "split_l: "); strcat(buf, "split_l: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
sprintf(buf + strlen(buf), "; oth %u; rgh %u", sprintf(buf + strlen(buf), "; oth %u; rgh %u",
xlrec->otherblk, xlrec->rightblk); xlrec->otherblk, xlrec->rightblk);
break; break;
} }
case XLOG_BTREE_SPLIT_R: case XLOG_BTREE_SPLIT_R:
{ {
xl_btree_split *xlrec = (xl_btree_split *) rec; xl_btree_split *xlrec = (xl_btree_split *) rec;
strcat(buf, "split_r: "); strcat(buf, "split_r: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
sprintf(buf + strlen(buf), "; oth %u; rgh %u", sprintf(buf + strlen(buf), "; oth %u; rgh %u",
xlrec->otherblk, xlrec->rightblk); xlrec->otherblk, xlrec->rightblk);
break; break;
} }
case XLOG_BTREE_SPLIT_L_ROOT: case XLOG_BTREE_SPLIT_L_ROOT:
{ {
xl_btree_split *xlrec = (xl_btree_split *) rec; xl_btree_split *xlrec = (xl_btree_split *) rec;
strcat(buf, "split_l_root: "); strcat(buf, "split_l_root: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
sprintf(buf + strlen(buf), "; oth %u; rgh %u", sprintf(buf + strlen(buf), "; oth %u; rgh %u",
xlrec->otherblk, xlrec->rightblk); xlrec->otherblk, xlrec->rightblk);
break; break;
} }
case XLOG_BTREE_SPLIT_R_ROOT: case XLOG_BTREE_SPLIT_R_ROOT:
{ {
xl_btree_split *xlrec = (xl_btree_split *) rec; xl_btree_split *xlrec = (xl_btree_split *) rec;
strcat(buf, "split_r_root: "); strcat(buf, "split_r_root: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
sprintf(buf + strlen(buf), "; oth %u; rgh %u", sprintf(buf + strlen(buf), "; oth %u; rgh %u",
xlrec->otherblk, xlrec->rightblk); xlrec->otherblk, xlrec->rightblk);
break; break;
} }
case XLOG_BTREE_DELETE: case XLOG_BTREE_DELETE:
{ {
xl_btree_delete *xlrec = (xl_btree_delete *) rec; xl_btree_delete *xlrec = (xl_btree_delete *) rec;
sprintf(buf + strlen(buf), "delete: node %u/%u; blk %u", sprintf(buf + strlen(buf), "delete: node %u/%u; blk %u",
xlrec->node.tblNode, xlrec->node.relNode, xlrec->block); xlrec->node.tblNode, xlrec->node.relNode, xlrec->block);
break; break;
} }
case XLOG_BTREE_DELETE_PAGE: case XLOG_BTREE_DELETE_PAGE:
case XLOG_BTREE_DELETE_PAGE_META: case XLOG_BTREE_DELETE_PAGE_META:
{ {
xl_btree_delete_page *xlrec = (xl_btree_delete_page *) rec; xl_btree_delete_page *xlrec = (xl_btree_delete_page *) rec;
strcat(buf, "delete_page: "); strcat(buf, "delete_page: ");
out_target(buf, &(xlrec->target)); out_target(buf, &(xlrec->target));
sprintf(buf + strlen(buf), "; dead %u; left %u; right %u", sprintf(buf + strlen(buf), "; dead %u; left %u; right %u",
xlrec->deadblk, xlrec->leftblk, xlrec->rightblk); xlrec->deadblk, xlrec->leftblk, xlrec->rightblk);
break; break;
} }
case XLOG_BTREE_NEWROOT: case XLOG_BTREE_NEWROOT:
{ {
xl_btree_newroot *xlrec = (xl_btree_newroot *) rec; xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
sprintf(buf + strlen(buf), "newroot: node %u/%u; root %u lev %u", sprintf(buf + strlen(buf), "newroot: node %u/%u; root %u lev %u",
xlrec->node.tblNode, xlrec->node.relNode, xlrec->node.tblNode, xlrec->node.relNode,
xlrec->rootblk, xlrec->level); xlrec->rootblk, xlrec->level);
break; break;
} }
case XLOG_BTREE_NEWMETA: case XLOG_BTREE_NEWMETA:
{ {
xl_btree_newmeta *xlrec = (xl_btree_newmeta *) rec; xl_btree_newmeta *xlrec = (xl_btree_newmeta *) rec;
sprintf(buf + strlen(buf), "newmeta: node %u/%u; root %u lev %u fast %u lev %u", sprintf(buf + strlen(buf), "newmeta: node %u/%u; root %u lev %u fast %u lev %u",
xlrec->node.tblNode, xlrec->node.relNode, xlrec->node.tblNode, xlrec->node.relNode,
xlrec->meta.root, xlrec->meta.level, xlrec->meta.root, xlrec->meta.level,
xlrec->meta.fastroot, xlrec->meta.fastlevel); xlrec->meta.fastroot, xlrec->meta.fastlevel);
break; break;
} }
case XLOG_BTREE_NEWPAGE: case XLOG_BTREE_NEWPAGE:
{ {
xl_btree_newpage *xlrec = (xl_btree_newpage *) rec; xl_btree_newpage *xlrec = (xl_btree_newpage *) rec;
sprintf(buf + strlen(buf), "newpage: node %u/%u; page %u", sprintf(buf + strlen(buf), "newpage: node %u/%u; page %u",
xlrec->node.tblNode, xlrec->node.relNode, xlrec->node.tblNode, xlrec->node.relNode,
xlrec->blkno); xlrec->blkno);
break; break;
} }
default: default:
strcat(buf, "UNKNOWN"); strcat(buf, "UNKNOWN");
break; break;

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},
@ -32,7 +32,7 @@ RmgrData RmgrTable[RM_MAX_ID+1] = {
{"Reserved 9", NULL, NULL, NULL, NULL, NULL}, {"Reserved 9", NULL, NULL, NULL, NULL, NULL},
{"Heap", heap_redo, heap_undo, heap_desc, NULL, NULL}, {"Heap", heap_redo, heap_undo, heap_desc, NULL, NULL},
{"Btree", btree_redo, btree_undo, btree_desc, {"Btree", btree_redo, btree_undo, btree_desc,
btree_xlog_startup, btree_xlog_cleanup}, btree_xlog_startup, btree_xlog_cleanup},
{"Hash", hash_redo, hash_undo, hash_desc, NULL, NULL}, {"Hash", hash_redo, hash_undo, hash_desc, NULL, NULL},
{"Rtree", rtree_redo, rtree_undo, rtree_desc, NULL, NULL}, {"Rtree", rtree_redo, rtree_undo, rtree_desc, NULL, NULL},
{"Gist", gist_redo, gist_undo, gist_desc, NULL, NULL}, {"Gist", gist_redo, gist_undo, gist_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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -93,7 +93,7 @@ typedef enum
SLRU_PAGE_CLEAN, /* page is valid and not dirty */ SLRU_PAGE_CLEAN, /* page is valid and not dirty */
SLRU_PAGE_DIRTY, /* page is valid but needs write */ SLRU_PAGE_DIRTY, /* page is valid but needs write */
SLRU_PAGE_WRITE_IN_PROGRESS /* page is being written out */ SLRU_PAGE_WRITE_IN_PROGRESS /* page is being written out */
} SlruPageStatus; } SlruPageStatus;
/* /*
* Shared-memory state * Shared-memory state
@ -117,7 +117,7 @@ typedef struct SlruSharedData
* swapping out the latest page. * swapping out the latest page.
*/ */
int latest_page_number; int latest_page_number;
} SlruSharedData; } SlruSharedData;
typedef SlruSharedData *SlruShared; typedef SlruSharedData *SlruShared;
@ -145,7 +145,7 @@ typedef enum
SLRU_SEEK_FAILED, SLRU_SEEK_FAILED,
SLRU_READ_FAILED, SLRU_READ_FAILED,
SLRU_WRITE_FAILED SLRU_WRITE_FAILED
} SlruErrorCause; } SlruErrorCause;
static SlruErrorCause slru_errcause; static SlruErrorCause slru_errcause;
static int slru_errno; static int slru_errno;
@ -166,9 +166,9 @@ SimpleLruShmemSize(void)
{ {
return MAXALIGN(sizeof(SlruSharedData)) + BLCKSZ * NUM_CLOG_BUFFERS return MAXALIGN(sizeof(SlruSharedData)) + BLCKSZ * NUM_CLOG_BUFFERS
#ifdef EXEC_BACKEND #ifdef EXEC_BACKEND
+ MAXALIGN(sizeof(SlruLockData)) + MAXALIGN(sizeof(SlruLockData))
#endif #endif
; ;
} }
void void
@ -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
*/ */
@ -199,7 +201,7 @@ SimpleLruInit(SlruCtl ctl, const char *name, const char *subdir)
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
/* Initialize locks and shared memory area */ /* Initialize locks and shared memory area */
{ {
char *bufptr; char *bufptr;
int slotno; int slotno;
@ -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++)
{ {
@ -247,7 +249,7 @@ int
SimpleLruZeroPage(SlruCtl ctl, int pageno) SimpleLruZeroPage(SlruCtl ctl, int pageno)
{ {
int slotno; int slotno;
SlruShared shared = (SlruShared) ctl->shared; SlruShared shared = (SlruShared) ctl->shared;
/* Find a suitable buffer slot for the page */ /* Find a suitable buffer slot for the page */
slotno = SlruSelectLRUPage(ctl, pageno); slotno = SlruSelectLRUPage(ctl, pageno);
@ -285,7 +287,7 @@ SimpleLruZeroPage(SlruCtl ctl, int pageno)
char * char *
SimpleLruReadPage(SlruCtl ctl, int pageno, TransactionId xid, bool forwrite) SimpleLruReadPage(SlruCtl ctl, int pageno, TransactionId xid, bool forwrite)
{ {
SlruShared shared = (SlruShared) ctl->shared; SlruShared shared = (SlruShared) ctl->shared;
/* Outer loop handles restart if we lose the buffer to someone else */ /* Outer loop handles restart if we lose the buffer to someone else */
for (;;) for (;;)
@ -383,7 +385,7 @@ SimpleLruWritePage(SlruCtl ctl, int slotno)
{ {
int pageno; int pageno;
bool ok; bool ok;
SlruShared shared = (SlruShared) ctl->shared; SlruShared shared = (SlruShared) ctl->shared;
/* Do nothing if page does not need writing */ /* Do nothing if page does not need writing */
if (shared->page_status[slotno] != SLRU_PAGE_DIRTY && if (shared->page_status[slotno] != SLRU_PAGE_DIRTY &&
@ -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)
@ -608,37 +610,37 @@ SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
case SLRU_OPEN_FAILED: case SLRU_OPEN_FAILED:
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not access status of transaction %u", xid), errmsg("could not access status of transaction %u", xid),
errdetail("open of file \"%s\" failed: %m", errdetail("open of file \"%s\" failed: %m",
path))); path)));
break; break;
case SLRU_CREATE_FAILED: case SLRU_CREATE_FAILED:
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not access status of transaction %u", xid), errmsg("could not access status of transaction %u", xid),
errdetail("creation of file \"%s\" failed: %m", errdetail("creation of file \"%s\" failed: %m",
path))); path)));
break; break;
case SLRU_SEEK_FAILED: case SLRU_SEEK_FAILED:
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not access status of transaction %u", xid), errmsg("could not access status of transaction %u", xid),
errdetail("lseek of file \"%s\", offset %u failed: %m", errdetail("lseek of file \"%s\", offset %u failed: %m",
path, offset))); path, offset)));
break; break;
case SLRU_READ_FAILED: case SLRU_READ_FAILED:
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not access status of transaction %u", xid), errmsg("could not access status of transaction %u", xid),
errdetail("read of file \"%s\", offset %u failed: %m", errdetail("read of file \"%s\", offset %u failed: %m",
path, offset))); path, offset)));
break; break;
case SLRU_WRITE_FAILED: case SLRU_WRITE_FAILED:
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not access status of transaction %u", xid), errmsg("could not access status of transaction %u", xid),
errdetail("write of file \"%s\", offset %u failed: %m", errdetail("write of file \"%s\", offset %u failed: %m",
path, offset))); path, offset)));
break; break;
default: default:
/* can't get here, we trust */ /* can't get here, we trust */
@ -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 (;;)
{ {
@ -689,7 +692,7 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
if (shared->page_status[slotno] == SLRU_PAGE_EMPTY) if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
return slotno; return slotno;
if (shared->page_lru_count[slotno] > bestcount && if (shared->page_lru_count[slotno] > bestcount &&
shared->page_number[slotno] != shared->latest_page_number) shared->page_number[slotno] != shared->latest_page_number)
{ {
bestslot = slotno; bestslot = slotno;
bestcount = shared->page_lru_count[slotno]; bestcount = shared->page_lru_count[slotno];
@ -705,12 +708,12 @@ 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],
InvalidTransactionId, false); InvalidTransactionId, false);
else else
SimpleLruWritePage(ctl, bestslot); SimpleLruWritePage(ctl, 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);
@ -870,7 +874,7 @@ SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
if (cldir == NULL) if (cldir == NULL)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m", ctl->Dir))); errmsg("could not open directory \"%s\": %m", ctl->Dir)));
errno = 0; errno = 0;
while ((clde = readdir(cldir)) != NULL) while ((clde = readdir(cldir)) != NULL)
@ -898,7 +902,7 @@ SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
if (errno) if (errno)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not read directory \"%s\": %m", ctl->Dir))); errmsg("could not read directory \"%s\": %m", ctl->Dir)));
closedir(cldir); closedir(cldir);
return found; return found;

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:
@ -92,7 +92,7 @@
* AbortTransactionBlock * AbortTransactionBlock
* *
* These are invoked only in response to a user "BEGIN WORK", "COMMIT", * These are invoked only in response to a user "BEGIN WORK", "COMMIT",
* or "ROLLBACK" command. The tricky part about these functions * or "ROLLBACK" command. The tricky part about these functions
* is that they are called within the postgres main loop, in between * is that they are called within the postgres main loop, in between
* the StartTransactionCommand() and CommitTransactionCommand(). * the StartTransactionCommand() and CommitTransactionCommand().
* *
@ -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;
@ -359,7 +359,7 @@ GetCurrentTransactionStartTimeUsec(int *msec)
* TransactionIdIsCurrentTransactionId * TransactionIdIsCurrentTransactionId
* *
* During bootstrap, we cheat and say "it's not my transaction ID" even though * During bootstrap, we cheat and say "it's not my transaction ID" even though
* it is. Along with transam.c's cheat to say that the bootstrap XID is * it is. Along with transam.c's cheat to say that the bootstrap XID is
* already committed, this causes the tqual.c routines to see previously * already committed, this causes the tqual.c routines to see previously
* inserted tuples as committed, which is what we need during bootstrap. * inserted tuples as committed, which is what we need during bootstrap.
*/ */
@ -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);
@ -1064,7 +1064,7 @@ AbortTransaction(void)
} }
/* /*
* Post-abort cleanup. See notes in CommitTransaction() concerning * Post-abort cleanup. See notes in CommitTransaction() concerning
* ordering. * ordering.
*/ */
@ -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);
@ -1370,9 +1370,10 @@ PreventTransactionChain(void *stmtNode, const char *stmtType)
if (IsTransactionBlock()) if (IsTransactionBlock())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
/* 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.
@ -1381,8 +1382,8 @@ PreventTransactionChain(void *stmtNode, const char *stmtType)
if (!MemoryContextContains(QueryContext, stmtNode)) if (!MemoryContextContains(QueryContext, stmtNode))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
/* translator: %s represents an SQL statement name */ /* translator: %s represents an SQL statement name */
errmsg("%s cannot be executed from a function", stmtType))); errmsg("%s cannot be executed from a function", stmtType)));
/* If we got past IsTransactionBlock test, should be in default state */ /* If we got past IsTransactionBlock test, should be in default state */
if (CurrentTransactionState->blockState != TBLOCK_DEFAULT) if (CurrentTransactionState->blockState != TBLOCK_DEFAULT)
elog(ERROR, "cannot prevent transaction chain"); elog(ERROR, "cannot prevent transaction chain");
@ -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.
@ -1423,7 +1425,7 @@ RequireTransactionChain(void *stmtNode, const char *stmtType)
return; return;
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION), (errcode(ERRCODE_NO_ACTIVE_SQL_TRANSACTION),
/* translator: %s represents an SQL statement name */ /* translator: %s represents an SQL statement name */
errmsg("%s may only be used in BEGIN/END transaction blocks", errmsg("%s may only be used in BEGIN/END transaction blocks",
stmtType))); stmtType)));
} }

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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1046,8 +1046,8 @@ XLogWrite(XLogwrtRqst WriteRqst)
if (close(openLogFile) != 0) if (close(openLogFile) != 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("close of log file %u, segment %u failed: %m", errmsg("close of log file %u, segment %u failed: %m",
openLogId, openLogSeg))); openLogId, openLogSeg)));
openLogFile = -1; openLogFile = -1;
} }
XLByteToPrevSeg(LogwrtResult.Write, openLogId, openLogSeg); XLByteToPrevSeg(LogwrtResult.Write, openLogId, openLogSeg);
@ -1162,8 +1162,8 @@ XLogWrite(XLogwrtRqst WriteRqst)
if (close(openLogFile) != 0) if (close(openLogFile) != 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("close of log file %u, segment %u failed: %m", errmsg("close of log file %u, segment %u failed: %m",
openLogId, openLogSeg))); openLogId, openLogSeg)));
openLogFile = -1; openLogFile = -1;
} }
if (openLogFile < 0) if (openLogFile < 0)
@ -1266,7 +1266,7 @@ XLogFlush(XLogRecPtr record)
XLogCtlInsert *Insert = &XLogCtl->Insert; XLogCtlInsert *Insert = &XLogCtl->Insert;
uint32 freespace = INSERT_FREESPACE(Insert); uint32 freespace = INSERT_FREESPACE(Insert);
if (freespace < SizeOfXLogRecord) /* buffer is full */ if (freespace < SizeOfXLogRecord) /* buffer is full */
WriteRqstPtr = XLogCtl->xlblocks[Insert->curridx]; WriteRqstPtr = XLogCtl->xlblocks[Insert->curridx];
else else
{ {
@ -1449,8 +1449,8 @@ XLogFileInit(uint32 log, uint32 seg,
if (fd < 0) if (fd < 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("open of \"%s\" (log file %u, segment %u) failed: %m", errmsg("open of \"%s\" (log file %u, segment %u) failed: %m",
path, log, seg))); path, log, seg)));
return (fd); return (fd);
} }
@ -1563,14 +1563,14 @@ XLogFileOpen(uint32 log, uint32 seg, bool econt)
{ {
ereport(LOG, ereport(LOG,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("open of \"%s\" (log file %u, segment %u) failed: %m", errmsg("open of \"%s\" (log file %u, segment %u) failed: %m",
path, log, seg))); path, log, seg)));
return (fd); return (fd);
} }
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("open of \"%s\" (log file %u, segment %u) failed: %m", errmsg("open of \"%s\" (log file %u, segment %u) failed: %m",
path, log, seg))); path, log, seg)));
} }
return (fd); return (fd);
@ -1621,8 +1621,8 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr)
if (xldir == NULL) if (xldir == NULL)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open transaction log directory \"%s\": %m", errmsg("could not open transaction log directory \"%s\": %m",
XLogDir))); XLogDir)));
sprintf(lastoff, "%08X%08X", log, seg); sprintf(lastoff, "%08X%08X", log, seg);
@ -1654,15 +1654,15 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr)
true)) true))
{ {
ereport(LOG, ereport(LOG,
(errmsg("recycled transaction log file \"%s\"", (errmsg("recycled transaction log file \"%s\"",
xlde->d_name))); xlde->d_name)));
} }
else else
{ {
/* No need for any more future segments... */ /* No need for any more future segments... */
ereport(LOG, ereport(LOG,
(errmsg("removing transaction log file \"%s\"", (errmsg("removing transaction log file \"%s\"",
xlde->d_name))); xlde->d_name)));
unlink(path); unlink(path);
} }
} }
@ -1672,8 +1672,8 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr)
if (errno) if (errno)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not read transaction log directory \"%s\": %m", errmsg("could not read transaction log directory \"%s\": %m",
XLogDir))); XLogDir)));
closedir(xldir); closedir(xldir);
} }
@ -1746,8 +1746,8 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
if (!EQ_CRC64(record->xl_crc, crc)) if (!EQ_CRC64(record->xl_crc, crc))
{ {
ereport(emode, ereport(emode,
(errmsg("bad resource manager data checksum in record at %X/%X", (errmsg("bad resource manager data checksum in record at %X/%X",
recptr.xlogid, recptr.xrecoff))); recptr.xlogid, recptr.xrecoff)));
return (false); return (false);
} }
@ -1769,8 +1769,8 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
if (!EQ_CRC64(cbuf, crc)) if (!EQ_CRC64(cbuf, crc))
{ {
ereport(emode, ereport(emode,
(errmsg("bad checksum of backup block %d in record at %X/%X", (errmsg("bad checksum of backup block %d in record at %X/%X",
i + 1, recptr.xlogid, recptr.xrecoff))); i + 1, recptr.xlogid, recptr.xrecoff)));
return (false); return (false);
} }
blk += sizeof(BkpBlock) + BLCKSZ; blk += sizeof(BkpBlock) + BLCKSZ;
@ -1931,7 +1931,7 @@ got_record:;
{ {
ereport(emode, ereport(emode,
(errmsg("invalid resource manager id %u at %X/%X", (errmsg("invalid resource manager id %u at %X/%X",
record->xl_rmid, RecPtr->xlogid, RecPtr->xrecoff))); record->xl_rmid, RecPtr->xlogid, RecPtr->xrecoff)));
goto next_record_is_invalid; goto next_record_is_invalid;
} }
nextRecord = NULL; nextRecord = NULL;
@ -2063,7 +2063,7 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode, bool checkSUI)
{ {
ereport(emode, ereport(emode,
(errmsg("unexpected pageaddr %X/%X in log file %u, segment %u, offset %u", (errmsg("unexpected pageaddr %X/%X in log file %u, segment %u, offset %u",
hdr->xlp_pageaddr.xlogid, hdr->xlp_pageaddr.xrecoff, hdr->xlp_pageaddr.xlogid, hdr->xlp_pageaddr.xrecoff,
readId, readSeg, readOff))); readId, readSeg, readOff)));
return false; return false;
} }
@ -2084,7 +2084,7 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode, bool checkSUI)
hdr->xlp_sui > lastReadSUI + 512) hdr->xlp_sui > lastReadSUI + 512)
{ {
ereport(emode, ereport(emode,
/* translator: SUI = startup id */ /* translator: SUI = startup id */
(errmsg("out-of-sequence SUI %u (after %u) in log file %u, segment %u, offset %u", (errmsg("out-of-sequence SUI %u (after %u) in log file %u, segment %u, offset %u",
hdr->xlp_sui, lastReadSUI, hdr->xlp_sui, lastReadSUI,
readId, readSeg, readOff))); readId, readSeg, readOff)));
@ -2235,8 +2235,8 @@ ReadControlFile(void)
ereport(FATAL, ereport(FATAL,
(errmsg("database files are incompatible with server"), (errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with PG_CONTROL_VERSION %d," errdetail("The database cluster was initialized with PG_CONTROL_VERSION %d,"
" but the server was compiled with PG_CONTROL_VERSION %d.", " but the server was compiled with PG_CONTROL_VERSION %d.",
ControlFile->pg_control_version, PG_CONTROL_VERSION), ControlFile->pg_control_version, PG_CONTROL_VERSION),
errhint("It looks like you need to initdb."))); errhint("It looks like you need to initdb.")));
/* Now check the CRC. */ /* Now check the CRC. */
INIT_CRC64(crc); INIT_CRC64(crc);
@ -2265,75 +2265,75 @@ ReadControlFile(void)
ereport(FATAL, ereport(FATAL,
(errmsg("database files are incompatible with server"), (errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with CATALOG_VERSION_NO %d," errdetail("The database cluster was initialized with CATALOG_VERSION_NO %d,"
" but the server was compiled with CATALOG_VERSION_NO %d.", " but the server was compiled with CATALOG_VERSION_NO %d.",
ControlFile->catalog_version_no, CATALOG_VERSION_NO), ControlFile->catalog_version_no, CATALOG_VERSION_NO),
errhint("It looks like you need to initdb."))); errhint("It looks like you need to initdb.")));
if (ControlFile->blcksz != BLCKSZ) if (ControlFile->blcksz != BLCKSZ)
ereport(FATAL, ereport(FATAL,
(errmsg("database files are incompatible with server"), (errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with BLCKSZ %d," errdetail("The database cluster was initialized with BLCKSZ %d,"
" but the server was compiled with BLCKSZ %d.", " but the server was compiled with BLCKSZ %d.",
ControlFile->blcksz, BLCKSZ), ControlFile->blcksz, BLCKSZ),
errhint("It looks like you need to recompile or initdb."))); errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->relseg_size != RELSEG_SIZE) if (ControlFile->relseg_size != RELSEG_SIZE)
ereport(FATAL, ereport(FATAL,
(errmsg("database files are incompatible with server"), (errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with RELSEG_SIZE %d," errdetail("The database cluster was initialized with RELSEG_SIZE %d,"
" but the server was compiled with RELSEG_SIZE %d.", " but the server was compiled with RELSEG_SIZE %d.",
ControlFile->relseg_size, RELSEG_SIZE), ControlFile->relseg_size, RELSEG_SIZE),
errhint("It looks like you need to recompile or initdb."))); errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->nameDataLen != NAMEDATALEN) if (ControlFile->nameDataLen != NAMEDATALEN)
ereport(FATAL, ereport(FATAL,
(errmsg("database files are incompatible with server"), (errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with NAMEDATALEN %d," errdetail("The database cluster was initialized with NAMEDATALEN %d,"
" but the server was compiled with NAMEDATALEN %d.", " but the server was compiled with NAMEDATALEN %d.",
ControlFile->nameDataLen, NAMEDATALEN), ControlFile->nameDataLen, NAMEDATALEN),
errhint("It looks like you need to recompile or initdb."))); errhint("It looks like you need to recompile or initdb.")));
if (ControlFile->funcMaxArgs != FUNC_MAX_ARGS) if (ControlFile->funcMaxArgs != FUNC_MAX_ARGS)
ereport(FATAL, ereport(FATAL,
(errmsg("database files are incompatible with server"), (errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with FUNC_MAX_ARGS %d," errdetail("The database cluster was initialized with FUNC_MAX_ARGS %d,"
" but the server was compiled with FUNC_MAX_ARGS %d.", " but the server was compiled with FUNC_MAX_ARGS %d.",
ControlFile->funcMaxArgs, FUNC_MAX_ARGS), ControlFile->funcMaxArgs, FUNC_MAX_ARGS),
errhint("It looks like you need to recompile or initdb."))); errhint("It looks like you need to recompile or initdb.")));
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
if (ControlFile->enableIntTimes != TRUE) if (ControlFile->enableIntTimes != TRUE)
ereport(FATAL, ereport(FATAL,
(errmsg("database files are incompatible with server"), (errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized without HAVE_INT64_TIMESTAMP" errdetail("The database cluster was initialized without HAVE_INT64_TIMESTAMP"
" but the server was compiled with HAVE_INT64_TIMESTAMP."), " but the server was compiled with HAVE_INT64_TIMESTAMP."),
errhint("It looks like you need to recompile or initdb."))); errhint("It looks like you need to recompile or initdb.")));
#else #else
if (ControlFile->enableIntTimes != FALSE) if (ControlFile->enableIntTimes != FALSE)
ereport(FATAL, ereport(FATAL,
(errmsg("database files are incompatible with server"), (errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with HAVE_INT64_TIMESTAMP" errdetail("The database cluster was initialized with HAVE_INT64_TIMESTAMP"
" but the server was compiled without HAVE_INT64_TIMESTAMP."), " but the server was compiled without HAVE_INT64_TIMESTAMP."),
errhint("It looks like you need to recompile or initdb."))); errhint("It looks like you need to recompile or initdb.")));
#endif #endif
if (ControlFile->localeBuflen != LOCALE_NAME_BUFLEN) if (ControlFile->localeBuflen != LOCALE_NAME_BUFLEN)
ereport(FATAL, ereport(FATAL,
(errmsg("database files are incompatible with server"), (errmsg("database files are incompatible with server"),
errdetail("The database cluster was initialized with LOCALE_NAME_BUFLEN %d," errdetail("The database cluster was initialized with LOCALE_NAME_BUFLEN %d,"
" but the server was compiled with LOCALE_NAME_BUFLEN %d.", " but the server was compiled with LOCALE_NAME_BUFLEN %d.",
ControlFile->localeBuflen, LOCALE_NAME_BUFLEN), ControlFile->localeBuflen, LOCALE_NAME_BUFLEN),
errhint("It looks like you need to recompile or initdb."))); errhint("It looks like you need to recompile or initdb.")));
if (setlocale(LC_COLLATE, ControlFile->lc_collate) == NULL) if (setlocale(LC_COLLATE, ControlFile->lc_collate) == NULL)
ereport(FATAL, ereport(FATAL,
(errmsg("database files are incompatible with operating system"), (errmsg("database files are incompatible with operating system"),
errdetail("The database cluster was initialized with LC_COLLATE \"%s\"," errdetail("The database cluster was initialized with LC_COLLATE \"%s\","
" which is not recognized by setlocale().", " which is not recognized by setlocale().",
ControlFile->lc_collate), ControlFile->lc_collate),
errhint("It looks like you need to initdb or install locale support."))); errhint("It looks like you need to initdb or install locale support.")));
if (setlocale(LC_CTYPE, ControlFile->lc_ctype) == NULL) if (setlocale(LC_CTYPE, ControlFile->lc_ctype) == NULL)
ereport(FATAL, ereport(FATAL,
(errmsg("database files are incompatible with operating system"), (errmsg("database files are incompatible with operating system"),
errdetail("The database cluster was initialized with LC_CTYPE \"%s\"," errdetail("The database cluster was initialized with LC_CTYPE \"%s\","
" which is not recognized by setlocale().", " which is not recognized by setlocale().",
ControlFile->lc_ctype), ControlFile->lc_ctype),
errhint("It looks like you need to initdb or install locale support."))); errhint("It looks like you need to initdb or install locale support.")));
/* Make the fixed locale settings visible as GUC variables, too */ /* Make the fixed locale settings visible as GUC variables, too */
SetConfigOption("lc_collate", ControlFile->lc_collate, SetConfigOption("lc_collate", ControlFile->lc_collate,
@ -2602,10 +2602,10 @@ StartupXLOG(void)
str_time(ControlFile->time)))); str_time(ControlFile->time))));
else if (ControlFile->state == DB_IN_RECOVERY) else if (ControlFile->state == DB_IN_RECOVERY)
ereport(LOG, ereport(LOG,
(errmsg("database system was interrupted while in recovery at %s", (errmsg("database system was interrupted while in recovery at %s",
str_time(ControlFile->time)), str_time(ControlFile->time)),
errhint("This probably means that some data is corrupted and" errhint("This probably means that some data is corrupted and"
" you will have to use the last backup for recovery."))); " you will have to use the last backup for recovery.")));
else if (ControlFile->state == DB_IN_PRODUCTION) else if (ControlFile->state == DB_IN_PRODUCTION)
ereport(LOG, ereport(LOG,
(errmsg("database system was interrupted at %s", (errmsg("database system was interrupted at %s",
@ -2637,12 +2637,12 @@ StartupXLOG(void)
checkPointLoc = ControlFile->prevCheckPoint; checkPointLoc = ControlFile->prevCheckPoint;
ereport(LOG, ereport(LOG,
(errmsg("using previous checkpoint record at %X/%X", (errmsg("using previous checkpoint record at %X/%X",
checkPointLoc.xlogid, checkPointLoc.xrecoff))); checkPointLoc.xlogid, checkPointLoc.xrecoff)));
InRecovery = true; /* force recovery even if SHUTDOWNED */ InRecovery = true; /* force recovery even if SHUTDOWNED */
} }
else else
ereport(PANIC, ereport(PANIC,
(errmsg("could not locate a valid checkpoint record"))); (errmsg("could not locate a valid checkpoint record")));
} }
LastRec = RecPtr = checkPointLoc; LastRec = RecPtr = checkPointLoc;
memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint)); memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));
@ -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;
@ -2690,7 +2691,7 @@ StartupXLOG(void)
{ {
if (wasShutdown) if (wasShutdown)
ereport(PANIC, ereport(PANIC,
(errmsg("invalid redo/undo record in shutdown checkpoint"))); (errmsg("invalid redo/undo record in shutdown checkpoint")));
InRecovery = true; InRecovery = true;
} }
else if (ControlFile->state != DB_SHUTDOWNED) else if (ControlFile->state != DB_SHUTDOWNED)
@ -2699,7 +2700,7 @@ StartupXLOG(void)
/* REDO */ /* REDO */
if (InRecovery) if (InRecovery)
{ {
int rmid; int rmid;
ereport(LOG, ereport(LOG,
(errmsg("database system was not properly shut down; " (errmsg("database system was not properly shut down; "
@ -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.
*/ */
@ -2859,7 +2861,7 @@ StartupXLOG(void)
if (InRecovery) if (InRecovery)
{ {
int rmid; int rmid;
/* /*
* Allow resource managers to do any required cleanup. * Allow resource managers to do any required cleanup.
@ -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;
@ -2973,9 +2977,9 @@ ReadCheckpointRecord(XLogRecPtr RecPtr,
if (!XRecOffIsValid(RecPtr.xrecoff)) if (!XRecOffIsValid(RecPtr.xrecoff))
{ {
ereport(LOG, ereport(LOG,
/* translator: %s is "primary" or "secondary" */ /* translator: %s is "primary" or "secondary" */
(errmsg("invalid %s checkpoint link in control file", (errmsg("invalid %s checkpoint link in control file",
(whichChkpt == 1) ? gettext("primary") : gettext("secondary")))); (whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
return NULL; return NULL;
} }
@ -2984,34 +2988,34 @@ ReadCheckpointRecord(XLogRecPtr RecPtr,
if (record == NULL) if (record == NULL)
{ {
ereport(LOG, ereport(LOG,
/* translator: %s is "primary" or "secondary" */ /* translator: %s is "primary" or "secondary" */
(errmsg("invalid %s checkpoint record", (errmsg("invalid %s checkpoint record",
(whichChkpt == 1) ? gettext("primary") : gettext("secondary")))); (whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
return NULL; return NULL;
} }
if (record->xl_rmid != RM_XLOG_ID) if (record->xl_rmid != RM_XLOG_ID)
{ {
ereport(LOG, ereport(LOG,
/* translator: %s is "primary" or "secondary" */ /* translator: %s is "primary" or "secondary" */
(errmsg("invalid resource manager id in %s checkpoint record", (errmsg("invalid resource manager id in %s checkpoint record",
(whichChkpt == 1) ? gettext("primary") : gettext("secondary")))); (whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
return NULL; return NULL;
} }
if (record->xl_info != XLOG_CHECKPOINT_SHUTDOWN && if (record->xl_info != XLOG_CHECKPOINT_SHUTDOWN &&
record->xl_info != XLOG_CHECKPOINT_ONLINE) record->xl_info != XLOG_CHECKPOINT_ONLINE)
{ {
ereport(LOG, ereport(LOG,
/* translator: %s is "primary" or "secondary" */ /* translator: %s is "primary" or "secondary" */
(errmsg("invalid xl_info in %s checkpoint record", (errmsg("invalid xl_info in %s checkpoint record",
(whichChkpt == 1) ? gettext("primary") : gettext("secondary")))); (whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
return NULL; return NULL;
} }
if (record->xl_len != sizeof(CheckPoint)) if (record->xl_len != sizeof(CheckPoint))
{ {
ereport(LOG, ereport(LOG,
/* translator: %s is "primary" or "secondary" */ /* translator: %s is "primary" or "secondary" */
(errmsg("invalid length of %s checkpoint record", (errmsg("invalid length of %s checkpoint record",
(whichChkpt == 1) ? gettext("primary") : gettext("secondary")))); (whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
return NULL; return NULL;
} }
return record; return record;
@ -3112,10 +3116,11 @@ CreateCheckPoint(bool shutdown, bool force)
if (MyXactMadeXLogEntry) if (MyXactMadeXLogEntry)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION), (errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
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 */
@ -3538,15 +3545,15 @@ assign_xlog_sync_method(const char *method, bool doit, bool interactive)
if (pg_fsync(openLogFile) != 0) if (pg_fsync(openLogFile) != 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("fsync of log file %u, segment %u failed: %m", errmsg("fsync of log file %u, segment %u failed: %m",
openLogId, openLogSeg))); openLogId, openLogSeg)));
if (open_sync_bit != new_sync_bit) if (open_sync_bit != new_sync_bit)
{ {
if (close(openLogFile) != 0) if (close(openLogFile) != 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("close of log file %u, segment %u failed: %m", errmsg("close of log file %u, segment %u failed: %m",
openLogId, openLogSeg))); openLogId, openLogSeg)));
openLogFile = -1; openLogFile = -1;
} }
} }
@ -3570,16 +3577,16 @@ issue_xlog_fsync(void)
if (pg_fsync(openLogFile) != 0) if (pg_fsync(openLogFile) != 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("fsync of log file %u, segment %u failed: %m", errmsg("fsync of log file %u, segment %u failed: %m",
openLogId, openLogSeg))); openLogId, openLogSeg)));
break; break;
#ifdef HAVE_FDATASYNC #ifdef HAVE_FDATASYNC
case SYNC_METHOD_FDATASYNC: case SYNC_METHOD_FDATASYNC:
if (pg_fdatasync(openLogFile) != 0) if (pg_fdatasync(openLogFile) != 0)
ereport(PANIC, ereport(PANIC,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("fdatasync of log file %u, segment %u failed: %m", errmsg("fdatasync of log file %u, segment %u failed: %m",
openLogId, openLogSeg))); openLogId, openLogSeg)));
break; break;
#endif #endif
case SYNC_METHOD_OPEN: case SYNC_METHOD_OPEN:

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
@ -285,22 +285,22 @@ BootstrapMain(int argc, char *argv[])
xlogop = atoi(optarg); xlogop = atoi(optarg);
break; break;
case 'p': case 'p':
{ {
/* indicates fork from postmaster */ /* indicates fork from postmaster */
#ifdef EXEC_BACKEND #ifdef EXEC_BACKEND
char *p; char *p;
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
break; break;
} }
case 'B': case 'B':
SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV); SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);
break; break;
@ -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,37 +97,40 @@ 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,
(grant_option || !is_grant) ? privileges : ACL_NO_RIGHTS, (grant_option || !is_grant) ? privileges : ACL_NO_RIGHTS,
idtype); idtype);
new_acl = aclinsert3(new_acl, &aclitem, modechg, behavior); new_acl = aclinsert3(new_acl, &aclitem, modechg, behavior);
@ -247,7 +250,7 @@ ExecuteGrantStmt_Relation(GrantStmt *stmt)
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privileges, stmt->grantees, privileges,
stmt->grant_option, stmt->behavior); stmt->grant_option, stmt->behavior);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values)); MemSet(values, 0, sizeof(values));
@ -346,7 +349,7 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privileges, stmt->grantees, privileges,
stmt->grant_option, stmt->behavior); stmt->grant_option, stmt->behavior);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values)); MemSet(values, 0, sizeof(values));
@ -443,7 +446,7 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privileges, stmt->grantees, privileges,
stmt->grant_option, stmt->behavior); stmt->grant_option, stmt->behavior);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values)); MemSet(values, 0, sizeof(values));
@ -543,7 +546,7 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privileges, stmt->grantees, privileges,
stmt->grant_option, stmt->behavior); stmt->grant_option, stmt->behavior);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values)); MemSet(values, 0, sizeof(values));
@ -619,7 +622,7 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple); pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
if (stmt->is_grant if (stmt->is_grant
&& !pg_namespace_ownercheck(HeapTupleGetOid(tuple), GetUserId()) && !pg_namespace_ownercheck(HeapTupleGetOid(tuple), GetUserId())
&& pg_namespace_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK) && pg_namespace_aclcheck(HeapTupleGetOid(tuple), GetUserId(), ACL_GRANT_OPTION_FOR(privileges)) != ACLCHECK_OK)
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE, aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE,
nspname); nspname);
@ -640,7 +643,7 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant, new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grantees, privileges, stmt->grantees, privileges,
stmt->grant_option, stmt->behavior); stmt->grant_option, stmt->behavior);
/* finished building new ACL value, now insert it */ /* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values)); MemSet(values, 0, sizeof(values));
@ -805,7 +808,7 @@ in_group(AclId uid, AclId gid)
static AclResult static AclResult
aclcheck(Acl *acl, AclId userid, AclMode mode) aclcheck(Acl *acl, AclId userid, AclMode mode)
{ {
AclItem *aidat; AclItem *aidat;
int i, int i,
num; num;
@ -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"),
@ -972,7 +975,7 @@ pg_class_aclcheck(Oid table_oid, AclId userid, AclMode mode)
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE), (errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation with OID %u does not exist", table_oid))); errmsg("relation with OID %u does not exist", table_oid)));
/* /*
* Deny anyone permission to update a system catalog unless * Deny anyone permission to update a system catalog unless
@ -1124,7 +1127,7 @@ pg_proc_aclcheck(Oid proc_oid, AclId userid, AclMode mode)
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION), (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("function with OID %u does not exist", proc_oid))); errmsg("function with OID %u does not exist", proc_oid)));
aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl, aclDatum = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_proacl,
&isNull); &isNull);
@ -1179,7 +1182,7 @@ pg_language_aclcheck(Oid lang_oid, AclId userid, AclMode mode)
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("language with OID %u does not exist", lang_oid))); errmsg("language with OID %u does not exist", lang_oid)));
aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl, aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
&isNull); &isNull);
@ -1288,7 +1291,7 @@ pg_class_ownercheck(Oid class_oid, AclId userid)
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE), (errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation with OID %u does not exist", class_oid))); errmsg("relation with OID %u does not exist", class_oid)));
owner_id = ((Form_pg_class) GETSTRUCT(tuple))->relowner; owner_id = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
@ -1344,7 +1347,7 @@ pg_oper_ownercheck(Oid oper_oid, AclId userid)
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION), (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("operator with OID %u does not exist", oper_oid))); errmsg("operator with OID %u does not exist", oper_oid)));
owner_id = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner; owner_id = ((Form_pg_operator) GETSTRUCT(tuple))->oprowner;
@ -1372,7 +1375,7 @@ pg_proc_ownercheck(Oid proc_oid, AclId userid)
if (!HeapTupleIsValid(tuple)) if (!HeapTupleIsValid(tuple))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION), (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("function with OID %u does not exist", proc_oid))); errmsg("function with OID %u does not exist", proc_oid)));
owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner; owner_id = ((Form_pg_proc) GETSTRUCT(tuple))->proowner;

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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -93,8 +93,8 @@ static Oid object_classes[MAX_OCLASS];
static void findAutoDeletableObjects(const ObjectAddress *object, static void findAutoDeletableObjects(const ObjectAddress *object,
ObjectAddresses *oktodelete, ObjectAddresses *oktodelete,
Relation depRel); Relation depRel);
static bool recursiveDeletion(const ObjectAddress *object, static bool recursiveDeletion(const ObjectAddress *object,
DropBehavior behavior, DropBehavior behavior,
int msglevel, int msglevel,
@ -102,11 +102,11 @@ static bool recursiveDeletion(const ObjectAddress *object,
ObjectAddresses *oktodelete, ObjectAddresses *oktodelete,
Relation depRel); Relation depRel);
static bool deleteDependentObjects(const ObjectAddress *object, static bool deleteDependentObjects(const ObjectAddress *object,
const char *objDescription, const char *objDescription,
DropBehavior behavior, DropBehavior behavior,
int msglevel, int msglevel,
ObjectAddresses *oktodelete, ObjectAddresses *oktodelete,
Relation depRel); Relation depRel);
static void doDeletion(const ObjectAddress *object); static void doDeletion(const ObjectAddress *object);
static bool find_expr_references_walker(Node *node, static bool find_expr_references_walker(Node *node,
find_expr_references_context *context); find_expr_references_context *context);
@ -118,7 +118,7 @@ static void add_object_address(ObjectClasses oclass, Oid objectId, int32 subId,
static void add_exact_object_address(const ObjectAddress *object, static void add_exact_object_address(const ObjectAddress *object,
ObjectAddresses *addrs); ObjectAddresses *addrs);
static bool object_address_present(const ObjectAddress *object, static bool object_address_present(const ObjectAddress *object,
ObjectAddresses *addrs); ObjectAddresses *addrs);
static void term_object_addresses(ObjectAddresses *addrs); static void term_object_addresses(ObjectAddresses *addrs);
static void init_object_classes(void); static void init_object_classes(void);
static ObjectClasses getObjectClass(const ObjectAddress *object); static ObjectClasses getObjectClass(const ObjectAddress *object);
@ -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);
@ -170,8 +170,8 @@ performDeletion(const ObjectAddress *object,
NULL, &oktodelete, depRel)) NULL, &oktodelete, depRel))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because other objects depend on it", errmsg("cannot drop %s because other objects depend on it",
objDescription), objDescription),
errhint("Use DROP ... CASCADE to drop the dependent objects too."))); errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
term_object_addresses(&oktodelete); term_object_addresses(&oktodelete);
@ -184,7 +184,7 @@ performDeletion(const ObjectAddress *object,
/* /*
* deleteWhatDependsOn: attempt to drop everything that depends on the * deleteWhatDependsOn: attempt to drop everything that depends on the
* specified object, though not the object itself. Behavior is always * specified object, though not the object itself. Behavior is always
* CASCADE. * CASCADE.
* *
* This is currently used only to clean out the contents of a schema * This is currently used only to clean out the contents of a schema
@ -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
@ -461,11 +462,11 @@ recursiveDeletion(const ObjectAddress *object,
char *otherObjDesc = getObjectDescription(&otherObject); char *otherObjDesc = getObjectDescription(&otherObject);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST), (errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
errmsg("cannot drop %s because %s requires it", errmsg("cannot drop %s because %s requires it",
objDescription, otherObjDesc), objDescription, otherObjDesc),
errhint("You may drop %s instead.", errhint("You may drop %s instead.",
otherObjDesc))); otherObjDesc)));
} }
/* /*
@ -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,
@ -872,7 +873,7 @@ recordDependencyOnExpr(const ObjectAddress *depender,
* recordDependencyOnSingleRelExpr - find expression dependencies * recordDependencyOnSingleRelExpr - find expression dependencies
* *
* As above, but only one relation is expected to be referenced (with * As above, but only one relation is expected to be referenced (with
* varno = 1 and varlevelsup = 0). Pass the relation OID instead of a * varno = 1 and varlevelsup = 0). Pass the relation OID instead of a
* range table. An additional frammish is that dependencies on that * range table. An additional frammish is that dependencies on that
* relation (or its component columns) will be marked with 'self_behavior', * relation (or its component columns) will be marked with 'self_behavior',
* whereas 'behavior' is used for everything else. * whereas 'behavior' is used for everything else.
@ -1001,7 +1002,7 @@ find_expr_references_walker(Node *node,
else if (rte->rtekind == RTE_JOIN) else if (rte->rtekind == RTE_JOIN)
{ {
/* Scan join output column to add references to join inputs */ /* Scan join output column to add references to join inputs */
List *save_rtables; List *save_rtables;
/* We must make the context appropriate for join's level */ /* We must make the context appropriate for join's level */
save_rtables = context->rtables; save_rtables = context->rtables;
@ -1026,7 +1027,7 @@ find_expr_references_walker(Node *node,
} }
if (IsA(node, OpExpr)) if (IsA(node, OpExpr))
{ {
OpExpr *opexpr = (OpExpr *) node; OpExpr *opexpr = (OpExpr *) node;
add_object_address(OCLASS_OPERATOR, opexpr->opno, 0, add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
&context->addrs); &context->addrs);
@ -1034,7 +1035,7 @@ find_expr_references_walker(Node *node,
} }
if (IsA(node, DistinctExpr)) if (IsA(node, DistinctExpr))
{ {
DistinctExpr *distinctexpr = (DistinctExpr *) node; DistinctExpr *distinctexpr = (DistinctExpr *) node;
add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0, add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
&context->addrs); &context->addrs);
@ -1042,7 +1043,7 @@ find_expr_references_walker(Node *node,
} }
if (IsA(node, ScalarArrayOpExpr)) if (IsA(node, ScalarArrayOpExpr))
{ {
ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node; ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
add_object_address(OCLASS_OPERATOR, opexpr->opno, 0, add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
&context->addrs); &context->addrs);
@ -1066,7 +1067,7 @@ find_expr_references_walker(Node *node,
} }
if (IsA(node, SubLink)) if (IsA(node, SubLink))
{ {
SubLink *sublink = (SubLink *) node; SubLink *sublink = (SubLink *) node;
List *opid; List *opid;
foreach(opid, sublink->operOids) foreach(opid, sublink->operOids)
@ -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...)
*/ */
@ -439,7 +439,7 @@ CheckAttributeType(const char *attname, Oid atttypid)
} }
else if (att_typtype == 'c') else if (att_typtype == 'c')
{ {
Oid typrelid = get_typ_typrelid(atttypid); Oid typrelid = get_typ_typrelid(atttypid);
if (get_rel_relkind(typrelid) == RELKIND_COMPOSITE_TYPE) if (get_rel_relkind(typrelid) == RELKIND_COMPOSITE_TYPE)
ereport(ERROR, ereport(ERROR,
@ -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;
@ -1401,7 +1402,7 @@ StoreRelCheck(Relation rel, char *ccname, char *ccbin)
' ', ' ',
' ', ' ',
' ', ' ',
InvalidOid, /* no associated index */ InvalidOid, /* no associated index */
expr, /* Tree form check constraint */ expr, /* Tree form check constraint */
ccbin, /* Binary form check constraint */ ccbin, /* Binary form check constraint */
ccsrc); /* Source form check constraint */ ccsrc); /* Source form check constraint */
@ -1568,8 +1569,8 @@ AddRelationRawConstraints(Relation rel,
if (strcmp(cdef2->name, ccname) == 0) if (strcmp(cdef2->name, ccname) == 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT), (errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("CHECK constraint \"%s\" already exists", errmsg("CHECK constraint \"%s\" already exists",
ccname))); ccname)));
} }
} }
else else
@ -1639,7 +1640,7 @@ AddRelationRawConstraints(Relation rel,
if (pstate->p_hasSubLinks) if (pstate->p_hasSubLinks)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use sub-select in CHECK constraint"))); errmsg("cannot use sub-select in CHECK constraint")));
if (pstate->p_hasAggs) if (pstate->p_hasAggs)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_GROUPING_ERROR), (errcode(ERRCODE_GROUPING_ERROR),
@ -1750,7 +1751,7 @@ cookDefault(ParseState *pstate,
if (contain_var_clause(expr)) if (contain_var_clause(expr))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE), (errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("cannot use column references in DEFAULT clause"))); errmsg("cannot use column references in DEFAULT clause")));
/* /*
* It can't return a set either. * It can't return a set either.
@ -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))
{ {
@ -1793,7 +1794,7 @@ cookDefault(ParseState *pstate,
attname, attname,
format_type_be(atttypid), format_type_be(atttypid),
format_type_be(type_id)), format_type_be(type_id)),
errhint("You will need to rewrite or cast the expression."))); errhint("You will need to rewrite or cast the expression.")));
} }
return expr; return expr;
@ -1952,7 +1953,7 @@ RelationTruncateIndexes(Oid heapId)
/* /*
* index_build will close both the heap and index relations (but * index_build will close both the heap and index relations (but
* not give up the locks we hold on them). We're done with this * not give up the locks we hold on them). We're done with this
* index, but we must re-open the heap rel. * index, but we must re-open the heap rel.
*/ */
heapRelation = heap_open(heapId, NoLock); heapRelation = heap_open(heapId, NoLock);

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
@ -65,8 +65,8 @@
/* non-export function prototypes */ /* non-export function prototypes */
static TupleDesc ConstructTupleDescriptor(Relation heapRelation, static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
IndexInfo *indexInfo, IndexInfo *indexInfo,
Oid *classObjectId); Oid *classObjectId);
static void UpdateRelationRelation(Relation indexRelation); static void UpdateRelationRelation(Relation indexRelation);
static void InitializeAttributeOids(Relation indexRelation, static void InitializeAttributeOids(Relation indexRelation,
int numatts, Oid indexoid); int numatts, Oid indexoid);
@ -124,7 +124,7 @@ ConstructTupleDescriptor(Relation heapRelation,
/* /*
* For simple index columns, we copy the pg_attribute row from the * For simple index columns, we copy the pg_attribute row from the
* parent relation and modify it as necessary. For expressions we * parent relation and modify it as necessary. For expressions we
* have to cons up a pg_attribute row the hard way. * have to cons up a pg_attribute row the hard way.
*/ */
for (i = 0; i < numatts; i++) for (i = 0; i < numatts; i++)
@ -149,7 +149,7 @@ ConstructTupleDescriptor(Relation heapRelation,
* here we are indexing on a system attribute (-1...-n) * here we are indexing on a system attribute (-1...-n)
*/ */
from = SystemAttributeDefinition(atnum, from = SystemAttributeDefinition(atnum,
heapRelation->rd_rel->relhasoids); heapRelation->rd_rel->relhasoids);
} }
else else
{ {
@ -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);
@ -185,7 +185,7 @@ ConstructTupleDescriptor(Relation heapRelation,
/* Expressional index */ /* Expressional index */
Node *indexkey; Node *indexkey;
if (indexprs == NIL) /* shouldn't happen */ if (indexprs == NIL) /* shouldn't happen */
elog(ERROR, "too few entries in indexprs list"); elog(ERROR, "too few entries in indexprs list");
indexkey = (Node *) lfirst(indexprs); indexkey = (Node *) lfirst(indexprs);
indexprs = lnext(indexprs); indexprs = lnext(indexprs);
@ -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,
@ -534,7 +535,7 @@ index_create(Oid heapRelationId,
if (shared_relation && IsUnderPostmaster) if (shared_relation && IsUnderPostmaster)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("shared indexes cannot be created after initdb"))); errmsg("shared indexes cannot be created after initdb")));
if (get_relname_relid(indexRelationName, namespaceId)) if (get_relname_relid(indexRelationName, namespaceId))
ereport(ERROR, ereport(ERROR,
@ -668,7 +669,7 @@ index_create(Oid heapRelationId,
' ', ' ',
' ', ' ',
' ', ' ',
InvalidOid, /* no associated index */ InvalidOid, /* no associated index */
NULL, /* no check constraint */ NULL, /* no check constraint */
NULL, NULL,
NULL); NULL);
@ -709,7 +710,7 @@ index_create(Oid heapRelationId,
if (indexInfo->ii_Expressions) if (indexInfo->ii_Expressions)
{ {
recordDependencyOnSingleRelExpr(&myself, recordDependencyOnSingleRelExpr(&myself,
(Node *) indexInfo->ii_Expressions, (Node *) indexInfo->ii_Expressions,
heapRelationId, heapRelationId,
DEPENDENCY_NORMAL, DEPENDENCY_NORMAL,
DEPENDENCY_AUTO); DEPENDENCY_AUTO);
@ -719,7 +720,7 @@ index_create(Oid heapRelationId,
if (indexInfo->ii_Predicate) if (indexInfo->ii_Predicate)
{ {
recordDependencyOnSingleRelExpr(&myself, recordDependencyOnSingleRelExpr(&myself,
(Node *) indexInfo->ii_Predicate, (Node *) indexInfo->ii_Predicate,
heapRelationId, heapRelationId,
DEPENDENCY_NORMAL, DEPENDENCY_NORMAL,
DEPENDENCY_AUTO); DEPENDENCY_AUTO);
@ -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.
@ -958,7 +959,7 @@ FormIndexDatum(IndexInfo *indexInfo,
if (indexprs == NIL) if (indexprs == NIL)
elog(ERROR, "wrong number of index expressions"); elog(ERROR, "wrong number of index expressions");
iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexprs), iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexprs),
GetPerTupleExprContext(estate), GetPerTupleExprContext(estate),
&isNull, &isNull,
NULL); NULL);
indexprs = lnext(indexprs); indexprs = lnext(indexprs);
@ -1160,7 +1161,7 @@ setNewRelfilenode(Relation relation)
if (!in_place_upd) if (!in_place_upd)
{ {
tuple = SearchSysCacheCopy(RELOID, tuple = SearchSysCacheCopy(RELOID,
ObjectIdGetDatum(RelationGetRelid(relation)), ObjectIdGetDatum(RelationGetRelid(relation)),
0, 0, 0); 0, 0, 0);
} }
else else
@ -1170,7 +1171,7 @@ setNewRelfilenode(Relation relation)
ScanKeyEntryInitialize(&key[0], 0, ScanKeyEntryInitialize(&key[0], 0,
ObjectIdAttributeNumber, ObjectIdAttributeNumber,
F_OIDEQ, F_OIDEQ,
ObjectIdGetDatum(RelationGetRelid(relation))); ObjectIdGetDatum(RelationGetRelid(relation)));
pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key); pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);
tuple = heap_getnext(pg_class_scan, ForwardScanDirection); tuple = heap_getnext(pg_class_scan, ForwardScanDirection);
@ -1325,9 +1326,9 @@ 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;
@ -1367,7 +1369,7 @@ UpdateStats(Oid relid, double reltuples)
/* /*
* We shouldn't have to do this, but we do... Modify the reldesc in * We shouldn't have to do this, but we do... Modify the reldesc in
* place with the new values so that the cache contains the latest * place with the new values so that the cache contains the latest
* copy. (XXX is this really still necessary? The relcache will get * copy. (XXX is this really still necessary? The relcache will get
* fixed at next CommandCounterIncrement, so why bother here?) * fixed at next CommandCounterIncrement, so why bother here?)
*/ */
whichRel->rd_rel->relpages = (int32) relpages; whichRel->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,15 +1744,15 @@ 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)
{ {
if (!IsIgnoringSystemIndexes()) if (!IsIgnoringSystemIndexes())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("the target relation %u is shared", indexId))); errmsg("the target relation %u is shared", indexId)));
inplace = true; inplace = true;
} }
if (iRel->rd_isnailed) if (iRel->rd_isnailed)
@ -1757,7 +1760,7 @@ reindex_index(Oid indexId, bool force, bool inplace)
if (!IsIgnoringSystemIndexes()) if (!IsIgnoringSystemIndexes())
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("the target relation %u is nailed", indexId))); errmsg("the target relation %u is nailed", indexId)));
inplace = true; inplace = true;
} }

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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -164,7 +164,7 @@ RangeVarGetRelid(const RangeVar *relation, bool failOK)
if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0) if (strcmp(relation->catalogname, get_database_name(MyDatabaseId)) != 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cross-database references are not implemented"))); errmsg("cross-database references are not implemented")));
} }
if (relation->schemaname) if (relation->schemaname)
@ -217,7 +217,7 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation)
if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0) if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cross-database references are not implemented"))); errmsg("cross-database references are not implemented")));
} }
if (newRelation->istemp) if (newRelation->istemp)
@ -226,7 +226,7 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation)
if (newRelation->schemaname) if (newRelation->schemaname)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION), (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("TEMP tables may not specify a schema name"))); errmsg("TEMP tables may not specify a schema name")));
/* Initialize temp namespace if first time through */ /* Initialize temp namespace if first time through */
if (!OidIsValid(myTempNamespace)) if (!OidIsValid(myTempNamespace))
InitTempTableNamespace(); InitTempTableNamespace();
@ -1057,7 +1057,7 @@ OpclassIsVisible(Oid opcid)
Oid Oid
ConversionGetConid(const char *conname) ConversionGetConid(const char *conname)
{ {
Oid conid; Oid conid;
List *lptr; List *lptr;
recomputeNamespacePath(); recomputeNamespacePath();
@ -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);
@ -1164,13 +1164,13 @@ DeconstructQualifiedName(List *names,
if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0) if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cross-database references are not implemented"))); errmsg("cross-database references are not implemented")));
break; break;
default: default:
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("improper qualified name (too many dotted names): %s", errmsg("improper qualified name (too many dotted names): %s",
NameListToString(names)))); NameListToString(names))));
break; break;
} }
@ -1281,8 +1281,8 @@ makeRangeVarFromNameList(List *names)
default: default:
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("improper relation name (too many dotted names): %s", errmsg("improper relation name (too many dotted names): %s",
NameListToString(names)))); NameListToString(names))));
break; break;
} }
@ -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);
@ -1797,7 +1797,7 @@ assign_search_path(const char *newval, bool doit, bool interactive)
0, 0, 0)) 0, 0, 0))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_SCHEMA), (errcode(ERRCODE_UNDEFINED_SCHEMA),
errmsg("schema \"%s\" does not exist", curname))); errmsg("schema \"%s\" does not exist", curname)));
} }
} }

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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -29,8 +29,8 @@
#include "utils/syscache.h" #include "utils/syscache.h"
static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types, static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
Oid *rettype); Oid *rettype);
/* /*
@ -79,7 +79,7 @@ AggregateCreate(const char *aggName,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("cannot determine transition datatype"), errmsg("cannot determine transition datatype"),
errdetail("An aggregate using ANYARRAY or ANYELEMENT as " errdetail("An aggregate using ANYARRAY or ANYELEMENT as "
"trans type must have one of them as its base type."))); "trans type must have one of them as its base type.")));
/* handle transfn */ /* handle transfn */
MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid)); MemSet(fnArgs, 0, FUNC_MAX_ARGS * sizeof(Oid));
@ -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.)
@ -163,8 +163,8 @@ AggregateCreate(const char *aggName,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("cannot determine result datatype"), errmsg("cannot determine result datatype"),
errdetail("An aggregate returning ANYARRAY or ANYELEMENT " errdetail("An aggregate returning ANYARRAY or ANYELEMENT "
"must have one of them as its base type."))); "must have one of them as its base type.")));
/* /*
* Everything looks okay. Try to create the pg_proc entry for the * Everything looks okay. Try to create the pg_proc entry for the
@ -278,21 +278,21 @@ lookup_agg_function(List *fnName,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_FUNCTION), (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("function %s does not exist", errmsg("function %s does not exist",
func_signature_string(fnName, nargs, input_types)))); func_signature_string(fnName, nargs, input_types))));
if (retset) if (retset)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("function %s returns a set", errmsg("function %s returns a set",
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 ||
(input_types[1] == ANYARRAYOID || input_types[1] == ANYELEMENTOID))) (input_types[1] == ANYARRAYOID || input_types[1] == ANYELEMENTOID)))
{ {
/* nothing to check here */ /* nothing to check here */
} }
@ -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 &&
@ -314,7 +314,7 @@ lookup_agg_function(List *fnName,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("function %s requires run-time type coercion", errmsg("function %s requires run-time type coercion",
func_signature_string(fnName, nargs, true_oid_array)))); func_signature_string(fnName, nargs, true_oid_array))));
if (nargs == 2 && if (nargs == 2 &&
true_oid_array[1] != ANYARRAYOID && true_oid_array[1] != ANYARRAYOID &&
@ -323,7 +323,7 @@ lookup_agg_function(List *fnName,
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("function %s requires run-time type coercion", errmsg("function %s requires run-time type coercion",
func_signature_string(fnName, nargs, true_oid_array)))); func_signature_string(fnName, nargs, true_oid_array))));
return fnOid; return fnOid;
} }

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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -195,7 +195,7 @@ CreateConstraintEntry(const char *constraintName,
/* /*
* Register auto dependency from constraint to owning domain * Register auto dependency from constraint to owning domain
*/ */
ObjectAddress domobject; ObjectAddress domobject;
domobject.classId = RelOid_pg_type; domobject.classId = RelOid_pg_type;
domobject.objectId = domainId; domobject.objectId = domainId;
@ -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);
@ -463,7 +463,7 @@ RemoveConstraintById(Oid conId)
con->conrelid); con->conrelid);
classForm = (Form_pg_class) GETSTRUCT(relTup); classForm = (Form_pg_class) GETSTRUCT(relTup);
if (classForm->relchecks == 0) /* should not happen */ if (classForm->relchecks == 0) /* should not happen */
elog(ERROR, "relation \"%s\" has relchecks = 0", elog(ERROR, "relation \"%s\" has relchecks = 0",
RelationGetRelationName(rel)); RelationGetRelationName(rel));
classForm->relchecks--; classForm->relchecks--;
@ -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);

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