mirror of https://github.com/postgres/postgres
pgindent run.
This commit is contained in:
parent
63354a0228
commit
089003fb46
|
@ -1,7 +1,7 @@
|
|||
#include "btree_gist.h"
|
||||
|
||||
PG_FUNCTION_INFO_V1(btree_decompress);
|
||||
Datum btree_decompress(PG_FUNCTION_ARGS);
|
||||
Datum btree_decompress(PG_FUNCTION_ARGS);
|
||||
|
||||
/*
|
||||
** GiST DeCompress methods
|
||||
|
|
|
@ -23,4 +23,3 @@ typedef struct rix
|
|||
|
||||
extern GIST_SPLITVEC *btree_picksplit(bytea *entryvec, GIST_SPLITVEC *v,
|
||||
BINARY_UNION bu, CMPFUNC cmp);
|
||||
|
||||
|
|
|
@ -28,11 +28,11 @@ extern int cube_yyparse();
|
|||
NDBOX *cube_in(char *str);
|
||||
NDBOX *cube(text *str);
|
||||
char *cube_out(NDBOX * cube);
|
||||
NDBOX *cube_f8(double *);
|
||||
NDBOX *cube_f8_f8(double *, double *);
|
||||
NDBOX *cube_c_f8(NDBOX *, double *);
|
||||
NDBOX *cube_c_f8_f8(NDBOX *, double *, double *);
|
||||
int4 cube_dim(NDBOX * a);
|
||||
NDBOX *cube_f8(double *);
|
||||
NDBOX *cube_f8_f8(double *, double *);
|
||||
NDBOX *cube_c_f8(NDBOX *, double *);
|
||||
NDBOX *cube_c_f8_f8(NDBOX *, double *, double *);
|
||||
int4 cube_dim(NDBOX * a);
|
||||
double *cube_ll_coord(NDBOX * a, int4 n);
|
||||
double *cube_ur_coord(NDBOX * a, int4 n);
|
||||
|
||||
|
@ -123,7 +123,7 @@ cube_out(NDBOX * cube)
|
|||
bool equal = true;
|
||||
int dim = cube->dim;
|
||||
int i;
|
||||
int ndig;
|
||||
int ndig;
|
||||
|
||||
initStringInfo(&buf);
|
||||
|
||||
|
@ -131,7 +131,8 @@ cube_out(NDBOX * cube)
|
|||
* Get the number of digits to display.
|
||||
*/
|
||||
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
|
||||
|
@ -1192,7 +1193,8 @@ cube_enlarge(NDBOX * a, double *r, int4 n)
|
|||
j,
|
||||
k;
|
||||
|
||||
if (n > CUBE_MAX_DIM) n = CUBE_MAX_DIM;
|
||||
if (n > CUBE_MAX_DIM)
|
||||
n = CUBE_MAX_DIM;
|
||||
if (*r > 0 && n > 0)
|
||||
dim = n;
|
||||
if (a->dim > dim)
|
||||
|
@ -1234,14 +1236,15 @@ NDBOX *
|
|||
cube_f8(double *x1)
|
||||
{
|
||||
NDBOX *result;
|
||||
int size;
|
||||
int size;
|
||||
|
||||
size = offsetof(NDBOX, x[0]) + sizeof(double) * 2;
|
||||
result = (NDBOX *) palloc(size);
|
||||
memset(result, 0, size);
|
||||
result->size = size;
|
||||
result->dim = 1;
|
||||
result->x[0] = *x1;
|
||||
result->x[1] = *x1;
|
||||
result->x[0] = *x1;
|
||||
result->x[1] = *x1;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -1250,56 +1253,61 @@ NDBOX *
|
|||
cube_f8_f8(double *x1, double *x2)
|
||||
{
|
||||
NDBOX *result;
|
||||
int size;
|
||||
int size;
|
||||
|
||||
size = offsetof(NDBOX, x[0]) + sizeof(double) * 2;
|
||||
result = (NDBOX *) palloc(size);
|
||||
memset(result, 0, size);
|
||||
result->size = size;
|
||||
result->dim = 1;
|
||||
result->x[0] = *x1;
|
||||
result->x[1] = *x2;
|
||||
result->x[0] = *x1;
|
||||
result->x[1] = *x2;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Add a dimension to an existing cube with the same values for the new
|
||||
coordinate */
|
||||
NDBOX *
|
||||
cube_c_f8(NDBOX *c, double *x1)
|
||||
cube_c_f8(NDBOX * c, double *x1)
|
||||
{
|
||||
NDBOX *result;
|
||||
int size;
|
||||
int i;
|
||||
size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) * 2;
|
||||
int size;
|
||||
int i;
|
||||
|
||||
size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
|
||||
result = (NDBOX *) palloc(size);
|
||||
memset(result, 0, size);
|
||||
result->size = size;
|
||||
result->dim = c->dim + 1;
|
||||
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[result->dim - 1] = *x1;
|
||||
result->x[2 * result->dim - 1] = *x1;
|
||||
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[result->dim - 1] = *x1;
|
||||
result->x[2 * result->dim - 1] = *x1;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Add a dimension to an existing cube */
|
||||
NDBOX *
|
||||
cube_c_f8_f8(NDBOX *c, double *x1, double *x2)
|
||||
cube_c_f8_f8(NDBOX * c, double *x1, double *x2)
|
||||
{
|
||||
NDBOX *result;
|
||||
int size;
|
||||
int i;
|
||||
size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) * 2;
|
||||
int size;
|
||||
int i;
|
||||
|
||||
size = offsetof(NDBOX, x[0]) + sizeof(double) * (c->dim + 1) *2;
|
||||
result = (NDBOX *) palloc(size);
|
||||
memset(result, 0, size);
|
||||
result->size = size;
|
||||
result->dim = c->dim + 1;
|
||||
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[result->dim - 1] = *x1;
|
||||
result->x[2 * result->dim - 1] = *x2;
|
||||
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[result->dim - 1] = *x1;
|
||||
result->x[2 * result->dim - 1] = *x2;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -443,17 +443,15 @@ do_inserts(PGconn *conn, char *table, dbhead * dbh)
|
|||
if (result == DBF_VALID)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
{
|
||||
j++;
|
||||
}
|
||||
|
||||
if (j > 1) /* not for the first field! */
|
||||
strcat(query, "\t"); /* COPY statement field
|
||||
|
|
|
@ -61,17 +61,17 @@
|
|||
|
||||
typedef struct remoteConn
|
||||
{
|
||||
PGconn *con; /* Hold the remote connection */
|
||||
bool remoteTrFlag; /* Indicates whether or not a transaction
|
||||
* on remote database is in progress*/
|
||||
} remoteConn;
|
||||
PGconn *con; /* Hold the remote connection */
|
||||
bool remoteTrFlag; /* Indicates whether or not a transaction
|
||||
* on remote database is in progress */
|
||||
} remoteConn;
|
||||
|
||||
/*
|
||||
* Internal declarations
|
||||
*/
|
||||
static remoteConn *getConnectionByName(const char *name);
|
||||
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 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);
|
||||
|
@ -86,15 +86,15 @@ static TupleDesc pgresultGetTupleDesc(PGresult *res);
|
|||
static char *generate_relation_name(Oid relid);
|
||||
|
||||
/* Global */
|
||||
List *res_id = NIL;
|
||||
int res_id_index = 0;
|
||||
PGconn *persistent_conn = NULL;
|
||||
static HTAB *remoteConnHash=NULL;
|
||||
List *res_id = NIL;
|
||||
int res_id_index = 0;
|
||||
PGconn *persistent_conn = NULL;
|
||||
static HTAB *remoteConnHash = NULL;
|
||||
|
||||
/*
|
||||
/*
|
||||
Following is list that holds multiple remote connections.
|
||||
Calling convention of each dblink function changes to accept
|
||||
connection name as the first parameter. The connection list is
|
||||
connection name as the first parameter. The connection list is
|
||||
much like ecpg e.g. a mapping between a name and a PGconn object.
|
||||
*/
|
||||
|
||||
|
@ -102,7 +102,7 @@ typedef struct remoteConnHashEnt
|
|||
{
|
||||
char name[NAMEDATALEN];
|
||||
remoteConn *rcon;
|
||||
} remoteConnHashEnt;
|
||||
} remoteConnHashEnt;
|
||||
|
||||
/* initial number of connection hashes */
|
||||
#define NUMCONN 16
|
||||
|
@ -186,18 +186,18 @@ dblink_connect(PG_FUNCTION_ARGS)
|
|||
PGconn *conn = NULL;
|
||||
remoteConn *rcon = NULL;
|
||||
|
||||
if(PG_NARGS()==2)
|
||||
if (PG_NARGS() == 2)
|
||||
{
|
||||
connstr = GET_STR(PG_GETARG_TEXT_P(1));
|
||||
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));
|
||||
|
||||
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
||||
|
||||
if(connname)
|
||||
rcon=(remoteConn *) palloc(sizeof(remoteConn));
|
||||
if (connname)
|
||||
rcon = (remoteConn *) palloc(sizeof(remoteConn));
|
||||
conn = PQconnectdb(connstr);
|
||||
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
@ -206,16 +206,16 @@ dblink_connect(PG_FUNCTION_ARGS)
|
|||
{
|
||||
msg = pstrdup(PQerrorMessage(conn));
|
||||
PQfinish(conn);
|
||||
if(rcon)
|
||||
if (rcon)
|
||||
pfree(rcon);
|
||||
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION),
|
||||
errmsg("could not establish connection"),
|
||||
errdetail("%s", msg)));
|
||||
(errcode(ERRCODE_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION),
|
||||
errmsg("could not establish connection"),
|
||||
errdetail("%s", msg)));
|
||||
}
|
||||
|
||||
if(connname)
|
||||
if (connname)
|
||||
{
|
||||
rcon->con = conn;
|
||||
createNewConnection(connname, rcon);
|
||||
|
@ -237,7 +237,7 @@ dblink_disconnect(PG_FUNCTION_ARGS)
|
|||
remoteConn *rcon = NULL;
|
||||
PGconn *conn = NULL;
|
||||
|
||||
if (PG_NARGS() ==1 )
|
||||
if (PG_NARGS() == 1)
|
||||
{
|
||||
conname = GET_STR(PG_GETARG_TEXT_P(0));
|
||||
rcon = getConnectionByName(conname);
|
||||
|
@ -276,13 +276,13 @@ dblink_open(PG_FUNCTION_ARGS)
|
|||
StringInfo str = makeStringInfo();
|
||||
remoteConn *rcon = NULL;
|
||||
|
||||
if(PG_NARGS() == 2)
|
||||
if (PG_NARGS() == 2)
|
||||
{
|
||||
curname = GET_STR(PG_GETARG_TEXT_P(0));
|
||||
sql = GET_STR(PG_GETARG_TEXT_P(1));
|
||||
conn = persistent_conn;
|
||||
}
|
||||
else if(PG_NARGS() == 3)
|
||||
else if (PG_NARGS() == 3)
|
||||
{
|
||||
conname = GET_STR(PG_GETARG_TEXT_P(0));
|
||||
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));
|
||||
conn = persistent_conn;
|
||||
}
|
||||
else if (PG_NARGS()==2)
|
||||
else if (PG_NARGS() == 2)
|
||||
{
|
||||
conname = GET_STR(PG_GETARG_TEXT_P(0));
|
||||
curname = GET_STR(PG_GETARG_TEXT_P(1));
|
||||
rcon = getConnectionByName(conname);
|
||||
if(rcon)
|
||||
if (rcon)
|
||||
conn = rcon->con;
|
||||
}
|
||||
|
||||
|
@ -381,7 +381,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
|
|||
PGresult *res = NULL;
|
||||
MemoryContext oldcontext;
|
||||
char *conname = NULL;
|
||||
remoteConn *rcon=NULL;
|
||||
remoteConn *rcon = NULL;
|
||||
|
||||
/* stuff done only on the first call of the function */
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
|
@ -401,7 +401,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
|
|||
howmany = PG_GETARG_INT32(2);
|
||||
|
||||
rcon = getConnectionByName(conname);
|
||||
if(rcon)
|
||||
if (rcon)
|
||||
conn = rcon->con;
|
||||
}
|
||||
else if (PG_NARGS() == 2)
|
||||
|
@ -411,7 +411,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
|
|||
conn = persistent_conn;
|
||||
}
|
||||
|
||||
if(!conn)
|
||||
if (!conn)
|
||||
DBLINK_CONN_NOT_AVAIL;
|
||||
|
||||
/* create a function context for cross-call persistence */
|
||||
|
@ -429,9 +429,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
|
|||
if (!res ||
|
||||
(PQresultStatus(res) != PGRES_COMMAND_OK &&
|
||||
PQresultStatus(res) != PGRES_TUPLES_OK))
|
||||
{
|
||||
DBLINK_RES_ERROR("sql error");
|
||||
}
|
||||
else if (PQresultStatus(res) == PGRES_COMMAND_OK)
|
||||
{
|
||||
/* cursor does not exist - closed already or bad name */
|
||||
|
@ -549,7 +547,7 @@ dblink_record(PG_FUNCTION_ARGS)
|
|||
char *connstr = NULL;
|
||||
char *sql = NULL;
|
||||
char *conname = NULL;
|
||||
remoteConn *rcon=NULL;
|
||||
remoteConn *rcon = NULL;
|
||||
|
||||
/* create a function context for cross-call persistence */
|
||||
funcctx = SRF_FIRSTCALL_INIT();
|
||||
|
@ -574,7 +572,7 @@ dblink_record(PG_FUNCTION_ARGS)
|
|||
/* shouldn't happen */
|
||||
elog(ERROR, "wrong number of arguments");
|
||||
|
||||
if(!conn)
|
||||
if (!conn)
|
||||
DBLINK_CONN_NOT_AVAIL;
|
||||
|
||||
res = PQexec(conn, sql);
|
||||
|
@ -591,8 +589,8 @@ dblink_record(PG_FUNCTION_ARGS)
|
|||
TEXTOID, -1, 0, false);
|
||||
|
||||
/*
|
||||
* and save a copy of the command status string to return
|
||||
* as our result tuple
|
||||
* and save a copy of the command status string to return as
|
||||
* our result tuple
|
||||
*/
|
||||
sql_cmd_status = PQcmdStatus(res);
|
||||
funcctx->max_calls = 1;
|
||||
|
@ -707,7 +705,7 @@ dblink_exec(PG_FUNCTION_ARGS)
|
|||
char *connstr = NULL;
|
||||
char *sql = NULL;
|
||||
char *conname = NULL;
|
||||
remoteConn *rcon=NULL;
|
||||
remoteConn *rcon = NULL;
|
||||
bool freeconn = true;
|
||||
|
||||
if (PG_NARGS() == 2)
|
||||
|
@ -724,7 +722,7 @@ dblink_exec(PG_FUNCTION_ARGS)
|
|||
/* shouldn't happen */
|
||||
elog(ERROR, "wrong number of arguments");
|
||||
|
||||
if(!conn)
|
||||
if (!conn)
|
||||
DBLINK_CONN_NOT_AVAIL;
|
||||
|
||||
res = PQexec(conn, sql);
|
||||
|
@ -741,15 +739,15 @@ dblink_exec(PG_FUNCTION_ARGS)
|
|||
TEXTOID, -1, 0, false);
|
||||
|
||||
/*
|
||||
* and save a copy of the command status string to return as
|
||||
* our result tuple
|
||||
* and save a copy of the command status string to return as our
|
||||
* result tuple
|
||||
*/
|
||||
sql_cmd_status = GET_TEXT(PQcmdStatus(res));
|
||||
}
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
|
||||
errmsg("statement returning results not allowed")));
|
||||
(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
|
||||
errmsg("statement returning results not allowed")));
|
||||
|
||||
PQclear(res);
|
||||
|
||||
|
@ -802,6 +800,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
|
|||
(errcode(ERRCODE_UNDEFINED_TABLE),
|
||||
errmsg("relation \"%s\" does not exist",
|
||||
GET_STR(PG_GETARG_TEXT_P(0)))));
|
||||
|
||||
/*
|
||||
* need a tuple descriptor representing one INT and one TEXT
|
||||
* column
|
||||
|
@ -980,8 +979,8 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
|
|||
if (src_nitems != pknumatts)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("source key array length must match number of key " \
|
||||
"attributes")));
|
||||
errmsg("source key array length must match number of key " \
|
||||
"attributes")));
|
||||
|
||||
/*
|
||||
* 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)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("target key array length must match number of key " \
|
||||
"attributes")));
|
||||
errmsg("target key array length must match number of key " \
|
||||
"attributes")));
|
||||
|
||||
/*
|
||||
* 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)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("target key array length must match number of key " \
|
||||
"attributes")));
|
||||
errmsg("target key array length must match number of key " \
|
||||
"attributes")));
|
||||
|
||||
/*
|
||||
* 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)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("source key array length must match number of key " \
|
||||
"attributes")));
|
||||
errmsg("source key array length must match number of key " \
|
||||
"attributes")));
|
||||
|
||||
/*
|
||||
* 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)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("target key array length must match number of key " \
|
||||
"attributes")));
|
||||
errmsg("target key array length must match number of key " \
|
||||
"attributes")));
|
||||
|
||||
/*
|
||||
* get array of pointers to c-strings from the input target array
|
||||
|
@ -1839,10 +1838,10 @@ pgresultGetTupleDesc(PGresult *res)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_MOST_SPECIFIC_TYPE_MISMATCH),
|
||||
errmsg("field size mismatch"),
|
||||
errdetail("Size of remote field \"%s\" does not match " \
|
||||
"size of local type \"%s\".", attname,
|
||||
format_type_with_typemod(atttypid,
|
||||
atttypmod))));
|
||||
errdetail("Size of remote field \"%s\" does not match " \
|
||||
"size of local type \"%s\".", attname,
|
||||
format_type_with_typemod(atttypid,
|
||||
atttypmod))));
|
||||
|
||||
attdim = 0;
|
||||
attisset = false;
|
||||
|
@ -1893,50 +1892,50 @@ generate_relation_name(Oid relid)
|
|||
static remoteConn *
|
||||
getConnectionByName(const char *name)
|
||||
{
|
||||
remoteConnHashEnt *hentry;
|
||||
char key[NAMEDATALEN];
|
||||
remoteConnHashEnt *hentry;
|
||||
char key[NAMEDATALEN];
|
||||
|
||||
if(!remoteConnHash)
|
||||
remoteConnHash=createConnHash();
|
||||
if (!remoteConnHash)
|
||||
remoteConnHash = createConnHash();
|
||||
|
||||
MemSet(key, 0, NAMEDATALEN);
|
||||
snprintf(key, NAMEDATALEN - 1, "%s", name);
|
||||
hentry = (remoteConnHashEnt*) hash_search(remoteConnHash,
|
||||
key, HASH_FIND, NULL);
|
||||
hentry = (remoteConnHashEnt *) hash_search(remoteConnHash,
|
||||
key, HASH_FIND, NULL);
|
||||
|
||||
if(hentry)
|
||||
return(hentry->rcon);
|
||||
if (hentry)
|
||||
return (hentry->rcon);
|
||||
|
||||
return(NULL);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static HTAB *
|
||||
createConnHash(void)
|
||||
{
|
||||
HASHCTL ctl;
|
||||
HTAB *ptr;
|
||||
HASHCTL ctl;
|
||||
HTAB *ptr;
|
||||
|
||||
ctl.keysize = NAMEDATALEN;
|
||||
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,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
|
||||
return(ptr);
|
||||
return (ptr);
|
||||
}
|
||||
|
||||
static void
|
||||
createNewConnection(const char *name, remoteConn *con)
|
||||
createNewConnection(const char *name, remoteConn * con)
|
||||
{
|
||||
remoteConnHashEnt *hentry;
|
||||
bool found;
|
||||
char key[NAMEDATALEN];
|
||||
remoteConnHashEnt *hentry;
|
||||
bool found;
|
||||
char key[NAMEDATALEN];
|
||||
|
||||
if(!remoteConnHash)
|
||||
if (!remoteConnHash)
|
||||
remoteConnHash = createConnHash();
|
||||
|
||||
MemSet(key, 0, NAMEDATALEN);
|
||||
|
@ -1944,12 +1943,12 @@ createNewConnection(const char *name, remoteConn *con)
|
|||
hentry = (remoteConnHashEnt *) hash_search(remoteConnHash, key,
|
||||
HASH_ENTER, &found);
|
||||
|
||||
if(!hentry)
|
||||
if (!hentry)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
|
||||
if(found)
|
||||
if (found)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||
errmsg("duplicate connection name")));
|
||||
|
@ -1961,12 +1960,12 @@ createNewConnection(const char *name, remoteConn *con)
|
|||
static void
|
||||
deleteConnection(const char *name)
|
||||
{
|
||||
remoteConnHashEnt *hentry;
|
||||
bool found;
|
||||
char key[NAMEDATALEN];
|
||||
remoteConnHashEnt *hentry;
|
||||
bool found;
|
||||
char key[NAMEDATALEN];
|
||||
|
||||
if(!remoteConnHash)
|
||||
remoteConnHash=createConnHash();
|
||||
if (!remoteConnHash)
|
||||
remoteConnHash = createConnHash();
|
||||
|
||||
MemSet(key, 0, NAMEDATALEN);
|
||||
snprintf(key, NAMEDATALEN - 1, "%s", name);
|
||||
|
@ -1974,7 +1973,7 @@ deleteConnection(const char *name)
|
|||
hentry = (remoteConnHashEnt *) hash_search(remoteConnHash,
|
||||
key, HASH_REMOVE, &found);
|
||||
|
||||
if(!hentry)
|
||||
if (!hentry)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
errmsg("undefined connection name")));
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/****************************************************************************
|
||||
* 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
|
||||
* to a pending table for mirroring.
|
||||
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
* Written by Steven Singer (ssinger@navtechinc.com)
|
||||
* (c) 2001-2002 Navtech Systems Support Inc.
|
||||
* ALL RIGHTS RESERVED
|
||||
* ALL RIGHTS RESERVED
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation for any purpose, without fee, and without a written agreement
|
||||
|
@ -79,8 +79,9 @@ recordchange(PG_FUNCTION_ARGS)
|
|||
HeapTuple retTuple = NULL;
|
||||
char *tblname;
|
||||
char op = 0;
|
||||
char *schemaname;
|
||||
char *schemaname;
|
||||
char *fullyqualtblname;
|
||||
|
||||
if (fcinfo->context != NULL)
|
||||
{
|
||||
|
||||
|
@ -94,13 +95,13 @@ recordchange(PG_FUNCTION_ARGS)
|
|||
tblname = SPI_getrelname(trigdata->tg_relation);
|
||||
#ifndef NOSCHEMAS
|
||||
schemaname = get_namespace_name(RelationGetNamespace(trigdata->tg_relation));
|
||||
fullyqualtblname = SPI_palloc(strlen(tblname) +
|
||||
strlen(schemaname) + 6);
|
||||
sprintf(fullyqualtblname,"\"%s\".\"%s\"",
|
||||
schemaname,tblname);
|
||||
fullyqualtblname = SPI_palloc(strlen(tblname) +
|
||||
strlen(schemaname) + 6);
|
||||
sprintf(fullyqualtblname, "\"%s\".\"%s\"",
|
||||
schemaname, tblname);
|
||||
#else
|
||||
fullyqualtblname = SPI_palloc(strlen(tblname) + 3);
|
||||
sprintf(fullyqualtblname,"\"%s\"",tblname);
|
||||
sprintf(fullyqualtblname, "\"%s\"", tblname);
|
||||
#endif
|
||||
tupdesc = trigdata->tg_relation->rd_att;
|
||||
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||
|
@ -166,8 +167,8 @@ storePending(char *cpTableName, HeapTuple tBeforeTuple,
|
|||
int iResult = 0;
|
||||
HeapTuple tCurTuple;
|
||||
|
||||
//Points the current tuple(before or after)
|
||||
Datum saPlanData[4];
|
||||
/* Points the current tuple(before or after) */
|
||||
Datum saPlanData[4];
|
||||
Oid taPlanArgTypes[3] = {NAMEOID, CHAROID, INT4OID};
|
||||
void *vpPlan;
|
||||
|
||||
|
@ -253,7 +254,7 @@ storeKeyInfo(char *cpTableName, HeapTuple tTupleData,
|
|||
if (cpKeyData == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
||||
/* cpTableName already contains quotes... */
|
||||
/* cpTableName already contains quotes... */
|
||||
errmsg("there is no PRIMARY KEY for table %s",
|
||||
cpTableName)));
|
||||
|
||||
|
@ -460,7 +461,7 @@ packageData(HeapTuple tTupleData, TupleDesc tTupleDesc,
|
|||
}
|
||||
else
|
||||
{
|
||||
sprintf(cpFormatedPtr," ");
|
||||
sprintf(cpFormatedPtr, " ");
|
||||
iUsedDataBlock++;
|
||||
cpFormatedPtr++;
|
||||
continue;
|
||||
|
@ -508,8 +509,8 @@ packageData(HeapTuple tTupleData, TupleDesc tTupleDesc,
|
|||
if (tpPKeys != NULL)
|
||||
SPI_pfree(tpPKeys);
|
||||
#if defined DEBUG_OUTPUT
|
||||
elog(NOTICE, "returning DataBlockSize:%d iUsedDataBlock:%d",iDataBlockSize,
|
||||
iUsedDataBlock);
|
||||
elog(NOTICE, "returning DataBlockSize:%d iUsedDataBlock:%d", iDataBlockSize,
|
||||
iUsedDataBlock);
|
||||
#endif
|
||||
memset(cpDataBlock + iUsedDataBlock, 0, iDataBlockSize - iUsedDataBlock);
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ database_size(PG_FUNCTION_ARGS)
|
|||
if (!OidIsValid(dbid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_DATABASE),
|
||||
errmsg("database \"%s\" does not exist", NameStr(*dbname))));
|
||||
errmsg("database \"%s\" does not exist", NameStr(*dbname))));
|
||||
|
||||
dbpath = GetDatabasePath(dbid);
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
|
||||
|
||||
/* Earth's radius is in statute miles. */
|
||||
const double EARTH_RADIUS = 3958.747716;
|
||||
const double TWO_PI = 2.0 * M_PI;
|
||||
const double EARTH_RADIUS = 3958.747716;
|
||||
const double TWO_PI = 2.0 * M_PI;
|
||||
|
||||
double *geo_distance(Point *pt1, Point *pt2);
|
||||
|
||||
|
@ -66,10 +66,11 @@ geo_distance(Point *pt1, Point *pt2)
|
|||
if (longdiff > M_PI)
|
||||
longdiff = TWO_PI - longdiff;
|
||||
|
||||
sino = sqrt(sin(fabs(lat1-lat2)/2.)*sin(fabs(lat1-lat2)/2.) +
|
||||
cos(lat1) * cos(lat2) * sin(longdiff/2.)*sin(longdiff/2.));
|
||||
if (sino > 1.) sino = 1.;
|
||||
*resultp = 2. * EARTH_RADIUS * asin(sino);
|
||||
sino = sqrt(sin(fabs(lat1 - lat2) / 2.) * sin(fabs(lat1 - lat2) / 2.) +
|
||||
cos(lat1) * cos(lat2) * sin(longdiff / 2.) * sin(longdiff / 2.));
|
||||
if (sino > 1.)
|
||||
sino = 1.;
|
||||
*resultp = 2. * EARTH_RADIUS * asin(sino);
|
||||
|
||||
return resultp;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* 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"
|
||||
|
||||
|
@ -14,23 +14,24 @@
|
|||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
PGconn *conn;
|
||||
PQExpBufferData sql;
|
||||
PGresult *res;
|
||||
PGresult *pkrel_res;
|
||||
PGresult *fkrel_res;
|
||||
char *fk_relname;
|
||||
char *fk_nspname;
|
||||
char *fk_attname;
|
||||
char *pk_relname;
|
||||
char *pk_nspname;
|
||||
int fk, pk; /* loop counters */
|
||||
PGconn *conn;
|
||||
PQExpBufferData sql;
|
||||
PGresult *res;
|
||||
PGresult *pkrel_res;
|
||||
PGresult *fkrel_res;
|
||||
char *fk_relname;
|
||||
char *fk_nspname;
|
||||
char *fk_attname;
|
||||
char *pk_relname;
|
||||
char *pk_nspname;
|
||||
int fk,
|
||||
pk; /* loop counters */
|
||||
|
||||
if (argc != 2)
|
||||
{
|
||||
fprintf(stderr, "Usage: %s database\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
initPQExpBuffer(&sql);
|
||||
|
||||
|
@ -48,13 +49,13 @@ main(int argc, char **argv)
|
|||
resetPQExpBuffer(&sql);
|
||||
|
||||
appendPQExpBuffer(&sql, "%s",
|
||||
"SET search_path = public;"
|
||||
"SELECT c.relname, (SELECT nspname FROM "
|
||||
"pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname "
|
||||
"FROM pg_catalog.pg_class c "
|
||||
"WHERE c.relkind = 'r' "
|
||||
"AND c.relhasoids "
|
||||
"ORDER BY nspname, c.relname"
|
||||
"SET search_path = public;"
|
||||
"SELECT c.relname, (SELECT nspname FROM "
|
||||
"pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname "
|
||||
"FROM pg_catalog.pg_class c "
|
||||
"WHERE c.relkind = 'r' "
|
||||
"AND c.relhasoids "
|
||||
"ORDER BY nspname, c.relname"
|
||||
);
|
||||
|
||||
res = PQexec(conn, sql.data);
|
||||
|
@ -70,20 +71,20 @@ main(int argc, char **argv)
|
|||
resetPQExpBuffer(&sql);
|
||||
|
||||
appendPQExpBuffer(&sql, "%s",
|
||||
"SELECT c.relname, "
|
||||
"(SELECT nspname FROM pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname, "
|
||||
"a.attname "
|
||||
"FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
|
||||
"WHERE a.attnum > 0 AND c.relkind = 'r' "
|
||||
"AND a.attrelid = c.oid "
|
||||
"AND a.atttypid IN ('pg_catalog.oid'::regtype, "
|
||||
" 'pg_catalog.regclass'::regtype, "
|
||||
" 'pg_catalog.regoper'::regtype, "
|
||||
" 'pg_catalog.regoperator'::regtype, "
|
||||
" 'pg_catalog.regproc'::regtype, "
|
||||
" 'pg_catalog.regprocedure'::regtype, "
|
||||
" 'pg_catalog.regtype'::regtype) "
|
||||
"ORDER BY nspname, c.relname, a.attnum"
|
||||
"SELECT c.relname, "
|
||||
"(SELECT nspname FROM pg_catalog.pg_namespace n WHERE n.oid = c.relnamespace) AS nspname, "
|
||||
"a.attname "
|
||||
"FROM pg_catalog.pg_class c, pg_catalog.pg_attribute a "
|
||||
"WHERE a.attnum > 0 AND c.relkind = 'r' "
|
||||
"AND a.attrelid = c.oid "
|
||||
"AND a.atttypid IN ('pg_catalog.oid'::regtype, "
|
||||
" 'pg_catalog.regclass'::regtype, "
|
||||
" 'pg_catalog.regoper'::regtype, "
|
||||
" 'pg_catalog.regoperator'::regtype, "
|
||||
" 'pg_catalog.regproc'::regtype, "
|
||||
" 'pg_catalog.regprocedure'::regtype, "
|
||||
" 'pg_catalog.regtype'::regtype) "
|
||||
"ORDER BY nspname, c.relname, a.attnum"
|
||||
);
|
||||
|
||||
res = PQexec(conn, sql.data);
|
||||
|
@ -95,8 +96,8 @@ main(int argc, char **argv)
|
|||
fkrel_res = res;
|
||||
|
||||
/*
|
||||
* For each column and each relation-having-OIDs, look to see if
|
||||
* the column contains any values matching entries in the relation.
|
||||
* For each column and each relation-having-OIDs, look to see if the
|
||||
* column contains any values matching entries in the relation.
|
||||
*/
|
||||
|
||||
for (fk = 0; fk < PQntuples(fkrel_res); fk++)
|
||||
|
@ -113,12 +114,12 @@ main(int argc, char **argv)
|
|||
resetPQExpBuffer(&sql);
|
||||
|
||||
appendPQExpBuffer(&sql,
|
||||
"SELECT 1 "
|
||||
"FROM \"%s\".\"%s\" t1, "
|
||||
"\"%s\".\"%s\" t2 "
|
||||
"WHERE t1.\"%s\"::pg_catalog.oid = t2.oid "
|
||||
"LIMIT 1",
|
||||
fk_nspname, fk_relname, pk_nspname, pk_relname, fk_attname);
|
||||
"SELECT 1 "
|
||||
"FROM \"%s\".\"%s\" t1, "
|
||||
"\"%s\".\"%s\" t2 "
|
||||
"WHERE t1.\"%s\"::pg_catalog.oid = t2.oid "
|
||||
"LIMIT 1",
|
||||
fk_nspname, fk_relname, pk_nspname, pk_relname, fk_attname);
|
||||
|
||||
res = PQexec(conn, sql.data);
|
||||
if (!res || PQresultStatus(res) != PGRES_TUPLES_OK)
|
||||
|
|
|
@ -304,7 +304,7 @@ fti(PG_FUNCTION_ARGS)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
||||
errmsg("column \"%s\" of \"%s\" does not exist",
|
||||
args[i + 1], indexname)));
|
||||
args[i + 1], indexname)));
|
||||
|
||||
/* Get the char* representation of the column */
|
||||
column = SPI_getvalue(rettuple, tupdesc, colnum);
|
||||
|
@ -339,8 +339,8 @@ fti(PG_FUNCTION_ARGS)
|
|||
ret = SPI_execp(*(plan->splan), values, NULL, 0);
|
||||
if (ret != SPI_OK_INSERT)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
|
||||
errmsg("error executing insert")));
|
||||
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
|
||||
errmsg("error executing insert")));
|
||||
}
|
||||
pfree(buff);
|
||||
pfree(data);
|
||||
|
|
|
@ -87,7 +87,7 @@ levenshtein(PG_FUNCTION_ARGS)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
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
|
||||
|
@ -220,7 +220,7 @@ metaphone(PG_FUNCTION_ARGS)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("argument exceeds max length: %d",
|
||||
MAX_METAPHONE_STRLEN)));
|
||||
MAX_METAPHONE_STRLEN)));
|
||||
|
||||
if (!(str_i_len > 0))
|
||||
ereport(ERROR,
|
||||
|
@ -232,7 +232,7 @@ metaphone(PG_FUNCTION_ARGS)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("output length exceeds max length: %d",
|
||||
MAX_METAPHONE_STRLEN)));
|
||||
MAX_METAPHONE_STRLEN)));
|
||||
|
||||
if (!(reqlen > 0))
|
||||
ereport(ERROR,
|
||||
|
|
|
@ -132,9 +132,9 @@ ShrinkPGArray(PGARRAY * p)
|
|||
|
||||
/* use current transaction context */
|
||||
pnew = palloc(cb);
|
||||
|
||||
/*
|
||||
* Fix up the fields in the new structure, so Postgres
|
||||
* understands
|
||||
* Fix up the fields in the new structure, so Postgres understands
|
||||
*/
|
||||
memcpy(pnew, p, cb);
|
||||
pnew->a.size = cb;
|
||||
|
@ -194,7 +194,7 @@ int_enum(PG_FUNCTION_ARGS)
|
|||
if (!rsi || !IsA(rsi, ReturnSetInfo))
|
||||
ereport(ERROR,
|
||||
(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)
|
||||
{
|
||||
|
|
|
@ -91,19 +91,19 @@ typedef char *BITVECP;
|
|||
*/
|
||||
typedef struct
|
||||
{
|
||||
int4 len;
|
||||
int4 flag;
|
||||
char data[1];
|
||||
} GISTTYPE;
|
||||
int4 len;
|
||||
int4 flag;
|
||||
char data[1];
|
||||
} GISTTYPE;
|
||||
|
||||
#define ALLISTRUE 0x04
|
||||
#define ALLISTRUE 0x04
|
||||
|
||||
#define ISALLTRUE(x) ( ((GISTTYPE*)x)->flag & ALLISTRUE )
|
||||
#define ISALLTRUE(x) ( ((GISTTYPE*)x)->flag & ALLISTRUE )
|
||||
|
||||
#define GTHDRSIZE ( sizeof(int4)*2 )
|
||||
#define GTHDRSIZE ( sizeof(int4)*2 )
|
||||
#define CALCGTSIZE(flag) ( GTHDRSIZE+(((flag) & ALLISTRUE) ? 0 : SIGLEN) )
|
||||
|
||||
#define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) )
|
||||
#define GETSIGN(x) ( (BITVECP)( (char*)x+GTHDRSIZE ) )
|
||||
|
||||
/*
|
||||
** types for functions
|
||||
|
@ -114,22 +114,22 @@ typedef void (*formfloat) (ArrayType *, float *);
|
|||
/*
|
||||
** useful function
|
||||
*/
|
||||
bool isort(int4 *a, const int len);
|
||||
ArrayType *new_intArrayType(int num);
|
||||
ArrayType *copy_intArrayType(ArrayType *a);
|
||||
ArrayType *resize_intArrayType(ArrayType *a, int num);
|
||||
int internal_size(int *a, int len);
|
||||
ArrayType *_int_unique(ArrayType *a);
|
||||
int32 intarray_match_first(ArrayType *a, int32 elem);
|
||||
ArrayType *intarray_add_elem(ArrayType *a, int32 elem);
|
||||
ArrayType *intarray_concat_arrays(ArrayType *a, ArrayType *b);
|
||||
ArrayType *int_to_intset(int32 elem);
|
||||
bool inner_int_overlap(ArrayType *a, ArrayType *b);
|
||||
bool inner_int_contains(ArrayType *a, ArrayType *b);
|
||||
ArrayType * inner_int_union(ArrayType *a, ArrayType *b);
|
||||
ArrayType * inner_int_inter(ArrayType *a, ArrayType *b);
|
||||
void rt__int_size(ArrayType *a, float *size);
|
||||
void gensign(BITVEC sign, int *a, int len);
|
||||
bool isort(int4 *a, const int len);
|
||||
ArrayType *new_intArrayType(int num);
|
||||
ArrayType *copy_intArrayType(ArrayType *a);
|
||||
ArrayType *resize_intArrayType(ArrayType *a, int num);
|
||||
int internal_size(int *a, int len);
|
||||
ArrayType *_int_unique(ArrayType *a);
|
||||
int32 intarray_match_first(ArrayType *a, int32 elem);
|
||||
ArrayType *intarray_add_elem(ArrayType *a, int32 elem);
|
||||
ArrayType *intarray_concat_arrays(ArrayType *a, ArrayType *b);
|
||||
ArrayType *int_to_intset(int32 elem);
|
||||
bool inner_int_overlap(ArrayType *a, ArrayType *b);
|
||||
bool inner_int_contains(ArrayType *a, ArrayType *b);
|
||||
ArrayType *inner_int_union(ArrayType *a, ArrayType *b);
|
||||
ArrayType *inner_int_inter(ArrayType *a, ArrayType *b);
|
||||
void rt__int_size(ArrayType *a, float *size);
|
||||
void gensign(BITVEC sign, int *a, int len);
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
|
@ -160,18 +160,16 @@ typedef struct
|
|||
#define COMPUTESIZE(size) ( HDRSIZEQT + size * sizeof(ITEM) )
|
||||
#define GETQUERY(x) (ITEM*)( (char*)(x)+HDRSIZEQT )
|
||||
|
||||
bool signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot);
|
||||
bool execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot);
|
||||
bool signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot);
|
||||
bool execconsistent(QUERYTYPE * query, ArrayType *array, bool calcnot);
|
||||
|
||||
|
||||
|
||||
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 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 )
|
||||
|
|
|
@ -299,7 +299,7 @@ signconsistent(QUERYTYPE * query, BITVEC sign, bool calcnot)
|
|||
GETQUERY(query) + query->size - 1,
|
||||
(void *) sign, calcnot,
|
||||
checkcondition_bit
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -326,7 +326,7 @@ rboolop(PG_FUNCTION_ARGS)
|
|||
boolop,
|
||||
PG_GETARG_DATUM(1),
|
||||
PG_GETARG_DATUM(0)
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
Datum
|
||||
|
@ -743,4 +743,3 @@ querytree(PG_FUNCTION_ARGS)
|
|||
|
||||
PG_RETURN_POINTER(res);
|
||||
}
|
||||
|
||||
|
|
|
@ -85,27 +85,31 @@ g_int_consistent(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
Datum
|
||||
g_int_union(PG_FUNCTION_ARGS) {
|
||||
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0);
|
||||
int *size = (int *) PG_GETARG_POINTER(1);
|
||||
int4 i,len = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
|
||||
ArrayType *res;
|
||||
int totlen=0,*ptr;
|
||||
g_int_union(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0);
|
||||
int *size = (int *) PG_GETARG_POINTER(1);
|
||||
int4 i,
|
||||
len = (VARSIZE(entryvec) - VARHDRSZ) / sizeof(GISTENTRY);
|
||||
ArrayType *res;
|
||||
int totlen = 0,
|
||||
*ptr;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
totlen+=ARRNELEMS( GETENTRY(entryvec,i) );
|
||||
totlen += ARRNELEMS(GETENTRY(entryvec, i));
|
||||
|
||||
res=new_intArrayType(totlen);
|
||||
ptr=ARRPTR(res);
|
||||
res = new_intArrayType(totlen);
|
||||
ptr = ARRPTR(res);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
memcpy(ptr, ARRPTR( GETENTRY(entryvec,i) ), ARRNELEMS( GETENTRY(entryvec,i) )*sizeof(int4) );
|
||||
ptr+=ARRNELEMS( GETENTRY(entryvec,i) );
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
memcpy(ptr, ARRPTR(GETENTRY(entryvec, i)), ARRNELEMS(GETENTRY(entryvec, i)) * sizeof(int4));
|
||||
ptr += ARRNELEMS(GETENTRY(entryvec, i));
|
||||
}
|
||||
|
||||
QSORT(res,1);
|
||||
res=_int_unique(res);
|
||||
*size = VARSIZE(res);
|
||||
QSORT(res, 1);
|
||||
res = _int_unique(res);
|
||||
*size = VARSIZE(res);
|
||||
PG_RETURN_POINTER(res);
|
||||
}
|
||||
|
||||
|
@ -239,22 +243,23 @@ g_int_decompress(PG_FUNCTION_ARGS)
|
|||
** The GiST Penalty method for _intments
|
||||
*/
|
||||
Datum
|
||||
g_int_penalty(PG_FUNCTION_ARGS) {
|
||||
GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
|
||||
float *result = (float *) PG_GETARG_POINTER(2);
|
||||
g_int_penalty(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0);
|
||||
GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
|
||||
float *result = (float *) PG_GETARG_POINTER(2);
|
||||
ArrayType *ud;
|
||||
float tmp1,
|
||||
tmp2;
|
||||
|
||||
ud = inner_int_union((ArrayType *) DatumGetPointer(origentry->key),
|
||||
(ArrayType *) DatumGetPointer(newentry->key));
|
||||
(ArrayType *) DatumGetPointer(newentry->key));
|
||||
rt__int_size(ud, &tmp1);
|
||||
rt__int_size((ArrayType *) DatumGetPointer(origentry->key), &tmp2);
|
||||
*result = tmp1 - tmp2;
|
||||
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
|
||||
*/
|
||||
Datum
|
||||
g_int_picksplit(PG_FUNCTION_ARGS) {
|
||||
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0);
|
||||
g_int_picksplit(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bytea *entryvec = (bytea *) PG_GETARG_POINTER(0);
|
||||
GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
|
||||
OffsetNumber i,
|
||||
j;
|
||||
|
@ -501,4 +507,3 @@ g_int_picksplit(PG_FUNCTION_ARGS) {
|
|||
|
||||
PG_RETURN_POINTER(v);
|
||||
}
|
||||
|
||||
|
|
|
@ -270,7 +270,7 @@ _int_unique(ArrayType *r)
|
|||
*data;
|
||||
int num = ARRNELEMS(r);
|
||||
|
||||
if ( num<2 )
|
||||
if (num < 2)
|
||||
return r;
|
||||
|
||||
data = tmp = dr = ARRPTR(r);
|
||||
|
@ -367,4 +367,3 @@ compDESC(const void *a, const void *b)
|
|||
return 0;
|
||||
return (*(int4 *) a < *(int4 *) b) ? 1 : -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ array_iterator(ArrayType *la, PGCALL2 callback, void *param, ltree ** found)
|
|||
|
||||
if (ARR_NDIM(la) != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("array must be one-dimensional")));
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("array must be one-dimensional")));
|
||||
|
||||
if (found)
|
||||
*found = NULL;
|
||||
|
@ -133,38 +133,40 @@ _ltq_rregex(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
_lt_q_regex(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ArrayType *_tree = PG_GETARG_ARRAYTYPE_P(0);
|
||||
ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
|
||||
lquery *query = (lquery *) ARR_DATA_PTR(_query);
|
||||
bool res = false;
|
||||
int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
|
||||
ArrayType *_tree = PG_GETARG_ARRAYTYPE_P(0);
|
||||
ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
|
||||
lquery *query = (lquery *) ARR_DATA_PTR(_query);
|
||||
bool res = false;
|
||||
int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
|
||||
|
||||
if (ARR_NDIM(_query) != 1)
|
||||
ereport(ERROR,
|
||||
if (ARR_NDIM(_query) != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("array must be one-dimensional")));
|
||||
|
||||
while (num > 0) {
|
||||
if ( array_iterator(_tree, ltq_regex, (void*)query, NULL) ) {
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
num--;
|
||||
query = (lquery*)NEXTVAL(query);
|
||||
}
|
||||
while (num > 0)
|
||||
{
|
||||
if (array_iterator(_tree, ltq_regex, (void *) query, NULL))
|
||||
{
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
num--;
|
||||
query = (lquery *) NEXTVAL(query);
|
||||
}
|
||||
|
||||
PG_FREE_IF_COPY(_tree, 0);
|
||||
PG_FREE_IF_COPY(_query, 1);
|
||||
PG_RETURN_BOOL(res);
|
||||
PG_FREE_IF_COPY(_tree, 0);
|
||||
PG_FREE_IF_COPY(_query, 1);
|
||||
PG_RETURN_BOOL(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
_lt_q_rregex(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_DATUM(DirectFunctionCall2(_lt_q_regex,
|
||||
PG_GETARG_DATUM(1),
|
||||
PG_GETARG_DATUM(0)
|
||||
));
|
||||
PG_RETURN_DATUM(DirectFunctionCall2(_lt_q_regex,
|
||||
PG_GETARG_DATUM(1),
|
||||
PG_GETARG_DATUM(0)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ getlexem(char *start, char *end, int *len)
|
|||
}
|
||||
|
||||
bool
|
||||
compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
|
||||
compare_subnode(ltree_level * t, char *qn, int len, int (*cmpptr) (const char *, const char *, size_t), bool anyend)
|
||||
{
|
||||
char *endt = t->name + t->len;
|
||||
char *endq = qn + len;
|
||||
|
@ -123,10 +123,15 @@ printFieldNot(FieldNot *fn ) {
|
|||
}
|
||||
*/
|
||||
|
||||
static struct {
|
||||
bool muse;
|
||||
uint32 high_pos;
|
||||
} SomeStack = {false,0,};
|
||||
static struct
|
||||
{
|
||||
bool muse;
|
||||
uint32 high_pos;
|
||||
} SomeStack =
|
||||
|
||||
{
|
||||
false, 0,
|
||||
};
|
||||
|
||||
static bool
|
||||
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;
|
||||
ltree_level *prevt = NULL;
|
||||
|
||||
if ( SomeStack.muse ) {
|
||||
if (SomeStack.muse)
|
||||
{
|
||||
high_pos = SomeStack.high_pos;
|
||||
qlen--;
|
||||
prevq = curq;
|
||||
|
@ -200,13 +206,15 @@ checkCond(lquery_level * curq, int query_numlevel, ltree_level * curt, int tree_
|
|||
curt = LEVEL_NEXT(curt);
|
||||
tlen--;
|
||||
cur_tpos++;
|
||||
if ( isok && prevq && prevq->numvar==0 && tlen>0 && cur_tpos <= high_pos ) {
|
||||
FieldNot tmpptr;
|
||||
if ( ptr )
|
||||
memcpy(&tmpptr,ptr,sizeof(FieldNot));
|
||||
SomeStack.high_pos = high_pos-cur_tpos;
|
||||
if (isok && prevq && prevq->numvar == 0 && tlen > 0 && cur_tpos <= high_pos)
|
||||
{
|
||||
FieldNot tmpptr;
|
||||
|
||||
if (ptr)
|
||||
memcpy(&tmpptr, ptr, sizeof(FieldNot));
|
||||
SomeStack.high_pos = high_pos - cur_tpos;
|
||||
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;
|
||||
}
|
||||
if (!isok && ptr)
|
||||
|
@ -311,19 +319,21 @@ Datum
|
|||
lt_q_regex(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ltree *tree = PG_GETARG_LTREE(0);
|
||||
ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
|
||||
lquery *query = (lquery *) ARR_DATA_PTR(_query);
|
||||
bool res = false;
|
||||
int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
|
||||
ArrayType *_query = PG_GETARG_ARRAYTYPE_P(1);
|
||||
lquery *query = (lquery *) ARR_DATA_PTR(_query);
|
||||
bool res = false;
|
||||
int num = ArrayGetNItems(ARR_NDIM(_query), ARR_DIMS(_query));
|
||||
|
||||
if (ARR_NDIM(_query) != 1)
|
||||
ereport(ERROR,
|
||||
if (ARR_NDIM(_query) != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("array must be one-dimensional")));
|
||||
|
||||
while (num > 0) {
|
||||
while (num > 0)
|
||||
{
|
||||
if (DatumGetBool(DirectFunctionCall2(ltq_regex,
|
||||
PointerGetDatum(tree), PointerGetDatum(query)))) {
|
||||
PointerGetDatum(tree), PointerGetDatum(query))))
|
||||
{
|
||||
|
||||
res = true;
|
||||
break;
|
||||
|
@ -345,5 +355,3 @@ lt_q_rregex(PG_FUNCTION_ARGS)
|
|||
PG_GETARG_DATUM(0)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ Datum lquery_out(PG_FUNCTION_ARGS);
|
|||
|
||||
#define UNCHAR ereport(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)));
|
||||
|
||||
|
||||
|
@ -81,8 +81,8 @@ ltree_in(PG_FUNCTION_ARGS)
|
|||
(errcode(ERRCODE_NAME_TOO_LONG),
|
||||
errmsg("name of level is too long"),
|
||||
errdetail("name length is %d, must " \
|
||||
"be < 256, in position %d",
|
||||
lptr->len, (int) (lptr->start - buf))));
|
||||
"be < 256, in position %d",
|
||||
lptr->len, (int) (lptr->start - buf))));
|
||||
|
||||
totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
|
||||
lptr++;
|
||||
|
@ -105,8 +105,8 @@ ltree_in(PG_FUNCTION_ARGS)
|
|||
(errcode(ERRCODE_NAME_TOO_LONG),
|
||||
errmsg("name of level is too long"),
|
||||
errdetail("name length is %d, must " \
|
||||
"be < 256, in position %d",
|
||||
lptr->len, (int) (lptr->start - buf))));
|
||||
"be < 256, in position %d",
|
||||
lptr->len, (int) (lptr->start - buf))));
|
||||
|
||||
totallen += MAXALIGN(lptr->len + LEVEL_HDRSIZE);
|
||||
lptr++;
|
||||
|
@ -283,8 +283,8 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||
(errcode(ERRCODE_NAME_TOO_LONG),
|
||||
errmsg("name of level is too long"),
|
||||
errdetail("name length is %d, must " \
|
||||
"be < 256, in position %d",
|
||||
lptr->len, (int) (lptr->start - buf))));
|
||||
"be < 256, in position %d",
|
||||
lptr->len, (int) (lptr->start - buf))));
|
||||
|
||||
state = LQPRS_WAITVAR;
|
||||
}
|
||||
|
@ -299,8 +299,8 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||
(errcode(ERRCODE_NAME_TOO_LONG),
|
||||
errmsg("name of level is too long"),
|
||||
errdetail("name length is %d, must " \
|
||||
"be < 256, in position %d",
|
||||
lptr->len, (int) (lptr->start - buf))));
|
||||
"be < 256, in position %d",
|
||||
lptr->len, (int) (lptr->start - buf))));
|
||||
|
||||
state = LQPRS_WAITLEVEL;
|
||||
curqlevel = NEXTLEV(curqlevel);
|
||||
|
@ -412,8 +412,8 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||
(errcode(ERRCODE_NAME_TOO_LONG),
|
||||
errmsg("name of level is too long"),
|
||||
errdetail("name length is %d, must " \
|
||||
"be < 256, in position %d",
|
||||
lptr->len, (int) (lptr->start - buf))));
|
||||
"be < 256, in position %d",
|
||||
lptr->len, (int) (lptr->start - buf))));
|
||||
}
|
||||
else if (state == LQPRS_WAITOPEN)
|
||||
curqlevel->high = 0xffff;
|
||||
|
@ -442,7 +442,7 @@ lquery_in(PG_FUNCTION_ARGS)
|
|||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("syntax error"),
|
||||
errdetail("Low limit(%d) is greater than upper(%d).",
|
||||
curqlevel->low, curqlevel->high)));
|
||||
curqlevel->low, curqlevel->high)));
|
||||
|
||||
curqlevel = NEXTLEV(curqlevel);
|
||||
}
|
||||
|
|
|
@ -83,49 +83,49 @@ Datum
|
|||
ltree_cmp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_INT32(res);
|
||||
PG_RETURN_INT32(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
ltree_lt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_BOOL((res < 0) ? true : false);
|
||||
PG_RETURN_BOOL((res < 0) ? true : false);
|
||||
}
|
||||
|
||||
Datum
|
||||
ltree_le(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_BOOL((res <= 0) ? true : false);
|
||||
PG_RETURN_BOOL((res <= 0) ? true : false);
|
||||
}
|
||||
|
||||
Datum
|
||||
ltree_eq(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_BOOL((res == 0) ? true : false);
|
||||
PG_RETURN_BOOL((res == 0) ? true : false);
|
||||
}
|
||||
|
||||
Datum
|
||||
ltree_ge(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_BOOL((res >= 0) ? true : false);
|
||||
PG_RETURN_BOOL((res >= 0) ? true : false);
|
||||
}
|
||||
|
||||
Datum
|
||||
ltree_gt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_BOOL((res > 0) ? true : false);
|
||||
PG_RETURN_BOOL((res > 0) ? true : false);
|
||||
}
|
||||
|
||||
Datum
|
||||
ltree_ne(PG_FUNCTION_ARGS)
|
||||
{
|
||||
RUNCMP
|
||||
PG_RETURN_BOOL((res != 0) ? true : false);
|
||||
PG_RETURN_BOOL((res != 0) ? true : false);
|
||||
}
|
||||
|
||||
Datum
|
||||
|
@ -331,46 +331,55 @@ ltree_index(PG_FUNCTION_ARGS)
|
|||
{
|
||||
ltree *a = PG_GETARG_LTREE(0);
|
||||
ltree *b = PG_GETARG_LTREE(1);
|
||||
int start=(fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
|
||||
int i,j;
|
||||
ltree_level *startptr, *aptr, *bptr;
|
||||
bool found=false;
|
||||
int start = (fcinfo->nargs == 3) ? PG_GETARG_INT32(2) : 0;
|
||||
int i,
|
||||
j;
|
||||
ltree_level *startptr,
|
||||
*aptr,
|
||||
*bptr;
|
||||
bool found = false;
|
||||
|
||||
if ( start < 0 ) {
|
||||
if ( -start >= a->numlevel )
|
||||
start=0;
|
||||
else
|
||||
start = (int)(a->numlevel)+start;
|
||||
if (start < 0)
|
||||
{
|
||||
if (-start >= a->numlevel)
|
||||
start = 0;
|
||||
else
|
||||
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(b, 1);
|
||||
PG_RETURN_INT32(-1);
|
||||
}
|
||||
|
||||
startptr=LTREE_FIRST(a);
|
||||
for(i=0; i<=a->numlevel-b->numlevel; i++) {
|
||||
if ( i>=start ) {
|
||||
aptr=startptr;
|
||||
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;
|
||||
aptr=LEVEL_NEXT(aptr);
|
||||
bptr=LEVEL_NEXT(bptr);
|
||||
startptr = LTREE_FIRST(a);
|
||||
for (i = 0; i <= a->numlevel - b->numlevel; i++)
|
||||
{
|
||||
if (i >= start)
|
||||
{
|
||||
aptr = startptr;
|
||||
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;
|
||||
aptr = LEVEL_NEXT(aptr);
|
||||
bptr = LEVEL_NEXT(bptr);
|
||||
}
|
||||
|
||||
if ( j==b->numlevel ) {
|
||||
found=true;
|
||||
|
||||
if (j == b->numlevel)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
startptr=LEVEL_NEXT(startptr);
|
||||
startptr = LEVEL_NEXT(startptr);
|
||||
}
|
||||
|
||||
if ( !found )
|
||||
i=-1;
|
||||
|
||||
if (!found)
|
||||
i = -1;
|
||||
|
||||
PG_FREE_IF_COPY(a, 0);
|
||||
PG_FREE_IF_COPY(b, 1);
|
||||
|
@ -496,18 +505,18 @@ Datum
|
|||
text2ltree(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *in = PG_GETARG_TEXT_P(0);
|
||||
char *s = (char *) palloc(VARSIZE(in) - VARHDRSZ + 1);
|
||||
ltree *out;
|
||||
char *s = (char *) palloc(VARSIZE(in) - VARHDRSZ + 1);
|
||||
ltree *out;
|
||||
|
||||
memcpy(s, VARDATA(in), VARSIZE(in) - VARHDRSZ);
|
||||
s[VARSIZE(in) - VARHDRSZ] = '\0';
|
||||
|
||||
out = (ltree *) DatumGetPointer(DirectFunctionCall1(
|
||||
ltree_in,
|
||||
PointerGetDatum(s)
|
||||
));
|
||||
ltree_in,
|
||||
PointerGetDatum(s)
|
||||
));
|
||||
pfree(s);
|
||||
PG_FREE_IF_COPY(in,0);
|
||||
PG_FREE_IF_COPY(in, 0);
|
||||
PG_RETURN_POINTER(out);
|
||||
}
|
||||
|
||||
|
@ -516,16 +525,18 @@ Datum
|
|||
ltree2text(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ltree *in = PG_GETARG_LTREE(0);
|
||||
char *ptr;
|
||||
int i;
|
||||
char *ptr;
|
||||
int i;
|
||||
ltree_level *curlevel;
|
||||
text *out;
|
||||
|
||||
out=(text*)palloc(in->len+VARHDRSZ);
|
||||
ptr = VARDATA(out);
|
||||
text *out;
|
||||
|
||||
out = (text *) palloc(in->len + VARHDRSZ);
|
||||
ptr = VARDATA(out);
|
||||
curlevel = LTREE_FIRST(in);
|
||||
for (i = 0; i < in->numlevel; i++) {
|
||||
if (i != 0) {
|
||||
for (i = 0; i < in->numlevel; i++)
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
*ptr = '.';
|
||||
ptr++;
|
||||
}
|
||||
|
@ -533,13 +544,9 @@ ltree2text(PG_FUNCTION_ARGS)
|
|||
ptr += curlevel->len;
|
||||
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_RETURN_POINTER(out);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -356,8 +356,8 @@ sql_exec_dumptable(PGconn *conn, int systables)
|
|||
snprintf(todo, 1024, "select relfilenode,relname from pg_class order by relname");
|
||||
else
|
||||
snprintf(todo, 1024, "select relfilenode,relname from pg_class "
|
||||
"where relkind not in ('v','s', 'c') and "
|
||||
"relname not like 'pg_%%' order by relname");
|
||||
"where relkind not in ('v','s', 'c') and "
|
||||
"relname not like 'pg_%%' order by relname");
|
||||
|
||||
sql_exec(conn, todo, 0);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -23,19 +23,19 @@
|
|||
#include "/usr/include/pgsql/server/lib/dllist.h"
|
||||
*/
|
||||
|
||||
#define AUTOVACUUM_DEBUG 1
|
||||
#define VACBASETHRESHOLD 1000
|
||||
#define VACSCALINGFACTOR 2
|
||||
#define SLEEPBASEVALUE 300
|
||||
#define SLEEPSCALINGFACTOR 2
|
||||
#define UPDATE_INTERVAL 2
|
||||
#define AUTOVACUUM_DEBUG 1
|
||||
#define VACBASETHRESHOLD 1000
|
||||
#define VACSCALINGFACTOR 2
|
||||
#define SLEEPBASEVALUE 300
|
||||
#define SLEEPSCALINGFACTOR 2
|
||||
#define UPDATE_INTERVAL 2
|
||||
|
||||
/* these two constants are used to tell update_table_stats what operation we just perfomred */
|
||||
#define VACUUM_ANALYZE 0
|
||||
#define ANALYZE_ONLY 1
|
||||
#define VACUUM_ANALYZE 0
|
||||
#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_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_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 FRONTEND
|
||||
#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'"
|
||||
|
@ -44,71 +44,96 @@
|
|||
/* define cmd_args stucture */
|
||||
struct cmdargs
|
||||
{
|
||||
int vacuum_base_threshold, analyze_base_threshold, sleep_base_value, debug, daemonize;
|
||||
float vacuum_scaling_factor, analyze_scaling_factor, sleep_scaling_factor;
|
||||
char *user, *password, *host, *logfile, *port;
|
||||
int vacuum_base_threshold,
|
||||
analyze_base_threshold,
|
||||
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;
|
||||
|
||||
/* 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.
|
||||
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
|
||||
{
|
||||
int oid, age;
|
||||
int analyze_threshold, vacuum_threshold; /* Use these as defaults for table thresholds */
|
||||
PGconn *conn;
|
||||
char *dbname, *username, *password;
|
||||
Dllist *table_list;
|
||||
int oid,
|
||||
age;
|
||||
int analyze_threshold,
|
||||
vacuum_threshold; /* Use these as defaults for table
|
||||
* thresholds */
|
||||
PGconn *conn;
|
||||
char *dbname,
|
||||
*username,
|
||||
*password;
|
||||
Dllist *table_list;
|
||||
};
|
||||
typedef struct dbinfo db_info;
|
||||
|
||||
struct tableinfo
|
||||
{
|
||||
char *schema_name, *table_name;
|
||||
int relfilenode, reltuples, relpages;
|
||||
long analyze_threshold, 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 */
|
||||
char *schema_name,
|
||||
*table_name;
|
||||
int relfilenode,
|
||||
reltuples,
|
||||
relpages;
|
||||
long analyze_threshold,
|
||||
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;
|
||||
|
||||
/* Functions for dealing with command line arguements */
|
||||
static cmd_args *get_cmd_args (int argc, char *argv[]);
|
||||
static void print_cmd_args (void);
|
||||
static void free_cmd_args (void);
|
||||
static void usage (void);
|
||||
static cmd_args *get_cmd_args(int argc, char *argv[]);
|
||||
static void print_cmd_args(void);
|
||||
static void free_cmd_args(void);
|
||||
static void usage(void);
|
||||
|
||||
/* Functions for managing database lists */
|
||||
static Dllist *init_db_list (void);
|
||||
static db_info *init_dbinfo (char *dbname, int oid, int age);
|
||||
static void update_db_list (Dllist * db_list);
|
||||
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_list (Dllist * db_list, int print_table_lists);
|
||||
static int xid_wraparound_check (db_info * dbi);
|
||||
static void free_db_list (Dllist * db_list);
|
||||
static Dllist *init_db_list(void);
|
||||
static db_info *init_dbinfo(char *dbname, int oid, int age);
|
||||
static void update_db_list(Dllist *db_list);
|
||||
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_list(Dllist *db_list, int print_table_lists);
|
||||
static int xid_wraparound_check(db_info * dbi);
|
||||
static void free_db_list(Dllist *db_list);
|
||||
|
||||
/* Functions for managing table lists */
|
||||
static tbl_info *init_table_info (PGresult * conn, int row, db_info *dbi);
|
||||
static void update_table_list (db_info * dbi);
|
||||
static void remove_table_from_list (Dlelem * tbl_to_remove);
|
||||
static void print_table_list (Dllist * tbl_node);
|
||||
static void print_table_info (tbl_info * tbl);
|
||||
static void update_table_thresholds (db_info * dbi, tbl_info * tbl, int vacuum_type);
|
||||
static void free_tbl_list (Dllist * tbl_list);
|
||||
static tbl_info *init_table_info(PGresult *conn, int row, db_info * dbi);
|
||||
static void update_table_list(db_info * dbi);
|
||||
static void remove_table_from_list(Dlelem *tbl_to_remove);
|
||||
static void print_table_list(Dllist *tbl_node);
|
||||
static void print_table_info(tbl_info * tbl);
|
||||
static void update_table_thresholds(db_info * dbi, tbl_info * tbl, int vacuum_type);
|
||||
static void free_tbl_list(Dllist *tbl_list);
|
||||
|
||||
/* A few database helper functions */
|
||||
static int check_stats_enabled (db_info * dbi);
|
||||
static PGconn *db_connect (db_info * dbi);
|
||||
static void db_disconnect (db_info * dbi);
|
||||
static PGresult *send_query (const char *query, db_info * dbi);
|
||||
static char *query_table_stats (db_info * dbi);
|
||||
static int check_stats_enabled(db_info * dbi);
|
||||
static PGconn *db_connect(db_info * dbi);
|
||||
static void db_disconnect(db_info * dbi);
|
||||
static PGresult *send_query(const char *query, db_info * dbi);
|
||||
static char *query_table_stats(db_info * dbi);
|
||||
|
||||
/* Other Generally needed Functions */
|
||||
static void daemonize(void);
|
||||
static void log_entry (const char *logentry);
|
||||
static void log_entry(const char *logentry);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* -------------------------------------------------------------------------
|
||||
* 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
|
||||
* -------------------------------------------------------------------------
|
||||
|
@ -26,7 +26,7 @@
|
|||
|
||||
#ifndef HAVE_GETOPT_LONG
|
||||
#include "getopt_long.h"
|
||||
int optreset;
|
||||
int optreset;
|
||||
#endif
|
||||
|
||||
char *progname = NULL;
|
||||
|
|
|
@ -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
|
||||
* written by Tatsuo Ishii
|
||||
|
@ -122,7 +122,7 @@ doConnect()
|
|||
{
|
||||
PGconn *con;
|
||||
PGresult *res;
|
||||
|
||||
|
||||
con = PQsetdbLogin(pghost, pgport, pgoptions, pgtty, dbName,
|
||||
login, pwd);
|
||||
if (con == NULL)
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* 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>
|
||||
|
@ -130,18 +130,19 @@ px_find_digest(const char *name, PX_MD ** res)
|
|||
* of functions does not allow enough flexibility
|
||||
* and forces some of the parameters (keylen,
|
||||
* padding) to SSL defaults.
|
||||
*
|
||||
*
|
||||
* So need to manage ciphers ourselves.
|
||||
*/
|
||||
|
||||
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 (*decrypt) (PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res);
|
||||
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 (*decrypt) (PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res);
|
||||
|
||||
int block_size;
|
||||
int max_key_size;
|
||||
int stream_cipher;
|
||||
int block_size;
|
||||
int max_key_size;
|
||||
int stream_cipher;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
|
@ -224,7 +225,7 @@ static int
|
|||
bf_ecb_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen, uint8 *res)
|
||||
{
|
||||
unsigned bs = gen_ossl_block_size(c);
|
||||
unsigned i;
|
||||
unsigned i;
|
||||
ossldata *od = c->ptr;
|
||||
|
||||
for (i = 0; i < dlen / bs; i++)
|
||||
|
@ -288,13 +289,13 @@ static int
|
|||
ossl_des_init(PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv)
|
||||
{
|
||||
ossldata *od = c->ptr;
|
||||
des_cblock xkey;
|
||||
des_cblock xkey;
|
||||
|
||||
memset(&xkey, 0, sizeof(xkey));
|
||||
memcpy(&xkey, key, klen > 8 ? 8 : klen);
|
||||
des_set_key(&xkey, od->u.des.key_schedule);
|
||||
memset(&xkey, 0, sizeof(xkey));
|
||||
|
||||
|
||||
if (iv)
|
||||
memcpy(od->iv, iv, 8);
|
||||
else
|
||||
|
@ -304,53 +305,53 @@ ossl_des_init(PX_Cipher * c, const uint8 *key, unsigned klen, const uint8 *iv)
|
|||
|
||||
static int
|
||||
ossl_des_ecb_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
|
||||
uint8 *res)
|
||||
uint8 *res)
|
||||
{
|
||||
unsigned bs = gen_ossl_block_size(c);
|
||||
unsigned i;
|
||||
unsigned i;
|
||||
ossldata *od = c->ptr;
|
||||
|
||||
for (i = 0; i < dlen / bs; i++)
|
||||
des_ecb_encrypt((des_cblock*)(data + i * bs),
|
||||
(des_cblock*)(res + i * bs),
|
||||
od->u.des.key_schedule, 1);
|
||||
des_ecb_encrypt((des_cblock *) (data + i * bs),
|
||||
(des_cblock *) (res + i * bs),
|
||||
od->u.des.key_schedule, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ossl_des_ecb_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
|
||||
uint8 *res)
|
||||
uint8 *res)
|
||||
{
|
||||
unsigned bs = gen_ossl_block_size(c);
|
||||
unsigned i;
|
||||
unsigned i;
|
||||
ossldata *od = c->ptr;
|
||||
|
||||
for (i = 0; i < dlen / bs; i++)
|
||||
des_ecb_encrypt((des_cblock*)(data + i * bs),
|
||||
(des_cblock*)(res + i * bs),
|
||||
od->u.des.key_schedule, 0);
|
||||
des_ecb_encrypt((des_cblock *) (data + i * bs),
|
||||
(des_cblock *) (res + i * bs),
|
||||
od->u.des.key_schedule, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ossl_des_cbc_encrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
|
||||
uint8 *res)
|
||||
uint8 *res)
|
||||
{
|
||||
ossldata *od = c->ptr;
|
||||
|
||||
des_ncbc_encrypt(data, res, dlen, od->u.des.key_schedule,
|
||||
(des_cblock*)od->iv, 1);
|
||||
(des_cblock *) od->iv, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ossl_des_cbc_decrypt(PX_Cipher * c, const uint8 *data, unsigned dlen,
|
||||
uint8 *res)
|
||||
uint8 *res)
|
||||
{
|
||||
ossldata *od = c->ptr;
|
||||
|
||||
des_ncbc_encrypt(data, res, dlen, od->u.des.key_schedule,
|
||||
(des_cblock*)od->iv, 0);
|
||||
(des_cblock *) od->iv, 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);
|
||||
ossldata *od = c->ptr;
|
||||
const uint8 *end = data + dlen - bs;
|
||||
const uint8 *end = data + dlen - bs;
|
||||
|
||||
for (; data <= end; data += bs, res += bs)
|
||||
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);
|
||||
ossldata *od = c->ptr;
|
||||
const uint8 *end = data + dlen - bs;
|
||||
const uint8 *end = data + dlen - bs;
|
||||
|
||||
for (; data <= end; data += bs, res += bs)
|
||||
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 = {
|
||||
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 = {
|
||||
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 = {
|
||||
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 = {
|
||||
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 = {
|
||||
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 = {
|
||||
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 = {
|
||||
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
|
||||
{
|
||||
const char *name;
|
||||
const char *name;
|
||||
const struct ossl_cipher *ciph;
|
||||
} ossl_cipher_types[] =
|
||||
|
||||
|
@ -510,8 +511,10 @@ px_find_cipher(const char *name, PX_Cipher ** res)
|
|||
const struct ossl_cipher *ossl_ciph = NULL;
|
||||
|
||||
name = px_resolve_alias(ossl_aliases, name);
|
||||
for (i = 0; ossl_cipher_types[i].name; i++) {
|
||||
if (!strcmp(ossl_cipher_types[i].name, name)) {
|
||||
for (i = 0; ossl_cipher_types[i].name; i++)
|
||||
{
|
||||
if (!strcmp(ossl_cipher_types[i].name, name))
|
||||
{
|
||||
ossl_ciph = ossl_cipher_types[i].ciph;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* 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>
|
||||
|
@ -241,7 +241,7 @@ pg_gen_salt_rounds(PG_FUNCTION_ARGS)
|
|||
if (len == 0)
|
||||
ereport(ERROR,
|
||||
(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);
|
||||
VARATT_SIZEP(res) = len + VARHDRSZ;
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
@ -221,5 +221,5 @@ pgstattuple_real(Relation rel)
|
|||
pfree(values[i]);
|
||||
pfree(values);
|
||||
|
||||
return(result);
|
||||
return (result);
|
||||
}
|
||||
|
|
|
@ -73,8 +73,8 @@ autoinc(PG_FUNCTION_ARGS)
|
|||
if (SPI_gettypeid(tupdesc, attnum) != INT4OID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
|
||||
errmsg("attribute \"%s\" of \"%s\" must be type INT4",
|
||||
args[i], relname)));
|
||||
errmsg("attribute \"%s\" of \"%s\" must be type INT4",
|
||||
args[i], relname)));
|
||||
|
||||
val = DatumGetInt32(SPI_getbinval(rettuple, tupdesc, attnum, &isnull));
|
||||
|
||||
|
|
|
@ -65,17 +65,17 @@ insert_username(PG_FUNCTION_ARGS)
|
|||
if (attnum < 0)
|
||||
ereport(ERROR,
|
||||
(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)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
|
||||
errmsg("attribute \"%s\" of \"%s\" must be type TEXT",
|
||||
args[0], relname)));
|
||||
args[0], relname)));
|
||||
|
||||
/* create fields containing name */
|
||||
newval = DirectFunctionCall1(textin,
|
||||
CStringGetDatum(GetUserNameFromId(GetUserId())));
|
||||
CStringGetDatum(GetUserNameFromId(GetUserId())));
|
||||
|
||||
/* construct new tuple */
|
||||
rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newval, NULL);
|
||||
|
|
|
@ -100,8 +100,8 @@ moddatetime(PG_FUNCTION_ARGS)
|
|||
if (SPI_gettypeid(tupdesc, attnum) != TIMESTAMPOID)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
|
||||
errmsg("attribute \"%s\" of \"%s\" must be type TIMESTAMP",
|
||||
args[0], relname)));
|
||||
errmsg("attribute \"%s\" of \"%s\" must be type TIMESTAMP",
|
||||
args[0], relname)));
|
||||
|
||||
/* 1 is the number of items in the arrays attnum and newdt.
|
||||
attnum is the positional number of the field to be updated.
|
||||
|
|
|
@ -134,8 +134,8 @@ check_primary_key(PG_FUNCTION_ARGS)
|
|||
if (fnumber < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
||||
errmsg("there is no attribute \"%s\" in relation \"%s\"",
|
||||
args[i], SPI_getrelname(rel))));
|
||||
errmsg("there is no attribute \"%s\" in relation \"%s\"",
|
||||
args[i], SPI_getrelname(rel))));
|
||||
|
||||
/* Well, get binary (in internal format) value of column */
|
||||
kvals[i] = SPI_getbinval(tuple, tupdesc, fnumber, &isnull);
|
||||
|
@ -365,8 +365,8 @@ check_foreign_key(PG_FUNCTION_ARGS)
|
|||
if (fnumber < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
||||
errmsg("there is no attribute \"%s\" in relation \"%s\"",
|
||||
args[i], SPI_getrelname(rel))));
|
||||
errmsg("there is no attribute \"%s\" in relation \"%s\"",
|
||||
args[i], SPI_getrelname(rel))));
|
||||
|
||||
/* Well, get binary (in internal format) value of column */
|
||||
kvals[i] = SPI_getbinval(trigtuple, tupdesc, fnumber, &isnull);
|
||||
|
@ -591,7 +591,7 @@ check_foreign_key(PG_FUNCTION_ARGS)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_TRIGGERED_ACTION_EXCEPTION),
|
||||
errmsg("\"%s\": tuple is referenced in \"%s\"",
|
||||
trigger->tgname, relname)));
|
||||
trigger->tgname, relname)));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
/* 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 "commands/trigger.h" /* -"- and triggers */
|
||||
#include "commands/trigger.h" /* -"- and triggers */
|
||||
#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); */
|
||||
Datum timetravel(PG_FUNCTION_ARGS);
|
||||
|
@ -28,13 +28,13 @@ static int nPlans = 0;
|
|||
|
||||
typedef struct _TTOffList
|
||||
{
|
||||
struct _TTOffList *next;
|
||||
char name[1];
|
||||
} TTOffList;
|
||||
struct _TTOffList *next;
|
||||
char name[1];
|
||||
} 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);
|
||||
|
||||
/*
|
||||
|
@ -71,57 +71,57 @@ static EPlan *find_plan(char *ident, EPlan ** eplan, int *nplans);
|
|||
|
||||
PG_FUNCTION_INFO_V1(timetravel);
|
||||
|
||||
Datum /* have to return HeapTuple to Executor */
|
||||
Datum /* have to return HeapTuple to Executor */
|
||||
timetravel(PG_FUNCTION_ARGS)
|
||||
{
|
||||
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||
Trigger *trigger; /* to get trigger name */
|
||||
int argc;
|
||||
char **args; /* arguments */
|
||||
int attnum[MaxAttrNum]; /* fnumbers of start/stop columns */
|
||||
TriggerData *trigdata = (TriggerData *) fcinfo->context;
|
||||
Trigger *trigger; /* to get trigger name */
|
||||
int argc;
|
||||
char **args; /* arguments */
|
||||
int attnum[MaxAttrNum]; /* fnumbers of start/stop columns */
|
||||
Datum oldtimeon,
|
||||
oldtimeoff;
|
||||
oldtimeoff;
|
||||
Datum newtimeon,
|
||||
newtimeoff,
|
||||
newuser,
|
||||
nulltext;
|
||||
Datum *cvals; /* column values */
|
||||
char *cnulls; /* column nulls */
|
||||
char *relname; /* triggered relation name */
|
||||
newtimeoff,
|
||||
newuser,
|
||||
nulltext;
|
||||
Datum *cvals; /* column values */
|
||||
char *cnulls; /* column nulls */
|
||||
char *relname; /* triggered relation name */
|
||||
Relation rel; /* triggered relation */
|
||||
HeapTuple trigtuple;
|
||||
HeapTuple newtuple = NULL;
|
||||
HeapTuple rettuple;
|
||||
TupleDesc tupdesc; /* tuple description */
|
||||
int natts; /* # of attributes */
|
||||
EPlan *plan; /* prepared plan */
|
||||
int natts; /* # of attributes */
|
||||
EPlan *plan; /* prepared plan */
|
||||
char ident[2 * NAMEDATALEN];
|
||||
bool isnull; /* to know is some column NULL or not */
|
||||
bool isinsert = false;
|
||||
int ret;
|
||||
int i;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Some checks first...
|
||||
*/
|
||||
|
||||
/* Called by trigger manager ? */
|
||||
if(!CALLED_AS_TRIGGER(fcinfo))
|
||||
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||
elog(ERROR, "timetravel: not fired by trigger manager");
|
||||
|
||||
/* 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");
|
||||
|
||||
/* 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");
|
||||
|
||||
/* INSERT ? */
|
||||
if(TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
||||
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
||||
isinsert = true;
|
||||
|
||||
if(TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||
newtuple = trigdata->tg_newtuple;
|
||||
|
||||
trigtuple = trigdata->tg_trigtuple;
|
||||
|
@ -130,7 +130,7 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
relname = SPI_getrelname(rel);
|
||||
|
||||
/* check if TT is OFF for this relation */
|
||||
if(0==findTTStatus(relname))
|
||||
if (0 == findTTStatus(relname))
|
||||
{
|
||||
/* OFF - nothing to do */
|
||||
pfree(relname);
|
||||
|
@ -140,7 +140,7 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
trigger = trigdata->tg_trigger;
|
||||
|
||||
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",
|
||||
relname, MinAttrNum, MaxAttrNum, trigger->tgnargs);
|
||||
|
||||
|
@ -148,39 +148,39 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
tupdesc = rel->rd_att;
|
||||
natts = tupdesc->natts;
|
||||
|
||||
for(i = 0 ; i < MinAttrNum ; i++)
|
||||
for (i = 0; i < MinAttrNum; 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]);
|
||||
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",
|
||||
relname, args[i]);
|
||||
}
|
||||
for( ; i < argc ; i++)
|
||||
for (; i < argc; 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]);
|
||||
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",
|
||||
relname, args[i]);
|
||||
}
|
||||
|
||||
/* create fields containing name */
|
||||
newuser = DirectFunctionCall1(textin, CStringGetDatum(GetUserNameFromId(GetUserId())));
|
||||
newuser = DirectFunctionCall1(textin, CStringGetDatum(GetUserNameFromId(GetUserId())));
|
||||
|
||||
nulltext = (Datum)NULL;
|
||||
nulltext = (Datum) NULL;
|
||||
|
||||
if(isinsert)
|
||||
{ /* INSERT */
|
||||
int chnattrs = 0;
|
||||
int chattrs[MaxAttrNum];
|
||||
Datum newvals[MaxAttrNum];
|
||||
char newnulls[MaxAttrNum];
|
||||
if (isinsert)
|
||||
{ /* INSERT */
|
||||
int chnattrs = 0;
|
||||
int chattrs[MaxAttrNum];
|
||||
Datum newvals[MaxAttrNum];
|
||||
char newnulls[MaxAttrNum];
|
||||
|
||||
oldtimeon = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_on], &isnull);
|
||||
if(isnull)
|
||||
if (isnull)
|
||||
{
|
||||
newvals[chnattrs] = GetCurrentAbsoluteTime();
|
||||
newnulls[chnattrs] = ' ';
|
||||
|
@ -189,10 +189,10 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
oldtimeoff = SPI_getbinval(trigtuple, tupdesc, attnum[a_time_off], &isnull);
|
||||
if(isnull)
|
||||
if (isnull)
|
||||
{
|
||||
if((chnattrs == 0 && DatumGetInt32(oldtimeon) >= NOEND_ABSTIME) ||
|
||||
(chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) >= NOEND_ABSTIME))
|
||||
if ((chnattrs == 0 && DatumGetInt32(oldtimeon) >= NOEND_ABSTIME) ||
|
||||
(chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) >= NOEND_ABSTIME))
|
||||
elog(ERROR, "timetravel (%s): %s is infinity", relname, args[a_time_on]);
|
||||
newvals[chnattrs] = NOEND_ABSTIME;
|
||||
newnulls[chnattrs] = ' ';
|
||||
|
@ -201,16 +201,16 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
}
|
||||
else
|
||||
{
|
||||
if((chnattrs == 0 && DatumGetInt32(oldtimeon) > DatumGetInt32(oldtimeoff)) ||
|
||||
(chnattrs > 0 && DatumGetInt32(newvals[a_time_on]) > DatumGetInt32(oldtimeoff)))
|
||||
if ((chnattrs == 0 && DatumGetInt32(oldtimeon) > 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]);
|
||||
}
|
||||
|
||||
pfree(relname);
|
||||
if(chnattrs <= 0)
|
||||
if (chnattrs <= 0)
|
||||
return PointerGetDatum(trigtuple);
|
||||
|
||||
if(argc == MaxAttrNum)
|
||||
if (argc == MaxAttrNum)
|
||||
{
|
||||
/* clear update_user value */
|
||||
newvals[chnattrs] = nulltext;
|
||||
|
@ -235,33 +235,34 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
|
||||
/* UPDATE/DELETE: */
|
||||
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]);
|
||||
|
||||
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]);
|
||||
|
||||
/*
|
||||
* If DELETE/UPDATE of tuple with stop_date neq INFINITY then say
|
||||
* upper Executor to skip operation for this tuple
|
||||
*/
|
||||
if(newtuple != NULL)
|
||||
{ /* UPDATE */
|
||||
if (newtuple != NULL)
|
||||
{ /* UPDATE */
|
||||
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]);
|
||||
|
||||
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]);
|
||||
|
||||
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)",
|
||||
relname, args[a_time_on], args[a_time_off]);
|
||||
}
|
||||
if(oldtimeoff != NOEND_ABSTIME)
|
||||
{ /* current record is a deleted/updated record */
|
||||
if (oldtimeoff != NOEND_ABSTIME)
|
||||
{ /* current record is a deleted/updated
|
||||
* record */
|
||||
pfree(relname);
|
||||
return PointerGetDatum(NULL);
|
||||
}
|
||||
|
@ -269,27 +270,28 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
newtimeoff = GetCurrentAbsoluteTime();
|
||||
|
||||
/* Connect to SPI manager */
|
||||
if((ret = SPI_connect()) < 0)
|
||||
if ((ret = SPI_connect()) < 0)
|
||||
elog(ERROR, "timetravel (%s): SPI_connect returned %d", relname, ret);
|
||||
|
||||
/* Fetch tuple values and nulls */
|
||||
cvals = (Datum *) palloc(natts * sizeof(Datum));
|
||||
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);
|
||||
cnulls[i] = (isnull) ? 'n' : ' ';
|
||||
}
|
||||
|
||||
/* 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] = ' ';
|
||||
|
||||
if(!newtuple)
|
||||
{ /* DELETE */
|
||||
if(argc == MaxAttrNum)
|
||||
if (!newtuple)
|
||||
{ /* DELETE */
|
||||
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] = ' ';
|
||||
}
|
||||
}
|
||||
|
@ -302,11 +304,11 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
plan = find_plan(ident, &Plans, &nPlans);
|
||||
|
||||
/* if there is no plan ... */
|
||||
if(plan->splan == NULL)
|
||||
if (plan->splan == NULL)
|
||||
{
|
||||
void *pplan;
|
||||
Oid *ctypes;
|
||||
char sql[8192];
|
||||
void *pplan;
|
||||
Oid *ctypes;
|
||||
char sql[8192];
|
||||
|
||||
/* allocate ctypes for preparation */
|
||||
ctypes = (Oid *) palloc(natts * sizeof(Oid));
|
||||
|
@ -315,15 +317,15 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
* Construct query: INSERT INTO _relation_ VALUES ($1, ...)
|
||||
*/
|
||||
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);
|
||||
if(!(tupdesc->attrs[i - 1]->attisdropped)) /* skip dropped columns */
|
||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "$%d%s",
|
||||
i, (i < natts) ? ", " : ")" );
|
||||
if (!(tupdesc->attrs[i - 1]->attisdropped)) /* skip dropped columns */
|
||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "$%d%s",
|
||||
i, (i < natts) ? ", " : ")");
|
||||
#if 0
|
||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "$%d /* %d */ %s",
|
||||
i, ctypes[i-1], (i < natts) ? ", " : ")" );
|
||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "$%d /* %d */ %s",
|
||||
i, ctypes[i - 1], (i < natts) ? ", " : ")");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -331,7 +333,7 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
|
||||
/* Prepare plan for query */
|
||||
pplan = SPI_prepare(sql, natts, ctypes);
|
||||
if(pplan == NULL)
|
||||
if (pplan == NULL)
|
||||
elog(ERROR, "timetravel (%s): SPI_prepare returned %d", relname, SPI_result);
|
||||
|
||||
/*
|
||||
|
@ -340,7 +342,7 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
* use.
|
||||
*/
|
||||
pplan = SPI_saveplan(pplan);
|
||||
if(pplan == NULL)
|
||||
if (pplan == NULL)
|
||||
elog(ERROR, "timetravel (%s): SPI_saveplan returned %d", relname, SPI_result);
|
||||
|
||||
plan->splan = pplan;
|
||||
|
@ -351,14 +353,14 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
*/
|
||||
ret = SPI_execp(plan->splan, cvals, cnulls, 0);
|
||||
|
||||
if(ret < 0)
|
||||
if (ret < 0)
|
||||
elog(ERROR, "timetravel (%s): SPI_execp returned %d", relname, ret);
|
||||
|
||||
/* Tuple to return to upper Executor ... */
|
||||
if(newtuple)
|
||||
{ /* UPDATE */
|
||||
int chnattrs = 0;
|
||||
int chattrs[MaxAttrNum];
|
||||
if (newtuple)
|
||||
{ /* UPDATE */
|
||||
int chnattrs = 0;
|
||||
int chattrs[MaxAttrNum];
|
||||
Datum newvals[MaxAttrNum];
|
||||
char newnulls[MaxAttrNum];
|
||||
|
||||
|
@ -372,7 +374,7 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
chattrs[chnattrs] = attnum[a_time_off];
|
||||
chnattrs++;
|
||||
|
||||
if(argc == MaxAttrNum)
|
||||
if (argc == MaxAttrNum)
|
||||
{
|
||||
/* set update_user value */
|
||||
newvals[chnattrs] = newuser;
|
||||
|
@ -399,7 +401,8 @@ timetravel(PG_FUNCTION_ARGS)
|
|||
*/
|
||||
/* SPI_pfree(tmptuple); */
|
||||
}
|
||||
else /* DELETE case */
|
||||
else
|
||||
/* DELETE case */
|
||||
rettuple = trigtuple;
|
||||
|
||||
SPI_finish(); /* don't forget say Bye to SPI mgr */
|
||||
|
@ -417,23 +420,24 @@ PG_FUNCTION_INFO_V1(set_timetravel);
|
|||
Datum
|
||||
set_timetravel(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Name relname = PG_GETARG_NAME(0);
|
||||
int32 on = PG_GETARG_INT32(1);
|
||||
char *rname;
|
||||
char *d;
|
||||
char *s;
|
||||
Name relname = PG_GETARG_NAME(0);
|
||||
int32 on = PG_GETARG_INT32(1);
|
||||
char *rname;
|
||||
char *d;
|
||||
char *s;
|
||||
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;
|
||||
}
|
||||
if(pp)
|
||||
if (pp)
|
||||
{
|
||||
/* OFF currently */
|
||||
if(on != 0)
|
||||
if (on != 0)
|
||||
{
|
||||
/* turn ON */
|
||||
p->next = pp->next;
|
||||
|
@ -444,20 +448,20 @@ set_timetravel(PG_FUNCTION_ARGS)
|
|||
else
|
||||
{
|
||||
/* ON currently */
|
||||
if(on == 0)
|
||||
if (on == 0)
|
||||
{
|
||||
/* turn OFF */
|
||||
s = rname = DatumGetCString(DirectFunctionCall1(nameout, NameGetDatum(relname)));
|
||||
if(s)
|
||||
if (s)
|
||||
{
|
||||
pp = malloc(sizeof(TTOffList)+strlen(rname));
|
||||
if(pp)
|
||||
pp = malloc(sizeof(TTOffList) + strlen(rname));
|
||||
if (pp)
|
||||
{
|
||||
pp->next = NULL;
|
||||
p->next = pp;
|
||||
d = pp->name;
|
||||
while (*s)
|
||||
*d++ = tolower((unsigned char)*s++);
|
||||
*d++ = tolower((unsigned char) *s++);
|
||||
*d = '\0';
|
||||
}
|
||||
pfree(rname);
|
||||
|
@ -470,7 +474,7 @@ set_timetravel(PG_FUNCTION_ARGS)
|
|||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
|
@ -478,11 +482,11 @@ Datum
|
|||
get_timetravel(PG_FUNCTION_ARGS)
|
||||
{
|
||||
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(1);
|
||||
|
@ -491,9 +495,10 @@ get_timetravel(PG_FUNCTION_ARGS)
|
|||
static int
|
||||
findTTStatus(char *name)
|
||||
{
|
||||
TTOffList* pp;
|
||||
for(pp = TTOff.next; pp; pp = pp->next)
|
||||
if(strcasecmp(name, pp->name) == 0)
|
||||
TTOffList *pp;
|
||||
|
||||
for (pp = TTOff.next; pp; pp = pp->next)
|
||||
if (strcasecmp(name, pp->name) == 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
@ -509,17 +514,17 @@ currabstime()
|
|||
static EPlan *
|
||||
find_plan(char *ident, EPlan ** eplan, int *nplans)
|
||||
{
|
||||
EPlan *newp;
|
||||
int i;
|
||||
EPlan *newp;
|
||||
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;
|
||||
}
|
||||
if(i != *nplans)
|
||||
if (i != *nplans)
|
||||
return (*eplan + i);
|
||||
*eplan = (EPlan *) realloc(*eplan, (i + 1) * sizeof(EPlan));
|
||||
newp = *eplan + i;
|
||||
|
|
|
@ -42,11 +42,11 @@
|
|||
|
||||
#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,
|
||||
int num_categories,
|
||||
TupleDesc tupdesc,
|
||||
MemoryContext per_query_ctx);
|
||||
int num_categories,
|
||||
TupleDesc tupdesc,
|
||||
MemoryContext per_query_ctx);
|
||||
static void validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial);
|
||||
static bool compatCrosstabTupleDescs(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,
|
||||
char *key_fld,
|
||||
char *parent_key_fld,
|
||||
char *orderby_fld,
|
||||
char *orderby_fld,
|
||||
char *branch_delim,
|
||||
char *start_with,
|
||||
int max_depth,
|
||||
|
@ -115,7 +115,7 @@ static HTAB *crosstab_HashTable;
|
|||
typedef struct crosstab_cat_desc
|
||||
{
|
||||
char *catname;
|
||||
int attidx; /* zero based */
|
||||
int attidx; /* zero based */
|
||||
} crosstab_cat_desc;
|
||||
|
||||
#define MAX_CATNAME_LEN NAMEDATALEN
|
||||
|
@ -157,9 +157,9 @@ do { \
|
|||
/* hash table */
|
||||
typedef struct crosstab_hashent
|
||||
{
|
||||
char internal_catname[MAX_CATNAME_LEN];
|
||||
crosstab_cat_desc *catdesc;
|
||||
} crosstab_HashEnt;
|
||||
char internal_catname[MAX_CATNAME_LEN];
|
||||
crosstab_cat_desc *catdesc;
|
||||
} crosstab_HashEnt;
|
||||
|
||||
/*
|
||||
* normal_rand - return requested number of random values
|
||||
|
@ -414,7 +414,7 @@ crosstab(PG_FUNCTION_ARGS)
|
|||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid source data SQL statement"),
|
||||
errdetail("The provided SQL must return 3 " \
|
||||
" columns; rowid, category, and values.")));
|
||||
" columns; rowid, category, and values.")));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -667,10 +667,10 @@ crosstab(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
/*
|
||||
* crosstab_hash - reimplement crosstab as materialized function and
|
||||
* crosstab_hash - reimplement crosstab as materialized function and
|
||||
* properly deal with missing values (i.e. don't pack remaining
|
||||
* values to the left)
|
||||
*
|
||||
*
|
||||
* crosstab - create a crosstab of rowids and values columns from a
|
||||
* SQL statement returning one rowid column, one category column,
|
||||
* and one value column.
|
||||
|
@ -705,13 +705,13 @@ PG_FUNCTION_INFO_V1(crosstab_hash);
|
|||
Datum
|
||||
crosstab_hash(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *sql = GET_STR(PG_GETARG_TEXT_P(0));
|
||||
char *cats_sql = GET_STR(PG_GETARG_TEXT_P(1));
|
||||
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
||||
TupleDesc tupdesc;
|
||||
MemoryContext per_query_ctx;
|
||||
MemoryContext oldcontext;
|
||||
int num_categories;
|
||||
char *sql = GET_STR(PG_GETARG_TEXT_P(0));
|
||||
char *cats_sql = GET_STR(PG_GETARG_TEXT_P(1));
|
||||
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
||||
TupleDesc tupdesc;
|
||||
MemoryContext per_query_ctx;
|
||||
MemoryContext oldcontext;
|
||||
int num_categories;
|
||||
|
||||
/* check to see if caller supports us returning a tuplestore */
|
||||
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
|
||||
*
|
||||
* Note we will attempt to coerce the values into whatever
|
||||
* the return attribute type is and depend on the "in"
|
||||
* function to complain if needed.
|
||||
* Note we will attempt to coerce the values into whatever the return
|
||||
* attribute type is and depend on the "in" function to complain if
|
||||
* needed.
|
||||
*/
|
||||
if (tupdesc->natts < 2)
|
||||
ereport(ERROR,
|
||||
|
@ -770,19 +770,19 @@ crosstab_hash(PG_FUNCTION_ARGS)
|
|||
static int
|
||||
load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
|
||||
{
|
||||
HASHCTL ctl;
|
||||
int ret;
|
||||
int proc;
|
||||
MemoryContext SPIcontext;
|
||||
int num_categories = 0;
|
||||
HASHCTL ctl;
|
||||
int ret;
|
||||
int proc;
|
||||
MemoryContext SPIcontext;
|
||||
int num_categories = 0;
|
||||
|
||||
/* initialize the category hash table */
|
||||
ctl.keysize = MAX_CATNAME_LEN;
|
||||
ctl.entrysize = sizeof(crosstab_HashEnt);
|
||||
|
||||
/*
|
||||
* use INIT_CATS, defined above as a guess of how
|
||||
* many hash table entries to create, initially
|
||||
* use INIT_CATS, defined above as a guess of how many hash table
|
||||
* entries to create, initially
|
||||
*/
|
||||
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 */
|
||||
if ((ret == SPI_OK_SELECT) && (proc > 0))
|
||||
{
|
||||
SPITupleTable *spi_tuptable = SPI_tuptable;
|
||||
TupleDesc spi_tupdesc = spi_tuptable->tupdesc;
|
||||
int i;
|
||||
SPITupleTable *spi_tuptable = SPI_tuptable;
|
||||
TupleDesc spi_tupdesc = spi_tuptable->tupdesc;
|
||||
int i;
|
||||
|
||||
/*
|
||||
* The provided categories SQL query must always return one column:
|
||||
* category - the label or identifier for each column
|
||||
* The provided categories SQL query must always return one
|
||||
* column: category - the label or identifier for each column
|
||||
*/
|
||||
if (spi_tupdesc->natts != 1)
|
||||
ereport(ERROR,
|
||||
|
@ -814,9 +814,9 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
|
|||
|
||||
for (i = 0; i < proc; i++)
|
||||
{
|
||||
crosstab_cat_desc *catdesc;
|
||||
char *catname;
|
||||
HeapTuple spi_tuple;
|
||||
crosstab_cat_desc *catdesc;
|
||||
char *catname;
|
||||
HeapTuple spi_tuple;
|
||||
|
||||
/* get the next sql result tuple */
|
||||
spi_tuple = spi_tuptable->vals[i];
|
||||
|
@ -862,13 +862,13 @@ get_crosstab_tuplestore(char *sql,
|
|||
TupleDesc tupdesc,
|
||||
MemoryContext per_query_ctx)
|
||||
{
|
||||
Tuplestorestate *tupstore;
|
||||
AttInMetadata *attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
||||
char **values;
|
||||
HeapTuple tuple;
|
||||
int ret;
|
||||
int proc;
|
||||
MemoryContext SPIcontext;
|
||||
Tuplestorestate *tupstore;
|
||||
AttInMetadata *attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
||||
char **values;
|
||||
HeapTuple tuple;
|
||||
int ret;
|
||||
int proc;
|
||||
MemoryContext SPIcontext;
|
||||
|
||||
/* initialize our tuplestore */
|
||||
tupstore = tuplestore_begin_heap(true, false, SortMem);
|
||||
|
@ -885,33 +885,36 @@ get_crosstab_tuplestore(char *sql,
|
|||
/* Check for qualifying tuples */
|
||||
if ((ret == SPI_OK_SELECT) && (proc > 0))
|
||||
{
|
||||
SPITupleTable *spi_tuptable = SPI_tuptable;
|
||||
TupleDesc spi_tupdesc = spi_tuptable->tupdesc;
|
||||
int ncols = spi_tupdesc->natts;
|
||||
char *rowid;
|
||||
char *lastrowid = NULL;
|
||||
int i, j;
|
||||
int result_ncols;
|
||||
SPITupleTable *spi_tuptable = SPI_tuptable;
|
||||
TupleDesc spi_tupdesc = spi_tuptable->tupdesc;
|
||||
int ncols = spi_tupdesc->natts;
|
||||
char *rowid;
|
||||
char *lastrowid = NULL;
|
||||
int i,
|
||||
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
|
||||
* 2. category the label for each value-column in the final result
|
||||
* 3. value the values used to populate the value-columns
|
||||
*
|
||||
* 2. category the label for each value-column in the final
|
||||
* result 3. value the values used to populate the
|
||||
* value-columns
|
||||
*
|
||||
* If there are more than three columns, the last two are taken as
|
||||
* "category" and "values". The first column is taken as "rowname".
|
||||
* Additional columns (2 thru N-2) are assumed the same for the same
|
||||
* "rowname", and are copied into the result tuple from the first
|
||||
* time we encounter a particular rowname.
|
||||
* "category" and "values". The first column is taken as
|
||||
* "rowname". Additional columns (2 thru N-2) are assumed the same
|
||||
* for the same "rowname", and are copied into the result tuple
|
||||
* from the first time we encounter a particular rowname.
|
||||
*/
|
||||
if (ncols < 3)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("invalid source data SQL statement"),
|
||||
errdetail("The provided SQL must return 3 " \
|
||||
" columns; rowid, category, and values.")));
|
||||
" columns; rowid, category, and values.")));
|
||||
|
||||
result_ncols = (ncols - 2) + num_categories;
|
||||
|
||||
|
@ -922,7 +925,7 @@ get_crosstab_tuplestore(char *sql,
|
|||
errmsg("invalid return type"),
|
||||
errdetail("query-specified return " \
|
||||
"tuple has %d columns but crosstab " \
|
||||
"returns %d", tupdesc->natts, result_ncols)));
|
||||
"returns %d", tupdesc->natts, result_ncols)));
|
||||
|
||||
/* allocate space */
|
||||
values = (char **) palloc(result_ncols * sizeof(char *));
|
||||
|
@ -932,9 +935,9 @@ get_crosstab_tuplestore(char *sql,
|
|||
|
||||
for (i = 0; i < proc; i++)
|
||||
{
|
||||
HeapTuple spi_tuple;
|
||||
crosstab_cat_desc *catdesc;
|
||||
char *catname;
|
||||
HeapTuple spi_tuple;
|
||||
crosstab_cat_desc *catdesc;
|
||||
char *catname;
|
||||
|
||||
/* get the next sql result tuple */
|
||||
spi_tuple = spi_tuptable->vals[i];
|
||||
|
@ -958,7 +961,10 @@ get_crosstab_tuplestore(char *sql,
|
|||
*/
|
||||
if (lastrowid != NULL)
|
||||
{
|
||||
/* switch to appropriate context while storing the tuple */
|
||||
/*
|
||||
* switch to appropriate context while storing the
|
||||
* tuple
|
||||
*/
|
||||
SPIcontext = MemoryContextSwitchTo(per_query_ctx);
|
||||
|
||||
/* rowid changed, flush the previous output row */
|
||||
|
@ -984,7 +990,7 @@ get_crosstab_tuplestore(char *sql,
|
|||
crosstab_HashTableLookup(catname, catdesc);
|
||||
|
||||
if (catdesc)
|
||||
values[catdesc->attidx + ncols - 2] =
|
||||
values[catdesc->attidx + ncols - 2] =
|
||||
SPI_getvalue(spi_tuple, spi_tupdesc, ncols);
|
||||
}
|
||||
|
||||
|
@ -1026,29 +1032,29 @@ get_crosstab_tuplestore(char *sql,
|
|||
*
|
||||
* keyid parent_keyid pos
|
||||
* ------+------------+--
|
||||
* row1 NULL 0
|
||||
* row2 row1 0
|
||||
* row3 row1 0
|
||||
* row4 row2 1
|
||||
* row5 row2 0
|
||||
* row6 row4 0
|
||||
* row7 row3 0
|
||||
* row8 row6 0
|
||||
* row9 row5 0
|
||||
* row1 NULL 0
|
||||
* row2 row1 0
|
||||
* row3 row1 0
|
||||
* row4 row2 1
|
||||
* row5 row2 0
|
||||
* row6 row4 0
|
||||
* row7 row3 0
|
||||
* row8 row6 0
|
||||
* row9 row5 0
|
||||
*
|
||||
*
|
||||
* connectby(text relname, text keyid_fld, text parent_keyid_fld
|
||||
* [, text orderby_fld], text start_with, int max_depth
|
||||
* [, text branch_delim])
|
||||
* [, text orderby_fld], text start_with, int max_depth
|
||||
* [, text branch_delim])
|
||||
* 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
|
||||
* row5 row2 1 row2~row5 2
|
||||
* row9 row5 2 row2~row5~row9 3
|
||||
* row4 row2 1 row2~row4 4
|
||||
* row6 row4 2 row2~row4~row6 5
|
||||
* row2 NULL 0 row2 1
|
||||
* row5 row2 1 row2~row5 2
|
||||
* row9 row5 2 row2~row5~row9 3
|
||||
* row4 row2 1 row2~row4 4
|
||||
* row6 row4 2 row2~row4~row6 5
|
||||
* row8 row6 3 row2~row4~row6~row8 6
|
||||
*
|
||||
*/
|
||||
|
@ -1114,7 +1120,7 @@ connectby_text(PG_FUNCTION_ARGS)
|
|||
rsinfo->setResult = connectby(relname,
|
||||
key_fld,
|
||||
parent_key_fld,
|
||||
NULL,
|
||||
NULL,
|
||||
branch_delim,
|
||||
start_with,
|
||||
max_depth,
|
||||
|
@ -1149,7 +1155,7 @@ connectby_text_serial(PG_FUNCTION_ARGS)
|
|||
char *branch_delim = NULL;
|
||||
bool show_branch = false;
|
||||
bool show_serial = true;
|
||||
|
||||
|
||||
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
|
||||
TupleDesc tupdesc;
|
||||
AttInMetadata *attinmeta;
|
||||
|
@ -1192,7 +1198,7 @@ connectby_text_serial(PG_FUNCTION_ARGS)
|
|||
rsinfo->setResult = connectby(relname,
|
||||
key_fld,
|
||||
parent_key_fld,
|
||||
orderby_fld,
|
||||
orderby_fld,
|
||||
branch_delim,
|
||||
start_with,
|
||||
max_depth,
|
||||
|
@ -1222,12 +1228,12 @@ static Tuplestorestate *
|
|||
connectby(char *relname,
|
||||
char *key_fld,
|
||||
char *parent_key_fld,
|
||||
char *orderby_fld,
|
||||
char *orderby_fld,
|
||||
char *branch_delim,
|
||||
char *start_with,
|
||||
int max_depth,
|
||||
bool show_branch,
|
||||
bool show_serial,
|
||||
bool show_serial,
|
||||
MemoryContext per_query_ctx,
|
||||
AttInMetadata *attinmeta)
|
||||
{
|
||||
|
@ -1235,7 +1241,7 @@ connectby(char *relname,
|
|||
int ret;
|
||||
MemoryContext oldcontext;
|
||||
|
||||
int serial = 1;
|
||||
int serial = 1;
|
||||
|
||||
/* Connect to SPI manager */
|
||||
if ((ret = SPI_connect()) < 0)
|
||||
|
@ -1303,25 +1309,25 @@ build_tuplestore_recursively(char *key_fld,
|
|||
if (!show_serial)
|
||||
{
|
||||
appendStringInfo(sql, "SELECT %s, %s FROM %s WHERE %s = '%s' AND %s IS NOT NULL",
|
||||
key_fld,
|
||||
parent_key_fld,
|
||||
relname,
|
||||
parent_key_fld,
|
||||
start_with,
|
||||
key_fld);
|
||||
serial_column=0;
|
||||
key_fld,
|
||||
parent_key_fld,
|
||||
relname,
|
||||
parent_key_fld,
|
||||
start_with,
|
||||
key_fld);
|
||||
serial_column = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
appendStringInfo(sql, "SELECT %s, %s FROM %s WHERE %s = '%s' AND %s IS NOT NULL ORDER BY %s",
|
||||
key_fld,
|
||||
parent_key_fld,
|
||||
relname,
|
||||
parent_key_fld,
|
||||
start_with,
|
||||
key_fld,
|
||||
orderby_fld);
|
||||
serial_column=1;
|
||||
key_fld,
|
||||
parent_key_fld,
|
||||
relname,
|
||||
parent_key_fld,
|
||||
start_with,
|
||||
key_fld,
|
||||
orderby_fld);
|
||||
serial_column = 1;
|
||||
}
|
||||
|
||||
/* Retrieve the desired rows */
|
||||
|
@ -1371,8 +1377,8 @@ build_tuplestore_recursively(char *key_fld,
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("invalid return type"),
|
||||
errdetail("Return and SQL tuple descriptions are " \
|
||||
"incompatible.")));
|
||||
errdetail("Return and SQL tuple descriptions are " \
|
||||
"incompatible.")));
|
||||
|
||||
/* root value is the one we initially start with */
|
||||
values[0] = start_with;
|
||||
|
@ -1395,7 +1401,7 @@ build_tuplestore_recursively(char *key_fld,
|
|||
if (show_branch)
|
||||
values[4] = serial_str;
|
||||
else
|
||||
values[3] = serial_str;
|
||||
values[3] = serial_str;
|
||||
}
|
||||
|
||||
/* construct the tuple */
|
||||
|
@ -1508,11 +1514,11 @@ build_tuplestore_recursively(char *key_fld,
|
|||
static void
|
||||
validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial)
|
||||
{
|
||||
int serial_column=0;
|
||||
int serial_column = 0;
|
||||
|
||||
if (show_serial)
|
||||
serial_column=1;
|
||||
|
||||
serial_column = 1;
|
||||
|
||||
/* are there the correct number of columns */
|
||||
if (show_branch)
|
||||
{
|
||||
|
@ -1546,7 +1552,7 @@ validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial
|
|||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("invalid return type"),
|
||||
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 */
|
||||
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),
|
||||
errmsg("invalid return type"),
|
||||
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 */
|
||||
if (show_branch && show_serial && tupdesc->attrs[4]->atttypid != INT4OID)
|
||||
|
@ -1565,7 +1571,7 @@ validateConnectbyTupleDesc(TupleDesc tupdesc, bool show_branch, bool show_serial
|
|||
if (!show_branch && show_serial && tupdesc->attrs[3]->atttypid != INT4OID)
|
||||
elog(ERROR, "Query-specified return tuple not valid for Connectby: "
|
||||
"fourth column must be type %s", format_type_be(INT4OID));
|
||||
|
||||
|
||||
/* OK, the tupdesc is valid for our purposes */
|
||||
}
|
||||
|
||||
|
@ -1596,7 +1602,7 @@ compatConnectbyTupleDescs(TupleDesc ret_tupdesc, TupleDesc sql_tupdesc)
|
|||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("invalid return type"),
|
||||
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 */
|
||||
return true;
|
||||
|
|
|
@ -51,7 +51,8 @@ DICT dicts[] = {
|
|||
#undef DICT_TABLE
|
||||
|
||||
/* array for storing dictionary's objects (if needed) */
|
||||
void *dictobjs[lengthof(dicts)];
|
||||
void *dictobjs[
|
||||
lengthof(dicts)];
|
||||
|
||||
#define STOPLEXEM -2
|
||||
#define BYLOCALE -1
|
||||
|
@ -175,7 +176,7 @@ lemmatize(char *word, int *len, int type)
|
|||
}
|
||||
else if (nd == BYLOCALE)
|
||||
{
|
||||
continue; /* no dict for current locale */
|
||||
continue; /* no dict for current locale */
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -4,80 +4,99 @@
|
|||
#include "ts_cfg.h"
|
||||
#include "dict.h"
|
||||
|
||||
text*
|
||||
char2text(char* in) {
|
||||
text *
|
||||
char2text(char *in)
|
||||
{
|
||||
return charl2text(in, strlen(in));
|
||||
}
|
||||
|
||||
text* charl2text(char* in, int len) {
|
||||
text *out=(text*)palloc(len+VARHDRSZ);
|
||||
text *
|
||||
charl2text(char *in, int len)
|
||||
{
|
||||
text *out = (text *) palloc(len + VARHDRSZ);
|
||||
|
||||
memcpy(VARDATA(out), in, len);
|
||||
VARATT_SIZEP(out) = len+VARHDRSZ;
|
||||
VARATT_SIZEP(out) = len + VARHDRSZ;
|
||||
return out;
|
||||
}
|
||||
|
||||
char
|
||||
*text2char(text* in) {
|
||||
char *out=palloc( VARSIZE(in) );
|
||||
memcpy(out, VARDATA(in), VARSIZE(in)-VARHDRSZ);
|
||||
out[ VARSIZE(in)-VARHDRSZ ] ='\0';
|
||||
char
|
||||
*
|
||||
text2char(text *in)
|
||||
{
|
||||
char *out = palloc(VARSIZE(in));
|
||||
|
||||
memcpy(out, VARDATA(in), VARSIZE(in) - VARHDRSZ);
|
||||
out[VARSIZE(in) - VARHDRSZ] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
char
|
||||
*pnstrdup(char* in, int len) {
|
||||
char *out=palloc( len+1 );
|
||||
char
|
||||
*
|
||||
pnstrdup(char *in, int len)
|
||||
{
|
||||
char *out = palloc(len + 1);
|
||||
|
||||
memcpy(out, in, len);
|
||||
out[len]='\0';
|
||||
out[len] = '\0';
|
||||
return out;
|
||||
}
|
||||
|
||||
text
|
||||
*ptextdup(text* in) {
|
||||
text *out=(text*)palloc( VARSIZE(in) );
|
||||
memcpy(out,in,VARSIZE(in));
|
||||
text
|
||||
*
|
||||
ptextdup(text *in)
|
||||
{
|
||||
text *out = (text *) palloc(VARSIZE(in));
|
||||
|
||||
memcpy(out, in, VARSIZE(in));
|
||||
return out;
|
||||
}
|
||||
|
||||
text
|
||||
*mtextdup(text* in) {
|
||||
text *out=(text*)malloc( VARSIZE(in) );
|
||||
if ( !out )
|
||||
text
|
||||
*
|
||||
mtextdup(text *in)
|
||||
{
|
||||
text *out = (text *) malloc(VARSIZE(in));
|
||||
|
||||
if (!out)
|
||||
ts_error(ERROR, "No memory");
|
||||
memcpy(out,in,VARSIZE(in));
|
||||
memcpy(out, in, VARSIZE(in));
|
||||
return out;
|
||||
}
|
||||
|
||||
void
|
||||
ts_error(int state, const char *format, ...) {
|
||||
va_list args;
|
||||
int tlen = 128, len=0;
|
||||
char *buf;
|
||||
|
||||
void
|
||||
ts_error(int state, const char *format,...)
|
||||
{
|
||||
va_list args;
|
||||
int tlen = 128,
|
||||
len = 0;
|
||||
char *buf;
|
||||
|
||||
reset_cfg();
|
||||
reset_dict();
|
||||
reset_prs();
|
||||
|
||||
va_start(args, format);
|
||||
buf = palloc(tlen);
|
||||
len = vsnprintf(buf, tlen-1, format, args);
|
||||
if ( len >= tlen ) {
|
||||
tlen=len+1;
|
||||
buf = repalloc( buf, tlen );
|
||||
vsnprintf(buf, tlen-1, format, args);
|
||||
len = vsnprintf(buf, tlen - 1, format, args);
|
||||
if (len >= tlen)
|
||||
{
|
||||
tlen = len + 1;
|
||||
buf = repalloc(buf, tlen);
|
||||
vsnprintf(buf, tlen - 1, format, args);
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
|
||||
/* ?? internal error ?? */
|
||||
elog(state, "%s", buf);
|
||||
pfree(buf);
|
||||
}
|
||||
|
||||
int
|
||||
text_cmp(text *a, text *b) {
|
||||
if ( VARSIZE(a) == VARSIZE(b) )
|
||||
return strncmp( VARDATA(a), VARDATA(b), VARSIZE(a)-VARHDRSZ );
|
||||
return (int)VARSIZE(a) - (int)VARSIZE(b);
|
||||
int
|
||||
text_cmp(text *a, text *b)
|
||||
{
|
||||
if (VARSIZE(a) == VARSIZE(b))
|
||||
return strncmp(VARDATA(a), VARDATA(b), VARSIZE(a) - VARHDRSZ);
|
||||
return (int) VARSIZE(a) - (int) VARSIZE(b);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -7,18 +7,18 @@
|
|||
#define PG_NARGS() (fcinfo->nargs)
|
||||
#endif
|
||||
|
||||
text* char2text(char* in);
|
||||
text* charl2text(char* in, int len);
|
||||
char *text2char(text* in);
|
||||
char *pnstrdup(char* in, int len);
|
||||
text *ptextdup(text* in);
|
||||
text *mtextdup(text* in);
|
||||
text *char2text(char *in);
|
||||
text *charl2text(char *in, int len);
|
||||
char *text2char(text *in);
|
||||
char *pnstrdup(char *in, int len);
|
||||
text *ptextdup(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 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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* interface functions to dictionary
|
||||
/*
|
||||
* interface functions to dictionary
|
||||
* Teodor Sigaev <teodor@sigaev.ru>
|
||||
*/
|
||||
#include <errno.h>
|
||||
|
@ -19,260 +19,285 @@
|
|||
|
||||
/*********top interface**********/
|
||||
|
||||
static void *plan_getdict=NULL;
|
||||
static void *plan_getdict = NULL;
|
||||
|
||||
void
|
||||
init_dict(Oid id, DictInfo *dict) {
|
||||
Oid arg[1]={ OIDOID };
|
||||
bool isnull;
|
||||
Datum pars[1]={ ObjectIdGetDatum(id) };
|
||||
int stat;
|
||||
init_dict(Oid id, DictInfo * dict)
|
||||
{
|
||||
Oid arg[1] = {OIDOID};
|
||||
bool isnull;
|
||||
Datum pars[1] = {ObjectIdGetDatum(id)};
|
||||
int stat;
|
||||
|
||||
memset(dict,0,sizeof(DictInfo));
|
||||
memset(dict, 0, sizeof(DictInfo));
|
||||
SPI_connect();
|
||||
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 )
|
||||
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");
|
||||
}
|
||||
|
||||
stat = SPI_execp(plan_getdict, pars, " ", 1);
|
||||
if ( stat < 0 )
|
||||
ts_error (ERROR, "SPI_execp return %d", stat);
|
||||
if ( SPI_processed > 0 ) {
|
||||
Datum opt;
|
||||
Oid oid=InvalidOid;
|
||||
oid=DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) );
|
||||
if ( !(isnull || oid==InvalidOid) ) {
|
||||
opt=SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 2, &isnull);
|
||||
dict->dictionary=(void*)DatumGetPointer(OidFunctionCall1(oid, opt));
|
||||
if (stat < 0)
|
||||
ts_error(ERROR, "SPI_execp return %d", stat);
|
||||
if (SPI_processed > 0)
|
||||
{
|
||||
Datum opt;
|
||||
Oid oid = InvalidOid;
|
||||
|
||||
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
||||
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) );
|
||||
if ( isnull || oid==InvalidOid )
|
||||
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 3, &isnull));
|
||||
if (isnull || oid == InvalidOid)
|
||||
ts_error(ERROR, "Null dict_lexize for dictonary %d", id);
|
||||
fmgr_info_cxt(oid, &(dict->lexize_info), TopMemoryContext);
|
||||
dict->dict_id=id;
|
||||
} else
|
||||
dict->dict_id = id;
|
||||
}
|
||||
else
|
||||
ts_error(ERROR, "No dictionary with id %d", id);
|
||||
SPI_finish();
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
DictInfo *last_dict;
|
||||
int len;
|
||||
int reallen;
|
||||
DictInfo *list;
|
||||
typedef struct
|
||||
{
|
||||
DictInfo *last_dict;
|
||||
int len;
|
||||
int reallen;
|
||||
DictInfo *list;
|
||||
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
|
||||
reset_dict(void) {
|
||||
freeSNMap( &(DList.name2id_map) );
|
||||
reset_dict(void)
|
||||
{
|
||||
freeSNMap(&(DList.name2id_map));
|
||||
/* XXX need to free DList.list[*].dictionary */
|
||||
if ( DList.list )
|
||||
if (DList.list)
|
||||
free(DList.list);
|
||||
memset(&DList,0,sizeof(DictList));
|
||||
memset(&DList, 0, sizeof(DictList));
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
comparedict(const void *a, const void *b) {
|
||||
return ((DictInfo*)a)->dict_id - ((DictInfo*)b)->dict_id;
|
||||
comparedict(const void *a, const void *b)
|
||||
{
|
||||
return ((DictInfo *) a)->dict_id - ((DictInfo *) b)->dict_id;
|
||||
}
|
||||
|
||||
DictInfo *
|
||||
finddict(Oid id) {
|
||||
finddict(Oid id)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
|
||||
/* already used dict */
|
||||
if ( DList.len != 0 ) {
|
||||
DictInfo key;
|
||||
key.dict_id=id;
|
||||
if (DList.len != 0)
|
||||
{
|
||||
DictInfo key;
|
||||
|
||||
key.dict_id = id;
|
||||
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;
|
||||
}
|
||||
|
||||
/* last chance */
|
||||
if ( DList.len==DList.reallen ) {
|
||||
DictInfo *tmp;
|
||||
int reallen = ( DList.reallen ) ? 2*DList.reallen : 16;
|
||||
tmp=(DictInfo*)realloc(DList.list,sizeof(DictInfo)*reallen);
|
||||
if ( !tmp )
|
||||
ts_error(ERROR,"No memory");
|
||||
DList.reallen=reallen;
|
||||
DList.list=tmp;
|
||||
if (DList.len == DList.reallen)
|
||||
{
|
||||
DictInfo *tmp;
|
||||
int reallen = (DList.reallen) ? 2 * DList.reallen : 16;
|
||||
|
||||
tmp = (DictInfo *) realloc(DList.list, sizeof(DictInfo) * reallen);
|
||||
if (!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);
|
||||
|
||||
DList.len++;
|
||||
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
|
||||
name2id_dict(text *name) {
|
||||
Oid arg[1]={ TEXTOID };
|
||||
bool isnull;
|
||||
Datum pars[1]={ PointerGetDatum(name) };
|
||||
int stat;
|
||||
Oid id=findSNMap_t( &(DList.name2id_map), name );
|
||||
name2id_dict(text *name)
|
||||
{
|
||||
Oid arg[1] = {TEXTOID};
|
||||
bool isnull;
|
||||
Datum pars[1] = {PointerGetDatum(name)};
|
||||
int stat;
|
||||
Oid id = findSNMap_t(&(DList.name2id_map), name);
|
||||
|
||||
if ( id )
|
||||
if (id)
|
||||
return id;
|
||||
|
||||
|
||||
SPI_connect();
|
||||
if ( !plan_name2id ) {
|
||||
plan_name2id = SPI_saveplan( SPI_prepare( "select oid from pg_ts_dict where dict_name = $1" , 1, arg ) );
|
||||
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)
|
||||
ts_error(ERROR, "SPI_prepare() failed");
|
||||
}
|
||||
|
||||
stat = SPI_execp(plan_name2id, pars, " ", 1);
|
||||
if ( stat < 0 )
|
||||
ts_error (ERROR, "SPI_execp return %d", stat);
|
||||
if ( SPI_processed > 0 )
|
||||
id=DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) );
|
||||
else
|
||||
if (stat < 0)
|
||||
ts_error(ERROR, "SPI_execp return %d", stat);
|
||||
if (SPI_processed > 0)
|
||||
id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
||||
else
|
||||
ts_error(ERROR, "No dictionary with name '%s'", text2char(name));
|
||||
SPI_finish();
|
||||
addSNMap_t( &(DList.name2id_map), name, id );
|
||||
addSNMap_t(&(DList.name2id_map), name, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
/******sql-level interface******/
|
||||
PG_FUNCTION_INFO_V1(lexize);
|
||||
Datum lexize(PG_FUNCTION_ARGS);
|
||||
Datum lexize(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum
|
||||
lexize(PG_FUNCTION_ARGS) {
|
||||
text *in=PG_GETARG_TEXT_P(1);
|
||||
DictInfo *dict = finddict( PG_GETARG_OID(0) );
|
||||
char **res, **ptr;
|
||||
Datum *da;
|
||||
ArrayType *a;
|
||||
lexize(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *in = PG_GETARG_TEXT_P(1);
|
||||
DictInfo *dict = finddict(PG_GETARG_OID(0));
|
||||
char **res,
|
||||
**ptr;
|
||||
Datum *da;
|
||||
ArrayType *a;
|
||||
|
||||
|
||||
ptr = res = (char**)DatumGetPointer(
|
||||
FunctionCall3(&(dict->lexize_info),
|
||||
PointerGetDatum(dict->dictionary),
|
||||
PointerGetDatum(VARDATA(in)),
|
||||
Int32GetDatum(VARSIZE(in)-VARHDRSZ)
|
||||
)
|
||||
);
|
||||
ptr = res = (char **) DatumGetPointer(
|
||||
FunctionCall3(&(dict->lexize_info),
|
||||
PointerGetDatum(dict->dictionary),
|
||||
PointerGetDatum(VARDATA(in)),
|
||||
Int32GetDatum(VARSIZE(in) - VARHDRSZ)
|
||||
)
|
||||
);
|
||||
PG_FREE_IF_COPY(in, 1);
|
||||
if ( !res ) {
|
||||
if (PG_NARGS() > 2)
|
||||
if (!res)
|
||||
{
|
||||
if (PG_NARGS() > 2)
|
||||
PG_RETURN_POINTER(NULL);
|
||||
else
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
while(*ptr) ptr++;
|
||||
da = (Datum*)palloc(sizeof(Datum)*(ptr-res+1));
|
||||
ptr=res;
|
||||
while(*ptr) {
|
||||
da[ ptr-res ] = PointerGetDatum( char2text(*ptr) );
|
||||
while (*ptr)
|
||||
ptr++;
|
||||
da = (Datum *) palloc(sizeof(Datum) * (ptr - res + 1));
|
||||
ptr = res;
|
||||
while (*ptr)
|
||||
{
|
||||
da[ptr - res] = PointerGetDatum(char2text(*ptr));
|
||||
ptr++;
|
||||
}
|
||||
|
||||
a = construct_array(
|
||||
da,
|
||||
ptr-res,
|
||||
TEXTOID,
|
||||
-1,
|
||||
false,
|
||||
'i'
|
||||
);
|
||||
da,
|
||||
ptr - res,
|
||||
TEXTOID,
|
||||
-1,
|
||||
false,
|
||||
'i'
|
||||
);
|
||||
|
||||
ptr=res;
|
||||
while(*ptr) {
|
||||
pfree( DatumGetPointer(da[ ptr-res ]) );
|
||||
pfree( *ptr );
|
||||
ptr = res;
|
||||
while (*ptr)
|
||||
{
|
||||
pfree(DatumGetPointer(da[ptr - res]));
|
||||
pfree(*ptr);
|
||||
ptr++;
|
||||
}
|
||||
pfree(res);
|
||||
pfree(da);
|
||||
|
||||
PG_RETURN_POINTER(a);
|
||||
|
||||
PG_RETURN_POINTER(a);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(lexize_byname);
|
||||
Datum lexize_byname(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
lexize_byname(PG_FUNCTION_ARGS) {
|
||||
text *dictname=PG_GETARG_TEXT_P(0);
|
||||
Datum res;
|
||||
Datum lexize_byname(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
lexize_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *dictname = PG_GETARG_TEXT_P(0);
|
||||
Datum res;
|
||||
|
||||
strdup("simple");
|
||||
res=DirectFunctionCall3(
|
||||
lexize,
|
||||
ObjectIdGetDatum(name2id_dict(dictname)),
|
||||
PG_GETARG_DATUM(1),
|
||||
(Datum)0
|
||||
);
|
||||
res = DirectFunctionCall3(
|
||||
lexize,
|
||||
ObjectIdGetDatum(name2id_dict(dictname)),
|
||||
PG_GETARG_DATUM(1),
|
||||
(Datum) 0
|
||||
);
|
||||
PG_FREE_IF_COPY(dictname, 0);
|
||||
if (res)
|
||||
PG_RETURN_DATUM(res);
|
||||
else
|
||||
if (res)
|
||||
PG_RETURN_DATUM(res);
|
||||
else
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
static Oid currect_dictionary_id=0;
|
||||
static Oid currect_dictionary_id = 0;
|
||||
|
||||
PG_FUNCTION_INFO_V1(set_curdict);
|
||||
Datum set_curdict(PG_FUNCTION_ARGS);
|
||||
Datum set_curdict(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
set_curdict(PG_FUNCTION_ARGS) {
|
||||
set_curdict(PG_FUNCTION_ARGS)
|
||||
{
|
||||
finddict(PG_GETARG_OID(0));
|
||||
currect_dictionary_id=PG_GETARG_OID(0);
|
||||
currect_dictionary_id = PG_GETARG_OID(0);
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(set_curdict_byname);
|
||||
Datum set_curdict_byname(PG_FUNCTION_ARGS);
|
||||
Datum set_curdict_byname(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
set_curdict_byname(PG_FUNCTION_ARGS) {
|
||||
text *dictname=PG_GETARG_TEXT_P(0);
|
||||
set_curdict_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *dictname = PG_GETARG_TEXT_P(0);
|
||||
|
||||
DirectFunctionCall1(
|
||||
set_curdict,
|
||||
ObjectIdGetDatum( name2id_dict(dictname) )
|
||||
);
|
||||
set_curdict,
|
||||
ObjectIdGetDatum(name2id_dict(dictname))
|
||||
);
|
||||
PG_FREE_IF_COPY(dictname, 0);
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(lexize_bycurrent);
|
||||
Datum lexize_bycurrent(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
lexize_bycurrent(PG_FUNCTION_ARGS) {
|
||||
Datum res;
|
||||
if ( currect_dictionary_id == 0 )
|
||||
Datum lexize_bycurrent(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
lexize_bycurrent(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum res;
|
||||
|
||||
if (currect_dictionary_id == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("no currect dictionary"),
|
||||
errhint("Execute select set_curdict().")));
|
||||
|
||||
res = DirectFunctionCall3(
|
||||
lexize,
|
||||
ObjectIdGetDatum(currect_dictionary_id),
|
||||
PG_GETARG_DATUM(0),
|
||||
(Datum)0
|
||||
);
|
||||
if (res)
|
||||
lexize,
|
||||
ObjectIdGetDatum(currect_dictionary_id),
|
||||
PG_GETARG_DATUM(0),
|
||||
(Datum) 0
|
||||
);
|
||||
if (res)
|
||||
PG_RETURN_DATUM(res);
|
||||
else
|
||||
else
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,36 +3,39 @@
|
|||
#include "postgres.h"
|
||||
#include "fmgr.h"
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
char **stop;
|
||||
char* (*wordop)(char*);
|
||||
} StopList;
|
||||
typedef struct
|
||||
{
|
||||
int len;
|
||||
char **stop;
|
||||
char *(*wordop) (char *);
|
||||
} StopList;
|
||||
|
||||
void sortstoplist(StopList *s);
|
||||
void freestoplist(StopList *s);
|
||||
void readstoplist(text *in, StopList *s);
|
||||
bool searchstoplist(StopList *s, char *key);
|
||||
char* lowerstr(char *str);
|
||||
void sortstoplist(StopList * s);
|
||||
void freestoplist(StopList * s);
|
||||
void readstoplist(text *in, StopList * s);
|
||||
bool searchstoplist(StopList * s, char *key);
|
||||
char *lowerstr(char *str);
|
||||
|
||||
typedef struct {
|
||||
Oid dict_id;
|
||||
FmgrInfo lexize_info;
|
||||
void *dictionary;
|
||||
} DictInfo;
|
||||
typedef struct
|
||||
{
|
||||
Oid dict_id;
|
||||
FmgrInfo lexize_info;
|
||||
void *dictionary;
|
||||
} DictInfo;
|
||||
|
||||
void init_dict(Oid id, DictInfo *dict);
|
||||
DictInfo* finddict(Oid id);
|
||||
Oid name2id_dict(text *name);
|
||||
void reset_dict(void);
|
||||
void init_dict(Oid id, DictInfo * dict);
|
||||
DictInfo *finddict(Oid id);
|
||||
Oid name2id_dict(text *name);
|
||||
void reset_dict(void);
|
||||
|
||||
|
||||
/* simple parser of cfg string */
|
||||
typedef struct {
|
||||
char *key;
|
||||
char *value;
|
||||
} Map;
|
||||
typedef struct
|
||||
{
|
||||
char *key;
|
||||
char *value;
|
||||
} Map;
|
||||
|
||||
void parse_cfgdict(text *in, Map **m);
|
||||
void parse_cfgdict(text *in, Map ** m);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* example of dictionary
|
||||
/*
|
||||
* example of dictionary
|
||||
* Teodor Sigaev <teodor@sigaev.ru>
|
||||
*/
|
||||
#include <errno.h>
|
||||
|
@ -11,30 +11,35 @@
|
|||
#include "dict.h"
|
||||
#include "common.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
StopList stoplist;
|
||||
} DictExample;
|
||||
} DictExample;
|
||||
|
||||
|
||||
PG_FUNCTION_INFO_V1(dex_init);
|
||||
Datum dex_init(PG_FUNCTION_ARGS);
|
||||
Datum dex_init(PG_FUNCTION_ARGS);
|
||||
|
||||
PG_FUNCTION_INFO_V1(dex_lexize);
|
||||
Datum dex_lexize(PG_FUNCTION_ARGS);
|
||||
Datum dex_lexize(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum
|
||||
dex_init(PG_FUNCTION_ARGS) {
|
||||
DictExample *d = (DictExample*)malloc( sizeof(DictExample) );
|
||||
Datum
|
||||
dex_init(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DictExample *d = (DictExample *) malloc(sizeof(DictExample));
|
||||
|
||||
if ( !d )
|
||||
if (!d)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
memset(d,0,sizeof(DictExample));
|
||||
memset(d, 0, sizeof(DictExample));
|
||||
|
||||
d->stoplist.wordop = lowerstr;
|
||||
|
||||
if (!PG_ARGISNULL(0) && PG_GETARG_POINTER(0) != NULL)
|
||||
{
|
||||
text *in = PG_GETARG_TEXT_P(0);
|
||||
|
||||
d->stoplist.wordop=lowerstr;
|
||||
|
||||
if ( !PG_ARGISNULL(0) && PG_GETARG_POINTER(0)!=NULL ) {
|
||||
text *in = PG_GETARG_TEXT_P(0);
|
||||
readstoplist(in, &(d->stoplist));
|
||||
sortstoplist(&(d->stoplist));
|
||||
PG_FREE_IF_COPY(in, 0);
|
||||
|
@ -44,18 +49,21 @@ dex_init(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
Datum
|
||||
dex_lexize(PG_FUNCTION_ARGS) {
|
||||
DictExample *d = (DictExample*)PG_GETARG_POINTER(0);
|
||||
char *in = (char*)PG_GETARG_POINTER(1);
|
||||
char *txt = pnstrdup(in, PG_GETARG_INT32(2));
|
||||
char **res=palloc(sizeof(char*)*2);
|
||||
dex_lexize(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DictExample *d = (DictExample *) PG_GETARG_POINTER(0);
|
||||
char *in = (char *) PG_GETARG_POINTER(1);
|
||||
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);
|
||||
res[0]=NULL;
|
||||
} else
|
||||
res[0]=txt;
|
||||
res[1]=NULL;
|
||||
res[0] = NULL;
|
||||
}
|
||||
else
|
||||
res[0] = txt;
|
||||
res[1] = NULL;
|
||||
|
||||
PG_RETURN_POINTER(res);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* ISpell interface
|
||||
* Teodor Sigaev <teodor@sigaev.ru>
|
||||
*/
|
||||
|
@ -12,96 +12,117 @@
|
|||
#include "common.h"
|
||||
#include "ispell/spell.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
StopList stoplist;
|
||||
IspellDict obj;
|
||||
} DictISpell;
|
||||
} DictISpell;
|
||||
|
||||
PG_FUNCTION_INFO_V1(spell_init);
|
||||
Datum spell_init(PG_FUNCTION_ARGS);
|
||||
Datum spell_init(PG_FUNCTION_ARGS);
|
||||
|
||||
PG_FUNCTION_INFO_V1(spell_lexize);
|
||||
Datum spell_lexize(PG_FUNCTION_ARGS);
|
||||
Datum spell_lexize(PG_FUNCTION_ARGS);
|
||||
|
||||
static void
|
||||
freeDictISpell(DictISpell *d) {
|
||||
freeDictISpell(DictISpell * d)
|
||||
{
|
||||
FreeIspell(&(d->obj));
|
||||
freestoplist(&(d->stoplist));
|
||||
free(d);
|
||||
}
|
||||
|
||||
Datum
|
||||
spell_init(PG_FUNCTION_ARGS) {
|
||||
DictISpell *d;
|
||||
Map *cfg, *pcfg;
|
||||
text *in;
|
||||
bool affloaded=false, dictloaded=false, stoploaded=false;
|
||||
Datum
|
||||
spell_init(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DictISpell *d;
|
||||
Map *cfg,
|
||||
*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,
|
||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||
errmsg("ISpell confguration error")));
|
||||
|
||||
d = (DictISpell*)malloc( sizeof(DictISpell) );
|
||||
if ( !d )
|
||||
|
||||
d = (DictISpell *) malloc(sizeof(DictISpell));
|
||||
if (!d)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
memset(d,0,sizeof(DictISpell));
|
||||
d->stoplist.wordop=lowerstr;
|
||||
memset(d, 0, sizeof(DictISpell));
|
||||
d->stoplist.wordop = lowerstr;
|
||||
|
||||
in = PG_GETARG_TEXT_P(0);
|
||||
parse_cfgdict(in,&cfg);
|
||||
parse_cfgdict(in, &cfg);
|
||||
PG_FREE_IF_COPY(in, 0);
|
||||
pcfg=cfg;
|
||||
while(pcfg->key) {
|
||||
if ( strcasecmp("DictFile", pcfg->key) == 0 ) {
|
||||
if ( dictloaded ) {
|
||||
pcfg = cfg;
|
||||
while (pcfg->key)
|
||||
{
|
||||
if (strcasecmp("DictFile", pcfg->key) == 0)
|
||||
{
|
||||
if (dictloaded)
|
||||
{
|
||||
freeDictISpell(d);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("dictionary already loaded")));
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("dictionary already loaded")));
|
||||
}
|
||||
if ( ImportDictionary(&(d->obj), pcfg->value) ) {
|
||||
if (ImportDictionary(&(d->obj), pcfg->value))
|
||||
{
|
||||
freeDictISpell(d);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||
errmsg("could not load dictionary file \"%s\"",
|
||||
pcfg->value)));
|
||||
}
|
||||
dictloaded=true;
|
||||
} else if ( strcasecmp("AffFile", pcfg->key) == 0 ) {
|
||||
if ( affloaded ) {
|
||||
dictloaded = true;
|
||||
}
|
||||
else if (strcasecmp("AffFile", pcfg->key) == 0)
|
||||
{
|
||||
if (affloaded)
|
||||
{
|
||||
freeDictISpell(d);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("affixes already loaded")));
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("affixes already loaded")));
|
||||
}
|
||||
if ( ImportAffixes(&(d->obj), pcfg->value) ) {
|
||||
if (ImportAffixes(&(d->obj), pcfg->value))
|
||||
{
|
||||
freeDictISpell(d);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||
errmsg("could not load affix file \"%s\"",
|
||||
pcfg->value)));
|
||||
}
|
||||
affloaded=true;
|
||||
} else if ( strcasecmp("StopFile", pcfg->key) == 0 ) {
|
||||
text *tmp=char2text(pcfg->value);
|
||||
if ( stoploaded ) {
|
||||
affloaded = true;
|
||||
}
|
||||
else if (strcasecmp("StopFile", pcfg->key) == 0)
|
||||
{
|
||||
text *tmp = char2text(pcfg->value);
|
||||
|
||||
if (stoploaded)
|
||||
{
|
||||
freeDictISpell(d);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("stop words already loaded")));
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("stop words already loaded")));
|
||||
}
|
||||
readstoplist(tmp, &(d->stoplist));
|
||||
sortstoplist(&(d->stoplist));
|
||||
pfree(tmp);
|
||||
stoploaded=true;
|
||||
} else {
|
||||
stoploaded = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
freeDictISpell(d);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("unrecognized option: %s => %s",
|
||||
pcfg->key, pcfg->value)));
|
||||
pcfg->key, pcfg->value)));
|
||||
}
|
||||
pfree(pcfg->key);
|
||||
pfree(pcfg->value);
|
||||
|
@ -109,15 +130,20 @@ spell_init(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
pfree(cfg);
|
||||
|
||||
if ( affloaded && dictloaded ) {
|
||||
if (affloaded && dictloaded)
|
||||
{
|
||||
SortDictionary(&(d->obj));
|
||||
SortAffixes(&(d->obj));
|
||||
} else if ( !affloaded ) {
|
||||
}
|
||||
else if (!affloaded)
|
||||
{
|
||||
freeDictISpell(d);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
errmsg("no affixes")));
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
freeDictISpell(d);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||
|
@ -128,37 +154,43 @@ spell_init(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
Datum
|
||||
spell_lexize(PG_FUNCTION_ARGS) {
|
||||
DictISpell *d = (DictISpell*)PG_GETARG_POINTER(0);
|
||||
char *in = (char*)PG_GETARG_POINTER(1);
|
||||
char *txt;
|
||||
char **res;
|
||||
char **ptr, **cptr;
|
||||
spell_lexize(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DictISpell *d = (DictISpell *) PG_GETARG_POINTER(0);
|
||||
char *in = (char *) PG_GETARG_POINTER(1);
|
||||
char *txt;
|
||||
char **res;
|
||||
char **ptr,
|
||||
**cptr;
|
||||
|
||||
if ( !PG_GETARG_INT32(2) )
|
||||
if (!PG_GETARG_INT32(2))
|
||||
PG_RETURN_POINTER(NULL);
|
||||
|
||||
res=palloc(sizeof(char*)*2);
|
||||
res = palloc(sizeof(char *) * 2);
|
||||
txt = pnstrdup(in, PG_GETARG_INT32(2));
|
||||
res=NormalizeWord(&(d->obj), txt);
|
||||
res = NormalizeWord(&(d->obj), txt);
|
||||
pfree(txt);
|
||||
|
||||
if ( res==NULL )
|
||||
if (res == NULL)
|
||||
PG_RETURN_POINTER(NULL);
|
||||
|
||||
ptr=cptr=res;
|
||||
while(*ptr) {
|
||||
if ( searchstoplist(&(d->stoplist),*ptr) ) {
|
||||
ptr = cptr = res;
|
||||
while (*ptr)
|
||||
{
|
||||
if (searchstoplist(&(d->stoplist), *ptr))
|
||||
{
|
||||
pfree(*ptr);
|
||||
*ptr=NULL;
|
||||
*ptr = NULL;
|
||||
ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
*cptr = *ptr;
|
||||
cptr++;
|
||||
ptr++;
|
||||
} else {
|
||||
*cptr=*ptr;
|
||||
cptr++; ptr++;
|
||||
}
|
||||
}
|
||||
*cptr=NULL;
|
||||
*cptr = NULL;
|
||||
|
||||
PG_RETURN_POINTER(res);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
/*
|
||||
* example of Snowball dictionary
|
||||
* http://snowball.tartarus.org/
|
||||
* http://snowball.tartarus.org/
|
||||
* Teodor Sigaev <teodor@sigaev.ru>
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
@ -14,103 +14,118 @@
|
|||
#include "snowball/english_stem.h"
|
||||
#include "snowball/russian_stem.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
struct SN_env *z;
|
||||
StopList stoplist;
|
||||
int (*stem)(struct SN_env * z);
|
||||
} DictSnowball;
|
||||
int (*stem) (struct SN_env * z);
|
||||
} DictSnowball;
|
||||
|
||||
|
||||
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);
|
||||
Datum snb_ru_init(PG_FUNCTION_ARGS);
|
||||
Datum snb_ru_init(PG_FUNCTION_ARGS);
|
||||
|
||||
PG_FUNCTION_INFO_V1(snb_lexize);
|
||||
Datum snb_lexize(PG_FUNCTION_ARGS);
|
||||
Datum snb_lexize(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum
|
||||
snb_en_init(PG_FUNCTION_ARGS) {
|
||||
DictSnowball *d = (DictSnowball*)malloc( sizeof(DictSnowball) );
|
||||
Datum
|
||||
snb_en_init(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DictSnowball *d = (DictSnowball *) malloc(sizeof(DictSnowball));
|
||||
|
||||
if ( !d )
|
||||
if (!d)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
memset(d,0,sizeof(DictSnowball));
|
||||
d->stoplist.wordop=lowerstr;
|
||||
|
||||
if ( !PG_ARGISNULL(0) && PG_GETARG_POINTER(0)!=NULL ) {
|
||||
text *in = PG_GETARG_TEXT_P(0);
|
||||
memset(d, 0, sizeof(DictSnowball));
|
||||
d->stoplist.wordop = lowerstr;
|
||||
|
||||
if (!PG_ARGISNULL(0) && PG_GETARG_POINTER(0) != NULL)
|
||||
{
|
||||
text *in = PG_GETARG_TEXT_P(0);
|
||||
|
||||
readstoplist(in, &(d->stoplist));
|
||||
sortstoplist(&(d->stoplist));
|
||||
PG_FREE_IF_COPY(in, 0);
|
||||
}
|
||||
|
||||
d->z = english_create_env();
|
||||
if (!d->z) {
|
||||
if (!d->z)
|
||||
{
|
||||
freestoplist(&(d->stoplist));
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
}
|
||||
d->stem=english_stem;
|
||||
d->stem = english_stem;
|
||||
|
||||
PG_RETURN_POINTER(d);
|
||||
}
|
||||
|
||||
Datum
|
||||
snb_ru_init(PG_FUNCTION_ARGS) {
|
||||
DictSnowball *d = (DictSnowball*)malloc( sizeof(DictSnowball) );
|
||||
Datum
|
||||
snb_ru_init(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DictSnowball *d = (DictSnowball *) malloc(sizeof(DictSnowball));
|
||||
|
||||
if ( !d )
|
||||
if (!d)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
memset(d,0,sizeof(DictSnowball));
|
||||
d->stoplist.wordop=lowerstr;
|
||||
|
||||
if ( !PG_ARGISNULL(0) && PG_GETARG_POINTER(0)!=NULL ) {
|
||||
text *in = PG_GETARG_TEXT_P(0);
|
||||
memset(d, 0, sizeof(DictSnowball));
|
||||
d->stoplist.wordop = lowerstr;
|
||||
|
||||
if (!PG_ARGISNULL(0) && PG_GETARG_POINTER(0) != NULL)
|
||||
{
|
||||
text *in = PG_GETARG_TEXT_P(0);
|
||||
|
||||
readstoplist(in, &(d->stoplist));
|
||||
sortstoplist(&(d->stoplist));
|
||||
PG_FREE_IF_COPY(in, 0);
|
||||
}
|
||||
|
||||
d->z = russian_create_env();
|
||||
if (!d->z) {
|
||||
if (!d->z)
|
||||
{
|
||||
freestoplist(&(d->stoplist));
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
}
|
||||
d->stem=russian_stem;
|
||||
d->stem = russian_stem;
|
||||
|
||||
PG_RETURN_POINTER(d);
|
||||
}
|
||||
|
||||
Datum
|
||||
snb_lexize(PG_FUNCTION_ARGS) {
|
||||
DictSnowball *d = (DictSnowball*)PG_GETARG_POINTER(0);
|
||||
char *in = (char*)PG_GETARG_POINTER(1);
|
||||
char *txt = pnstrdup(in, PG_GETARG_INT32(2));
|
||||
char **res=palloc(sizeof(char*)*2);
|
||||
snb_lexize(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DictSnowball *d = (DictSnowball *) PG_GETARG_POINTER(0);
|
||||
char *in = (char *) PG_GETARG_POINTER(1);
|
||||
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);
|
||||
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[0] = NULL;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* ISpell interface
|
||||
* Teodor Sigaev <teodor@sigaev.ru>
|
||||
*/
|
||||
|
@ -13,93 +13,106 @@
|
|||
#include "common.h"
|
||||
|
||||
#define SYNBUFLEN 4096
|
||||
typedef struct {
|
||||
char *in;
|
||||
char *out;
|
||||
} Syn;
|
||||
typedef struct
|
||||
{
|
||||
char *in;
|
||||
char *out;
|
||||
} Syn;
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
Syn *syn;
|
||||
} DictSyn;
|
||||
typedef struct
|
||||
{
|
||||
int len;
|
||||
Syn *syn;
|
||||
} DictSyn;
|
||||
|
||||
PG_FUNCTION_INFO_V1(syn_init);
|
||||
Datum syn_init(PG_FUNCTION_ARGS);
|
||||
Datum syn_init(PG_FUNCTION_ARGS);
|
||||
|
||||
PG_FUNCTION_INFO_V1(syn_lexize);
|
||||
Datum syn_lexize(PG_FUNCTION_ARGS);
|
||||
Datum syn_lexize(PG_FUNCTION_ARGS);
|
||||
|
||||
static char *
|
||||
findwrd(char *in, char **end) {
|
||||
char *start;
|
||||
findwrd(char *in, char **end)
|
||||
{
|
||||
char *start;
|
||||
|
||||
*end=NULL;
|
||||
while(*in && isspace(*in))
|
||||
*end = NULL;
|
||||
while (*in && isspace(*in))
|
||||
in++;
|
||||
|
||||
if ( !in )
|
||||
if (!in)
|
||||
return NULL;
|
||||
start=in;
|
||||
start = in;
|
||||
|
||||
while(*in && !isspace(*in))
|
||||
while (*in && !isspace(*in))
|
||||
in++;
|
||||
|
||||
*end=in;
|
||||
*end = in;
|
||||
return start;
|
||||
}
|
||||
|
||||
static int
|
||||
compareSyn(const void *a, const void *b) {
|
||||
return strcmp( ((Syn*)a)->in, ((Syn*)b)->in );
|
||||
compareSyn(const void *a, const void *b)
|
||||
{
|
||||
return strcmp(((Syn *) a)->in, ((Syn *) b)->in);
|
||||
}
|
||||
|
||||
|
||||
Datum
|
||||
syn_init(PG_FUNCTION_ARGS) {
|
||||
text *in;
|
||||
DictSyn *d;
|
||||
int cur=0;
|
||||
FILE *fin;
|
||||
char *filename;
|
||||
char buf[SYNBUFLEN];
|
||||
char *starti,*starto,*end=NULL;
|
||||
int slen;
|
||||
Datum
|
||||
syn_init(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *in;
|
||||
DictSyn *d;
|
||||
int cur = 0;
|
||||
FILE *fin;
|
||||
char *filename;
|
||||
char buf[SYNBUFLEN];
|
||||
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,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("NULL config")));
|
||||
|
||||
in = PG_GETARG_TEXT_P(0);
|
||||
if ( VARSIZE(in) - VARHDRSZ == 0 )
|
||||
if (VARSIZE(in) - VARHDRSZ == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("VOID config")));
|
||||
|
||||
filename=text2char(in);
|
||||
filename = text2char(in);
|
||||
PG_FREE_IF_COPY(in, 0);
|
||||
if ( (fin=fopen(filename,"r")) == NULL )
|
||||
if ((fin = fopen(filename, "r")) == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not open file \"%s\": %m",
|
||||
filename)));
|
||||
filename)));
|
||||
|
||||
d = (DictSyn*)malloc( sizeof(DictSyn) );
|
||||
if ( !d ) {
|
||||
d = (DictSyn *) malloc(sizeof(DictSyn));
|
||||
if (!d)
|
||||
{
|
||||
fclose(fin);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
}
|
||||
memset(d,0,sizeof(DictSyn));
|
||||
memset(d, 0, sizeof(DictSyn));
|
||||
|
||||
while( fgets(buf,SYNBUFLEN,fin) ) {
|
||||
slen = strlen(buf)-1;
|
||||
while (fgets(buf, SYNBUFLEN, fin))
|
||||
{
|
||||
slen = strlen(buf) - 1;
|
||||
buf[slen] = '\0';
|
||||
if ( *buf=='\0' ) continue;
|
||||
if (cur==d->len) {
|
||||
d->len = (d->len) ? 2*d->len : 16;
|
||||
d->syn=(Syn*)realloc( d->syn, sizeof(Syn)*d->len );
|
||||
if ( !d->syn ) {
|
||||
if (*buf == '\0')
|
||||
continue;
|
||||
if (cur == d->len)
|
||||
{
|
||||
d->len = (d->len) ? 2 * d->len : 16;
|
||||
d->syn = (Syn *) realloc(d->syn, sizeof(Syn) * d->len);
|
||||
if (!d->syn)
|
||||
{
|
||||
fclose(fin);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
|
@ -107,64 +120,66 @@ syn_init(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
}
|
||||
|
||||
starti=findwrd(buf,&end);
|
||||
if ( !starti )
|
||||
starti = findwrd(buf, &end);
|
||||
if (!starti)
|
||||
continue;
|
||||
*end='\0';
|
||||
if ( end >= buf+slen )
|
||||
*end = '\0';
|
||||
if (end >= buf + slen)
|
||||
continue;
|
||||
|
||||
starto= findwrd(end+1, &end);
|
||||
if ( !starto )
|
||||
starto = findwrd(end + 1, &end);
|
||||
if (!starto)
|
||||
continue;
|
||||
*end='\0';
|
||||
*end = '\0';
|
||||
|
||||
d->syn[cur].in=strdup(lowerstr(starti));
|
||||
d->syn[cur].out=strdup(lowerstr(starto));
|
||||
if ( !(d->syn[cur].in && d->syn[cur].out) ) {
|
||||
d->syn[cur].in = strdup(lowerstr(starti));
|
||||
d->syn[cur].out = strdup(lowerstr(starto));
|
||||
if (!(d->syn[cur].in && d->syn[cur].out))
|
||||
{
|
||||
fclose(fin);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
}
|
||||
|
||||
cur++;
|
||||
cur++;
|
||||
}
|
||||
|
||||
fclose(fin);
|
||||
|
||||
d->len=cur;
|
||||
if ( cur>1 )
|
||||
qsort(d->syn, d->len, sizeof(Syn), compareSyn);
|
||||
|
||||
fclose(fin);
|
||||
|
||||
d->len = cur;
|
||||
if (cur > 1)
|
||||
qsort(d->syn, d->len, sizeof(Syn), compareSyn);
|
||||
|
||||
pfree(filename);
|
||||
PG_RETURN_POINTER(d);
|
||||
PG_RETURN_POINTER(d);
|
||||
}
|
||||
|
||||
Datum
|
||||
syn_lexize(PG_FUNCTION_ARGS) {
|
||||
DictSyn *d = (DictSyn*)PG_GETARG_POINTER(0);
|
||||
char *in = (char*)PG_GETARG_POINTER(1);
|
||||
Syn key,*found;
|
||||
char **res=NULL;
|
||||
syn_lexize(PG_FUNCTION_ARGS)
|
||||
{
|
||||
DictSyn *d = (DictSyn *) PG_GETARG_POINTER(0);
|
||||
char *in = (char *) PG_GETARG_POINTER(1);
|
||||
Syn key,
|
||||
*found;
|
||||
char **res = NULL;
|
||||
|
||||
if ( !PG_GETARG_INT32(2) )
|
||||
if (!PG_GETARG_INT32(2))
|
||||
PG_RETURN_POINTER(NULL);
|
||||
|
||||
key.out=NULL;
|
||||
key.in=lowerstr(pnstrdup(in, PG_GETARG_INT32(2)));
|
||||
key.out = NULL;
|
||||
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);
|
||||
|
||||
if ( !found )
|
||||
if (!found)
|
||||
PG_RETURN_POINTER(NULL);
|
||||
|
||||
res=palloc(sizeof(char*)*2);
|
||||
res = palloc(sizeof(char *) * 2);
|
||||
|
||||
res[0]=pstrdup(found->out);
|
||||
res[1]=NULL;
|
||||
res[0] = pstrdup(found->out);
|
||||
res[1] = NULL;
|
||||
|
||||
PG_RETURN_POINTER(res);
|
||||
PG_RETURN_POINTER(res);
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,48 +4,53 @@
|
|||
#include <sys/types.h>
|
||||
#include <regex.h>
|
||||
|
||||
typedef struct spell_struct {
|
||||
char * word;
|
||||
char flag[10];
|
||||
} SPELL;
|
||||
typedef struct spell_struct
|
||||
{
|
||||
char *word;
|
||||
char flag[10];
|
||||
} SPELL;
|
||||
|
||||
typedef struct aff_struct {
|
||||
char flag;
|
||||
char type;
|
||||
char mask[33];
|
||||
char find[16];
|
||||
char repl[16];
|
||||
regex_t reg;
|
||||
size_t replen;
|
||||
char compile;
|
||||
} AFFIX;
|
||||
typedef struct aff_struct
|
||||
{
|
||||
char flag;
|
||||
char type;
|
||||
char mask[33];
|
||||
char find[16];
|
||||
char repl[16];
|
||||
regex_t reg;
|
||||
size_t replen;
|
||||
char compile;
|
||||
} AFFIX;
|
||||
|
||||
typedef struct Tree_struct {
|
||||
int Left[256], Right[256];
|
||||
} Tree_struct;
|
||||
typedef struct Tree_struct
|
||||
{
|
||||
int Left[256],
|
||||
Right[256];
|
||||
} Tree_struct;
|
||||
|
||||
typedef struct {
|
||||
int maffixes;
|
||||
int naffixes;
|
||||
AFFIX * Affix;
|
||||
typedef struct
|
||||
{
|
||||
int maffixes;
|
||||
int naffixes;
|
||||
AFFIX *Affix;
|
||||
|
||||
int nspell;
|
||||
int mspell;
|
||||
SPELL *Spell;
|
||||
Tree_struct SpellTree;
|
||||
Tree_struct PrefixTree;
|
||||
Tree_struct SuffixTree;
|
||||
int nspell;
|
||||
int mspell;
|
||||
SPELL *Spell;
|
||||
Tree_struct SpellTree;
|
||||
Tree_struct PrefixTree;
|
||||
Tree_struct SuffixTree;
|
||||
|
||||
} IspellDict;
|
||||
} IspellDict;
|
||||
|
||||
char ** NormalizeWord(IspellDict * Conf,char *word);
|
||||
int ImportAffixes(IspellDict * Conf, const char *filename);
|
||||
int ImportDictionary(IspellDict * Conf,const char *filename);
|
||||
char **NormalizeWord(IspellDict * Conf, char *word);
|
||||
int ImportAffixes(IspellDict * Conf, const char *filename);
|
||||
int ImportDictionary(IspellDict * Conf, const char *filename);
|
||||
|
||||
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);
|
||||
void SortDictionary(IspellDict * Conf);
|
||||
void SortAffixes(IspellDict * Conf);
|
||||
void FreeIspell (IspellDict *Conf);
|
||||
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);
|
||||
void SortDictionary(IspellDict * Conf);
|
||||
void SortAffixes(IspellDict * Conf);
|
||||
void FreeIspell(IspellDict * Conf);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Simple config parser
|
||||
/*
|
||||
* Simple config parser
|
||||
* Teodor Sigaev <teodor@sigaev.ru>
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
@ -16,126 +16,164 @@
|
|||
#define CS_WAITEQ 2
|
||||
#define CS_WAITVALUE 3
|
||||
#define CS_INVALUE 4
|
||||
#define CS_IN2VALUE 5
|
||||
#define CS_IN2VALUE 5
|
||||
#define CS_WAITDELIM 6
|
||||
#define CS_INESC 7
|
||||
#define CS_IN2ESC 8
|
||||
|
||||
static char *
|
||||
nstrdup(char *ptr, int len) {
|
||||
char *res=palloc(len+1), *cptr;
|
||||
memcpy(res,ptr,len);
|
||||
res[len]='\0';
|
||||
nstrdup(char *ptr, int len)
|
||||
{
|
||||
char *res = palloc(len + 1),
|
||||
*cptr;
|
||||
|
||||
memcpy(res, ptr, len);
|
||||
res[len] = '\0';
|
||||
cptr = ptr = res;
|
||||
while(*ptr) {
|
||||
if ( *ptr == '\\' )
|
||||
while (*ptr)
|
||||
{
|
||||
if (*ptr == '\\')
|
||||
ptr++;
|
||||
*cptr=*ptr; ptr++; cptr++;
|
||||
*cptr = *ptr;
|
||||
ptr++;
|
||||
cptr++;
|
||||
}
|
||||
*cptr='\0';
|
||||
*cptr = '\0';
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
parse_cfgdict(text *in, Map **m) {
|
||||
Map *mptr;
|
||||
char *ptr=VARDATA(in), *begin=NULL;
|
||||
char num=0;
|
||||
int state=CS_WAITKEY;
|
||||
parse_cfgdict(text *in, Map ** m)
|
||||
{
|
||||
Map *mptr;
|
||||
char *ptr = VARDATA(in),
|
||||
*begin = NULL;
|
||||
char num = 0;
|
||||
int state = CS_WAITKEY;
|
||||
|
||||
while( ptr-VARDATA(in) < VARSIZE(in) - VARHDRSZ ) {
|
||||
if ( *ptr==',' ) num++;
|
||||
while (ptr - VARDATA(in) < VARSIZE(in) - VARHDRSZ)
|
||||
{
|
||||
if (*ptr == ',')
|
||||
num++;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
*m=mptr=(Map*)palloc( sizeof(Map)*(num+2) );
|
||||
memset(mptr, 0, sizeof(Map)*(num+2) );
|
||||
ptr=VARDATA(in);
|
||||
while( ptr-VARDATA(in) < VARSIZE(in) - VARHDRSZ ) {
|
||||
if (state==CS_WAITKEY) {
|
||||
if (isalpha(*ptr)) {
|
||||
begin=ptr;
|
||||
state=CS_INKEY;
|
||||
} 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_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;
|
||||
*m = mptr = (Map *) palloc(sizeof(Map) * (num + 2));
|
||||
memset(mptr, 0, sizeof(Map) * (num + 2));
|
||||
ptr = VARDATA(in);
|
||||
while (ptr - VARDATA(in) < VARSIZE(in) - VARHDRSZ)
|
||||
{
|
||||
if (state == CS_WAITKEY)
|
||||
{
|
||||
if (isalpha(*ptr))
|
||||
{
|
||||
begin = ptr;
|
||||
state = CS_INKEY;
|
||||
}
|
||||
} 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) )
|
||||
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
|
||||
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)
|
||||
{
|
||||
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,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("bad parser state"),
|
||||
errdetail("%d at position %d near \"%c\"",
|
||||
state, (int) (ptr-VARDATA(in)), *ptr)));
|
||||
state, (int) (ptr - VARDATA(in)), *ptr)));
|
||||
ptr++;
|
||||
}
|
||||
|
||||
if (state==CS_IN2VALUE) {
|
||||
mptr->value = nstrdup(begin, ptr-begin);
|
||||
if (state == CS_IN2VALUE)
|
||||
{
|
||||
mptr->value = nstrdup(begin, ptr - begin);
|
||||
mptr++;
|
||||
} else if ( !(state==CS_WAITDELIM || state==CS_WAITKEY) )
|
||||
}
|
||||
else if (!(state == CS_WAITDELIM || state == CS_WAITKEY))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("unexpected end of line")));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -99,28 +99,40 @@ typedef struct
|
|||
TI_IN_STATE valstate;
|
||||
|
||||
/* tscfg */
|
||||
int cfg_id;
|
||||
int cfg_id;
|
||||
} QPRS_STATE;
|
||||
|
||||
static char*
|
||||
get_weight(char *buf, int2 *weight) {
|
||||
static char *
|
||||
get_weight(char *buf, int2 *weight)
|
||||
{
|
||||
*weight = 0;
|
||||
|
||||
if ( *buf != ':' )
|
||||
if (*buf != ':')
|
||||
return buf;
|
||||
|
||||
buf++;
|
||||
while( *buf ) {
|
||||
switch(tolower(*buf)) {
|
||||
case 'a': *weight |= 1<<3; break;
|
||||
case 'b': *weight |= 1<<2; break;
|
||||
case 'c': *weight |= 1<<1; break;
|
||||
case 'd': *weight |= 1; break;
|
||||
default: return buf;
|
||||
while (*buf)
|
||||
{
|
||||
switch (tolower(*buf))
|
||||
{
|
||||
case 'a':
|
||||
*weight |= 1 << 3;
|
||||
break;
|
||||
case 'b':
|
||||
*weight |= 1 << 2;
|
||||
break;
|
||||
case 'c':
|
||||
*weight |= 1 << 1;
|
||||
break;
|
||||
case 'd':
|
||||
*weight |= 1;
|
||||
break;
|
||||
default:
|
||||
return buf;
|
||||
}
|
||||
buf++;
|
||||
}
|
||||
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
@ -146,11 +158,15 @@ gettoken_query(QPRS_STATE * state, int4 *val, int4 *lenval, char **strval, int2
|
|||
state->count++;
|
||||
(state->buf)++;
|
||||
return OPEN;
|
||||
} else if ( *(state->buf) == ':' ) {
|
||||
}
|
||||
else if (*(state->buf) == ':')
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("error at start of operand")));
|
||||
} else if (*(state->buf) != ' ') {
|
||||
}
|
||||
else if (*(state->buf) != ' ')
|
||||
{
|
||||
state->valstate.prsbuf = state->buf;
|
||||
state->state = WAITOPERATOR;
|
||||
if (gettoken_tsvector(&(state->valstate)))
|
||||
|
@ -257,7 +273,7 @@ static void
|
|||
pushval_morph(QPRS_STATE * state, int typeval, char *strval, int lenval, int2 weight)
|
||||
{
|
||||
int4 count = 0;
|
||||
PRSTEXT prs;
|
||||
PRSTEXT prs;
|
||||
|
||||
prs.lenwords = 32;
|
||||
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);
|
||||
|
||||
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);
|
||||
pfree( prs.words[count].word );
|
||||
pfree(prs.words[count].word);
|
||||
if (count)
|
||||
pushquery(state, OPR, (int4) '&', 0, 0, 0 );
|
||||
}
|
||||
pushquery(state, OPR, (int4) '&', 0, 0, 0);
|
||||
}
|
||||
pfree(prs.words);
|
||||
|
||||
/* XXX */
|
||||
if ( prs.curwords==0 )
|
||||
if (prs.curwords == 0)
|
||||
pushval_asis(state, VALTRUE, 0, 0, 0);
|
||||
}
|
||||
|
||||
|
@ -381,15 +398,18 @@ ValCompare(CHKVAL * chkval, WordEntry * ptr, ITEM * item)
|
|||
* check weight info
|
||||
*/
|
||||
static bool
|
||||
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)) );
|
||||
while (len--) {
|
||||
if ( item->weight & ( 1<<ptr->weight ) )
|
||||
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)));
|
||||
|
||||
while (len--)
|
||||
{
|
||||
if (item->weight & (1 << ptr->weight))
|
||||
return true;
|
||||
ptr++;
|
||||
}
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -410,8 +430,8 @@ checkcondition_str(void *checkval, ITEM * val)
|
|||
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
|
||||
difference = ValCompare((CHKVAL *) checkval, StopMiddle, val);
|
||||
if (difference == 0)
|
||||
return ( val->weight && StopMiddle->haspos ) ?
|
||||
checkclass_str((CHKVAL *) checkval,StopMiddle, val) : true;
|
||||
return (val->weight && StopMiddle->haspos) ?
|
||||
checkclass_str((CHKVAL *) checkval, StopMiddle, val) : true;
|
||||
else if (difference < 0)
|
||||
StopLow = StopMiddle + 1;
|
||||
else
|
||||
|
@ -468,7 +488,7 @@ rexectsq(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
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)));
|
||||
CHKVAL chkval;
|
||||
bool result;
|
||||
|
@ -485,10 +505,10 @@ exectsq(PG_FUNCTION_ARGS)
|
|||
chkval.values = STRPTR(val);
|
||||
chkval.operand = GETOPERAND(query);
|
||||
result = TS_execute(
|
||||
GETQUERY(query),
|
||||
&chkval,
|
||||
true,
|
||||
checkcondition_str
|
||||
GETQUERY(query),
|
||||
&chkval,
|
||||
true,
|
||||
checkcondition_str
|
||||
);
|
||||
|
||||
PG_FREE_IF_COPY(val, 0);
|
||||
|
@ -534,7 +554,7 @@ findoprnd(ITEM * ptr, int4 *pos)
|
|||
* input
|
||||
*/
|
||||
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;
|
||||
int4 i;
|
||||
|
@ -555,7 +575,7 @@ queryin(char *buf, void (*pushval) (QPRS_STATE *, int, char *, int, int2), int c
|
|||
state.count = 0;
|
||||
state.num = 0;
|
||||
state.str = NULL;
|
||||
state.cfg_id=cfg_id;
|
||||
state.cfg_id = cfg_id;
|
||||
|
||||
/* init value parser's state */
|
||||
state.valstate.oprisdelim = true;
|
||||
|
@ -678,12 +698,30 @@ infix(INFIX * in, bool first)
|
|||
}
|
||||
*(in->cur) = '\'';
|
||||
in->cur++;
|
||||
if ( in->curpol->weight ) {
|
||||
*(in->cur) = ':'; in->cur++;
|
||||
if ( in->curpol->weight & (1<<3) ) { *(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++; }
|
||||
if (in->curpol->weight)
|
||||
{
|
||||
*(in->cur) = ':';
|
||||
in->cur++;
|
||||
if (in->curpol->weight & (1 << 3))
|
||||
{
|
||||
*(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->curpol++;
|
||||
|
@ -827,15 +865,16 @@ tsquerytree(PG_FUNCTION_ARGS)
|
|||
}
|
||||
|
||||
Datum
|
||||
to_tsquery(PG_FUNCTION_ARGS) {
|
||||
text *in = PG_GETARG_TEXT_P(1);
|
||||
char *str;
|
||||
to_tsquery(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *in = PG_GETARG_TEXT_P(1);
|
||||
char *str;
|
||||
QUERYTYPE *query;
|
||||
ITEM *res;
|
||||
int4 len;
|
||||
|
||||
str=text2char(in);
|
||||
PG_FREE_IF_COPY(in,1);
|
||||
str = text2char(in);
|
||||
PG_FREE_IF_COPY(in, 1);
|
||||
|
||||
query = queryin(str, pushval_morph, PG_GETARG_INT32(0));
|
||||
res = clean_fakeval_v2(GETQUERY(query), &len);
|
||||
|
@ -851,25 +890,25 @@ to_tsquery(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
Datum
|
||||
to_tsquery_name(PG_FUNCTION_ARGS) {
|
||||
text *name=PG_GETARG_TEXT_P(0);
|
||||
Datum res= DirectFunctionCall2(
|
||||
to_tsquery,
|
||||
Int32GetDatum( name2id_cfg(name) ),
|
||||
PG_GETARG_DATUM(1)
|
||||
to_tsquery_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *name = PG_GETARG_TEXT_P(0);
|
||||
Datum res = DirectFunctionCall2(
|
||||
to_tsquery,
|
||||
Int32GetDatum(name2id_cfg(name)),
|
||||
PG_GETARG_DATUM(1)
|
||||
);
|
||||
|
||||
PG_FREE_IF_COPY(name,1);
|
||||
|
||||
PG_FREE_IF_COPY(name, 1);
|
||||
PG_RETURN_DATUM(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
to_tsquery_current(PG_FUNCTION_ARGS) {
|
||||
PG_RETURN_DATUM( DirectFunctionCall2(
|
||||
to_tsquery,
|
||||
Int32GetDatum( get_currcfg() ),
|
||||
PG_GETARG_DATUM(0)
|
||||
));
|
||||
to_tsquery_current(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_DATUM(DirectFunctionCall2(
|
||||
to_tsquery,
|
||||
Int32GetDatum(get_currcfg()),
|
||||
PG_GETARG_DATUM(0)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -16,10 +16,10 @@ typedef struct ITEM
|
|||
int2 left;
|
||||
int4 val;
|
||||
/* user-friendly value, must correlate with WordEntry */
|
||||
uint32
|
||||
unused:1,
|
||||
length:11,
|
||||
distance:20;
|
||||
uint32
|
||||
unused:1,
|
||||
length:11,
|
||||
distance:20;
|
||||
} ITEM;
|
||||
|
||||
/*
|
||||
|
@ -50,6 +50,6 @@ typedef struct
|
|||
#define VALFALSE 7
|
||||
|
||||
bool TS_execute(ITEM * curitem, void *checkval,
|
||||
bool calcnot, bool (*chkcond) (void *checkval, ITEM * val));
|
||||
bool calcnot, bool (*chkcond) (void *checkval, ITEM * val));
|
||||
|
||||
#endif
|
||||
|
|
|
@ -37,29 +37,35 @@ Datum rank_cd_def(PG_FUNCTION_ARGS);
|
|||
PG_FUNCTION_INFO_V1(get_covers);
|
||||
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 DEF_NORM_METHOD 0
|
||||
#define DEF_NORM_METHOD 0
|
||||
|
||||
/*
|
||||
* Returns a weight of a word collocation
|
||||
*/
|
||||
static float4 word_distance ( int4 w ) {
|
||||
if ( w>100 )
|
||||
return 1e-30;
|
||||
static float4
|
||||
word_distance(int4 w)
|
||||
{
|
||||
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
|
||||
cnt_length( tsvector *t ) {
|
||||
WordEntry *ptr=ARRPTR(t), *end=(WordEntry*)STRPTR(t);
|
||||
int len = 0, clen;
|
||||
cnt_length(tsvector * t)
|
||||
{
|
||||
WordEntry *ptr = ARRPTR(t),
|
||||
*end = (WordEntry *) STRPTR(t);
|
||||
int len = 0,
|
||||
clen;
|
||||
|
||||
while(ptr < end) {
|
||||
if ( (clen=POSDATALEN(t, ptr)) == 0 )
|
||||
while (ptr < end)
|
||||
{
|
||||
if ((clen = POSDATALEN(t, ptr)) == 0)
|
||||
len += 1;
|
||||
else
|
||||
len += clen;
|
||||
|
@ -70,191 +76,225 @@ cnt_length( tsvector *t ) {
|
|||
}
|
||||
|
||||
static int4
|
||||
WordECompareITEM(char *eval, char *qval, WordEntry * ptr, ITEM * item) {
|
||||
if (ptr->len == item->length)
|
||||
return strncmp(
|
||||
eval + ptr->pos,
|
||||
qval + item->distance,
|
||||
item->length);
|
||||
WordECompareITEM(char *eval, char *qval, WordEntry * ptr, ITEM * item)
|
||||
{
|
||||
if (ptr->len == item->length)
|
||||
return strncmp(
|
||||
eval + ptr->pos,
|
||||
qval + item->distance,
|
||||
item->length);
|
||||
|
||||
return (ptr->len > item->length) ? 1 : -1;
|
||||
return (ptr->len > item->length) ? 1 : -1;
|
||||
}
|
||||
|
||||
static WordEntry*
|
||||
find_wordentry(tsvector *t, QUERYTYPE *q, ITEM *item) {
|
||||
WordEntry *StopLow = ARRPTR(t);
|
||||
WordEntry *StopHigh = (WordEntry*)STRPTR(t);
|
||||
WordEntry *StopMiddle;
|
||||
int difference;
|
||||
static WordEntry *
|
||||
find_wordentry(tsvector * t, QUERYTYPE * q, ITEM * item)
|
||||
{
|
||||
WordEntry *StopLow = ARRPTR(t);
|
||||
WordEntry *StopHigh = (WordEntry *) STRPTR(t);
|
||||
WordEntry *StopMiddle;
|
||||
int difference;
|
||||
|
||||
/* Loop invariant: StopLow <= item < StopHigh */
|
||||
/* Loop invariant: StopLow <= item < StopHigh */
|
||||
|
||||
while (StopLow < StopHigh)
|
||||
{
|
||||
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
|
||||
difference = WordECompareITEM(STRPTR(t), GETOPERAND(q), StopMiddle, item);
|
||||
if (difference == 0)
|
||||
return StopMiddle;
|
||||
else if (difference < 0)
|
||||
StopLow = StopMiddle + 1;
|
||||
else
|
||||
StopHigh = StopMiddle;
|
||||
}
|
||||
while (StopLow < StopHigh)
|
||||
{
|
||||
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
|
||||
difference = WordECompareITEM(STRPTR(t), GETOPERAND(q), StopMiddle, item);
|
||||
if (difference == 0)
|
||||
return StopMiddle;
|
||||
else if (difference < 0)
|
||||
StopLow = StopMiddle + 1;
|
||||
else
|
||||
StopHigh = StopMiddle;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static WordEntryPos POSNULL[]={
|
||||
{0,0},
|
||||
{0,MAXENTRYPOS-1}
|
||||
static WordEntryPos POSNULL[] = {
|
||||
{0, 0},
|
||||
{0, MAXENTRYPOS - 1}
|
||||
};
|
||||
|
||||
static float
|
||||
calc_rank_and(float *w, tsvector *t, QUERYTYPE *q) {
|
||||
uint16 **pos=(uint16**)palloc(sizeof(uint16*) * q->size);
|
||||
int i,k,l,p;
|
||||
WordEntry *entry;
|
||||
WordEntryPos *post,*ct;
|
||||
int4 dimt,lenct,dist;
|
||||
float res=-1.0;
|
||||
ITEM *item=GETQUERY(q);
|
||||
calc_rank_and(float *w, tsvector * t, QUERYTYPE * q)
|
||||
{
|
||||
uint16 **pos = (uint16 **) palloc(sizeof(uint16 *) * q->size);
|
||||
int i,
|
||||
k,
|
||||
l,
|
||||
p;
|
||||
WordEntry *entry;
|
||||
WordEntryPos *post,
|
||||
*ct;
|
||||
int4 dimt,
|
||||
lenct,
|
||||
dist;
|
||||
float res = -1.0;
|
||||
ITEM *item = GETQUERY(q);
|
||||
|
||||
memset(pos,0,sizeof(uint16**) * q->size);
|
||||
*(uint16*)POSNULL = lengthof(POSNULL)-1;
|
||||
memset(pos, 0, sizeof(uint16 **) * q->size);
|
||||
*(uint16 *) POSNULL = lengthof(POSNULL) - 1;
|
||||
|
||||
for(i=0; i<q->size; i++) {
|
||||
|
||||
if ( item[i].type != VAL )
|
||||
for (i = 0; i < q->size; i++)
|
||||
{
|
||||
|
||||
if (item[i].type != VAL)
|
||||
continue;
|
||||
|
||||
entry=find_wordentry(t,q,&(item[i]));
|
||||
if ( !entry )
|
||||
entry = find_wordentry(t, q, &(item[i]));
|
||||
if (!entry)
|
||||
continue;
|
||||
|
||||
if ( entry->haspos )
|
||||
pos[i] = (uint16*)_POSDATAPTR(t,entry);
|
||||
if (entry->haspos)
|
||||
pos[i] = (uint16 *) _POSDATAPTR(t, entry);
|
||||
else
|
||||
pos[i] = (uint16*)POSNULL;
|
||||
pos[i] = (uint16 *) POSNULL;
|
||||
|
||||
|
||||
dimt = *(uint16*)(pos[i]);
|
||||
post = (WordEntryPos*)(pos[i]+1);
|
||||
for( k=0; k<i; k++ ) {
|
||||
if ( !pos[k] ) continue;
|
||||
lenct = *(uint16*)(pos[k]);
|
||||
ct = (WordEntryPos*)(pos[k]+1);
|
||||
for(l=0; l<dimt; l++) {
|
||||
for(p=0; p<lenct; p++) {
|
||||
dist = abs( post[l].pos - ct[p].pos );
|
||||
if ( dist || (dist==0 && (pos[i]==(uint16*)POSNULL || pos[k]==(uint16*)POSNULL) ) ) {
|
||||
float curw;
|
||||
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 );
|
||||
dimt = *(uint16 *) (pos[i]);
|
||||
post = (WordEntryPos *) (pos[i] + 1);
|
||||
for (k = 0; k < i; k++)
|
||||
{
|
||||
if (!pos[k])
|
||||
continue;
|
||||
lenct = *(uint16 *) (pos[k]);
|
||||
ct = (WordEntryPos *) (pos[k] + 1);
|
||||
for (l = 0; l < dimt; l++)
|
||||
{
|
||||
for (p = 0; p < lenct; p++)
|
||||
{
|
||||
dist = abs(post[l].pos - ct[p].pos);
|
||||
if (dist || (dist == 0 && (pos[i] == (uint16 *) POSNULL || pos[k] == (uint16 *) POSNULL)))
|
||||
{
|
||||
float curw;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pfree(pos);
|
||||
return res;
|
||||
return res;
|
||||
}
|
||||
|
||||
static float
|
||||
calc_rank_or(float *w, tsvector *t, QUERYTYPE *q) {
|
||||
WordEntry *entry;
|
||||
WordEntryPos *post;
|
||||
int4 dimt,j,i;
|
||||
float res=-1.0;
|
||||
ITEM *item=GETQUERY(q);
|
||||
calc_rank_or(float *w, tsvector * t, QUERYTYPE * q)
|
||||
{
|
||||
WordEntry *entry;
|
||||
WordEntryPos *post;
|
||||
int4 dimt,
|
||||
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++) {
|
||||
if ( item[i].type != VAL )
|
||||
for (i = 0; i < q->size; i++)
|
||||
{
|
||||
if (item[i].type != VAL)
|
||||
continue;
|
||||
|
||||
entry=find_wordentry(t,q,&(item[i]));
|
||||
if ( !entry )
|
||||
entry = find_wordentry(t, q, &(item[i]));
|
||||
if (!entry)
|
||||
continue;
|
||||
|
||||
if ( entry->haspos ) {
|
||||
dimt = POSDATALEN(t,entry);
|
||||
post = POSDATAPTR(t,entry);
|
||||
} else {
|
||||
dimt = *(uint16*)POSNULL;
|
||||
post = POSNULL+1;
|
||||
if (entry->haspos)
|
||||
{
|
||||
dimt = POSDATALEN(t, entry);
|
||||
post = POSDATAPTR(t, entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
dimt = *(uint16 *) POSNULL;
|
||||
post = POSNULL + 1;
|
||||
}
|
||||
|
||||
for(j=0;j<dimt;j++) {
|
||||
if ( res < 0 )
|
||||
res = wpos( &(post[j]) );
|
||||
for (j = 0; j < dimt; j++)
|
||||
{
|
||||
if (res < 0)
|
||||
res = wpos(&(post[j]));
|
||||
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;
|
||||
}
|
||||
|
||||
static float
|
||||
calc_rank(float *w, tsvector *t, QUERYTYPE *q, int4 method) {
|
||||
ITEM *item = GETQUERY(q);
|
||||
float res=0.0;
|
||||
calc_rank(float *w, tsvector * t, QUERYTYPE * q, int4 method)
|
||||
{
|
||||
ITEM *item = GETQUERY(q);
|
||||
float res = 0.0;
|
||||
|
||||
if (!t->size || !q->size)
|
||||
return 0.0;
|
||||
|
||||
res = ( item->type != VAL && item->val == (int4) '&' ) ?
|
||||
calc_rank_and(w,t,q) : calc_rank_or(w,t,q);
|
||||
res = (item->type != VAL && item->val == (int4) '&') ?
|
||||
calc_rank_and(w, t, q) : calc_rank_or(w, t, q);
|
||||
|
||||
if ( res < 0 )
|
||||
if (res < 0)
|
||||
res = 1e-20;
|
||||
|
||||
switch(method) {
|
||||
case 0: break;
|
||||
case 1: res /= log((float)cnt_length(t)); break;
|
||||
case 2: res /= (float)cnt_length(t); break;
|
||||
switch (method)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
res /= log((float) cnt_length(t));
|
||||
break;
|
||||
case 2:
|
||||
res /= (float) cnt_length(t);
|
||||
break;
|
||||
default:
|
||||
/* internal error */
|
||||
elog(ERROR,"unrecognized normalization method: %d", method);
|
||||
}
|
||||
/* internal error */
|
||||
elog(ERROR, "unrecognized normalization method: %d", method);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
Datum
|
||||
rank(PG_FUNCTION_ARGS) {
|
||||
rank(PG_FUNCTION_ARGS)
|
||||
{
|
||||
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));
|
||||
int method=DEF_NORM_METHOD;
|
||||
float res=0.0;
|
||||
float ws[ lengthof(weights) ];
|
||||
int i;
|
||||
int method = DEF_NORM_METHOD;
|
||||
float res = 0.0;
|
||||
float ws[lengthof(weights)];
|
||||
int i;
|
||||
|
||||
if ( ARR_NDIM(win) != 1 )
|
||||
if (ARR_NDIM(win) != 1)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("array of weight must be one-dimensional")));
|
||||
|
||||
if ( ARRNELEMS(win) < lengthof(weights) )
|
||||
if (ARRNELEMS(win) < lengthof(weights))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
||||
errmsg("array of weight is too short")));
|
||||
|
||||
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 )
|
||||
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)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("weight out of range")));
|
||||
}
|
||||
}
|
||||
|
||||
if ( PG_NARGS() == 4 )
|
||||
method=PG_GETARG_INT32(3);
|
||||
if (PG_NARGS() == 4)
|
||||
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(txt, 1);
|
||||
PG_FREE_IF_COPY(query, 2);
|
||||
|
@ -262,108 +302,127 @@ rank(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
Datum
|
||||
rank_def(PG_FUNCTION_ARGS) {
|
||||
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
rank_def(PG_FUNCTION_ARGS)
|
||||
{
|
||||
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||
float res=0.0;
|
||||
int method=DEF_NORM_METHOD;
|
||||
float res = 0.0;
|
||||
int method = DEF_NORM_METHOD;
|
||||
|
||||
if ( PG_NARGS() == 3 )
|
||||
method=PG_GETARG_INT32(2);
|
||||
if (PG_NARGS() == 3)
|
||||
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(query, 1);
|
||||
PG_RETURN_FLOAT4(res);
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
ITEM *item;
|
||||
int32 pos;
|
||||
} DocRepresentation;
|
||||
typedef struct
|
||||
{
|
||||
ITEM *item;
|
||||
int32 pos;
|
||||
} DocRepresentation;
|
||||
|
||||
static int
|
||||
compareDocR(const void *a, const void *b) {
|
||||
if ( ((DocRepresentation *) a)->pos == ((DocRepresentation *) b)->pos )
|
||||
compareDocR(const void *a, const void *b)
|
||||
{
|
||||
if (((DocRepresentation *) a)->pos == ((DocRepresentation *) b)->pos)
|
||||
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;
|
||||
int len;
|
||||
int len;
|
||||
} ChkDocR;
|
||||
|
||||
static bool
|
||||
checkcondition_DR(void *checkval, ITEM *val) {
|
||||
DocRepresentation *ptr = ((ChkDocR*)checkval)->doc;
|
||||
checkcondition_DR(void *checkval, ITEM * val)
|
||||
{
|
||||
DocRepresentation *ptr = ((ChkDocR *) checkval)->doc;
|
||||
|
||||
while( ptr - ((ChkDocR*)checkval)->doc < ((ChkDocR*)checkval)->len ) {
|
||||
if ( val == ptr->item )
|
||||
while (ptr - ((ChkDocR *) checkval)->doc < ((ChkDocR *) checkval)->len)
|
||||
{
|
||||
if (val == ptr->item)
|
||||
return true;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static bool
|
||||
Cover(DocRepresentation *doc, int len, QUERYTYPE *query, int *pos, int *p, int *q) {
|
||||
int i;
|
||||
DocRepresentation *ptr,*f=(DocRepresentation*)0xffffffff;
|
||||
ITEM *item=GETQUERY(query);
|
||||
int lastpos=*pos;
|
||||
int oldq=*q;
|
||||
Cover(DocRepresentation * doc, int len, QUERYTYPE * query, int *pos, int *p, int *q)
|
||||
{
|
||||
int i;
|
||||
DocRepresentation *ptr,
|
||||
*f = (DocRepresentation *) 0xffffffff;
|
||||
ITEM *item = GETQUERY(query);
|
||||
int lastpos = *pos;
|
||||
int oldq = *q;
|
||||
|
||||
*p=0x7fffffff;
|
||||
*q=0;
|
||||
*p = 0x7fffffff;
|
||||
*q = 0;
|
||||
|
||||
for(i=0; i<query->size; i++) {
|
||||
if ( item->type != VAL ) {
|
||||
for (i = 0; i < query->size; i++)
|
||||
{
|
||||
if (item->type != VAL)
|
||||
{
|
||||
item++;
|
||||
continue;
|
||||
}
|
||||
ptr = doc + *pos;
|
||||
|
||||
while(ptr-doc<len) {
|
||||
if ( ptr->item == item ) {
|
||||
if ( ptr->pos > *q ) {
|
||||
while (ptr - doc < len)
|
||||
{
|
||||
if (ptr->item == item)
|
||||
{
|
||||
if (ptr->pos > *q)
|
||||
{
|
||||
*q = ptr->pos;
|
||||
lastpos= ptr - doc;
|
||||
}
|
||||
lastpos = ptr - doc;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
item++;
|
||||
}
|
||||
|
||||
if (*q==0 )
|
||||
if (*q == 0)
|
||||
return false;
|
||||
|
||||
if (*q==oldq) { /* already check this pos */
|
||||
if (*q == oldq)
|
||||
{ /* already check this pos */
|
||||
(*pos)++;
|
||||
return Cover(doc, len, query, pos,p,q);
|
||||
}
|
||||
return Cover(doc, len, query, pos, p, q);
|
||||
}
|
||||
|
||||
item=GETQUERY(query);
|
||||
for(i=0; i<query->size; i++) {
|
||||
if ( item->type != VAL ) {
|
||||
item = GETQUERY(query);
|
||||
for (i = 0; i < query->size; i++)
|
||||
{
|
||||
if (item->type != VAL)
|
||||
{
|
||||
item++;
|
||||
continue;
|
||||
}
|
||||
ptr = doc + lastpos;
|
||||
|
||||
while(ptr>=doc+*pos) {
|
||||
if ( ptr->item == item ) {
|
||||
if ( ptr->pos < *p ) {
|
||||
while (ptr >= doc + *pos)
|
||||
{
|
||||
if (ptr->item == item)
|
||||
{
|
||||
if (ptr->pos < *p)
|
||||
{
|
||||
*p = ptr->pos;
|
||||
f=ptr;
|
||||
f = ptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -371,106 +430,135 @@ Cover(DocRepresentation *doc, int len, QUERYTYPE *query, int *pos, int *p, int *
|
|||
}
|
||||
item++;
|
||||
}
|
||||
|
||||
if ( *p<=*q ) {
|
||||
ChkDocR ch = { f, (doc + lastpos)-f+1 };
|
||||
*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);*/
|
||||
|
||||
if (*p <= *q)
|
||||
{
|
||||
ChkDocR ch = {f, (doc + lastpos) - f + 1};
|
||||
|
||||
*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;
|
||||
} else
|
||||
return Cover(doc, len, query, pos,p,q);
|
||||
}
|
||||
else
|
||||
return Cover(doc, len, query, pos, p, q);
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static DocRepresentation*
|
||||
get_docrep(tsvector *txt, QUERYTYPE *query, int *doclen) {
|
||||
ITEM *item=GETQUERY(query);
|
||||
WordEntry *entry;
|
||||
WordEntryPos *post;
|
||||
int4 dimt,j,i;
|
||||
int len=query->size*4,cur=0;
|
||||
static DocRepresentation *
|
||||
get_docrep(tsvector * txt, QUERYTYPE * query, int *doclen)
|
||||
{
|
||||
ITEM *item = GETQUERY(query);
|
||||
WordEntry *entry;
|
||||
WordEntryPos *post;
|
||||
int4 dimt,
|
||||
j,
|
||||
i;
|
||||
int len = query->size * 4,
|
||||
cur = 0;
|
||||
DocRepresentation *doc;
|
||||
|
||||
*(uint16*)POSNULL = lengthof(POSNULL)-1;
|
||||
doc = (DocRepresentation*)palloc(sizeof(DocRepresentation)*len);
|
||||
for(i=0; i<query->size; i++) {
|
||||
if ( item[i].type != VAL )
|
||||
*(uint16 *) POSNULL = lengthof(POSNULL) - 1;
|
||||
doc = (DocRepresentation *) palloc(sizeof(DocRepresentation) * len);
|
||||
for (i = 0; i < query->size; i++)
|
||||
{
|
||||
if (item[i].type != VAL)
|
||||
continue;
|
||||
|
||||
entry=find_wordentry(txt,query,&(item[i]));
|
||||
if ( !entry )
|
||||
entry = find_wordentry(txt, query, &(item[i]));
|
||||
if (!entry)
|
||||
continue;
|
||||
|
||||
if ( entry->haspos ) {
|
||||
dimt = POSDATALEN(txt,entry);
|
||||
post = POSDATAPTR(txt,entry);
|
||||
} else {
|
||||
dimt = *(uint16*)POSNULL;
|
||||
post = POSNULL+1;
|
||||
if (entry->haspos)
|
||||
{
|
||||
dimt = POSDATALEN(txt, entry);
|
||||
post = POSDATAPTR(txt, entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
dimt = *(uint16 *) POSNULL;
|
||||
post = POSNULL + 1;
|
||||
}
|
||||
|
||||
while( cur+dimt >= len ) {
|
||||
len*=2;
|
||||
doc = (DocRepresentation*)repalloc(doc,sizeof(DocRepresentation)*len);
|
||||
while (cur + dimt >= len)
|
||||
{
|
||||
len *= 2;
|
||||
doc = (DocRepresentation *) repalloc(doc, sizeof(DocRepresentation) * len);
|
||||
}
|
||||
|
||||
for(j=0;j<dimt;j++) {
|
||||
doc[cur].item=&(item[i]);
|
||||
doc[cur].pos=post[j].pos;
|
||||
for (j = 0; j < dimt; j++)
|
||||
{
|
||||
doc[cur].item = &(item[i]);
|
||||
doc[cur].pos = post[j].pos;
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
|
||||
*doclen=cur;
|
||||
|
||||
if ( cur>0 ) {
|
||||
if ( cur>1 )
|
||||
*doclen = cur;
|
||||
|
||||
if (cur > 0)
|
||||
{
|
||||
if (cur > 1)
|
||||
qsort((void *) doc, cur, sizeof(DocRepresentation), compareDocR);
|
||||
return doc;
|
||||
}
|
||||
|
||||
|
||||
pfree(doc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
Datum
|
||||
rank_cd(PG_FUNCTION_ARGS) {
|
||||
int K = PG_GETARG_INT32(0);
|
||||
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||
rank_cd(PG_FUNCTION_ARGS)
|
||||
{
|
||||
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));
|
||||
int method=DEF_NORM_METHOD;
|
||||
DocRepresentation *doc;
|
||||
float res=0.0;
|
||||
int p=0,q=0,len,cur;
|
||||
int method = DEF_NORM_METHOD;
|
||||
DocRepresentation *doc;
|
||||
float res = 0.0;
|
||||
int p = 0,
|
||||
q = 0,
|
||||
len,
|
||||
cur;
|
||||
|
||||
doc = get_docrep(txt, query, &len);
|
||||
if ( !doc ) {
|
||||
if (!doc)
|
||||
{
|
||||
PG_FREE_IF_COPY(txt, 1);
|
||||
PG_FREE_IF_COPY(query, 2);
|
||||
PG_RETURN_FLOAT4(0.0);
|
||||
}
|
||||
|
||||
cur=0;
|
||||
if (K<=0)
|
||||
K=4;
|
||||
while( Cover(doc, len, query, &cur, &p, &q) )
|
||||
res += ( q-p+1 > K ) ? ((float)K)/((float)(q-p+1)) : 1.0;
|
||||
cur = 0;
|
||||
if (K <= 0)
|
||||
K = 4;
|
||||
while (Cover(doc, len, query, &cur, &p, &q))
|
||||
res += (q - p + 1 > K) ? ((float) K) / ((float) (q - p + 1)) : 1.0;
|
||||
|
||||
if ( PG_NARGS() == 4 )
|
||||
method=PG_GETARG_INT32(3);
|
||||
if (PG_NARGS() == 4)
|
||||
method = PG_GETARG_INT32(3);
|
||||
|
||||
switch(method) {
|
||||
case 0: break;
|
||||
case 1: res /= log((float)cnt_length(txt)); break;
|
||||
case 2: res /= (float)cnt_length(txt); break;
|
||||
switch (method)
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
res /= log((float) cnt_length(txt));
|
||||
break;
|
||||
case 2:
|
||||
res /= (float) cnt_length(txt);
|
||||
break;
|
||||
default:
|
||||
/* internal error */
|
||||
elog(ERROR,"unrecognized normalization method: %d", method);
|
||||
}
|
||||
/* internal error */
|
||||
elog(ERROR, "unrecognized normalization method: %d", method);
|
||||
}
|
||||
|
||||
pfree(doc);
|
||||
PG_FREE_IF_COPY(txt, 1);
|
||||
|
@ -481,120 +569,141 @@ rank_cd(PG_FUNCTION_ARGS) {
|
|||
|
||||
|
||||
Datum
|
||||
rank_cd_def(PG_FUNCTION_ARGS) {
|
||||
PG_RETURN_DATUM( DirectFunctionCall4(
|
||||
rank_cd,
|
||||
Int32GetDatum(-1),
|
||||
PG_GETARG_DATUM(0),
|
||||
PG_GETARG_DATUM(1),
|
||||
( PG_NARGS() == 3 ) ? PG_GETARG_DATUM(2) : Int32GetDatum(DEF_NORM_METHOD)
|
||||
));
|
||||
rank_cd_def(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_DATUM(DirectFunctionCall4(
|
||||
rank_cd,
|
||||
Int32GetDatum(-1),
|
||||
PG_GETARG_DATUM(0),
|
||||
PG_GETARG_DATUM(1),
|
||||
(PG_NARGS() == 3) ? PG_GETARG_DATUM(2) : Int32GetDatum(DEF_NORM_METHOD)
|
||||
));
|
||||
}
|
||||
|
||||
/**************debug*************/
|
||||
|
||||
typedef struct {
|
||||
char *w;
|
||||
int2 len;
|
||||
int2 pos;
|
||||
int2 start;
|
||||
int2 finish;
|
||||
} DocWord;
|
||||
typedef struct
|
||||
{
|
||||
char *w;
|
||||
int2 len;
|
||||
int2 pos;
|
||||
int2 start;
|
||||
int2 finish;
|
||||
} DocWord;
|
||||
|
||||
static int
|
||||
compareDocWord(const void *a, const void *b) {
|
||||
if ( ((DocWord *) a)->pos == ((DocWord *) b)->pos )
|
||||
compareDocWord(const void *a, const void *b)
|
||||
{
|
||||
if (((DocWord *) a)->pos == ((DocWord *) b)->pos)
|
||||
return 1;
|
||||
return ( ((DocWord *) a)->pos > ((DocWord *) b)->pos ) ? 1 : -1;
|
||||
return (((DocWord *) a)->pos > ((DocWord *) b)->pos) ? 1 : -1;
|
||||
}
|
||||
|
||||
|
||||
Datum
|
||||
get_covers(PG_FUNCTION_ARGS) {
|
||||
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
Datum
|
||||
get_covers(PG_FUNCTION_ARGS)
|
||||
{
|
||||
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
QUERYTYPE *query = (QUERYTYPE *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||
WordEntry *pptr=ARRPTR(txt);
|
||||
int i,dlen=0,j,cur=0,len=0,rlen;
|
||||
DocWord *dw,*dwptr;
|
||||
text *out;
|
||||
char *cptr;
|
||||
WordEntry *pptr = ARRPTR(txt);
|
||||
int i,
|
||||
dlen = 0,
|
||||
j,
|
||||
cur = 0,
|
||||
len = 0,
|
||||
rlen;
|
||||
DocWord *dw,
|
||||
*dwptr;
|
||||
text *out;
|
||||
char *cptr;
|
||||
DocRepresentation *doc;
|
||||
int pos=0,p,q,olddwpos=0;
|
||||
int ncover=1;
|
||||
int pos = 0,
|
||||
p,
|
||||
q,
|
||||
olddwpos = 0;
|
||||
int ncover = 1;
|
||||
|
||||
doc = get_docrep(txt, query, &rlen);
|
||||
|
||||
if ( !doc ) {
|
||||
out=palloc(VARHDRSZ);
|
||||
if (!doc)
|
||||
{
|
||||
out = palloc(VARHDRSZ);
|
||||
VARATT_SIZEP(out) = VARHDRSZ;
|
||||
PG_FREE_IF_COPY(txt,0);
|
||||
PG_FREE_IF_COPY(query,1);
|
||||
PG_FREE_IF_COPY(txt, 0);
|
||||
PG_FREE_IF_COPY(query, 1);
|
||||
PG_RETURN_POINTER(out);
|
||||
}
|
||||
|
||||
for(i=0;i<txt->size;i++) {
|
||||
for (i = 0; i < txt->size; i++)
|
||||
{
|
||||
if (!pptr[i].haspos)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("no pos info")));
|
||||
dlen += POSDATALEN(txt,&(pptr[i]));
|
||||
dlen += POSDATALEN(txt, &(pptr[i]));
|
||||
}
|
||||
|
||||
dwptr=dw=palloc(sizeof(DocWord)*dlen);
|
||||
memset(dw,0,sizeof(DocWord)*dlen);
|
||||
dwptr = dw = palloc(sizeof(DocWord) * dlen);
|
||||
memset(dw, 0, sizeof(DocWord) * dlen);
|
||||
|
||||
for(i=0;i<txt->size;i++) {
|
||||
WordEntryPos *posdata = POSDATAPTR(txt,&(pptr[i]));
|
||||
for(j=0;j<POSDATALEN(txt,&(pptr[i]));j++) {
|
||||
dw[cur].w=STRPTR(txt)+pptr[i].pos;
|
||||
dw[cur].len=pptr[i].len;
|
||||
dw[cur].pos=posdata[j].pos;
|
||||
for (i = 0; i < txt->size; i++)
|
||||
{
|
||||
WordEntryPos *posdata = POSDATAPTR(txt, &(pptr[i]));
|
||||
|
||||
for (j = 0; j < POSDATALEN(txt, &(pptr[i])); j++)
|
||||
{
|
||||
dw[cur].w = STRPTR(txt) + pptr[i].pos;
|
||||
dw[cur].len = pptr[i].len;
|
||||
dw[cur].pos = posdata[j].pos;
|
||||
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);
|
||||
|
||||
while( Cover(doc, rlen, query, &pos, &p, &q) ) {
|
||||
dwptr=dw+olddwpos;
|
||||
while(dwptr->pos < p && dwptr-dw<dlen)
|
||||
while (Cover(doc, rlen, query, &pos, &p, &q))
|
||||
{
|
||||
dwptr = dw + olddwpos;
|
||||
while (dwptr->pos < p && dwptr - dw < dlen)
|
||||
dwptr++;
|
||||
olddwpos=dwptr-dw;
|
||||
dwptr->start=ncover;
|
||||
while(dwptr->pos < q+1 && dwptr-dw<dlen)
|
||||
olddwpos = dwptr - dw;
|
||||
dwptr->start = ncover;
|
||||
while (dwptr->pos < q + 1 && dwptr - dw < dlen)
|
||||
dwptr++;
|
||||
(dwptr-1)->finish=ncover;
|
||||
len+= 4 /* {}+two spaces */ + 2*16 /*numbers*/;
|
||||
ncover++;
|
||||
}
|
||||
|
||||
out=palloc(VARHDRSZ+len);
|
||||
cptr=((char*)out)+VARHDRSZ;
|
||||
dwptr=dw;
|
||||
(dwptr - 1)->finish = ncover;
|
||||
len += 4 /* {}+two spaces */ + 2 * 16 /* numbers */ ;
|
||||
ncover++;
|
||||
}
|
||||
|
||||
while( dwptr-dw < dlen) {
|
||||
if ( dwptr->start ) {
|
||||
sprintf(cptr,"{%d ",dwptr->start);
|
||||
cptr=strchr(cptr,'\0');
|
||||
out = palloc(VARHDRSZ + len);
|
||||
cptr = ((char *) out) + VARHDRSZ;
|
||||
dwptr = dw;
|
||||
|
||||
while (dwptr - dw < dlen)
|
||||
{
|
||||
if (dwptr->start)
|
||||
{
|
||||
sprintf(cptr, "{%d ", dwptr->start);
|
||||
cptr = strchr(cptr, '\0');
|
||||
}
|
||||
memcpy(cptr,dwptr->w,dwptr->len);
|
||||
cptr+=dwptr->len;
|
||||
*cptr=' ';
|
||||
memcpy(cptr, dwptr->w, dwptr->len);
|
||||
cptr += dwptr->len;
|
||||
*cptr = ' ';
|
||||
cptr++;
|
||||
if ( dwptr->finish ) {
|
||||
sprintf(cptr,"}%d ",dwptr->finish);
|
||||
cptr=strchr(cptr,'\0');
|
||||
if (dwptr->finish)
|
||||
{
|
||||
sprintf(cptr, "}%d ", dwptr->finish);
|
||||
cptr = strchr(cptr, '\0');
|
||||
}
|
||||
dwptr++;
|
||||
}
|
||||
}
|
||||
|
||||
VARATT_SIZEP(out) = cptr - ((char *) out);
|
||||
|
||||
VARATT_SIZEP(out) = cptr - ((char*)out);
|
||||
|
||||
pfree(dw);
|
||||
pfree(doc);
|
||||
|
||||
PG_FREE_IF_COPY(txt,0);
|
||||
PG_FREE_IF_COPY(query,1);
|
||||
PG_FREE_IF_COPY(txt, 0);
|
||||
PG_FREE_IF_COPY(query, 1);
|
||||
PG_RETURN_POINTER(out);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* simple but fast map from str to Oid
|
||||
* Teodor Sigaev <teodor@sigaev.ru>
|
||||
*/
|
||||
|
@ -11,69 +11,85 @@
|
|||
#include "common.h"
|
||||
|
||||
static int
|
||||
compareSNMapEntry(const void *a, const void *b) {
|
||||
return strcmp( ((SNMapEntry*)a)->key, ((SNMapEntry*)b)->key );
|
||||
compareSNMapEntry(const void *a, const void *b)
|
||||
{
|
||||
return strcmp(((SNMapEntry *) a)->key, ((SNMapEntry *) b)->key);
|
||||
}
|
||||
|
||||
void
|
||||
addSNMap( SNMap *map, char *key, Oid value ) {
|
||||
if (map->len>=map->reallen) {
|
||||
void
|
||||
addSNMap(SNMap * map, char *key, Oid value)
|
||||
{
|
||||
if (map->len >= map->reallen)
|
||||
{
|
||||
SNMapEntry *tmp;
|
||||
int len = (map->reallen) ? 2*map->reallen : 16;
|
||||
tmp=(SNMapEntry*)realloc(map->list, sizeof(SNMapEntry) * len);
|
||||
if ( !tmp )
|
||||
int len = (map->reallen) ? 2 * map->reallen : 16;
|
||||
|
||||
tmp = (SNMapEntry *) realloc(map->list, sizeof(SNMapEntry) * len);
|
||||
if (!tmp)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
map->reallen=len;
|
||||
map->list=tmp;
|
||||
map->reallen = len;
|
||||
map->list = tmp;
|
||||
}
|
||||
map->list[ map->len ].key = strdup(key);
|
||||
if ( ! map->list[ map->len ].key )
|
||||
map->list[map->len].key = strdup(key);
|
||||
if (!map->list[map->len].key)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
map->list[ map->len ].value=value;
|
||||
map->list[map->len].value = value;
|
||||
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
|
||||
addSNMap_t( SNMap *map, text *key, Oid value ) {
|
||||
char *k=text2char( key );
|
||||
void
|
||||
addSNMap_t(SNMap * map, text *key, Oid value)
|
||||
{
|
||||
char *k = text2char(key);
|
||||
|
||||
addSNMap(map, k, value);
|
||||
pfree(k);
|
||||
}
|
||||
|
||||
Oid
|
||||
findSNMap( SNMap *map, char *key ) {
|
||||
Oid
|
||||
findSNMap(SNMap * map, char *key)
|
||||
{
|
||||
SNMapEntry *ptr;
|
||||
SNMapEntry ks = {key, 0};
|
||||
if ( map->len==0 || !map->list )
|
||||
return 0;
|
||||
ptr = (SNMapEntry*) bsearch(&ks, map->list, map->len, sizeof(SNMapEntry), compareSNMapEntry);
|
||||
SNMapEntry ks = {key, 0};
|
||||
|
||||
if (map->len == 0 || !map->list)
|
||||
return 0;
|
||||
ptr = (SNMapEntry *) bsearch(&ks, map->list, map->len, sizeof(SNMapEntry), compareSNMapEntry);
|
||||
return (ptr) ? ptr->value : 0;
|
||||
}
|
||||
|
||||
Oid
|
||||
findSNMap_t( SNMap *map, text *key ) {
|
||||
char *k=text2char(key);
|
||||
int res;
|
||||
res= findSNMap(map, k);
|
||||
Oid
|
||||
findSNMap_t(SNMap * map, text *key)
|
||||
{
|
||||
char *k = text2char(key);
|
||||
int res;
|
||||
|
||||
res = findSNMap(map, k);
|
||||
pfree(k);
|
||||
return res;
|
||||
}
|
||||
|
||||
void freeSNMap( SNMap *map ) {
|
||||
SNMapEntry *entry=map->list;
|
||||
if ( map->list ) {
|
||||
while( map->len ) {
|
||||
if ( entry->key ) free(entry->key);
|
||||
entry++; map->len--;
|
||||
void
|
||||
freeSNMap(SNMap * map)
|
||||
{
|
||||
SNMapEntry *entry = map->list;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -3,21 +3,23 @@
|
|||
|
||||
#include "postgres.h"
|
||||
|
||||
typedef struct {
|
||||
char *key;
|
||||
Oid value;
|
||||
} SNMapEntry;
|
||||
typedef struct
|
||||
{
|
||||
char *key;
|
||||
Oid value;
|
||||
} SNMapEntry;
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
int reallen;
|
||||
SNMapEntry *list;
|
||||
} SNMap;
|
||||
typedef struct
|
||||
{
|
||||
int len;
|
||||
int reallen;
|
||||
SNMapEntry *list;
|
||||
} SNMap;
|
||||
|
||||
void addSNMap( SNMap *map, char *key, Oid value );
|
||||
void addSNMap_t( SNMap *map, text *key, Oid value );
|
||||
Oid findSNMap( SNMap *map, char *key );
|
||||
Oid findSNMap_t( SNMap *map, text *key );
|
||||
void freeSNMap( SNMap *map );
|
||||
void addSNMap(SNMap * map, char *key, Oid value);
|
||||
void addSNMap_t(SNMap * map, text *key, Oid value);
|
||||
Oid findSNMap(SNMap * map, char *key);
|
||||
Oid findSNMap_t(SNMap * map, text *key);
|
||||
void freeSNMap(SNMap * map);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,48 +2,64 @@
|
|||
|
||||
#include "header.h"
|
||||
|
||||
extern struct SN_env * SN_create_env(int S_size, int I_size, int B_size)
|
||||
{ struct SN_env * z = (struct SN_env *) calloc(1, sizeof(struct SN_env));
|
||||
z->p = create_s();
|
||||
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)
|
||||
extern struct SN_env *
|
||||
SN_create_env(int S_size, int I_size, int B_size)
|
||||
{
|
||||
if (z->S_size)
|
||||
{
|
||||
{ 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);
|
||||
struct SN_env *z = (struct SN_env *) calloc(1, sizeof(struct SN_env));
|
||||
|
||||
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_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);
|
||||
z->c = 0;
|
||||
if (z->S_size)
|
||||
{
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -11,17 +11,24 @@ typedef unsigned char symbol;
|
|||
|
||||
*/
|
||||
|
||||
struct SN_env {
|
||||
symbol * p;
|
||||
int c; int a; int l; int lb; int bra; int ket;
|
||||
int S_size; int I_size; int B_size;
|
||||
symbol * * S;
|
||||
int * I;
|
||||
symbol * B;
|
||||
struct SN_env
|
||||
{
|
||||
symbol *p;
|
||||
int c;
|
||||
int a;
|
||||
int l;
|
||||
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_set_current(struct SN_env * z, int size, const symbol * s);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,7 @@
|
|||
|
||||
/* 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 int english_stem(struct SN_env * z);
|
||||
|
||||
extern int english_stem(struct SN_env * z);
|
||||
|
|
|
@ -2,41 +2,42 @@
|
|||
|
||||
#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 CAPACITY(p) ((int *)(p))[-2]
|
||||
|
||||
struct among
|
||||
{ int s_size; /* number of chars in string */
|
||||
symbol * s; /* search string */
|
||||
int substring_i;/* index to longest matching substring */
|
||||
int result; /* result of the lookup */
|
||||
int (* function)(struct SN_env *);
|
||||
{
|
||||
int s_size; /* number of chars in string */
|
||||
symbol *s; /* search string */
|
||||
int substring_i; /* index to longest matching substring */
|
||||
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 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 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 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 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 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 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 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 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 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_v(struct SN_env * z, symbol * p);
|
||||
extern int eq_v_b(struct SN_env * z, symbol * p);
|
||||
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_v(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_b(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 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 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 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_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_v(struct SN_env * z, int bra, int ket, symbol * p);
|
||||
|
||||
extern symbol * slice_to(struct SN_env * z, symbol * p);
|
||||
extern symbol * assign_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 void debug(struct SN_env * z, int number, int line_count);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,7 @@
|
|||
|
||||
/* 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 int russian_stem(struct SN_env * z);
|
||||
|
||||
extern int russian_stem(struct SN_env * z);
|
||||
|
|
|
@ -9,320 +9,507 @@
|
|||
|
||||
#define CREATE_SIZE 1
|
||||
|
||||
extern symbol * create_s(void)
|
||||
{ symbol * p = (symbol *) (HEAD + (char *) malloc(HEAD + (CREATE_SIZE + 1) * sizeof(symbol)));
|
||||
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)
|
||||
extern symbol *
|
||||
create_s(void)
|
||||
{
|
||||
int i = 0;
|
||||
int j = v_size;
|
||||
symbol *p = (symbol *) (HEAD + (char *) malloc(HEAD + (CREATE_SIZE + 1) * sizeof(symbol)));
|
||||
|
||||
int c = z->c; int l = z->l;
|
||||
symbol * q = z->p + c;
|
||||
CAPACITY(p) = CREATE_SIZE;
|
||||
SET_SIZE(p, CREATE_SIZE);
|
||||
return p;
|
||||
}
|
||||
|
||||
struct among * w;
|
||||
extern void lose_s(symbol * p)
|
||||
{
|
||||
free((char *) p - HEAD);
|
||||
}
|
||||
|
||||
int common_i = 0;
|
||||
int common_j = 0;
|
||||
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];
|
||||
|
||||
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)
|
||||
{ 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 */
|
||||
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];
|
||||
|
||||
/* - but now we need to go round once more to get
|
||||
v->s inspected. This looks messy, but is actually
|
||||
the optimal approach. */
|
||||
if
|
||||
(ch > max || (ch -= min) < 0 ||
|
||||
(s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
|
||||
return 0;
|
||||
}
|
||||
z->c--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
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 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;
|
||||
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 */
|
||||
|
||||
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 j = v_size;
|
||||
int i = 0;
|
||||
int j = v_size;
|
||||
|
||||
int c = z->c; int lb = z->lb;
|
||||
symbol * q = z->p + c - 1;
|
||||
int c = z->c;
|
||||
int lb = z->lb;
|
||||
symbol *q = z->p + c - 1;
|
||||
|
||||
struct among * w;
|
||||
struct among *w;
|
||||
|
||||
int common_i = 0;
|
||||
int common_j = 0;
|
||||
int common_i = 0;
|
||||
int common_j = 0;
|
||||
|
||||
int first_key_inspected = 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;
|
||||
w = v + k;
|
||||
{ int i; for (i = w->s_size - 1 - common; i >= 0; i--)
|
||||
{ if (c - common == lb) { diff = -1; break; }
|
||||
diff = q[- common] - w->s[i];
|
||||
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;
|
||||
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;
|
||||
}
|
||||
while (1)
|
||||
{
|
||||
int k = i + ((j - i) >> 1);
|
||||
int diff = 0;
|
||||
int common = common_i < common_j ? common_i : common_j;
|
||||
|
||||
w = v + k;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = w->s_size - 1 - common; i >= 0; i--)
|
||||
{
|
||||
if (c - common == lb)
|
||||
{
|
||||
diff = -1;
|
||||
break;
|
||||
}
|
||||
diff = q[-common] - w->s[i];
|
||||
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;
|
||||
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)
|
||||
{ int new_size = n + 20;
|
||||
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;
|
||||
extern symbol *
|
||||
increase_size(symbol * p, int n)
|
||||
{
|
||||
int new_size = n + 20;
|
||||
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
|
||||
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)
|
||||
{ int adjustment = s_size - (c_ket - c_bra);
|
||||
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)
|
||||
extern int
|
||||
replace_s(struct SN_env * z, int c_bra, int c_ket, int s_size, const symbol * 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);
|
||||
}
|
||||
int adjustment = s_size - (c_ket - c_bra);
|
||||
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;
|
||||
}
|
||||
|
||||
extern void 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);
|
||||
static void
|
||||
slice_check(struct SN_env * z)
|
||||
{
|
||||
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)
|
||||
{ slice_from_s(z, SIZE(p), p);
|
||||
extern void
|
||||
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)
|
||||
{ slice_from_s(z, 0, 0);
|
||||
extern void
|
||||
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)
|
||||
{ int adjustment = replace_s(z, bra, ket, s_size, s);
|
||||
if (bra <= z->bra) z->bra += adjustment;
|
||||
if (bra <= z->ket) z->ket += adjustment;
|
||||
extern void
|
||||
slice_del(struct SN_env * z)
|
||||
{
|
||||
slice_from_s(z, 0, 0);
|
||||
}
|
||||
|
||||
extern void insert_v(struct SN_env * z, int bra, int ket, symbol * p)
|
||||
{ int adjustment = replace_s(z, bra, ket, SIZE(p), p);
|
||||
if (bra <= z->bra) z->bra += adjustment;
|
||||
if (bra <= z->ket) z->ket += adjustment;
|
||||
extern void
|
||||
insert_s(struct SN_env * z, int bra, int ket, int s_size, symbol * s)
|
||||
{
|
||||
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)
|
||||
{ slice_check(z);
|
||||
{ int len = z->ket - z->bra;
|
||||
if (CAPACITY(p) < len) p = increase_size(p, len);
|
||||
memmove(p, z->p + z->bra, len * sizeof(symbol));
|
||||
SET_SIZE(p, len);
|
||||
}
|
||||
return p;
|
||||
extern void
|
||||
insert_v(struct SN_env * z, int bra, int ket, symbol * p)
|
||||
{
|
||||
int adjustment = replace_s(z, bra, ket, SIZE(p), p);
|
||||
|
||||
if (bra <= z->bra)
|
||||
z->bra += adjustment;
|
||||
if (bra <= z->ket)
|
||||
z->ket += adjustment;
|
||||
}
|
||||
|
||||
extern symbol * assign_to(struct SN_env * z, symbol * p)
|
||||
{ int len = z->l;
|
||||
if (CAPACITY(p) < len) p = increase_size(p, len);
|
||||
memmove(p, z->p, len * sizeof(symbol));
|
||||
SET_SIZE(p, len);
|
||||
return p;
|
||||
extern symbol *
|
||||
slice_to(struct SN_env * z, symbol * p)
|
||||
{
|
||||
slice_check(z);
|
||||
{
|
||||
int len = z->ket - z->bra;
|
||||
|
||||
if (CAPACITY(p) < len)
|
||||
p = increase_size(p, len);
|
||||
memmove(p, z->p + z->bra, len * sizeof(symbol));
|
||||
SET_SIZE(p, len);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
extern void debug(struct SN_env * z, int number, int line_count)
|
||||
{ int i;
|
||||
int limit = SIZE(z->p);
|
||||
/*if (number >= 0) printf("%3d (line %4d): '", number, line_count);*/
|
||||
if (number >= 0) printf("%3d (line %4d): [%d]'", number, line_count,limit);
|
||||
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");
|
||||
extern symbol *
|
||||
assign_to(struct SN_env * z, symbol * p)
|
||||
{
|
||||
int len = z->l;
|
||||
|
||||
if (CAPACITY(p) < len)
|
||||
p = increase_size(p, len);
|
||||
memmove(p, z->p, len * sizeof(symbol));
|
||||
SET_SIZE(p, len);
|
||||
return p;
|
||||
}
|
||||
|
||||
extern void
|
||||
debug(struct SN_env * z, int number, int line_count)
|
||||
{
|
||||
int i;
|
||||
int limit = SIZE(z->p);
|
||||
|
||||
/* if (number >= 0) printf("%3d (line %4d): '", number, line_count); */
|
||||
if (number >= 0)
|
||||
printf("%3d (line %4d): [%d]'", number, line_count, limit);
|
||||
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");
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*
|
||||
/*
|
||||
* stopword library
|
||||
* Teodor Sigaev <teodor@sigaev.ru>
|
||||
*/
|
||||
|
@ -13,97 +13,114 @@
|
|||
|
||||
#define STOPBUFLEN 4096
|
||||
|
||||
char*
|
||||
lowerstr(char *str) {
|
||||
char *ptr=str;
|
||||
while(*ptr) {
|
||||
*ptr = tolower(*(unsigned char*)ptr);
|
||||
char *
|
||||
lowerstr(char *str)
|
||||
{
|
||||
char *ptr = str;
|
||||
|
||||
while (*ptr)
|
||||
{
|
||||
*ptr = tolower(*(unsigned char *) ptr);
|
||||
ptr++;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
void
|
||||
freestoplist(StopList *s) {
|
||||
char **ptr=s->stop;
|
||||
if ( ptr )
|
||||
while( *ptr && s->len >0 ) {
|
||||
freestoplist(StopList * s)
|
||||
{
|
||||
char **ptr = s->stop;
|
||||
|
||||
if (ptr)
|
||||
while (*ptr && s->len > 0)
|
||||
{
|
||||
free(*ptr);
|
||||
ptr++; s->len--;
|
||||
free(s->stop);
|
||||
}
|
||||
memset(s,0,sizeof(StopList));
|
||||
ptr++;
|
||||
s->len--;
|
||||
free(s->stop);
|
||||
}
|
||||
memset(s, 0, sizeof(StopList));
|
||||
}
|
||||
|
||||
void
|
||||
readstoplist(text *in, StopList *s) {
|
||||
char **stop=NULL;
|
||||
s->len=0;
|
||||
if ( in && VARSIZE(in) - VARHDRSZ > 0 ) {
|
||||
char *filename=text2char(in);
|
||||
FILE *hin=NULL;
|
||||
char buf[STOPBUFLEN];
|
||||
int reallen=0;
|
||||
readstoplist(text *in, StopList * s)
|
||||
{
|
||||
char **stop = NULL;
|
||||
|
||||
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,
|
||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||
errmsg("could not open file \"%s\": %m",
|
||||
filename)));
|
||||
filename)));
|
||||
|
||||
while( fgets(buf,STOPBUFLEN,hin) ) {
|
||||
buf[strlen(buf)-1] = '\0';
|
||||
if ( *buf=='\0' ) continue;
|
||||
while (fgets(buf, STOPBUFLEN, hin))
|
||||
{
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
if (*buf == '\0')
|
||||
continue;
|
||||
|
||||
if ( s->len>= reallen ) {
|
||||
char **tmp;
|
||||
reallen=(reallen) ? reallen*2 : 16;
|
||||
tmp=(char**)realloc((void*)stop, sizeof(char*)*reallen);
|
||||
if (!tmp) {
|
||||
if (s->len >= reallen)
|
||||
{
|
||||
char **tmp;
|
||||
|
||||
reallen = (reallen) ? reallen * 2 : 16;
|
||||
tmp = (char **) realloc((void *) stop, sizeof(char *) * reallen);
|
||||
if (!tmp)
|
||||
{
|
||||
freestoplist(s);
|
||||
fclose(hin);
|
||||
fclose(hin);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
}
|
||||
stop=tmp;
|
||||
stop = tmp;
|
||||
}
|
||||
|
||||
stop[s->len]=strdup(buf);
|
||||
if ( !stop[s->len] ) {
|
||||
|
||||
stop[s->len] = strdup(buf);
|
||||
if (!stop[s->len])
|
||||
{
|
||||
freestoplist(s);
|
||||
fclose(hin);
|
||||
fclose(hin);
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_OUT_OF_MEMORY),
|
||||
errmsg("out of memory")));
|
||||
}
|
||||
if ( s->wordop )
|
||||
stop[s->len]=(s->wordop)(stop[s->len]);
|
||||
if (s->wordop)
|
||||
stop[s->len] = (s->wordop) (stop[s->len]);
|
||||
|
||||
(s->len)++;
|
||||
(s->len)++;
|
||||
}
|
||||
fclose(hin);
|
||||
pfree(filename);
|
||||
pfree(filename);
|
||||
}
|
||||
s->stop=stop;
|
||||
}
|
||||
s->stop = stop;
|
||||
}
|
||||
|
||||
static int
|
||||
comparestr(const void *a, const void *b) {
|
||||
return strcmp( *(char**)a, *(char**)b );
|
||||
comparestr(const void *a, const void *b)
|
||||
{
|
||||
return strcmp(*(char **) a, *(char **) b);
|
||||
}
|
||||
|
||||
void
|
||||
sortstoplist(StopList *s) {
|
||||
if (s->stop && s->len>0)
|
||||
qsort(s->stop, s->len, sizeof(char*), comparestr);
|
||||
sortstoplist(StopList * s)
|
||||
{
|
||||
if (s->stop && s->len > 0)
|
||||
qsort(s->stop, s->len, sizeof(char *), comparestr);
|
||||
}
|
||||
|
||||
bool
|
||||
searchstoplist(StopList *s, char *key) {
|
||||
if ( s->wordop )
|
||||
key=(*(s->wordop))(key);
|
||||
return ( s->stop && s->len>0 && bsearch(&key, s->stop, s->len, sizeof(char*), comparestr) ) ? true : false;
|
||||
searchstoplist(StopList * s, char *key)
|
||||
{
|
||||
if (s->wordop)
|
||||
key = (*(s->wordop)) (key);
|
||||
return (s->stop && s->len > 0 && bsearch(&key, s->stop, s->len, sizeof(char *), comparestr)) ? true : false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* interface functions to tscfg
|
||||
/*
|
||||
* interface functions to tscfg
|
||||
* Teodor Sigaev <teodor@sigaev.ru>
|
||||
*/
|
||||
#include <errno.h>
|
||||
|
@ -23,263 +23,299 @@
|
|||
|
||||
/*********top interface**********/
|
||||
|
||||
static void *plan_getcfg_bylocale=NULL;
|
||||
static void *plan_getcfg=NULL;
|
||||
static void *plan_getmap=NULL;
|
||||
static void *plan_name2id=NULL;
|
||||
static Oid current_cfg_id=0;
|
||||
static void *plan_getcfg_bylocale = NULL;
|
||||
static void *plan_getcfg = NULL;
|
||||
static void *plan_getmap = NULL;
|
||||
static void *plan_name2id = NULL;
|
||||
static Oid current_cfg_id = 0;
|
||||
|
||||
void
|
||||
init_cfg(Oid id, TSCfgInfo *cfg) {
|
||||
Oid arg[2]={ OIDOID, OIDOID };
|
||||
bool isnull;
|
||||
Datum pars[2]={ ObjectIdGetDatum(id), ObjectIdGetDatum(id) } ;
|
||||
int stat,i,j;
|
||||
text *ptr;
|
||||
text *prsname=NULL;
|
||||
MemoryContext oldcontext;
|
||||
init_cfg(Oid id, TSCfgInfo * cfg)
|
||||
{
|
||||
Oid arg[2] = {OIDOID, OIDOID};
|
||||
bool isnull;
|
||||
Datum pars[2] = {ObjectIdGetDatum(id), ObjectIdGetDatum(id)};
|
||||
int stat,
|
||||
i,
|
||||
j;
|
||||
text *ptr;
|
||||
text *prsname = NULL;
|
||||
MemoryContext oldcontext;
|
||||
|
||||
memset(cfg,0,sizeof(TSCfgInfo));
|
||||
memset(cfg, 0, sizeof(TSCfgInfo));
|
||||
SPI_connect();
|
||||
if ( !plan_getcfg ) {
|
||||
plan_getcfg = SPI_saveplan( SPI_prepare( "select prs_name from pg_ts_cfg where oid = $1" , 1, arg ) );
|
||||
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)
|
||||
ts_error(ERROR, "SPI_prepare() failed");
|
||||
}
|
||||
|
||||
stat = SPI_execp(plan_getcfg, pars, " ", 1);
|
||||
if ( stat < 0 )
|
||||
ts_error (ERROR, "SPI_execp return %d", stat);
|
||||
if ( SPI_processed > 0 ) {
|
||||
prsname = (text*) DatumGetPointer(
|
||||
SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)
|
||||
);
|
||||
if (stat < 0)
|
||||
ts_error(ERROR, "SPI_execp return %d", stat);
|
||||
if (SPI_processed > 0)
|
||||
{
|
||||
prsname = (text *) DatumGetPointer(
|
||||
SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull)
|
||||
);
|
||||
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
||||
prsname = ptextdup( prsname );
|
||||
prsname = ptextdup(prsname);
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
||||
cfg->id=id;
|
||||
} else
|
||||
|
||||
cfg->id = id;
|
||||
}
|
||||
else
|
||||
ts_error(ERROR, "No tsearch cfg with id %d", id);
|
||||
|
||||
arg[0]=TEXTOID;
|
||||
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 )
|
||||
arg[0] = TEXTOID;
|
||||
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");
|
||||
}
|
||||
|
||||
pars[0]=PointerGetDatum( prsname );
|
||||
pars[0] = PointerGetDatum(prsname);
|
||||
stat = SPI_execp(plan_getmap, pars, " ", 0);
|
||||
if ( stat < 0 )
|
||||
ts_error (ERROR, "SPI_execp return %d", stat);
|
||||
if ( SPI_processed <= 0 )
|
||||
if (stat < 0)
|
||||
ts_error(ERROR, "SPI_execp return %d", stat);
|
||||
if (SPI_processed <= 0)
|
||||
ts_error(ERROR, "No parser with id %d", id);
|
||||
|
||||
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));
|
||||
ArrayType *a;
|
||||
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));
|
||||
ArrayType *a;
|
||||
|
||||
if ( !cfg->map ) {
|
||||
cfg->len=lexid+1;
|
||||
cfg->map = (ListDictionary*)malloc( sizeof(ListDictionary)*cfg->len );
|
||||
if ( !cfg->map )
|
||||
if (!cfg->map)
|
||||
{
|
||||
cfg->len = lexid + 1;
|
||||
cfg->map = (ListDictionary *) malloc(sizeof(ListDictionary) * cfg->len);
|
||||
if (!cfg->map)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_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)
|
||||
continue;
|
||||
|
||||
a=(ArrayType*)PointerGetDatum( PG_DETOAST_DATUM( DatumGetPointer(toasted_a) ) );
|
||||
|
||||
if ( ARR_NDIM(a) != 1 )
|
||||
ts_error(ERROR,"Wrong dimension");
|
||||
if ( ARRNELEMS(a) < 1 )
|
||||
a = (ArrayType *) PointerGetDatum(PG_DETOAST_DATUM(DatumGetPointer(toasted_a)));
|
||||
|
||||
if (ARR_NDIM(a) != 1)
|
||||
ts_error(ERROR, "Wrong dimension");
|
||||
if (ARRNELEMS(a) < 1)
|
||||
continue;
|
||||
|
||||
cfg->map[lexid].len=ARRNELEMS(a);
|
||||
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 );
|
||||
ptr=(text*)ARR_DATA_PTR(a);
|
||||
cfg->map[lexid].len = ARRNELEMS(a);
|
||||
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);
|
||||
ptr = (text *) ARR_DATA_PTR(a);
|
||||
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));
|
||||
ptr=NEXTVAL(ptr);
|
||||
}
|
||||
ptr = NEXTVAL(ptr);
|
||||
}
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
||||
if ( a != toasted_a )
|
||||
if (a != toasted_a)
|
||||
pfree(a);
|
||||
}
|
||||
|
||||
|
||||
SPI_finish();
|
||||
cfg->prs_id = name2id_prs( prsname );
|
||||
cfg->prs_id = name2id_prs(prsname);
|
||||
pfree(prsname);
|
||||
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] );
|
||||
cfg->map[i].dict_id[j] = ObjectIdGetDatum( name2id_dict(ptr) );
|
||||
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]);
|
||||
cfg->map[i].dict_id[j] = ObjectIdGetDatum(name2id_dict(ptr));
|
||||
pfree(ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
TSCfgInfo *last_cfg;
|
||||
int len;
|
||||
int reallen;
|
||||
TSCfgInfo *list;
|
||||
typedef struct
|
||||
{
|
||||
TSCfgInfo *last_cfg;
|
||||
int len;
|
||||
int reallen;
|
||||
TSCfgInfo *list;
|
||||
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
|
||||
reset_cfg(void) {
|
||||
freeSNMap( &(CList.name2id_map) );
|
||||
if ( CList.list ) {
|
||||
int i,j;
|
||||
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 )
|
||||
reset_cfg(void)
|
||||
{
|
||||
freeSNMap(&(CList.name2id_map));
|
||||
if (CList.list)
|
||||
{
|
||||
int i,
|
||||
j;
|
||||
|
||||
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 );
|
||||
free(CList.list[i].map);
|
||||
}
|
||||
free(CList.list);
|
||||
free(CList.list);
|
||||
}
|
||||
memset(&CList,0,sizeof(CFGList));
|
||||
memset(&CList, 0, sizeof(CFGList));
|
||||
}
|
||||
|
||||
static int
|
||||
comparecfg(const void *a, const void *b) {
|
||||
return ((TSCfgInfo*)a)->id - ((TSCfgInfo*)b)->id;
|
||||
comparecfg(const void *a, const void *b)
|
||||
{
|
||||
return ((TSCfgInfo *) a)->id - ((TSCfgInfo *) b)->id;
|
||||
}
|
||||
|
||||
TSCfgInfo *
|
||||
findcfg(Oid id) {
|
||||
findcfg(Oid id)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
/* already used cfg */
|
||||
if ( CList.len != 0 ) {
|
||||
TSCfgInfo key;
|
||||
key.id=id;
|
||||
if (CList.len != 0)
|
||||
{
|
||||
TSCfgInfo key;
|
||||
|
||||
key.id = id;
|
||||
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;
|
||||
}
|
||||
|
||||
/* last chance */
|
||||
if ( CList.len==CList.reallen ) {
|
||||
TSCfgInfo *tmp;
|
||||
int reallen = ( CList.reallen ) ? 2*CList.reallen : 16;
|
||||
tmp=(TSCfgInfo*)realloc(CList.list,sizeof(TSCfgInfo)*reallen);
|
||||
if ( !tmp )
|
||||
ts_error(ERROR,"No memory");
|
||||
CList.reallen=reallen;
|
||||
CList.list=tmp;
|
||||
if (CList.len == CList.reallen)
|
||||
{
|
||||
TSCfgInfo *tmp;
|
||||
int reallen = (CList.reallen) ? 2 * CList.reallen : 16;
|
||||
|
||||
tmp = (TSCfgInfo *) realloc(CList.list, sizeof(TSCfgInfo) * reallen);
|
||||
if (!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);
|
||||
CList.len++;
|
||||
qsort(CList.list, CList.len, sizeof(TSCfgInfo), comparecfg);
|
||||
return findcfg(id); /* qsort changed order!! */;
|
||||
return findcfg(id); /* qsort changed order!! */ ;
|
||||
}
|
||||
|
||||
|
||||
Oid
|
||||
name2id_cfg(text *name) {
|
||||
Oid arg[1]={ TEXTOID };
|
||||
bool isnull;
|
||||
Datum pars[1]={ PointerGetDatum(name) };
|
||||
int stat;
|
||||
Oid id=findSNMap_t( &(CList.name2id_map), name );
|
||||
|
||||
if ( id )
|
||||
name2id_cfg(text *name)
|
||||
{
|
||||
Oid arg[1] = {TEXTOID};
|
||||
bool isnull;
|
||||
Datum pars[1] = {PointerGetDatum(name)};
|
||||
int stat;
|
||||
Oid id = findSNMap_t(&(CList.name2id_map), name);
|
||||
|
||||
if (id)
|
||||
return id;
|
||||
|
||||
|
||||
SPI_connect();
|
||||
if ( !plan_name2id ) {
|
||||
plan_name2id = SPI_saveplan( SPI_prepare( "select oid from pg_ts_cfg where ts_name = $1" , 1, arg ) );
|
||||
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)
|
||||
/* internal error */
|
||||
elog(ERROR, "SPI_prepare() failed");
|
||||
}
|
||||
|
||||
stat = SPI_execp(plan_name2id, pars, " ", 1);
|
||||
if ( stat < 0 )
|
||||
if (stat < 0)
|
||||
/* internal error */
|
||||
elog (ERROR, "SPI_execp return %d", stat);
|
||||
if ( SPI_processed > 0 ) {
|
||||
id=DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) );
|
||||
if ( isnull )
|
||||
elog(ERROR, "SPI_execp return %d", stat);
|
||||
if (SPI_processed > 0)
|
||||
{
|
||||
id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
||||
if (isnull)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||
errmsg("null id for tsearch config")));
|
||||
} else
|
||||
}
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||
errmsg("no tsearch config")));
|
||||
|
||||
SPI_finish();
|
||||
addSNMap_t( &(CList.name2id_map), name, id );
|
||||
addSNMap_t(&(CList.name2id_map), name, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
parsetext_v2(TSCfgInfo *cfg, PRSTEXT * prs, char *buf, int4 buflen) {
|
||||
int type, lenlemm, i;
|
||||
char *lemm=NULL;
|
||||
void
|
||||
parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
|
||||
{
|
||||
int type,
|
||||
lenlemm,
|
||||
i;
|
||||
char *lemm = NULL;
|
||||
WParserInfo *prsobj = findprs(cfg->prs_id);
|
||||
|
||||
prsobj->prs=(void*)DatumGetPointer(
|
||||
FunctionCall2(
|
||||
&(prsobj->start_info),
|
||||
PointerGetDatum(buf),
|
||||
Int32GetDatum(buflen)
|
||||
)
|
||||
);
|
||||
prsobj->prs = (void *) DatumGetPointer(
|
||||
FunctionCall2(
|
||||
&(prsobj->start_info),
|
||||
PointerGetDatum(buf),
|
||||
Int32GetDatum(buflen)
|
||||
)
|
||||
);
|
||||
|
||||
while( ( type=DatumGetInt32(FunctionCall3(
|
||||
&(prsobj->getlexeme_info),
|
||||
PointerGetDatum(prsobj->prs),
|
||||
PointerGetDatum(&lemm),
|
||||
PointerGetDatum(&lenlemm))) ) != 0 ) {
|
||||
while ((type = DatumGetInt32(FunctionCall3(
|
||||
&(prsobj->getlexeme_info),
|
||||
PointerGetDatum(prsobj->prs),
|
||||
PointerGetDatum(&lemm),
|
||||
PointerGetDatum(&lenlemm)))) != 0)
|
||||
{
|
||||
|
||||
if ( lenlemm >= MAXSTRLEN )
|
||||
if (lenlemm >= MAXSTRLEN)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("word is too long")));
|
||||
|
||||
if ( type >= cfg->len ) /* skip this type of lexem */
|
||||
continue;
|
||||
if (type >= cfg->len) /* skip this type of lexem */
|
||||
continue;
|
||||
|
||||
for(i=0;i<cfg->map[type].len;i++) {
|
||||
DictInfo *dict=finddict( DatumGetObjectId(cfg->map[type].dict_id[i]) );
|
||||
char **norms, **ptr;
|
||||
|
||||
norms = ptr = (char**)DatumGetPointer(
|
||||
FunctionCall3(
|
||||
&(dict->lexize_info),
|
||||
PointerGetDatum(dict->dictionary),
|
||||
PointerGetDatum(lemm),
|
||||
PointerGetDatum(lenlemm)
|
||||
)
|
||||
);
|
||||
if ( !norms ) /* dictionary doesn't know this lexem */
|
||||
for (i = 0; i < cfg->map[type].len; i++)
|
||||
{
|
||||
DictInfo *dict = finddict(DatumGetObjectId(cfg->map[type].dict_id[i]));
|
||||
char **norms,
|
||||
**ptr;
|
||||
|
||||
norms = ptr = (char **) DatumGetPointer(
|
||||
FunctionCall3(
|
||||
&(dict->lexize_info),
|
||||
PointerGetDatum(dict->dictionary),
|
||||
PointerGetDatum(lemm),
|
||||
PointerGetDatum(lenlemm)
|
||||
)
|
||||
);
|
||||
if (!norms) /* dictionary doesn't know this lexem */
|
||||
continue;
|
||||
|
||||
prs->pos++; /*set pos*/
|
||||
prs->pos++; /* set pos */
|
||||
|
||||
while( *ptr ) {
|
||||
if (prs->curwords == prs->lenwords) {
|
||||
while (*ptr)
|
||||
{
|
||||
if (prs->curwords == prs->lenwords)
|
||||
{
|
||||
prs->lenwords *= 2;
|
||||
prs->words = (WORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(WORD));
|
||||
}
|
||||
|
@ -292,191 +328,220 @@ parsetext_v2(TSCfgInfo *cfg, PRSTEXT * prs, char *buf, int4 buflen) {
|
|||
prs->curwords++;
|
||||
}
|
||||
pfree(norms);
|
||||
break; /* lexem already normalized or is stop word*/
|
||||
break; /* lexem already normalized or is stop
|
||||
* word */
|
||||
}
|
||||
}
|
||||
|
||||
FunctionCall1(
|
||||
&(prsobj->end_info),
|
||||
PointerGetDatum(prsobj->prs)
|
||||
);
|
||||
&(prsobj->end_info),
|
||||
PointerGetDatum(prsobj->prs)
|
||||
);
|
||||
}
|
||||
|
||||
static void
|
||||
hladdword(HLPRSTEXT * prs, char *buf, int4 buflen, int type) {
|
||||
while (prs->curwords >= prs->lenwords) {
|
||||
hladdword(HLPRSTEXT * prs, char *buf, int4 buflen, int type)
|
||||
{
|
||||
while (prs->curwords >= prs->lenwords)
|
||||
{
|
||||
prs->lenwords *= 2;
|
||||
prs->words = (HLWORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(HLWORD));
|
||||
}
|
||||
memset( &(prs->words[prs->curwords]), 0, sizeof(HLWORD) );
|
||||
prs->words[prs->curwords].type = (uint8)type;
|
||||
prs->words[prs->curwords].len = buflen;
|
||||
memset(&(prs->words[prs->curwords]), 0, sizeof(HLWORD));
|
||||
prs->words[prs->curwords].type = (uint8) type;
|
||||
prs->words[prs->curwords].len = buflen;
|
||||
prs->words[prs->curwords].word = palloc(buflen);
|
||||
memcpy(prs->words[prs->curwords].word, buf, buflen);
|
||||
prs->curwords++;
|
||||
prs->curwords++;
|
||||
}
|
||||
|
||||
static void
|
||||
hlfinditem(HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int buflen ) {
|
||||
int i;
|
||||
ITEM *item=GETQUERY(query);
|
||||
HLWORD *word=&( prs->words[prs->curwords-1] );
|
||||
hlfinditem(HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int buflen)
|
||||
{
|
||||
int i;
|
||||
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->words = (HLWORD *) repalloc((void *) prs->words, prs->lenwords * sizeof(HLWORD));
|
||||
}
|
||||
|
||||
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 ) {
|
||||
memcpy( &(prs->words[prs->curwords]), word, sizeof(HLWORD) );
|
||||
prs->words[prs->curwords].item=item;
|
||||
prs->words[prs->curwords].repeated=1;
|
||||
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)
|
||||
{
|
||||
memcpy(&(prs->words[prs->curwords]), word, sizeof(HLWORD));
|
||||
prs->words[prs->curwords].item = item;
|
||||
prs->words[prs->curwords].repeated = 1;
|
||||
prs->curwords++;
|
||||
} else
|
||||
word->item=item;
|
||||
}
|
||||
else
|
||||
word->item = item;
|
||||
}
|
||||
item++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hlparsetext(TSCfgInfo *cfg, HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int4 buflen) {
|
||||
int type, lenlemm, i;
|
||||
char *lemm=NULL;
|
||||
void
|
||||
hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4 buflen)
|
||||
{
|
||||
int type,
|
||||
lenlemm,
|
||||
i;
|
||||
char *lemm = NULL;
|
||||
WParserInfo *prsobj = findprs(cfg->prs_id);
|
||||
|
||||
prsobj->prs=(void*)DatumGetPointer(
|
||||
FunctionCall2(
|
||||
&(prsobj->start_info),
|
||||
PointerGetDatum(buf),
|
||||
Int32GetDatum(buflen)
|
||||
)
|
||||
);
|
||||
prsobj->prs = (void *) DatumGetPointer(
|
||||
FunctionCall2(
|
||||
&(prsobj->start_info),
|
||||
PointerGetDatum(buf),
|
||||
Int32GetDatum(buflen)
|
||||
)
|
||||
);
|
||||
|
||||
while( ( type=DatumGetInt32(FunctionCall3(
|
||||
&(prsobj->getlexeme_info),
|
||||
PointerGetDatum(prsobj->prs),
|
||||
PointerGetDatum(&lemm),
|
||||
PointerGetDatum(&lenlemm))) ) != 0 ) {
|
||||
while ((type = DatumGetInt32(FunctionCall3(
|
||||
&(prsobj->getlexeme_info),
|
||||
PointerGetDatum(prsobj->prs),
|
||||
PointerGetDatum(&lemm),
|
||||
PointerGetDatum(&lenlemm)))) != 0)
|
||||
{
|
||||
|
||||
if ( lenlemm >= MAXSTRLEN )
|
||||
if (lenlemm >= MAXSTRLEN)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("word is too long")));
|
||||
|
||||
hladdword(prs,lemm,lenlemm,type);
|
||||
hladdword(prs, lemm, lenlemm, type);
|
||||
|
||||
if ( type >= cfg->len )
|
||||
continue;
|
||||
if (type >= cfg->len)
|
||||
continue;
|
||||
|
||||
for(i=0;i<cfg->map[type].len;i++) {
|
||||
DictInfo *dict=finddict( DatumGetObjectId(cfg->map[type].dict_id[i]) );
|
||||
char **norms, **ptr;
|
||||
|
||||
norms = ptr = (char**)DatumGetPointer(
|
||||
FunctionCall3(
|
||||
&(dict->lexize_info),
|
||||
PointerGetDatum(dict->dictionary),
|
||||
PointerGetDatum(lemm),
|
||||
PointerGetDatum(lenlemm)
|
||||
)
|
||||
);
|
||||
if ( !norms ) /* dictionary doesn't know this lexem */
|
||||
for (i = 0; i < cfg->map[type].len; i++)
|
||||
{
|
||||
DictInfo *dict = finddict(DatumGetObjectId(cfg->map[type].dict_id[i]));
|
||||
char **norms,
|
||||
**ptr;
|
||||
|
||||
norms = ptr = (char **) DatumGetPointer(
|
||||
FunctionCall3(
|
||||
&(dict->lexize_info),
|
||||
PointerGetDatum(dict->dictionary),
|
||||
PointerGetDatum(lemm),
|
||||
PointerGetDatum(lenlemm)
|
||||
)
|
||||
);
|
||||
if (!norms) /* dictionary doesn't know this lexem */
|
||||
continue;
|
||||
|
||||
while( *ptr ) {
|
||||
hlfinditem(prs,query,*ptr,strlen(*ptr));
|
||||
while (*ptr)
|
||||
{
|
||||
hlfinditem(prs, query, *ptr, strlen(*ptr));
|
||||
pfree(*ptr);
|
||||
ptr++;
|
||||
}
|
||||
pfree(norms);
|
||||
break; /* lexem already normalized or is stop word*/
|
||||
break; /* lexem already normalized or is stop
|
||||
* word */
|
||||
}
|
||||
}
|
||||
|
||||
FunctionCall1(
|
||||
&(prsobj->end_info),
|
||||
PointerGetDatum(prsobj->prs)
|
||||
);
|
||||
&(prsobj->end_info),
|
||||
PointerGetDatum(prsobj->prs)
|
||||
);
|
||||
}
|
||||
|
||||
text*
|
||||
genhl(HLPRSTEXT * prs) {
|
||||
text *out;
|
||||
int len=128;
|
||||
char *ptr;
|
||||
HLWORD *wrd=prs->words;
|
||||
text *
|
||||
genhl(HLPRSTEXT * prs)
|
||||
{
|
||||
text *out;
|
||||
int len = 128;
|
||||
char *ptr;
|
||||
HLWORD *wrd = prs->words;
|
||||
|
||||
out = (text*)palloc( len );
|
||||
ptr=((char*)out) + VARHDRSZ;
|
||||
out = (text *) palloc(len);
|
||||
ptr = ((char *) out) + VARHDRSZ;
|
||||
|
||||
while( wrd - prs->words < prs->curwords ) {
|
||||
while ( wrd->len + prs->stopsellen + prs->startsellen + (ptr - ((char*)out)) >= len ) {
|
||||
int dist = ptr - ((char*)out);
|
||||
len*= 2;
|
||||
while (wrd - prs->words < prs->curwords)
|
||||
{
|
||||
while (wrd->len + prs->stopsellen + prs->startsellen + (ptr - ((char *) out)) >= len)
|
||||
{
|
||||
int dist = ptr - ((char *) out);
|
||||
|
||||
len *= 2;
|
||||
out = (text *) repalloc(out, len);
|
||||
ptr=((char*)out) + dist;
|
||||
ptr = ((char *) out) + dist;
|
||||
}
|
||||
|
||||
if ( wrd->in && !wrd->skip && !wrd->repeated ) {
|
||||
if ( wrd->replace ) {
|
||||
*ptr=' ';
|
||||
if (wrd->in && !wrd->skip && !wrd->repeated)
|
||||
{
|
||||
if (wrd->replace)
|
||||
{
|
||||
*ptr = ' ';
|
||||
ptr++;
|
||||
} else {
|
||||
if (wrd->selected) {
|
||||
memcpy(ptr,prs->startsel,prs->startsellen);
|
||||
ptr+=prs->startsellen;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (wrd->selected)
|
||||
{
|
||||
memcpy(ptr, prs->startsel, prs->startsellen);
|
||||
ptr += prs->startsellen;
|
||||
}
|
||||
memcpy(ptr,wrd->word,wrd->len);
|
||||
ptr+=wrd->len;
|
||||
if (wrd->selected) {
|
||||
memcpy(ptr,prs->stopsel,prs->stopsellen);
|
||||
ptr+=prs->stopsellen;
|
||||
memcpy(ptr, wrd->word, wrd->len);
|
||||
ptr += wrd->len;
|
||||
if (wrd->selected)
|
||||
{
|
||||
memcpy(ptr, prs->stopsel, prs->stopsellen);
|
||||
ptr += prs->stopsellen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !wrd->repeated )
|
||||
if (!wrd->repeated)
|
||||
pfree(wrd->word);
|
||||
|
||||
wrd++;
|
||||
}
|
||||
|
||||
VARATT_SIZEP(out)=ptr - ((char*)out);
|
||||
return out;
|
||||
VARATT_SIZEP(out) = ptr - ((char *) out);
|
||||
return out;
|
||||
}
|
||||
|
||||
int
|
||||
get_currcfg(void) {
|
||||
Oid arg[1]={ TEXTOID };
|
||||
int
|
||||
get_currcfg(void)
|
||||
{
|
||||
Oid arg[1] = {TEXTOID};
|
||||
const char *curlocale;
|
||||
Datum pars[1];
|
||||
bool isnull;
|
||||
int stat;
|
||||
Datum pars[1];
|
||||
bool isnull;
|
||||
int stat;
|
||||
|
||||
if ( current_cfg_id > 0 )
|
||||
if (current_cfg_id > 0)
|
||||
return current_cfg_id;
|
||||
|
||||
SPI_connect();
|
||||
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 )
|
||||
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 */
|
||||
elog(ERROR, "SPI_prepare() failed");
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if ( stat < 0 )
|
||||
if (stat < 0)
|
||||
/* internal error */
|
||||
elog (ERROR, "SPI_execp return %d", stat);
|
||||
if ( SPI_processed > 0 )
|
||||
current_cfg_id = DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) );
|
||||
else
|
||||
elog(ERROR, "SPI_execp return %d", stat);
|
||||
if (SPI_processed > 0)
|
||||
current_cfg_id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_CONFIG_FILE_ERROR),
|
||||
errmsg("could not find tsearch config by locale")));
|
||||
|
@ -487,39 +552,43 @@ get_currcfg(void) {
|
|||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(set_curcfg);
|
||||
Datum set_curcfg(PG_FUNCTION_ARGS);
|
||||
Datum set_curcfg(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
set_curcfg(PG_FUNCTION_ARGS) {
|
||||
findcfg(PG_GETARG_OID(0));
|
||||
current_cfg_id=PG_GETARG_OID(0);
|
||||
PG_RETURN_VOID();
|
||||
set_curcfg(PG_FUNCTION_ARGS)
|
||||
{
|
||||
findcfg(PG_GETARG_OID(0));
|
||||
current_cfg_id = PG_GETARG_OID(0);
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
|
||||
PG_FUNCTION_INFO_V1(set_curcfg_byname);
|
||||
Datum set_curcfg_byname(PG_FUNCTION_ARGS);
|
||||
Datum set_curcfg_byname(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
set_curcfg_byname(PG_FUNCTION_ARGS) {
|
||||
text *name=PG_GETARG_TEXT_P(0);
|
||||
|
||||
DirectFunctionCall1(
|
||||
set_curcfg,
|
||||
ObjectIdGetDatum( name2id_cfg(name) )
|
||||
);
|
||||
PG_FREE_IF_COPY(name, 0);
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
set_curcfg_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *name = PG_GETARG_TEXT_P(0);
|
||||
|
||||
DirectFunctionCall1(
|
||||
set_curcfg,
|
||||
ObjectIdGetDatum(name2id_cfg(name))
|
||||
);
|
||||
PG_FREE_IF_COPY(name, 0);
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(show_curcfg);
|
||||
Datum show_curcfg(PG_FUNCTION_ARGS);
|
||||
Datum show_curcfg(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
show_curcfg(PG_FUNCTION_ARGS) {
|
||||
PG_RETURN_OID( get_currcfg() );
|
||||
show_curcfg(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_OID(get_currcfg());
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(reset_tsearch);
|
||||
Datum reset_tsearch(PG_FUNCTION_ARGS);
|
||||
Datum reset_tsearch(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
reset_tsearch(PG_FUNCTION_ARGS) {
|
||||
ts_error(NOTICE,"TSearch cache cleaned");
|
||||
PG_RETURN_VOID();
|
||||
reset_tsearch(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ts_error(NOTICE, "TSearch cache cleaned");
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
|
|
@ -3,66 +3,73 @@
|
|||
#include "postgres.h"
|
||||
#include "query.h"
|
||||
|
||||
typedef struct {
|
||||
int len;
|
||||
Datum *dict_id;
|
||||
} ListDictionary;
|
||||
typedef struct
|
||||
{
|
||||
int len;
|
||||
Datum *dict_id;
|
||||
} ListDictionary;
|
||||
|
||||
typedef struct {
|
||||
Oid id;
|
||||
Oid prs_id;
|
||||
int len;
|
||||
ListDictionary *map;
|
||||
typedef struct
|
||||
{
|
||||
Oid id;
|
||||
Oid prs_id;
|
||||
int len;
|
||||
ListDictionary *map;
|
||||
} TSCfgInfo;
|
||||
|
||||
Oid name2id_cfg(text *name);
|
||||
TSCfgInfo * findcfg(Oid id);
|
||||
void init_cfg(Oid id, TSCfgInfo *cfg);
|
||||
void reset_cfg(void);
|
||||
Oid name2id_cfg(text *name);
|
||||
TSCfgInfo *findcfg(Oid id);
|
||||
void init_cfg(Oid id, TSCfgInfo * cfg);
|
||||
void reset_cfg(void);
|
||||
|
||||
typedef struct {
|
||||
uint16 len;
|
||||
union {
|
||||
typedef struct
|
||||
{
|
||||
uint16 len;
|
||||
union
|
||||
{
|
||||
uint16 pos;
|
||||
uint16 *apos;
|
||||
} pos;
|
||||
char *word;
|
||||
uint32 alen;
|
||||
} WORD;
|
||||
|
||||
typedef struct {
|
||||
WORD *words;
|
||||
int4 lenwords;
|
||||
int4 curwords;
|
||||
uint16 *apos;
|
||||
} pos;
|
||||
char *word;
|
||||
uint32 alen;
|
||||
} WORD;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
WORD *words;
|
||||
int4 lenwords;
|
||||
int4 curwords;
|
||||
int4 pos;
|
||||
} PRSTEXT;
|
||||
} PRSTEXT;
|
||||
|
||||
typedef struct {
|
||||
uint16 len;
|
||||
uint8 selected:1,
|
||||
in:1,
|
||||
skip:1,
|
||||
replace:1,
|
||||
repeated:1;
|
||||
uint8 type;
|
||||
char *word;
|
||||
ITEM *item;
|
||||
} HLWORD;
|
||||
|
||||
typedef struct {
|
||||
HLWORD *words;
|
||||
int4 lenwords;
|
||||
int4 curwords;
|
||||
char *startsel;
|
||||
char *stopsel;
|
||||
int2 startsellen;
|
||||
int2 stopsellen;
|
||||
} HLPRSTEXT;
|
||||
typedef struct
|
||||
{
|
||||
uint16 len;
|
||||
uint8 selected:1,
|
||||
in:1,
|
||||
skip:1,
|
||||
replace:1,
|
||||
repeated:1;
|
||||
uint8 type;
|
||||
char *word;
|
||||
ITEM *item;
|
||||
} HLWORD;
|
||||
|
||||
void hlparsetext(TSCfgInfo *cfg, HLPRSTEXT * prs, QUERYTYPE *query, char *buf, int4 buflen);
|
||||
text* genhl(HLPRSTEXT * prs);
|
||||
typedef struct
|
||||
{
|
||||
HLWORD *words;
|
||||
int4 lenwords;
|
||||
int4 curwords;
|
||||
char *startsel;
|
||||
char *stopsel;
|
||||
int2 startsellen;
|
||||
int2 stopsellen;
|
||||
} HLPRSTEXT;
|
||||
|
||||
void parsetext_v2(TSCfgInfo *cfg, PRSTEXT * prs, char *buf, int4 buflen);
|
||||
int get_currcfg(void);
|
||||
void hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4 buflen);
|
||||
text *genhl(HLPRSTEXT * prs);
|
||||
|
||||
void parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen);
|
||||
int get_currcfg(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -10,108 +10,128 @@
|
|||
#include "common.h"
|
||||
|
||||
PG_FUNCTION_INFO_V1(tsstat_in);
|
||||
Datum tsstat_in(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
tsstat_in(PG_FUNCTION_ARGS) {
|
||||
tsstat *stat=palloc(STATHDRSIZE);
|
||||
stat->len=STATHDRSIZE;
|
||||
stat->size=0;
|
||||
Datum tsstat_in(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
tsstat_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
tsstat *stat = palloc(STATHDRSIZE);
|
||||
|
||||
stat->len = STATHDRSIZE;
|
||||
stat->size = 0;
|
||||
PG_RETURN_POINTER(stat);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(tsstat_out);
|
||||
Datum tsstat_out(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
tsstat_out(PG_FUNCTION_ARGS) {
|
||||
Datum tsstat_out(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
tsstat_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("tsstat_out not implemented")));
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
static WordEntry**
|
||||
SEI_realloc( WordEntry** in, uint32 *len ) {
|
||||
if ( *len==0 || in==NULL ) {
|
||||
*len=8;
|
||||
in=palloc( sizeof(WordEntry*)* (*len) );
|
||||
} else {
|
||||
static WordEntry **
|
||||
SEI_realloc(WordEntry ** in, uint32 *len)
|
||||
{
|
||||
if (*len == 0 || in == NULL)
|
||||
{
|
||||
*len = 8;
|
||||
in = palloc(sizeof(WordEntry *) * (*len));
|
||||
}
|
||||
else
|
||||
{
|
||||
*len *= 2;
|
||||
in=repalloc( in, sizeof(WordEntry*)* (*len) );
|
||||
in = repalloc(in, sizeof(WordEntry *) * (*len));
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
static int
|
||||
compareStatWord(StatEntry *a, WordEntry *b, tsstat *stat, tsvector *txt) {
|
||||
if ( a->len == b->len )
|
||||
compareStatWord(StatEntry * a, WordEntry * b, tsstat * stat, tsvector * txt)
|
||||
{
|
||||
if (a->len == b->len)
|
||||
return strncmp(
|
||||
STATSTRPTR(stat) + a->pos,
|
||||
STRPTR(txt) + b->pos,
|
||||
a->len
|
||||
STATSTRPTR(stat) + a->pos,
|
||||
STRPTR(txt) + b->pos,
|
||||
a->len
|
||||
);
|
||||
return ( a->len > b->len ) ? 1 : -1;
|
||||
return (a->len > b->len) ? 1 : -1;
|
||||
}
|
||||
|
||||
static tsstat*
|
||||
formstat(tsstat *stat, tsvector *txt, WordEntry** entry, uint32 len) {
|
||||
tsstat *newstat;
|
||||
uint32 totallen, nentry;
|
||||
uint32 slen=0;
|
||||
WordEntry **ptr=entry;
|
||||
char *curptr;
|
||||
StatEntry *sptr,*nptr;
|
||||
static tsstat *
|
||||
formstat(tsstat * stat, tsvector * txt, WordEntry ** entry, uint32 len)
|
||||
{
|
||||
tsstat *newstat;
|
||||
uint32 totallen,
|
||||
nentry;
|
||||
uint32 slen = 0;
|
||||
WordEntry **ptr = entry;
|
||||
char *curptr;
|
||||
StatEntry *sptr,
|
||||
*nptr;
|
||||
|
||||
while(ptr-entry<len) {
|
||||
while (ptr - entry < len)
|
||||
{
|
||||
slen += (*ptr)->len;
|
||||
ptr++;
|
||||
}
|
||||
|
||||
nentry=stat->size + len;
|
||||
slen+=STATSTRSIZE(stat);
|
||||
totallen=CALCSTATSIZE(nentry,slen);
|
||||
newstat=palloc(totallen);
|
||||
newstat->len=totallen;
|
||||
newstat->size=nentry;
|
||||
nentry = stat->size + len;
|
||||
slen += STATSTRSIZE(stat);
|
||||
totallen = CALCSTATSIZE(nentry, slen);
|
||||
newstat = palloc(totallen);
|
||||
newstat->len = totallen;
|
||||
newstat->size = nentry;
|
||||
|
||||
memcpy(STATSTRPTR(newstat), STATSTRPTR(stat), STATSTRSIZE(stat));
|
||||
curptr=STATSTRPTR(newstat) + STATSTRSIZE(stat);
|
||||
curptr = STATSTRPTR(newstat) + STATSTRSIZE(stat);
|
||||
|
||||
ptr=entry;
|
||||
sptr=STATPTR(stat);
|
||||
nptr=STATPTR(newstat);
|
||||
ptr = entry;
|
||||
sptr = STATPTR(stat);
|
||||
nptr = STATPTR(newstat);
|
||||
|
||||
if ( len == 1 ) {
|
||||
StatEntry *StopLow = STATPTR(stat);
|
||||
StatEntry *StopHigh = (StatEntry*)STATSTRPTR(stat);
|
||||
if (len == 1)
|
||||
{
|
||||
StatEntry *StopLow = STATPTR(stat);
|
||||
StatEntry *StopHigh = (StatEntry *) STATSTRPTR(stat);
|
||||
|
||||
while (StopLow < StopHigh) {
|
||||
sptr=StopLow + (StopHigh - StopLow) / 2;
|
||||
if ( compareStatWord(sptr,*ptr,stat,txt) < 0 )
|
||||
while (StopLow < StopHigh)
|
||||
{
|
||||
sptr = StopLow + (StopHigh - StopLow) / 2;
|
||||
if (compareStatWord(sptr, *ptr, stat, txt) < 0)
|
||||
StopLow = sptr + 1;
|
||||
else
|
||||
StopHigh = sptr;
|
||||
StopHigh = sptr;
|
||||
}
|
||||
nptr =STATPTR(newstat) + (StopLow-STATPTR(stat));
|
||||
memcpy( STATPTR(newstat), STATPTR(stat), sizeof(StatEntry) * (StopLow-STATPTR(stat)) );
|
||||
nptr->nentry=POSDATALEN(txt,*ptr);
|
||||
if ( nptr->nentry==0 )
|
||||
nptr->nentry=1;
|
||||
nptr->ndoc=1;
|
||||
nptr->len=(*ptr)->len;
|
||||
nptr = STATPTR(newstat) + (StopLow - STATPTR(stat));
|
||||
memcpy(STATPTR(newstat), STATPTR(stat), sizeof(StatEntry) * (StopLow - STATPTR(stat)));
|
||||
nptr->nentry = POSDATALEN(txt, *ptr);
|
||||
if (nptr->nentry == 0)
|
||||
nptr->nentry = 1;
|
||||
nptr->ndoc = 1;
|
||||
nptr->len = (*ptr)->len;
|
||||
memcpy(curptr, STRPTR(txt) + (*ptr)->pos, nptr->len);
|
||||
nptr->pos = curptr - STATSTRPTR(newstat);
|
||||
memcpy( nptr+1, StopLow, sizeof(StatEntry) * ( ((StatEntry*)STATSTRPTR(stat))-StopLow ) );
|
||||
} else {
|
||||
while( sptr-STATPTR(stat) < stat->size && ptr-entry<len) {
|
||||
if ( compareStatWord(sptr,*ptr,stat,txt) < 0 ) {
|
||||
memcpy(nptr + 1, StopLow, sizeof(StatEntry) * (((StatEntry *) STATSTRPTR(stat)) - StopLow));
|
||||
}
|
||||
else
|
||||
{
|
||||
while (sptr - STATPTR(stat) < stat->size && ptr - entry < len)
|
||||
{
|
||||
if (compareStatWord(sptr, *ptr, stat, txt) < 0)
|
||||
{
|
||||
memcpy(nptr, sptr, sizeof(StatEntry));
|
||||
sptr++;
|
||||
} else {
|
||||
nptr->nentry=POSDATALEN(txt,*ptr);
|
||||
if ( nptr->nentry==0 )
|
||||
nptr->nentry=1;
|
||||
nptr->ndoc=1;
|
||||
nptr->len=(*ptr)->len;
|
||||
}
|
||||
else
|
||||
{
|
||||
nptr->nentry = POSDATALEN(txt, *ptr);
|
||||
if (nptr->nentry == 0)
|
||||
nptr->nentry = 1;
|
||||
nptr->ndoc = 1;
|
||||
nptr->len = (*ptr)->len;
|
||||
memcpy(curptr, STRPTR(txt) + (*ptr)->pos, nptr->len);
|
||||
nptr->pos = curptr - STATSTRPTR(newstat);
|
||||
curptr += nptr->len;
|
||||
|
@ -120,138 +140,168 @@ formstat(tsstat *stat, tsvector *txt, WordEntry** entry, uint32 len) {
|
|||
nptr++;
|
||||
}
|
||||
|
||||
memcpy( nptr, sptr, sizeof(StatEntry)*( stat->size - (sptr-STATPTR(stat)) ) );
|
||||
|
||||
while(ptr-entry<len) {
|
||||
nptr->nentry=POSDATALEN(txt,*ptr);
|
||||
if ( nptr->nentry==0 )
|
||||
nptr->nentry=1;
|
||||
nptr->ndoc=1;
|
||||
nptr->len=(*ptr)->len;
|
||||
memcpy(nptr, sptr, sizeof(StatEntry) * (stat->size - (sptr - STATPTR(stat))));
|
||||
|
||||
while (ptr - entry < len)
|
||||
{
|
||||
nptr->nentry = POSDATALEN(txt, *ptr);
|
||||
if (nptr->nentry == 0)
|
||||
nptr->nentry = 1;
|
||||
nptr->ndoc = 1;
|
||||
nptr->len = (*ptr)->len;
|
||||
memcpy(curptr, STRPTR(txt) + (*ptr)->pos, nptr->len);
|
||||
nptr->pos = curptr - STATSTRPTR(newstat);
|
||||
curptr += nptr->len;
|
||||
ptr++; nptr++;
|
||||
ptr++;
|
||||
nptr++;
|
||||
}
|
||||
}
|
||||
|
||||
return newstat;
|
||||
}
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(ts_accum);
|
||||
Datum ts_accum(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
ts_accum(PG_FUNCTION_ARGS) {
|
||||
tsstat *newstat,*stat= (tsstat*)PG_GETARG_POINTER(0);
|
||||
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||
WordEntry **newentry=NULL;
|
||||
uint32 len=0, cur=0;
|
||||
StatEntry *sptr;
|
||||
WordEntry *wptr;
|
||||
Datum ts_accum(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
ts_accum(PG_FUNCTION_ARGS)
|
||||
{
|
||||
tsstat *newstat,
|
||||
*stat = (tsstat *) PG_GETARG_POINTER(0);
|
||||
tsvector *txt = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
|
||||
WordEntry **newentry = NULL;
|
||||
uint32 len = 0,
|
||||
cur = 0;
|
||||
StatEntry *sptr;
|
||||
WordEntry *wptr;
|
||||
|
||||
if ( stat==NULL || PG_ARGISNULL(0) ) { /* Init in first */
|
||||
stat=palloc(STATHDRSIZE);
|
||||
stat->len=STATHDRSIZE;
|
||||
stat->size=0;
|
||||
if (stat == NULL || PG_ARGISNULL(0))
|
||||
{ /* Init in first */
|
||||
stat = palloc(STATHDRSIZE);
|
||||
stat->len = STATHDRSIZE;
|
||||
stat->size = 0;
|
||||
}
|
||||
|
||||
/* simple check of correctness */
|
||||
if ( txt==NULL || PG_ARGISNULL(1) || txt->size==0 ) {
|
||||
PG_FREE_IF_COPY(txt,1);
|
||||
if (txt == NULL || PG_ARGISNULL(1) || txt->size == 0)
|
||||
{
|
||||
PG_FREE_IF_COPY(txt, 1);
|
||||
PG_RETURN_POINTER(stat);
|
||||
}
|
||||
|
||||
sptr=STATPTR(stat);
|
||||
wptr=ARRPTR(txt);
|
||||
sptr = STATPTR(stat);
|
||||
wptr = ARRPTR(txt);
|
||||
|
||||
if ( stat->size < 100*txt->size ) { /* merge */
|
||||
while( sptr-STATPTR(stat) < stat->size && wptr-ARRPTR(txt) < txt->size ) {
|
||||
int cmp = compareStatWord(sptr,wptr,stat,txt);
|
||||
if ( cmp<0 ) {
|
||||
if (stat->size < 100 * txt->size)
|
||||
{ /* merge */
|
||||
while (sptr - STATPTR(stat) < stat->size && wptr - ARRPTR(txt) < txt->size)
|
||||
{
|
||||
int cmp = compareStatWord(sptr, wptr, stat, txt);
|
||||
|
||||
if (cmp < 0)
|
||||
sptr++;
|
||||
} else if ( cmp==0 ) {
|
||||
int n=POSDATALEN(txt,wptr);
|
||||
|
||||
if (n==0) n=1;
|
||||
else if (cmp == 0)
|
||||
{
|
||||
int n = POSDATALEN(txt, wptr);
|
||||
|
||||
if (n == 0)
|
||||
n = 1;
|
||||
sptr->ndoc++;
|
||||
sptr->nentry +=n ;
|
||||
sptr++; wptr++;
|
||||
} else {
|
||||
if ( cur==len )
|
||||
newentry=SEI_realloc(newentry, &len);
|
||||
newentry[cur]=wptr;
|
||||
wptr++; cur++;
|
||||
sptr->nentry += n;
|
||||
sptr++;
|
||||
wptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cur == len)
|
||||
newentry = SEI_realloc(newentry, &len);
|
||||
newentry[cur] = wptr;
|
||||
wptr++;
|
||||
cur++;
|
||||
}
|
||||
}
|
||||
|
||||
while( wptr-ARRPTR(txt) < txt->size ) {
|
||||
if ( cur==len )
|
||||
newentry=SEI_realloc(newentry, &len);
|
||||
newentry[cur]=wptr;
|
||||
wptr++; cur++;
|
||||
while (wptr - ARRPTR(txt) < txt->size)
|
||||
{
|
||||
if (cur == len)
|
||||
newentry = SEI_realloc(newentry, &len);
|
||||
newentry[cur] = wptr;
|
||||
wptr++;
|
||||
cur++;
|
||||
}
|
||||
} else { /* search */
|
||||
while( wptr-ARRPTR(txt) < txt->size ) {
|
||||
StatEntry *StopLow = STATPTR(stat);
|
||||
StatEntry *StopHigh = (StatEntry*)STATSTRPTR(stat);
|
||||
int cmp;
|
||||
}
|
||||
else
|
||||
{ /* search */
|
||||
while (wptr - ARRPTR(txt) < txt->size)
|
||||
{
|
||||
StatEntry *StopLow = STATPTR(stat);
|
||||
StatEntry *StopHigh = (StatEntry *) STATSTRPTR(stat);
|
||||
int cmp;
|
||||
|
||||
while (StopLow < StopHigh) {
|
||||
sptr=StopLow + (StopHigh - StopLow) / 2;
|
||||
cmp = compareStatWord(sptr,wptr,stat,txt);
|
||||
if (cmp==0) {
|
||||
int n=POSDATALEN(txt,wptr);
|
||||
if (n==0) n=1;
|
||||
while (StopLow < StopHigh)
|
||||
{
|
||||
sptr = StopLow + (StopHigh - StopLow) / 2;
|
||||
cmp = compareStatWord(sptr, wptr, stat, txt);
|
||||
if (cmp == 0)
|
||||
{
|
||||
int n = POSDATALEN(txt, wptr);
|
||||
|
||||
if (n == 0)
|
||||
n = 1;
|
||||
sptr->ndoc++;
|
||||
sptr->nentry +=n ;
|
||||
sptr->nentry += n;
|
||||
break;
|
||||
} else if ( cmp < 0 )
|
||||
}
|
||||
else if (cmp < 0)
|
||||
StopLow = sptr + 1;
|
||||
else
|
||||
StopHigh = sptr;
|
||||
StopHigh = sptr;
|
||||
}
|
||||
|
||||
if ( StopLow >= StopHigh ) { /* not found */
|
||||
if ( cur==len )
|
||||
newentry=SEI_realloc(newentry, &len);
|
||||
newentry[cur]=wptr;
|
||||
|
||||
if (StopLow >= StopHigh)
|
||||
{ /* not found */
|
||||
if (cur == len)
|
||||
newentry = SEI_realloc(newentry, &len);
|
||||
newentry[cur] = wptr;
|
||||
cur++;
|
||||
}
|
||||
wptr++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( cur==0 ) { /* no new words */
|
||||
PG_FREE_IF_COPY(txt,1);
|
||||
|
||||
if (cur == 0)
|
||||
{ /* no new words */
|
||||
PG_FREE_IF_COPY(txt, 1);
|
||||
PG_RETURN_POINTER(stat);
|
||||
}
|
||||
|
||||
newstat = formstat(stat, txt, newentry, cur);
|
||||
pfree(newentry);
|
||||
PG_FREE_IF_COPY(txt,1);
|
||||
PG_FREE_IF_COPY(txt, 1);
|
||||
/* pfree(stat); */
|
||||
|
||||
PG_RETURN_POINTER(newstat);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
uint32 cur;
|
||||
tsvector *stat;
|
||||
} StatStorage;
|
||||
typedef struct
|
||||
{
|
||||
uint32 cur;
|
||||
tsvector *stat;
|
||||
} StatStorage;
|
||||
|
||||
static void
|
||||
ts_setup_firstcall(FuncCallContext *funcctx, tsstat *stat) {
|
||||
TupleDesc tupdesc;
|
||||
MemoryContext oldcontext;
|
||||
StatStorage *st;
|
||||
|
||||
ts_setup_firstcall(FuncCallContext *funcctx, tsstat * stat)
|
||||
{
|
||||
TupleDesc tupdesc;
|
||||
MemoryContext oldcontext;
|
||||
StatStorage *st;
|
||||
|
||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||
st=palloc( sizeof(StatStorage) );
|
||||
st->cur=0;
|
||||
st->stat=palloc( stat->len );
|
||||
st = palloc(sizeof(StatStorage));
|
||||
st->cur = 0;
|
||||
st->stat = palloc(stat->len);
|
||||
memcpy(st->stat, stat, stat->len);
|
||||
funcctx->user_fctx = (void*)st;
|
||||
funcctx->user_fctx = (void *) st;
|
||||
tupdesc = RelationNameGetTupleDesc("statinfo");
|
||||
funcctx->slot = TupleDescGetSlot(tupdesc);
|
||||
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
||||
|
@ -260,162 +310,175 @@ ts_setup_firstcall(FuncCallContext *funcctx, tsstat *stat) {
|
|||
|
||||
|
||||
static Datum
|
||||
ts_process_call(FuncCallContext *funcctx) {
|
||||
StatStorage *st;
|
||||
st=(StatStorage*)funcctx->user_fctx;
|
||||
ts_process_call(FuncCallContext *funcctx)
|
||||
{
|
||||
StatStorage *st;
|
||||
|
||||
if ( st->cur < st->stat->size ) {
|
||||
Datum result;
|
||||
char* values[3];
|
||||
char ndoc[16];
|
||||
char nentry[16];
|
||||
StatEntry *entry=STATPTR(st->stat) + st->cur;
|
||||
HeapTuple tuple;
|
||||
st = (StatStorage *) funcctx->user_fctx;
|
||||
|
||||
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';
|
||||
if (st->cur < st->stat->size)
|
||||
{
|
||||
Datum result;
|
||||
char *values[3];
|
||||
char ndoc[16];
|
||||
char nentry[16];
|
||||
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);
|
||||
result = TupleGetDatum(funcctx->slot, tuple);
|
||||
|
||||
pfree(values[0]);
|
||||
st->cur++;
|
||||
return result;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
pfree(st->stat);
|
||||
pfree(st);
|
||||
}
|
||||
|
||||
return (Datum)0;
|
||||
|
||||
return (Datum) 0;
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(ts_accum_finish);
|
||||
Datum ts_accum_finish(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
ts_accum_finish(PG_FUNCTION_ARGS) {
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
Datum ts_accum_finish(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
ts_accum_finish(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
|
||||
if (SRF_IS_FIRSTCALL()) {
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
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();
|
||||
if ( (result=ts_process_call(funcctx)) != (Datum)0 )
|
||||
if ((result = ts_process_call(funcctx)) != (Datum) 0)
|
||||
SRF_RETURN_NEXT(funcctx, result);
|
||||
SRF_RETURN_DONE(funcctx);
|
||||
}
|
||||
|
||||
static Oid tiOid=InvalidOid;
|
||||
static void
|
||||
get_ti_Oid(void) {
|
||||
int ret;
|
||||
bool isnull;
|
||||
static Oid tiOid = InvalidOid;
|
||||
static void
|
||||
get_ti_Oid(void)
|
||||
{
|
||||
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 */
|
||||
elog(ERROR, "SPI_exec to get tsvector oid returns %d", ret);
|
||||
|
||||
if ( SPI_processed<0 )
|
||||
if (SPI_processed < 0)
|
||||
/* internal error */
|
||||
elog(ERROR, "There is no tsvector type");
|
||||
tiOid = DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) );
|
||||
if ( tiOid==InvalidOid )
|
||||
tiOid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
||||
if (tiOid == InvalidOid)
|
||||
/* internal error */
|
||||
elog(ERROR, "tsvector type has InvalidOid");
|
||||
}
|
||||
|
||||
static tsstat*
|
||||
ts_stat_sql(text *txt) {
|
||||
char *query=text2char(txt);
|
||||
int i;
|
||||
tsstat *newstat,*stat;
|
||||
bool isnull;
|
||||
Portal portal;
|
||||
void *plan;
|
||||
static tsstat *
|
||||
ts_stat_sql(text *txt)
|
||||
{
|
||||
char *query = text2char(txt);
|
||||
int i;
|
||||
tsstat *newstat,
|
||||
*stat;
|
||||
bool isnull;
|
||||
Portal portal;
|
||||
void *plan;
|
||||
|
||||
if ( tiOid==InvalidOid )
|
||||
if (tiOid == InvalidOid)
|
||||
get_ti_Oid();
|
||||
|
||||
if ( (plan = SPI_prepare(query,0,NULL))==NULL )
|
||||
if ((plan = SPI_prepare(query, 0, NULL)) == NULL)
|
||||
/* 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 */
|
||||
elog(ERROR, "SPI_cursor_open('%s') returns NULL",query);
|
||||
elog(ERROR, "SPI_cursor_open('%s') returns NULL", query);
|
||||
|
||||
SPI_cursor_fetch(portal, true, 100);
|
||||
|
||||
if ( SPI_tuptable->tupdesc->natts != 1 )
|
||||
if (SPI_tuptable->tupdesc->natts != 1)
|
||||
/* internal error */
|
||||
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 */
|
||||
elog(ERROR, "column isn't of tsvector type");
|
||||
|
||||
stat=palloc(STATHDRSIZE);
|
||||
stat->len=STATHDRSIZE;
|
||||
stat->size=0;
|
||||
stat = palloc(STATHDRSIZE);
|
||||
stat->len = STATHDRSIZE;
|
||||
stat->size = 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);
|
||||
while (SPI_processed > 0)
|
||||
{
|
||||
for (i = 0; i < SPI_processed; i++)
|
||||
{
|
||||
Datum data = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull);
|
||||
|
||||
if ( !isnull ) {
|
||||
newstat = (tsstat*)DatumGetPointer(DirectFunctionCall2(
|
||||
ts_accum,
|
||||
PointerGetDatum(stat),
|
||||
data
|
||||
));
|
||||
if ( stat!=newstat && stat )
|
||||
if (!isnull)
|
||||
{
|
||||
newstat = (tsstat *) DatumGetPointer(DirectFunctionCall2(
|
||||
ts_accum,
|
||||
PointerGetDatum(stat),
|
||||
data
|
||||
));
|
||||
if (stat != newstat && stat)
|
||||
pfree(stat);
|
||||
stat=newstat;
|
||||
stat = newstat;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SPI_freetuptable(SPI_tuptable);
|
||||
SPI_cursor_fetch(portal, true, 100);
|
||||
}
|
||||
SPI_cursor_fetch(portal, true, 100);
|
||||
}
|
||||
|
||||
SPI_freetuptable(SPI_tuptable);
|
||||
SPI_cursor_close(portal);
|
||||
SPI_freeplan(plan);
|
||||
pfree(query);
|
||||
|
||||
return stat;
|
||||
return stat;
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(ts_stat);
|
||||
Datum ts_stat(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
ts_stat(PG_FUNCTION_ARGS) {
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
Datum ts_stat(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
ts_stat(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
tsstat *stat;
|
||||
text *txt = PG_GETARG_TEXT_P(0);
|
||||
|
||||
if (SRF_IS_FIRSTCALL()) {
|
||||
tsstat *stat;
|
||||
text *txt=PG_GETARG_TEXT_P(0);
|
||||
|
||||
funcctx = SRF_FIRSTCALL_INIT();
|
||||
SPI_connect();
|
||||
stat = ts_stat_sql(txt);
|
||||
PG_FREE_IF_COPY(txt,0);
|
||||
ts_setup_firstcall(funcctx, stat );
|
||||
PG_FREE_IF_COPY(txt, 0);
|
||||
ts_setup_firstcall(funcctx, stat);
|
||||
SPI_finish();
|
||||
}
|
||||
|
||||
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_DONE(funcctx);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -8,14 +8,16 @@
|
|||
#include "utils/builtins.h"
|
||||
#include "storage/bufpage.h"
|
||||
|
||||
typedef struct {
|
||||
uint32 len;
|
||||
uint32 pos;
|
||||
uint32 ndoc;
|
||||
uint32 nentry;
|
||||
typedef struct
|
||||
{
|
||||
uint32 len;
|
||||
uint32 pos;
|
||||
uint32 ndoc;
|
||||
uint32 nentry;
|
||||
} StatEntry;
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
int4 len;
|
||||
int4 size;
|
||||
char data[1];
|
||||
|
|
|
@ -31,8 +31,10 @@ Datum tsvector_out(PG_FUNCTION_ARGS);
|
|||
|
||||
PG_FUNCTION_INFO_V1(to_tsvector);
|
||||
Datum to_tsvector(PG_FUNCTION_ARGS);
|
||||
|
||||
PG_FUNCTION_INFO_V1(to_tsvector_current);
|
||||
Datum to_tsvector_current(PG_FUNCTION_ARGS);
|
||||
|
||||
PG_FUNCTION_INFO_V1(to_tsvector_name);
|
||||
Datum to_tsvector_name(PG_FUNCTION_ARGS);
|
||||
|
||||
|
@ -45,32 +47,38 @@ Datum tsvector_length(PG_FUNCTION_ARGS);
|
|||
/*
|
||||
* in/out text index type
|
||||
*/
|
||||
static int
|
||||
comparePos(const void *a, const void *b) {
|
||||
if ( ((WordEntryPos *) a)->pos == ((WordEntryPos *) b)->pos )
|
||||
static int
|
||||
comparePos(const void *a, const void *b)
|
||||
{
|
||||
if (((WordEntryPos *) a)->pos == ((WordEntryPos *) b)->pos)
|
||||
return 1;
|
||||
return ( ((WordEntryPos *) a)->pos > ((WordEntryPos *) b)->pos ) ? 1 : -1;
|
||||
return (((WordEntryPos *) a)->pos > ((WordEntryPos *) b)->pos) ? 1 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
uniquePos(WordEntryPos *a, int4 l) {
|
||||
WordEntryPos *ptr, *res;
|
||||
uniquePos(WordEntryPos * a, int4 l)
|
||||
{
|
||||
WordEntryPos *ptr,
|
||||
*res;
|
||||
|
||||
res=a;
|
||||
if (l==1)
|
||||
res = a;
|
||||
if (l == 1)
|
||||
return l;
|
||||
|
||||
qsort((void *) a, l, sizeof(WordEntryPos), comparePos);
|
||||
|
||||
ptr = a + 1;
|
||||
while (ptr - a < l) {
|
||||
if ( ptr->pos != res->pos ) {
|
||||
while (ptr - a < l)
|
||||
{
|
||||
if (ptr->pos != res->pos)
|
||||
{
|
||||
res++;
|
||||
res->pos = ptr->pos;
|
||||
res->weight = ptr->weight;
|
||||
if ( res-a >= MAXNUMPOS-1 || res->pos == MAXENTRYPOS-1 )
|
||||
if (res - a >= MAXNUMPOS - 1 || res->pos == MAXENTRYPOS - 1)
|
||||
break;
|
||||
} else if ( ptr->weight > res->weight )
|
||||
}
|
||||
else if (ptr->weight > res->weight)
|
||||
res->weight = ptr->weight;
|
||||
ptr++;
|
||||
}
|
||||
|
@ -81,27 +89,29 @@ static char *BufferStr;
|
|||
static int
|
||||
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(
|
||||
&BufferStr[((WordEntryIN *) a)->entry.pos],
|
||||
&BufferStr[((WordEntryIN *) b)->entry.pos],
|
||||
((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
|
||||
uniqueentry(WordEntryIN * a, int4 l, char *buf, int4 *outbuflen)
|
||||
{
|
||||
WordEntryIN *ptr,
|
||||
WordEntryIN *ptr,
|
||||
*res;
|
||||
|
||||
res = a;
|
||||
if (l == 1) {
|
||||
if ( a->entry.haspos ) {
|
||||
*(uint16*)(a->pos) = uniquePos( &(a->pos[1]), *(uint16*)(a->pos));
|
||||
*outbuflen = SHORTALIGN(res->entry.len) + (*(uint16*)(a->pos) +1 )*sizeof(WordEntryPos);
|
||||
if (l == 1)
|
||||
{
|
||||
if (a->entry.haspos)
|
||||
{
|
||||
*(uint16 *) (a->pos) = uniquePos(&(a->pos[1]), *(uint16 *) (a->pos));
|
||||
*outbuflen = SHORTALIGN(res->entry.len) + (*(uint16 *) (a->pos) + 1) * sizeof(WordEntryPos);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
@ -115,31 +125,39 @@ uniqueentry(WordEntryIN * a, int4 l, char *buf, int4 *outbuflen)
|
|||
if (!(ptr->entry.len == res->entry.len &&
|
||||
strncmp(&buf[ptr->entry.pos], &buf[res->entry.pos], res->entry.len) == 0))
|
||||
{
|
||||
if ( res->entry.haspos ) {
|
||||
*(uint16*)(res->pos) = uniquePos( &(res->pos[1]), *(uint16*)(res->pos));
|
||||
*outbuflen += *(uint16*)(res->pos) * sizeof(WordEntryPos);
|
||||
if (res->entry.haspos)
|
||||
{
|
||||
*(uint16 *) (res->pos) = uniquePos(&(res->pos[1]), *(uint16 *) (res->pos));
|
||||
*outbuflen += *(uint16 *) (res->pos) * sizeof(WordEntryPos);
|
||||
}
|
||||
*outbuflen += SHORTALIGN(res->entry.len);
|
||||
res++;
|
||||
memcpy(res,ptr,sizeof(WordEntryIN));
|
||||
} else if ( ptr->entry.haspos ){
|
||||
if ( res->entry.haspos ) {
|
||||
int4 len=*(uint16*)(ptr->pos) + 1 + *(uint16*)(res->pos);
|
||||
res->pos=(WordEntryPos*)repalloc( res->pos, len*sizeof(WordEntryPos));
|
||||
memcpy( &(res->pos[ *(uint16*)(res->pos) + 1 ]),
|
||||
&(ptr->pos[1]), *(uint16*)(ptr->pos) * sizeof(WordEntryPos));
|
||||
*(uint16*)(res->pos) += *(uint16*)(ptr->pos);
|
||||
pfree( ptr->pos );
|
||||
} else {
|
||||
res->entry.haspos=1;
|
||||
memcpy(res, ptr, sizeof(WordEntryIN));
|
||||
}
|
||||
else if (ptr->entry.haspos)
|
||||
{
|
||||
if (res->entry.haspos)
|
||||
{
|
||||
int4 len = *(uint16 *) (ptr->pos) + 1 + *(uint16 *) (res->pos);
|
||||
|
||||
res->pos = (WordEntryPos *) repalloc(res->pos, len * sizeof(WordEntryPos));
|
||||
memcpy(&(res->pos[*(uint16 *) (res->pos) + 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;
|
||||
}
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
if ( res->entry.haspos ) {
|
||||
*(uint16*)(res->pos) = uniquePos( &(res->pos[1]), *(uint16*)(res->pos));
|
||||
*outbuflen += *(uint16*)(res->pos) * sizeof(WordEntryPos);
|
||||
if (res->entry.haspos)
|
||||
{
|
||||
*(uint16 *) (res->pos) = uniquePos(&(res->pos[1]), *(uint16 *) (res->pos));
|
||||
*outbuflen += *(uint16 *) (res->pos) * sizeof(WordEntryPos);
|
||||
}
|
||||
*outbuflen += SHORTALIGN(res->entry.len);
|
||||
|
||||
|
@ -150,7 +168,7 @@ uniqueentry(WordEntryIN * a, int4 l, char *buf, int4 *outbuflen)
|
|||
#define WAITENDWORD 2
|
||||
#define WAITNEXTCHAR 3
|
||||
#define WAITENDCMPLX 4
|
||||
#define WAITPOSINFO 5
|
||||
#define WAITPOSINFO 5
|
||||
#define INPOSINFO 6
|
||||
#define WAITPOSDELIM 7
|
||||
|
||||
|
@ -172,7 +190,7 @@ gettoken_tsvector(TI_IN_STATE * state)
|
|||
|
||||
state->curpos = state->word;
|
||||
state->state = WAITWORD;
|
||||
state->alen=0;
|
||||
state->alen = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
@ -228,14 +246,16 @@ gettoken_tsvector(TI_IN_STATE * state)
|
|||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("syntax error")));
|
||||
*(state->curpos) = '\0';
|
||||
return 1;
|
||||
} else if ( *(state->prsbuf) == ':' ) {
|
||||
return 1;
|
||||
}
|
||||
else if (*(state->prsbuf) == ':')
|
||||
{
|
||||
if (state->curpos == state->word)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("syntax error")));
|
||||
*(state->curpos) = '\0';
|
||||
if ( state->oprisdelim )
|
||||
if (state->oprisdelim)
|
||||
return 1;
|
||||
else
|
||||
state->state = INPOSINFO;
|
||||
|
@ -257,10 +277,12 @@ gettoken_tsvector(TI_IN_STATE * state)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("syntax error")));
|
||||
if ( state->oprisdelim ) {
|
||||
if (state->oprisdelim)
|
||||
{
|
||||
state->prsbuf++;
|
||||
return 1;
|
||||
} else
|
||||
}
|
||||
else
|
||||
state->state = WAITPOSINFO;
|
||||
}
|
||||
else if (*(state->prsbuf) == '\\')
|
||||
|
@ -278,67 +300,87 @@ gettoken_tsvector(TI_IN_STATE * state)
|
|||
*(state->curpos) = *(state->prsbuf);
|
||||
state->curpos++;
|
||||
}
|
||||
} else if (state->state == WAITPOSINFO) {
|
||||
if ( *(state->prsbuf) == ':' )
|
||||
state->state=INPOSINFO;
|
||||
}
|
||||
else if (state->state == WAITPOSINFO)
|
||||
{
|
||||
if (*(state->prsbuf) == ':')
|
||||
state->state = INPOSINFO;
|
||||
else
|
||||
return 1;
|
||||
} else if (state->state == INPOSINFO) {
|
||||
if ( isdigit(*(state->prsbuf)) ) {
|
||||
if ( state->alen==0 ) {
|
||||
state->alen=4;
|
||||
state->pos = (WordEntryPos*)palloc( sizeof(WordEntryPos)*state->alen );
|
||||
*(uint16*)(state->pos)=0;
|
||||
} else if ( *(uint16*)(state->pos) +1 >= state->alen ) {
|
||||
state->alen *= 2;
|
||||
state->pos = (WordEntryPos*)repalloc( state->pos, sizeof(WordEntryPos)*state->alen );
|
||||
}
|
||||
else if (state->state == INPOSINFO)
|
||||
{
|
||||
if (isdigit(*(state->prsbuf)))
|
||||
{
|
||||
if (state->alen == 0)
|
||||
{
|
||||
state->alen = 4;
|
||||
state->pos = (WordEntryPos *) palloc(sizeof(WordEntryPos) * state->alen);
|
||||
*(uint16 *) (state->pos) = 0;
|
||||
}
|
||||
( *(uint16*)(state->pos) )++;
|
||||
state->pos[ *(uint16*)(state->pos) ].pos = LIMITPOS(atoi(state->prsbuf));
|
||||
if ( state->pos[ *(uint16*)(state->pos) ].pos == 0 )
|
||||
else if (*(uint16 *) (state->pos) + 1 >= state->alen)
|
||||
{
|
||||
state->alen *= 2;
|
||||
state->pos = (WordEntryPos *) repalloc(state->pos, sizeof(WordEntryPos) * state->alen);
|
||||
}
|
||||
(*(uint16 *) (state->pos))++;
|
||||
state->pos[*(uint16 *) (state->pos)].pos = LIMITPOS(atoi(state->prsbuf));
|
||||
if (state->pos[*(uint16 *) (state->pos)].pos == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("wrong position info")));
|
||||
state->pos[ *(uint16*)(state->pos) ].weight = 0;
|
||||
state->pos[*(uint16 *) (state->pos)].weight = 0;
|
||||
state->state = WAITPOSDELIM;
|
||||
} else
|
||||
}
|
||||
else
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("syntax error")));
|
||||
} else if (state->state == WAITPOSDELIM) {
|
||||
if ( *(state->prsbuf) == ',' ) {
|
||||
}
|
||||
else if (state->state == WAITPOSDELIM)
|
||||
{
|
||||
if (*(state->prsbuf) == ',')
|
||||
state->state = INPOSINFO;
|
||||
} else if ( tolower(*(state->prsbuf)) == 'a' || *(state->prsbuf)=='*' ) {
|
||||
if ( state->pos[ *(uint16*)(state->pos) ].weight )
|
||||
else if (tolower(*(state->prsbuf)) == 'a' || *(state->prsbuf) == '*')
|
||||
{
|
||||
if (state->pos[*(uint16 *) (state->pos)].weight)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("syntax error")));
|
||||
state->pos[ *(uint16*)(state->pos) ].weight = 3;
|
||||
} else if ( tolower(*(state->prsbuf)) == 'b' ) {
|
||||
if ( state->pos[ *(uint16*)(state->pos) ].weight )
|
||||
state->pos[*(uint16 *) (state->pos)].weight = 3;
|
||||
}
|
||||
else if (tolower(*(state->prsbuf)) == 'b')
|
||||
{
|
||||
if (state->pos[*(uint16 *) (state->pos)].weight)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("syntax error")));
|
||||
state->pos[ *(uint16*)(state->pos) ].weight = 2;
|
||||
} else if ( tolower(*(state->prsbuf)) == 'c' ) {
|
||||
if ( state->pos[ *(uint16*)(state->pos) ].weight )
|
||||
state->pos[*(uint16 *) (state->pos)].weight = 2;
|
||||
}
|
||||
else if (tolower(*(state->prsbuf)) == 'c')
|
||||
{
|
||||
if (state->pos[*(uint16 *) (state->pos)].weight)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("syntax error")));
|
||||
state->pos[ *(uint16*)(state->pos) ].weight = 1;
|
||||
} else if ( tolower(*(state->prsbuf)) == 'd' ) {
|
||||
if ( state->pos[ *(uint16*)(state->pos) ].weight )
|
||||
state->pos[*(uint16 *) (state->pos)].weight = 1;
|
||||
}
|
||||
else if (tolower(*(state->prsbuf)) == 'd')
|
||||
{
|
||||
if (state->pos[*(uint16 *) (state->pos)].weight)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("syntax error")));
|
||||
state->pos[ *(uint16*)(state->pos) ].weight = 0;
|
||||
} else if ( isspace(*(state->prsbuf)) || *(state->prsbuf) == '\0' ) {
|
||||
state->pos[*(uint16 *) (state->pos)].weight = 0;
|
||||
}
|
||||
else if (isspace(*(state->prsbuf)) || *(state->prsbuf) == '\0')
|
||||
return 1;
|
||||
} else if ( !isdigit(*(state->prsbuf)) )
|
||||
else if (!isdigit(*(state->prsbuf)))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("syntax error")));
|
||||
} else
|
||||
}
|
||||
else
|
||||
/* internal error */
|
||||
elog(ERROR, "internal error");
|
||||
state->prsbuf++;
|
||||
|
@ -352,11 +394,11 @@ tsvector_in(PG_FUNCTION_ARGS)
|
|||
{
|
||||
char *buf = PG_GETARG_CSTRING(0);
|
||||
TI_IN_STATE state;
|
||||
WordEntryIN *arr;
|
||||
WordEntryIN *arr;
|
||||
WordEntry *inarr;
|
||||
int4 len = 0,
|
||||
totallen = 64;
|
||||
tsvector *in;
|
||||
tsvector *in;
|
||||
char *tmpbuf,
|
||||
*cur;
|
||||
int4 i,
|
||||
|
@ -388,28 +430,30 @@ tsvector_in(PG_FUNCTION_ARGS)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
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)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
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);
|
||||
cur += arr[len].entry.len;
|
||||
if ( state.alen ) {
|
||||
arr[len].entry.haspos=1;
|
||||
if (state.alen)
|
||||
{
|
||||
arr[len].entry.haspos = 1;
|
||||
arr[len].pos = state.pos;
|
||||
} else
|
||||
arr[len].entry.haspos=0;
|
||||
}
|
||||
else
|
||||
arr[len].entry.haspos = 0;
|
||||
len++;
|
||||
}
|
||||
pfree(state.word);
|
||||
|
||||
if ( len > 0 )
|
||||
if (len > 0)
|
||||
len = uniqueentry(arr, len, tmpbuf, &buflen);
|
||||
totallen = CALCDATASIZE(len, buflen);
|
||||
in = (tsvector *) palloc(totallen);
|
||||
memset(in,0,totallen);
|
||||
memset(in, 0, totallen);
|
||||
in->len = totallen;
|
||||
in->size = len;
|
||||
cur = STRPTR(in);
|
||||
|
@ -417,14 +461,15 @@ tsvector_in(PG_FUNCTION_ARGS)
|
|||
for (i = 0; i < len; i++)
|
||||
{
|
||||
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);
|
||||
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);
|
||||
pfree( arr[i].pos );
|
||||
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);
|
||||
pfree(arr[i].pos);
|
||||
}
|
||||
memcpy( &(inarr[i]), &(arr[i].entry), sizeof(WordEntry) );
|
||||
memcpy(&(inarr[i]), &(arr[i].entry), sizeof(WordEntry));
|
||||
}
|
||||
pfree(tmpbuf);
|
||||
pfree(arr);
|
||||
|
@ -434,7 +479,7 @@ tsvector_in(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
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;
|
||||
|
||||
PG_FREE_IF_COPY(in, 0);
|
||||
|
@ -444,26 +489,28 @@ tsvector_length(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
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;
|
||||
int4 i,
|
||||
j,
|
||||
lenbuf = 0, pp;
|
||||
lenbuf = 0,
|
||||
pp;
|
||||
WordEntry *ptr = ARRPTR(out);
|
||||
char *curin,
|
||||
*curout;
|
||||
|
||||
lenbuf=out->size * 2 /* '' */ + out->size - 1 /* space */ + 2 /*\0*/;
|
||||
for (i = 0; i < out->size; i++) {
|
||||
lenbuf += ptr[i].len*2 /*for escape */;
|
||||
if ( ptr[i].haspos )
|
||||
lenbuf += 7*POSDATALEN(out, &(ptr[i]));
|
||||
}
|
||||
lenbuf = out->size * 2 /* '' */ + out->size - 1 /* space */ + 2 /* \0 */ ;
|
||||
for (i = 0; i < out->size; i++)
|
||||
{
|
||||
lenbuf += ptr[i].len * 2 /* for escape */ ;
|
||||
if (ptr[i].haspos)
|
||||
lenbuf += 7 * POSDATALEN(out, &(ptr[i]));
|
||||
}
|
||||
|
||||
curout = outbuf = (char *) palloc(lenbuf);
|
||||
for (i = 0; i < out->size; i++)
|
||||
{
|
||||
curin = STRPTR(out)+ptr->pos;
|
||||
curin = STRPTR(out) + ptr->pos;
|
||||
if (i != 0)
|
||||
*curout++ = ' ';
|
||||
*curout++ = '\'';
|
||||
|
@ -481,27 +528,40 @@ tsvector_out(PG_FUNCTION_ARGS)
|
|||
*curout++ = *curin++;
|
||||
}
|
||||
*curout++ = '\'';
|
||||
if ( (pp=POSDATALEN(out,ptr)) != 0 ) {
|
||||
if ((pp = POSDATALEN(out, ptr)) != 0)
|
||||
{
|
||||
WordEntryPos *wptr;
|
||||
|
||||
*curout++ = ':';
|
||||
wptr=POSDATAPTR(out,ptr);
|
||||
while(pp) {
|
||||
sprintf(curout,"%d",wptr->pos);
|
||||
curout=strchr(curout,'\0');
|
||||
switch( wptr->weight ) {
|
||||
case 3: *curout++ = 'A'; break;
|
||||
case 2: *curout++ = 'B'; break;
|
||||
case 1: *curout++ = 'C'; break;
|
||||
case 0:
|
||||
default: break;
|
||||
wptr = POSDATAPTR(out, ptr);
|
||||
while (pp)
|
||||
{
|
||||
sprintf(curout, "%d", wptr->pos);
|
||||
curout = strchr(curout, '\0');
|
||||
switch (wptr->weight)
|
||||
{
|
||||
case 3:
|
||||
*curout++ = 'A';
|
||||
break;
|
||||
case 2:
|
||||
*curout++ = 'B';
|
||||
break;
|
||||
case 1:
|
||||
*curout++ = 'C';
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if ( pp>1 ) *curout++ = ',';
|
||||
pp--; wptr++;
|
||||
if (pp > 1)
|
||||
*curout++ = ',';
|
||||
pp--;
|
||||
wptr++;
|
||||
}
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
*curout='\0';
|
||||
*curout = '\0';
|
||||
outbuf[lenbuf - 1] = '\0';
|
||||
PG_FREE_IF_COPY(out, 0);
|
||||
PG_RETURN_POINTER(outbuf);
|
||||
|
@ -510,13 +570,15 @@ tsvector_out(PG_FUNCTION_ARGS)
|
|||
static int
|
||||
compareWORD(const void *a, const void *b)
|
||||
{
|
||||
if (((WORD *) a)->len == ((WORD *) b)->len) {
|
||||
int res = strncmp(
|
||||
((WORD *) a)->word,
|
||||
((WORD *) b)->word,
|
||||
((WORD *) b)->len);
|
||||
if ( res==0 )
|
||||
return ( ((WORD *) a)->pos.pos > ((WORD *) b)->pos.pos ) ? 1 : -1;
|
||||
if (((WORD *) a)->len == ((WORD *) b)->len)
|
||||
{
|
||||
int res = strncmp(
|
||||
((WORD *) a)->word,
|
||||
((WORD *) b)->word,
|
||||
((WORD *) b)->len);
|
||||
|
||||
if (res == 0)
|
||||
return (((WORD *) a)->pos.pos > ((WORD *) b)->pos.pos) ? 1 : -1;
|
||||
return res;
|
||||
}
|
||||
return (((WORD *) a)->len > ((WORD *) b)->len) ? 1 : -1;
|
||||
|
@ -527,14 +589,15 @@ uniqueWORD(WORD * a, int4 l)
|
|||
{
|
||||
WORD *ptr,
|
||||
*res;
|
||||
int tmppos;
|
||||
int tmppos;
|
||||
|
||||
if (l == 1) {
|
||||
tmppos=LIMITPOS(a->pos.pos);
|
||||
a->alen=2;
|
||||
a->pos.apos=(uint16*)palloc( sizeof(uint16)*a->alen );
|
||||
a->pos.apos[0]=1;
|
||||
a->pos.apos[1]=tmppos;
|
||||
if (l == 1)
|
||||
{
|
||||
tmppos = LIMITPOS(a->pos.pos);
|
||||
a->alen = 2;
|
||||
a->pos.apos = (uint16 *) palloc(sizeof(uint16) * a->alen);
|
||||
a->pos.apos[0] = 1;
|
||||
a->pos.apos[1] = tmppos;
|
||||
return l;
|
||||
}
|
||||
|
||||
|
@ -542,11 +605,11 @@ uniqueWORD(WORD * a, int4 l)
|
|||
ptr = a + 1;
|
||||
|
||||
qsort((void *) a, l, sizeof(WORD), compareWORD);
|
||||
tmppos=LIMITPOS(a->pos.pos);
|
||||
a->alen=2;
|
||||
a->pos.apos=(uint16*)palloc( sizeof(uint16)*a->alen );
|
||||
a->pos.apos[0]=1;
|
||||
a->pos.apos[1]=tmppos;
|
||||
tmppos = LIMITPOS(a->pos.pos);
|
||||
a->alen = 2;
|
||||
a->pos.apos = (uint16 *) palloc(sizeof(uint16) * a->alen);
|
||||
a->pos.apos[0] = 1;
|
||||
a->pos.apos[1] = tmppos;
|
||||
|
||||
while (ptr - a < l)
|
||||
{
|
||||
|
@ -556,20 +619,24 @@ uniqueWORD(WORD * a, int4 l)
|
|||
res++;
|
||||
res->len = ptr->len;
|
||||
res->word = ptr->word;
|
||||
tmppos=LIMITPOS(ptr->pos.pos);
|
||||
res->alen=2;
|
||||
res->pos.apos=(uint16*)palloc( sizeof(uint16)*res->alen );
|
||||
res->pos.apos[0]=1;
|
||||
res->pos.apos[1]=tmppos;
|
||||
} else {
|
||||
tmppos = LIMITPOS(ptr->pos.pos);
|
||||
res->alen = 2;
|
||||
res->pos.apos = (uint16 *) palloc(sizeof(uint16) * res->alen);
|
||||
res->pos.apos[0] = 1;
|
||||
res->pos.apos[1] = tmppos;
|
||||
}
|
||||
else
|
||||
{
|
||||
pfree(ptr->word);
|
||||
if ( res->pos.apos[0] < MAXNUMPOS-1 && res->pos.apos[ res->pos.apos[0] ] != MAXENTRYPOS-1 ) {
|
||||
if ( res->pos.apos[0]+1 >= res->alen ) {
|
||||
res->alen*=2;
|
||||
res->pos.apos=(uint16*)repalloc( res->pos.apos, sizeof(uint16)*res->alen );
|
||||
if (res->pos.apos[0] < MAXNUMPOS - 1 && res->pos.apos[res->pos.apos[0]] != MAXENTRYPOS - 1)
|
||||
{
|
||||
if (res->pos.apos[0] + 1 >= res->alen)
|
||||
{
|
||||
res->alen *= 2;
|
||||
res->pos.apos = (uint16 *) repalloc(res->pos.apos, sizeof(uint16) * res->alen);
|
||||
}
|
||||
res->pos.apos[ res->pos.apos[0]+1 ] = LIMITPOS(ptr->pos.pos);
|
||||
res->pos.apos[0]++;
|
||||
res->pos.apos[res->pos.apos[0] + 1] = LIMITPOS(ptr->pos.pos);
|
||||
res->pos.apos[0]++;
|
||||
}
|
||||
}
|
||||
ptr++;
|
||||
|
@ -584,25 +651,27 @@ uniqueWORD(WORD * a, int4 l)
|
|||
static tsvector *
|
||||
makevalue(PRSTEXT * prs)
|
||||
{
|
||||
int4 i,j,
|
||||
int4 i,
|
||||
j,
|
||||
lenstr = 0,
|
||||
totallen;
|
||||
tsvector *in;
|
||||
tsvector *in;
|
||||
WordEntry *ptr;
|
||||
char *str,
|
||||
*cur;
|
||||
|
||||
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);
|
||||
|
||||
if ( prs->words[i].alen )
|
||||
if (prs->words[i].alen)
|
||||
lenstr += sizeof(uint16) + prs->words[i].pos.apos[0] * sizeof(WordEntryPos);
|
||||
}
|
||||
|
||||
totallen = CALCDATASIZE(prs->curwords, lenstr);
|
||||
in = (tsvector *) palloc(totallen);
|
||||
memset(in,0,totallen);
|
||||
memset(in, 0, totallen);
|
||||
in->len = totallen;
|
||||
in->size = prs->curwords;
|
||||
|
||||
|
@ -615,24 +684,27 @@ makevalue(PRSTEXT * prs)
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
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);
|
||||
pfree(prs->words[i].word);
|
||||
cur += SHORTALIGN(prs->words[i].len);
|
||||
if ( prs->words[i].alen ) {
|
||||
if (prs->words[i].alen)
|
||||
{
|
||||
WordEntryPos *wptr;
|
||||
|
||||
ptr->haspos=1;
|
||||
*(uint16*)cur = prs->words[i].pos.apos[0];
|
||||
wptr=POSDATAPTR(in,ptr);
|
||||
for(j=0;j<*(uint16*)cur;j++) {
|
||||
wptr[j].weight=0;
|
||||
wptr[j].pos=prs->words[i].pos.apos[j+1];
|
||||
|
||||
ptr->haspos = 1;
|
||||
*(uint16 *) cur = prs->words[i].pos.apos[0];
|
||||
wptr = POSDATAPTR(in, ptr);
|
||||
for (j = 0; j < *(uint16 *) cur; j++)
|
||||
{
|
||||
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);
|
||||
pfree(prs->words[i].pos.apos);
|
||||
} else
|
||||
ptr->haspos=0;
|
||||
}
|
||||
else
|
||||
ptr->haspos = 0;
|
||||
ptr++;
|
||||
}
|
||||
pfree(prs->words);
|
||||
|
@ -645,70 +717,78 @@ to_tsvector(PG_FUNCTION_ARGS)
|
|||
{
|
||||
text *in = PG_GETARG_TEXT_P(1);
|
||||
PRSTEXT prs;
|
||||
tsvector *out = NULL;
|
||||
TSCfgInfo *cfg=findcfg(PG_GETARG_INT32(0));
|
||||
tsvector *out = NULL;
|
||||
TSCfgInfo *cfg = findcfg(PG_GETARG_INT32(0));
|
||||
|
||||
prs.lenwords = 32;
|
||||
prs.curwords = 0;
|
||||
prs.pos = 0;
|
||||
prs.words = (WORD *) palloc(sizeof(WORD) * prs.lenwords);
|
||||
|
||||
|
||||
parsetext_v2(cfg, &prs, VARDATA(in), VARSIZE(in) - VARHDRSZ);
|
||||
PG_FREE_IF_COPY(in, 1);
|
||||
|
||||
if (prs.curwords)
|
||||
out = makevalue(&prs);
|
||||
else {
|
||||
else
|
||||
{
|
||||
pfree(prs.words);
|
||||
out = palloc(CALCDATASIZE(0,0));
|
||||
out->len = CALCDATASIZE(0,0);
|
||||
out = palloc(CALCDATASIZE(0, 0));
|
||||
out->len = CALCDATASIZE(0, 0);
|
||||
out->size = 0;
|
||||
}
|
||||
}
|
||||
PG_RETURN_POINTER(out);
|
||||
}
|
||||
|
||||
Datum
|
||||
to_tsvector_name(PG_FUNCTION_ARGS) {
|
||||
text *cfg=PG_GETARG_TEXT_P(0);
|
||||
Datum res = DirectFunctionCall3(
|
||||
to_tsvector,
|
||||
Int32GetDatum( name2id_cfg( cfg ) ),
|
||||
PG_GETARG_DATUM(1),
|
||||
(Datum)0
|
||||
to_tsvector_name(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *cfg = PG_GETARG_TEXT_P(0);
|
||||
Datum res = DirectFunctionCall3(
|
||||
to_tsvector,
|
||||
Int32GetDatum(name2id_cfg(cfg)),
|
||||
PG_GETARG_DATUM(1),
|
||||
(Datum) 0
|
||||
);
|
||||
PG_FREE_IF_COPY(cfg,0);
|
||||
PG_RETURN_DATUM(res);
|
||||
|
||||
PG_FREE_IF_COPY(cfg, 0);
|
||||
PG_RETURN_DATUM(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
to_tsvector_current(PG_FUNCTION_ARGS) {
|
||||
Datum res = DirectFunctionCall3(
|
||||
to_tsvector,
|
||||
Int32GetDatum( get_currcfg() ),
|
||||
PG_GETARG_DATUM(0),
|
||||
(Datum)0
|
||||
to_tsvector_current(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Datum res = DirectFunctionCall3(
|
||||
to_tsvector,
|
||||
Int32GetDatum(get_currcfg()),
|
||||
PG_GETARG_DATUM(0),
|
||||
(Datum) 0
|
||||
);
|
||||
PG_RETURN_DATUM(res);
|
||||
|
||||
PG_RETURN_DATUM(res);
|
||||
}
|
||||
|
||||
static Oid
|
||||
findFunc(char *fname) {
|
||||
FuncCandidateList clist,ptr;
|
||||
Oid funcid = InvalidOid;
|
||||
List *names=makeList1(makeString(fname));
|
||||
findFunc(char *fname)
|
||||
{
|
||||
FuncCandidateList clist,
|
||||
ptr;
|
||||
Oid funcid = InvalidOid;
|
||||
List *names = makeList1(makeString(fname));
|
||||
|
||||
ptr = clist = FuncnameGetCandidates(names, 1);
|
||||
freeList(names);
|
||||
|
||||
if ( !ptr )
|
||||
if (!ptr)
|
||||
return funcid;
|
||||
|
||||
while(ptr) {
|
||||
if ( ptr->args[0] == TEXTOID && funcid == InvalidOid )
|
||||
funcid=ptr->oid;
|
||||
clist=ptr->next;
|
||||
while (ptr)
|
||||
{
|
||||
if (ptr->args[0] == TEXTOID && funcid == InvalidOid)
|
||||
funcid = ptr->oid;
|
||||
clist = ptr->next;
|
||||
pfree(ptr);
|
||||
ptr=clist;
|
||||
ptr = clist;
|
||||
}
|
||||
|
||||
return funcid;
|
||||
|
@ -724,12 +804,12 @@ tsearch2(PG_FUNCTION_ARGS)
|
|||
Trigger *trigger;
|
||||
Relation rel;
|
||||
HeapTuple rettuple = NULL;
|
||||
TSCfgInfo *cfg=findcfg(get_currcfg());
|
||||
TSCfgInfo *cfg = findcfg(get_currcfg());
|
||||
int numidxattr,
|
||||
i;
|
||||
PRSTEXT prs;
|
||||
Datum datum = (Datum) 0;
|
||||
Oid funcoid = InvalidOid;
|
||||
Oid funcoid = InvalidOid;
|
||||
|
||||
if (!CALLED_AS_TRIGGER(fcinfo))
|
||||
/* internal error */
|
||||
|
@ -782,8 +862,8 @@ tsearch2(PG_FUNCTION_ARGS)
|
|||
numattr = SPI_fnumber(rel->rd_att, trigger->tgargs[i]);
|
||||
if (numattr == SPI_ERROR_NOATTRIBUTE)
|
||||
{
|
||||
funcoid=findFunc(trigger->tgargs[i]);
|
||||
if ( funcoid==InvalidOid )
|
||||
funcoid = findFunc(trigger->tgargs[i]);
|
||||
if (funcoid == InvalidOid)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
||||
errmsg("could not find function or field \"%s\"",
|
||||
|
@ -805,19 +885,22 @@ tsearch2(PG_FUNCTION_ARGS)
|
|||
if (isnull)
|
||||
continue;
|
||||
|
||||
if ( funcoid!=InvalidOid ) {
|
||||
text *txttmp = (text *) DatumGetPointer( OidFunctionCall1(
|
||||
funcoid,
|
||||
PointerGetDatum(txt_toasted)
|
||||
));
|
||||
if (funcoid != InvalidOid)
|
||||
{
|
||||
text *txttmp = (text *) DatumGetPointer(OidFunctionCall1(
|
||||
funcoid,
|
||||
PointerGetDatum(txt_toasted)
|
||||
));
|
||||
|
||||
txt = (text *) DatumGetPointer(PG_DETOAST_DATUM(PointerGetDatum(txttmp)));
|
||||
if ( txt == txttmp )
|
||||
if (txt == txttmp)
|
||||
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);
|
||||
if (txt != (text*)DatumGetPointer(txt_toasted) )
|
||||
if (txt != (text *) DatumGetPointer(txt_toasted))
|
||||
pfree(txt);
|
||||
}
|
||||
|
||||
|
@ -831,8 +914,9 @@ tsearch2(PG_FUNCTION_ARGS)
|
|||
}
|
||||
else
|
||||
{
|
||||
tsvector *out = palloc(CALCDATASIZE(0,0));
|
||||
out->len = CALCDATASIZE(0,0);
|
||||
tsvector *out = palloc(CALCDATASIZE(0, 0));
|
||||
|
||||
out->len = CALCDATASIZE(0, 0);
|
||||
out->size = 0;
|
||||
datum = PointerGetDatum(out);
|
||||
pfree(prs.words);
|
||||
|
|
|
@ -12,23 +12,27 @@
|
|||
#include "utils/builtins.h"
|
||||
#include "storage/bufpage.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint32
|
||||
haspos:1,
|
||||
len:11, /* MAX 2Kb */
|
||||
pos:20; /* MAX 1Mb */
|
||||
haspos:1,
|
||||
len:11, /* MAX 2Kb */
|
||||
pos:20; /* MAX 1Mb */
|
||||
} WordEntry;
|
||||
|
||||
#define MAXSTRLEN ( 1<<11 )
|
||||
#define MAXSTRPOS ( 1<<20 )
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
uint16
|
||||
weight:2,
|
||||
pos:14;
|
||||
} WordEntryPos;
|
||||
#define MAXENTRYPOS (1<<14)
|
||||
weight:2,
|
||||
pos:14;
|
||||
} WordEntryPos;
|
||||
|
||||
#define MAXENTRYPOS (1<<14)
|
||||
#define MAXNUMPOS 256
|
||||
#define LIMITPOS(x) ( ( (x) >= MAXENTRYPOS ) ? (MAXENTRYPOS-1) : (x) )
|
||||
#define LIMITPOS(x) ( ( (x) >= MAXENTRYPOS ) ? (MAXENTRYPOS-1) : (x) )
|
||||
|
||||
typedef struct
|
||||
{
|
||||
|
@ -43,13 +47,14 @@ typedef struct
|
|||
#define STRPTR(x) ( (char*)x + 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 POSDATALEN(x,e) ( ( ((WordEntry*)(e))->haspos ) ? (*(uint16*)_POSDATAPTR(x,e)) : 0 )
|
||||
#define POSDATAPTR(x,e) ( (WordEntryPos*)( _POSDATAPTR(x,e)+sizeof(uint16) ) )
|
||||
#define POSDATALEN(x,e) ( ( ((WordEntry*)(e))->haspos ) ? (*(uint16*)_POSDATAPTR(x,e)) : 0 )
|
||||
#define POSDATAPTR(x,e) ( (WordEntryPos*)( _POSDATAPTR(x,e)+sizeof(uint16) ) )
|
||||
|
||||
|
||||
typedef struct {
|
||||
WordEntry entry;
|
||||
WordEntryPos *pos;
|
||||
typedef struct
|
||||
{
|
||||
WordEntry entry;
|
||||
WordEntryPos *pos;
|
||||
} WordEntryIN;
|
||||
|
||||
typedef struct
|
||||
|
@ -60,7 +65,7 @@ typedef struct
|
|||
int4 len;
|
||||
int4 state;
|
||||
int4 alen;
|
||||
WordEntryPos *pos;
|
||||
WordEntryPos *pos;
|
||||
bool oprisdelim;
|
||||
} TI_IN_STATE;
|
||||
|
||||
|
|
|
@ -33,30 +33,33 @@ Datum concat(PG_FUNCTION_ARGS);
|
|||
Datum
|
||||
strip(PG_FUNCTION_ARGS)
|
||||
{
|
||||
tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
tsvector *out;
|
||||
int i,len=0;
|
||||
WordEntry *arrin=ARRPTR(in), *arrout;
|
||||
char *cur;
|
||||
tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
tsvector *out;
|
||||
int i,
|
||||
len = 0;
|
||||
WordEntry *arrin = ARRPTR(in),
|
||||
*arrout;
|
||||
char *cur;
|
||||
|
||||
for(i=0;i<in->size;i++)
|
||||
len += SHORTALIGN( arrin[i].len );
|
||||
for (i = 0; i < in->size; i++)
|
||||
len += SHORTALIGN(arrin[i].len);
|
||||
|
||||
len = CALCDATASIZE(in->size, len);
|
||||
out=(tsvector*)palloc(len);
|
||||
memset(out,0,len);
|
||||
out->len=len;
|
||||
out->size=in->size;
|
||||
arrout=ARRPTR(out);
|
||||
cur=STRPTR(out);
|
||||
for(i=0;i<in->size;i++) {
|
||||
memcpy(cur, STRPTR(in)+arrin[i].pos, arrin[i].len);
|
||||
out = (tsvector *) palloc(len);
|
||||
memset(out, 0, len);
|
||||
out->len = len;
|
||||
out->size = in->size;
|
||||
arrout = ARRPTR(out);
|
||||
cur = STRPTR(out);
|
||||
for (i = 0; i < in->size; i++)
|
||||
{
|
||||
memcpy(cur, STRPTR(in) + arrin[i].pos, arrin[i].len);
|
||||
arrout[i].haspos = 0;
|
||||
arrout[i].len = arrin[i].len;
|
||||
arrout[i].pos = cur - STRPTR(out);
|
||||
cur += SHORTALIGN( arrout[i].len );
|
||||
cur += SHORTALIGN(arrout[i].len);
|
||||
}
|
||||
|
||||
|
||||
PG_FREE_IF_COPY(in, 0);
|
||||
PG_RETURN_POINTER(out);
|
||||
}
|
||||
|
@ -64,200 +67,263 @@ strip(PG_FUNCTION_ARGS)
|
|||
Datum
|
||||
setweight(PG_FUNCTION_ARGS)
|
||||
{
|
||||
tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
char cw = PG_GETARG_CHAR(1);
|
||||
tsvector *out;
|
||||
int i,j;
|
||||
WordEntry *entry;
|
||||
tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
|
||||
char cw = PG_GETARG_CHAR(1);
|
||||
tsvector *out;
|
||||
int i,
|
||||
j;
|
||||
WordEntry *entry;
|
||||
WordEntryPos *p;
|
||||
int w=0;
|
||||
int w = 0;
|
||||
|
||||
switch(tolower(cw)) {
|
||||
case 'a': w=3; break;
|
||||
case 'b': w=2; break;
|
||||
case 'c': w=1; break;
|
||||
case 'd': w=0; break;
|
||||
/* internal error */
|
||||
default: elog(ERROR,"unrecognized weight");
|
||||
switch (tolower(cw))
|
||||
{
|
||||
case 'a':
|
||||
w = 3;
|
||||
break;
|
||||
case 'b':
|
||||
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);
|
||||
memcpy(out,in,in->len);
|
||||
entry=ARRPTR(out);
|
||||
i=out->size;
|
||||
while(i--) {
|
||||
if ( (j=POSDATALEN(out,entry)) != 0 ) {
|
||||
p=POSDATAPTR(out,entry);
|
||||
while(j--) {
|
||||
p->weight=w;
|
||||
out = (tsvector *) palloc(in->len);
|
||||
memcpy(out, in, in->len);
|
||||
entry = ARRPTR(out);
|
||||
i = out->size;
|
||||
while (i--)
|
||||
{
|
||||
if ((j = POSDATALEN(out, entry)) != 0)
|
||||
{
|
||||
p = POSDATAPTR(out, entry);
|
||||
while (j--)
|
||||
{
|
||||
p->weight = w;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
entry++;
|
||||
}
|
||||
|
||||
|
||||
PG_FREE_IF_COPY(in, 0);
|
||||
PG_RETURN_POINTER(out);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return strncmp(
|
||||
ptra + a->pos,
|
||||
ptrb + b->pos,
|
||||
a->len);
|
||||
}
|
||||
return ( a->len > b->len ) ? 1 : -1;
|
||||
if (a->len == b->len)
|
||||
{
|
||||
return strncmp(
|
||||
ptra + a->pos,
|
||||
ptrb + b->pos,
|
||||
a->len);
|
||||
}
|
||||
return (a->len > b->len) ? 1 : -1;
|
||||
}
|
||||
|
||||
static int4
|
||||
add_pos(tsvector *src, WordEntry *srcptr, tsvector *dest, WordEntry *destptr, int4 maxpos ) {
|
||||
uint16 *clen = (uint16*)_POSDATAPTR(dest,destptr);
|
||||
int i;
|
||||
uint16 slen = POSDATALEN(src, srcptr), startlen;
|
||||
WordEntryPos *spos=POSDATAPTR(src, srcptr), *dpos=POSDATAPTR(dest,destptr);
|
||||
add_pos(tsvector * src, WordEntry * srcptr, tsvector * dest, WordEntry * destptr, int4 maxpos)
|
||||
{
|
||||
uint16 *clen = (uint16 *) _POSDATAPTR(dest, destptr);
|
||||
int i;
|
||||
uint16 slen = POSDATALEN(src, srcptr),
|
||||
startlen;
|
||||
WordEntryPos *spos = POSDATAPTR(src, srcptr),
|
||||
*dpos = POSDATAPTR(dest, destptr);
|
||||
|
||||
if ( ! destptr->haspos )
|
||||
*clen=0;
|
||||
if (!destptr->haspos)
|
||||
*clen = 0;
|
||||
|
||||
startlen = *clen;
|
||||
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);
|
||||
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);
|
||||
(*clen)++;
|
||||
}
|
||||
|
||||
if ( *clen != startlen )
|
||||
destptr->haspos=1;
|
||||
return *clen - startlen;
|
||||
if (*clen != startlen)
|
||||
destptr->haspos = 1;
|
||||
return *clen - startlen;
|
||||
}
|
||||
|
||||
|
||||
Datum
|
||||
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 *out;
|
||||
WordEntry *ptr;
|
||||
WordEntry *ptr1,*ptr2;
|
||||
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 *out;
|
||||
WordEntry *ptr;
|
||||
WordEntry *ptr1,
|
||||
*ptr2;
|
||||
WordEntryPos *p;
|
||||
int maxpos=0,i,j,i1,i2;
|
||||
char *cur;
|
||||
char *data,*data1,*data2;
|
||||
int maxpos = 0,
|
||||
i,
|
||||
j,
|
||||
i1,
|
||||
i2;
|
||||
char *cur;
|
||||
char *data,
|
||||
*data1,
|
||||
*data2;
|
||||
|
||||
ptr=ARRPTR(in1);
|
||||
i=in1->size;
|
||||
while(i--) {
|
||||
if ( (j=POSDATALEN(in1,ptr)) != 0 ) {
|
||||
p=POSDATAPTR(in1,ptr);
|
||||
while(j--) {
|
||||
if ( p->pos > maxpos )
|
||||
ptr = ARRPTR(in1);
|
||||
i = in1->size;
|
||||
while (i--)
|
||||
{
|
||||
if ((j = POSDATALEN(in1, ptr)) != 0)
|
||||
{
|
||||
p = POSDATAPTR(in1, ptr);
|
||||
while (j--)
|
||||
{
|
||||
if (p->pos > maxpos)
|
||||
maxpos = p->pos;
|
||||
p++;
|
||||
}
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
|
||||
ptr1=ARRPTR(in1); ptr2=ARRPTR(in2);
|
||||
data1=STRPTR(in1); data2=STRPTR(in2);
|
||||
i1=in1->size; i2=in2->size;
|
||||
out=(tsvector*)palloc( in1->len + in2->len );
|
||||
memset(out,0,in1->len + in2->len);
|
||||
|
||||
ptr1 = ARRPTR(in1);
|
||||
ptr2 = ARRPTR(in2);
|
||||
data1 = STRPTR(in1);
|
||||
data2 = STRPTR(in2);
|
||||
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->size = in1->size + in2->size;
|
||||
data=cur=STRPTR(out);
|
||||
ptr=ARRPTR(out);
|
||||
while( i1 && i2 ) {
|
||||
int cmp=compareEntry(data1,ptr1,data2,ptr2);
|
||||
if ( cmp < 0 ) { /* in1 first */
|
||||
data = cur = STRPTR(out);
|
||||
ptr = ARRPTR(out);
|
||||
while (i1 && i2)
|
||||
{
|
||||
int cmp = compareEntry(data1, ptr1, data2, ptr2);
|
||||
|
||||
if (cmp < 0)
|
||||
{ /* in1 first */
|
||||
ptr->haspos = ptr1->haspos;
|
||||
ptr->len = ptr1->len;
|
||||
memcpy( cur, data1 + ptr1->pos, ptr1->len );
|
||||
ptr->pos = cur - data;
|
||||
cur+=SHORTALIGN(ptr1->len);
|
||||
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, data1 + ptr1->pos, ptr1->len);
|
||||
ptr->pos = cur - data;
|
||||
cur += SHORTALIGN(ptr1->len);
|
||||
if (ptr->haspos)
|
||||
{
|
||||
memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
|
||||
cur += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
|
||||
}
|
||||
ptr++; ptr1++; i1--;
|
||||
} else if ( cmp>0 ) { /* in2 first */
|
||||
ptr++;
|
||||
ptr1++;
|
||||
i1--;
|
||||
}
|
||||
else if (cmp > 0)
|
||||
{ /* in2 first */
|
||||
ptr->haspos = ptr2->haspos;
|
||||
ptr->len = ptr2->len;
|
||||
memcpy( cur, data2 + ptr2->pos, ptr2->len );
|
||||
ptr->pos = cur - data;
|
||||
cur+=SHORTALIGN(ptr2->len);
|
||||
if ( ptr->haspos ) {
|
||||
int addlen = add_pos(in2, ptr2, out, ptr, maxpos );
|
||||
if ( addlen == 0 )
|
||||
ptr->haspos=0;
|
||||
memcpy(cur, data2 + ptr2->pos, ptr2->len);
|
||||
ptr->pos = cur - data;
|
||||
cur += SHORTALIGN(ptr2->len);
|
||||
if (ptr->haspos)
|
||||
{
|
||||
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
|
||||
|
||||
if (addlen == 0)
|
||||
ptr->haspos = 0;
|
||||
else
|
||||
cur += addlen*sizeof(WordEntryPos) + sizeof(uint16);
|
||||
cur += addlen * sizeof(WordEntryPos) + sizeof(uint16);
|
||||
}
|
||||
ptr++; ptr2++; i2--;
|
||||
} else {
|
||||
ptr++;
|
||||
ptr2++;
|
||||
i2--;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr->haspos = ptr1->haspos | ptr2->haspos;
|
||||
ptr->len = ptr1->len;
|
||||
memcpy( cur, data1 + ptr1->pos, ptr1->len );
|
||||
ptr->pos = cur - data;
|
||||
cur+=SHORTALIGN(ptr1->len);
|
||||
if ( ptr->haspos ) {
|
||||
if ( ptr1->haspos ) {
|
||||
memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1)*sizeof(WordEntryPos) + sizeof(uint16));
|
||||
cur+=POSDATALEN(in1, ptr1)*sizeof(WordEntryPos) + sizeof(uint16);
|
||||
if ( ptr2->haspos )
|
||||
cur += add_pos(in2, ptr2, out, ptr, maxpos )*sizeof(WordEntryPos);
|
||||
} else if ( ptr2->haspos ) {
|
||||
int addlen = add_pos(in2, ptr2, out, ptr, maxpos );
|
||||
if ( addlen == 0 )
|
||||
ptr->haspos=0;
|
||||
memcpy(cur, data1 + ptr1->pos, ptr1->len);
|
||||
ptr->pos = cur - data;
|
||||
cur += SHORTALIGN(ptr1->len);
|
||||
if (ptr->haspos)
|
||||
{
|
||||
if (ptr1->haspos)
|
||||
{
|
||||
memcpy(cur, _POSDATAPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
|
||||
cur += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
|
||||
if (ptr2->haspos)
|
||||
cur += add_pos(in2, ptr2, out, ptr, maxpos) * sizeof(WordEntryPos);
|
||||
}
|
||||
else if (ptr2->haspos)
|
||||
{
|
||||
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
|
||||
|
||||
if (addlen == 0)
|
||||
ptr->haspos = 0;
|
||||
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->len = ptr1->len;
|
||||
memcpy( cur, data1 + ptr1->pos, ptr1->len );
|
||||
ptr->pos = cur - data;
|
||||
cur+=SHORTALIGN(ptr1->len);
|
||||
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, data1 + ptr1->pos, ptr1->len);
|
||||
ptr->pos = cur - data;
|
||||
cur += SHORTALIGN(ptr1->len);
|
||||
if (ptr->haspos)
|
||||
{
|
||||
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->len = ptr2->len;
|
||||
memcpy( cur, data2 + ptr2->pos, ptr2->len );
|
||||
ptr->pos = cur - data;
|
||||
cur+=SHORTALIGN(ptr2->len);
|
||||
if ( ptr->haspos ) {
|
||||
int addlen = add_pos(in2, ptr2, out, ptr, maxpos );
|
||||
if ( addlen == 0 )
|
||||
ptr->haspos=0;
|
||||
memcpy(cur, data2 + ptr2->pos, ptr2->len);
|
||||
ptr->pos = cur - data;
|
||||
cur += SHORTALIGN(ptr2->len);
|
||||
if (ptr->haspos)
|
||||
{
|
||||
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
|
||||
|
||||
if (addlen == 0)
|
||||
ptr->haspos = 0;
|
||||
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->len = CALCDATASIZE( out->size, cur-data );
|
||||
if ( data != STRPTR(out) )
|
||||
memmove( STRPTR(out), data, cur-data );
|
||||
|
||||
out->size = ptr - ARRPTR(out);
|
||||
out->len = CALCDATASIZE(out->size, cur - data);
|
||||
if (data != STRPTR(out))
|
||||
memmove(STRPTR(out), data, cur - data);
|
||||
|
||||
PG_FREE_IF_COPY(in1, 0);
|
||||
PG_FREE_IF_COPY(in2, 1);
|
||||
PG_RETURN_POINTER(out);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "deflex.h"
|
||||
|
||||
const char *lex_descr[]={
|
||||
const char *lex_descr[] = {
|
||||
"",
|
||||
"Latin word",
|
||||
"Non-latin word",
|
||||
|
@ -27,7 +27,7 @@ const char *lex_descr[]={
|
|||
"HTML Entity"
|
||||
};
|
||||
|
||||
const char *tok_alias[]={
|
||||
const char *tok_alias[] = {
|
||||
"",
|
||||
"lword",
|
||||
"nlword",
|
||||
|
@ -53,4 +53,3 @@ const char *tok_alias[]={
|
|||
"uint",
|
||||
"entity"
|
||||
};
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* interface functions to parser
|
||||
/*
|
||||
* interface functions to parser
|
||||
* Teodor Sigaev <teodor@sigaev.ru>
|
||||
*/
|
||||
#include <errno.h>
|
||||
|
@ -21,154 +21,171 @@
|
|||
|
||||
/*********top interface**********/
|
||||
|
||||
static void *plan_getparser=NULL;
|
||||
static Oid current_parser_id=InvalidOid;
|
||||
static void *plan_getparser = NULL;
|
||||
static Oid current_parser_id = InvalidOid;
|
||||
|
||||
void
|
||||
init_prs(Oid id, WParserInfo *prs) {
|
||||
Oid arg[1]={ OIDOID };
|
||||
bool isnull;
|
||||
Datum pars[1]={ ObjectIdGetDatum(id) };
|
||||
int stat;
|
||||
init_prs(Oid id, WParserInfo * prs)
|
||||
{
|
||||
Oid arg[1] = {OIDOID};
|
||||
bool isnull;
|
||||
Datum pars[1] = {ObjectIdGetDatum(id)};
|
||||
int stat;
|
||||
|
||||
memset(prs,0,sizeof(WParserInfo));
|
||||
memset(prs, 0, sizeof(WParserInfo));
|
||||
SPI_connect();
|
||||
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 )
|
||||
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");
|
||||
}
|
||||
|
||||
stat = SPI_execp(plan_getparser, pars, " ", 1);
|
||||
if ( stat < 0 )
|
||||
ts_error (ERROR, "SPI_execp return %d", stat);
|
||||
if ( SPI_processed > 0 ) {
|
||||
Oid oid=InvalidOid;
|
||||
oid=DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) );
|
||||
if (stat < 0)
|
||||
ts_error(ERROR, "SPI_execp return %d", stat);
|
||||
if (SPI_processed > 0)
|
||||
{
|
||||
Oid oid = InvalidOid;
|
||||
|
||||
oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
||||
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);
|
||||
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);
|
||||
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) );
|
||||
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));
|
||||
fmgr_info_cxt(oid, &(prs->headline_info), TopMemoryContext);
|
||||
prs->prs_id=id;
|
||||
} else
|
||||
prs->prs_id = id;
|
||||
}
|
||||
else
|
||||
ts_error(ERROR, "No parser with id %d", id);
|
||||
SPI_finish();
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
WParserInfo *last_prs;
|
||||
int len;
|
||||
int reallen;
|
||||
WParserInfo *list;
|
||||
typedef struct
|
||||
{
|
||||
WParserInfo *last_prs;
|
||||
int len;
|
||||
int reallen;
|
||||
WParserInfo *list;
|
||||
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
|
||||
reset_prs(void) {
|
||||
freeSNMap( &(PList.name2id_map) );
|
||||
if ( PList.list )
|
||||
void
|
||||
reset_prs(void)
|
||||
{
|
||||
freeSNMap(&(PList.name2id_map));
|
||||
if (PList.list)
|
||||
free(PList.list);
|
||||
memset(&PList,0,sizeof(PrsList));
|
||||
memset(&PList, 0, sizeof(PrsList));
|
||||
}
|
||||
|
||||
static int
|
||||
compareprs(const void *a, const void *b) {
|
||||
return ((WParserInfo*)a)->prs_id - ((WParserInfo*)b)->prs_id;
|
||||
compareprs(const void *a, const void *b)
|
||||
{
|
||||
return ((WParserInfo *) a)->prs_id - ((WParserInfo *) b)->prs_id;
|
||||
}
|
||||
|
||||
WParserInfo *
|
||||
findprs(Oid id) {
|
||||
findprs(Oid id)
|
||||
{
|
||||
/* 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;
|
||||
|
||||
/* already used prs */
|
||||
if ( PList.len != 0 ) {
|
||||
if (PList.len != 0)
|
||||
{
|
||||
WParserInfo key;
|
||||
key.prs_id=id;
|
||||
|
||||
key.prs_id = id;
|
||||
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;
|
||||
}
|
||||
|
||||
/* last chance */
|
||||
if ( PList.len==PList.reallen ) {
|
||||
if (PList.len == PList.reallen)
|
||||
{
|
||||
WParserInfo *tmp;
|
||||
int reallen = ( PList.reallen ) ? 2*PList.reallen : 16;
|
||||
tmp=(WParserInfo*)realloc(PList.list,sizeof(WParserInfo)*reallen);
|
||||
if ( !tmp )
|
||||
ts_error(ERROR,"No memory");
|
||||
PList.reallen=reallen;
|
||||
PList.list=tmp;
|
||||
int reallen = (PList.reallen) ? 2 * PList.reallen : 16;
|
||||
|
||||
tmp = (WParserInfo *) realloc(PList.list, sizeof(WParserInfo) * reallen);
|
||||
if (!tmp)
|
||||
ts_error(ERROR, "No memory");
|
||||
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);
|
||||
PList.len++;
|
||||
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
|
||||
name2id_prs(text *name) {
|
||||
Oid arg[1]={ TEXTOID };
|
||||
bool isnull;
|
||||
Datum pars[1]={ PointerGetDatum(name) };
|
||||
int stat;
|
||||
Oid id=findSNMap_t( &(PList.name2id_map), name );
|
||||
|
||||
if ( id )
|
||||
name2id_prs(text *name)
|
||||
{
|
||||
Oid arg[1] = {TEXTOID};
|
||||
bool isnull;
|
||||
Datum pars[1] = {PointerGetDatum(name)};
|
||||
int stat;
|
||||
Oid id = findSNMap_t(&(PList.name2id_map), name);
|
||||
|
||||
if (id)
|
||||
return id;
|
||||
|
||||
|
||||
|
||||
SPI_connect();
|
||||
if ( !plan_name2id ) {
|
||||
plan_name2id = SPI_saveplan( SPI_prepare( "select oid from pg_ts_parser where prs_name = $1" , 1, arg ) );
|
||||
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)
|
||||
ts_error(ERROR, "SPI_prepare() failed");
|
||||
}
|
||||
|
||||
stat = SPI_execp(plan_name2id, pars, " ", 1);
|
||||
if ( stat < 0 )
|
||||
ts_error (ERROR, "SPI_execp return %d", stat);
|
||||
if ( SPI_processed > 0 )
|
||||
id=DatumGetObjectId( SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull) );
|
||||
else
|
||||
if (stat < 0)
|
||||
ts_error(ERROR, "SPI_execp return %d", stat);
|
||||
if (SPI_processed > 0)
|
||||
id = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
|
||||
else
|
||||
ts_error(ERROR, "No parser '%s'", text2char(name));
|
||||
SPI_finish();
|
||||
addSNMap_t( &(PList.name2id_map), name, id );
|
||||
addSNMap_t(&(PList.name2id_map), name, id);
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
/******sql-level interface******/
|
||||
typedef struct {
|
||||
int cur;
|
||||
LexDescr *list;
|
||||
} TypeStorage;
|
||||
typedef struct
|
||||
{
|
||||
int cur;
|
||||
LexDescr *list;
|
||||
} TypeStorage;
|
||||
|
||||
static void
|
||||
setup_firstcall(FuncCallContext *funcctx, Oid prsid) {
|
||||
TupleDesc tupdesc;
|
||||
MemoryContext oldcontext;
|
||||
TypeStorage *st;
|
||||
WParserInfo *prs = findprs(prsid);
|
||||
setup_firstcall(FuncCallContext *funcctx, Oid prsid)
|
||||
{
|
||||
TupleDesc tupdesc;
|
||||
MemoryContext oldcontext;
|
||||
TypeStorage *st;
|
||||
WParserInfo *prs = findprs(prsid);
|
||||
|
||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||
|
||||
st=(TypeStorage*)palloc( sizeof(TypeStorage) );
|
||||
st->cur=0;
|
||||
st->list = (LexDescr*)DatumGetPointer(
|
||||
OidFunctionCall1( prs->lextype, PointerGetDatum(prs->prs) )
|
||||
);
|
||||
funcctx->user_fctx = (void*)st;
|
||||
st = (TypeStorage *) palloc(sizeof(TypeStorage));
|
||||
st->cur = 0;
|
||||
st->list = (LexDescr *) DatumGetPointer(
|
||||
OidFunctionCall1(prs->lextype, PointerGetDatum(prs->prs))
|
||||
);
|
||||
funcctx->user_fctx = (void *) st;
|
||||
tupdesc = RelationNameGetTupleDesc("tokentype");
|
||||
funcctx->slot = TupleDescGetSlot(tupdesc);
|
||||
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
||||
|
@ -176,20 +193,22 @@ setup_firstcall(FuncCallContext *funcctx, Oid prsid) {
|
|||
}
|
||||
|
||||
static Datum
|
||||
process_call(FuncCallContext *funcctx) {
|
||||
TypeStorage *st;
|
||||
process_call(FuncCallContext *funcctx)
|
||||
{
|
||||
TypeStorage *st;
|
||||
|
||||
st=(TypeStorage*)funcctx->user_fctx;
|
||||
if ( st->list && st->list[st->cur].lexid ) {
|
||||
Datum result;
|
||||
char* values[3];
|
||||
char txtid[16];
|
||||
HeapTuple tuple;
|
||||
st = (TypeStorage *) funcctx->user_fctx;
|
||||
if (st->list && st->list[st->cur].lexid)
|
||||
{
|
||||
Datum result;
|
||||
char *values[3];
|
||||
char txtid[16];
|
||||
HeapTuple tuple;
|
||||
|
||||
values[0]=txtid;
|
||||
sprintf(txtid,"%d",st->list[st->cur].lexid);
|
||||
values[1]=st->list[st->cur].alias;
|
||||
values[2]=st->list[st->cur].descr;
|
||||
values[0] = txtid;
|
||||
sprintf(txtid, "%d", st->list[st->cur].lexid);
|
||||
values[1] = st->list[st->cur].alias;
|
||||
values[2] = st->list[st->cur].descr;
|
||||
|
||||
tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
|
||||
result = TupleGetDatum(funcctx->slot, tuple);
|
||||
|
@ -198,161 +217,179 @@ process_call(FuncCallContext *funcctx) {
|
|||
pfree(values[2]);
|
||||
st->cur++;
|
||||
return result;
|
||||
} else {
|
||||
if ( st->list ) pfree(st->list);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (st->list)
|
||||
pfree(st->list);
|
||||
pfree(st);
|
||||
}
|
||||
return (Datum)0;
|
||||
return (Datum) 0;
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(token_type);
|
||||
Datum token_type(PG_FUNCTION_ARGS);
|
||||
Datum token_type(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum
|
||||
token_type(PG_FUNCTION_ARGS) {
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
token_type(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
|
||||
if (SRF_IS_FIRSTCALL()) {
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
funcctx = SRF_FIRSTCALL_INIT();
|
||||
setup_firstcall(funcctx, PG_GETARG_OID(0) );
|
||||
setup_firstcall(funcctx, PG_GETARG_OID(0));
|
||||
}
|
||||
|
||||
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_DONE(funcctx);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(token_type_byname);
|
||||
Datum token_type_byname(PG_FUNCTION_ARGS);
|
||||
Datum token_type_byname(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
token_type_byname(PG_FUNCTION_ARGS) {
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
token_type_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
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();
|
||||
setup_firstcall(funcctx, name2id_prs( name ) );
|
||||
PG_FREE_IF_COPY(name,0);
|
||||
setup_firstcall(funcctx, name2id_prs(name));
|
||||
PG_FREE_IF_COPY(name, 0);
|
||||
}
|
||||
|
||||
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_DONE(funcctx);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(token_type_current);
|
||||
Datum token_type_current(PG_FUNCTION_ARGS);
|
||||
Datum token_type_current(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
token_type_current(PG_FUNCTION_ARGS) {
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
token_type_current(PG_FUNCTION_ARGS)
|
||||
{
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
|
||||
if (SRF_IS_FIRSTCALL()) {
|
||||
if (SRF_IS_FIRSTCALL())
|
||||
{
|
||||
funcctx = SRF_FIRSTCALL_INIT();
|
||||
if ( current_parser_id==InvalidOid )
|
||||
current_parser_id = name2id_prs( char2text("default") );
|
||||
setup_firstcall(funcctx, current_parser_id );
|
||||
if (current_parser_id == InvalidOid)
|
||||
current_parser_id = name2id_prs(char2text("default"));
|
||||
setup_firstcall(funcctx, current_parser_id);
|
||||
}
|
||||
|
||||
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_DONE(funcctx);
|
||||
}
|
||||
|
||||
|
||||
PG_FUNCTION_INFO_V1(set_curprs);
|
||||
Datum set_curprs(PG_FUNCTION_ARGS);
|
||||
Datum set_curprs(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
set_curprs(PG_FUNCTION_ARGS) {
|
||||
findprs(PG_GETARG_OID(0));
|
||||
current_parser_id=PG_GETARG_OID(0);
|
||||
PG_RETURN_VOID();
|
||||
set_curprs(PG_FUNCTION_ARGS)
|
||||
{
|
||||
findprs(PG_GETARG_OID(0));
|
||||
current_parser_id = PG_GETARG_OID(0);
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(set_curprs_byname);
|
||||
Datum set_curprs_byname(PG_FUNCTION_ARGS);
|
||||
Datum set_curprs_byname(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
set_curprs_byname(PG_FUNCTION_ARGS) {
|
||||
text *name=PG_GETARG_TEXT_P(0);
|
||||
|
||||
DirectFunctionCall1(
|
||||
set_curprs,
|
||||
ObjectIdGetDatum( name2id_prs(name) )
|
||||
);
|
||||
PG_FREE_IF_COPY(name, 0);
|
||||
PG_RETURN_VOID();
|
||||
set_curprs_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *name = PG_GETARG_TEXT_P(0);
|
||||
|
||||
DirectFunctionCall1(
|
||||
set_curprs,
|
||||
ObjectIdGetDatum(name2id_prs(name))
|
||||
);
|
||||
PG_FREE_IF_COPY(name, 0);
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
char *lexem;
|
||||
} LexemEntry;
|
||||
typedef struct
|
||||
{
|
||||
int type;
|
||||
char *lexem;
|
||||
} LexemEntry;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int cur;
|
||||
int len;
|
||||
LexemEntry *list;
|
||||
} PrsStorage;
|
||||
|
||||
typedef struct {
|
||||
int cur;
|
||||
int len;
|
||||
LexemEntry *list;
|
||||
} PrsStorage;
|
||||
|
||||
|
||||
static void
|
||||
prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt) {
|
||||
TupleDesc tupdesc;
|
||||
MemoryContext oldcontext;
|
||||
PrsStorage *st;
|
||||
WParserInfo *prs = findprs(prsid);
|
||||
char *lex=NULL;
|
||||
int llen=0, type=0;
|
||||
prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt)
|
||||
{
|
||||
TupleDesc tupdesc;
|
||||
MemoryContext oldcontext;
|
||||
PrsStorage *st;
|
||||
WParserInfo *prs = findprs(prsid);
|
||||
char *lex = NULL;
|
||||
int llen = 0,
|
||||
type = 0;
|
||||
|
||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||
|
||||
st=(PrsStorage*)palloc( sizeof(PrsStorage) );
|
||||
st->cur=0;
|
||||
st->len=16;
|
||||
st->list=(LexemEntry*)palloc( sizeof(LexemEntry)*st->len );
|
||||
st = (PrsStorage *) palloc(sizeof(PrsStorage));
|
||||
st->cur = 0;
|
||||
st->len = 16;
|
||||
st->list = (LexemEntry *) palloc(sizeof(LexemEntry) * st->len);
|
||||
|
||||
prs->prs = (void*)DatumGetPointer(
|
||||
FunctionCall2(
|
||||
&(prs->start_info),
|
||||
PointerGetDatum(VARDATA(txt)),
|
||||
Int32GetDatum(VARSIZE(txt)-VARHDRSZ)
|
||||
)
|
||||
);
|
||||
prs->prs = (void *) DatumGetPointer(
|
||||
FunctionCall2(
|
||||
&(prs->start_info),
|
||||
PointerGetDatum(VARDATA(txt)),
|
||||
Int32GetDatum(VARSIZE(txt) - VARHDRSZ)
|
||||
)
|
||||
);
|
||||
|
||||
while( ( type=DatumGetInt32(FunctionCall3(
|
||||
&(prs->getlexeme_info),
|
||||
PointerGetDatum(prs->prs),
|
||||
PointerGetDatum(&lex),
|
||||
PointerGetDatum(&llen))) ) != 0 ) {
|
||||
while ((type = DatumGetInt32(FunctionCall3(
|
||||
&(prs->getlexeme_info),
|
||||
PointerGetDatum(prs->prs),
|
||||
PointerGetDatum(&lex),
|
||||
PointerGetDatum(&llen)))) != 0)
|
||||
{
|
||||
|
||||
if ( st->cur>=st->len ) {
|
||||
st->len=2*st->len;
|
||||
st->list=(LexemEntry*)repalloc(st->list, sizeof(LexemEntry)*st->len);
|
||||
if (st->cur >= 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);
|
||||
memcpy( st->list[st->cur].lexem, lex, llen);
|
||||
st->list[st->cur].lexem[llen]='\0';
|
||||
st->list[st->cur].type=type;
|
||||
st->list[st->cur].lexem = palloc(llen + 1);
|
||||
memcpy(st->list[st->cur].lexem, lex, llen);
|
||||
st->list[st->cur].lexem[llen] = '\0';
|
||||
st->list[st->cur].type = type;
|
||||
st->cur++;
|
||||
}
|
||||
|
||||
FunctionCall1(
|
||||
&(prs->end_info),
|
||||
PointerGetDatum(prs->prs)
|
||||
);
|
||||
|
||||
st->len=st->cur;
|
||||
st->cur=0;
|
||||
|
||||
funcctx->user_fctx = (void*)st;
|
||||
FunctionCall1(
|
||||
&(prs->end_info),
|
||||
PointerGetDatum(prs->prs)
|
||||
);
|
||||
|
||||
st->len = st->cur;
|
||||
st->cur = 0;
|
||||
|
||||
funcctx->user_fctx = (void *) st;
|
||||
tupdesc = RelationNameGetTupleDesc("tokenout");
|
||||
funcctx->slot = TupleDescGetSlot(tupdesc);
|
||||
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
||||
|
@ -360,132 +397,148 @@ prs_setup_firstcall(FuncCallContext *funcctx, int prsid, text *txt) {
|
|||
}
|
||||
|
||||
static Datum
|
||||
prs_process_call(FuncCallContext *funcctx) {
|
||||
PrsStorage *st;
|
||||
prs_process_call(FuncCallContext *funcctx)
|
||||
{
|
||||
PrsStorage *st;
|
||||
|
||||
st=(PrsStorage*)funcctx->user_fctx;
|
||||
if ( st->cur < st->len ) {
|
||||
Datum result;
|
||||
char* values[2];
|
||||
char tid[16];
|
||||
HeapTuple tuple;
|
||||
st = (PrsStorage *) funcctx->user_fctx;
|
||||
if (st->cur < st->len)
|
||||
{
|
||||
Datum result;
|
||||
char *values[2];
|
||||
char tid[16];
|
||||
HeapTuple tuple;
|
||||
|
||||
values[0]=tid;
|
||||
sprintf(tid,"%d",st->list[st->cur].type);
|
||||
values[1]=st->list[st->cur].lexem;
|
||||
values[0] = tid;
|
||||
sprintf(tid, "%d", st->list[st->cur].type);
|
||||
values[1] = st->list[st->cur].lexem;
|
||||
tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
|
||||
result = TupleGetDatum(funcctx->slot, tuple);
|
||||
|
||||
pfree(values[1]);
|
||||
st->cur++;
|
||||
return result;
|
||||
} else {
|
||||
if ( st->list ) pfree(st->list);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (st->list)
|
||||
pfree(st->list);
|
||||
pfree(st);
|
||||
}
|
||||
return (Datum)0;
|
||||
return (Datum) 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PG_FUNCTION_INFO_V1(parse);
|
||||
Datum parse(PG_FUNCTION_ARGS);
|
||||
Datum parse(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
parse(PG_FUNCTION_ARGS) {
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
parse(PG_FUNCTION_ARGS)
|
||||
{
|
||||
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();
|
||||
prs_setup_firstcall(funcctx, PG_GETARG_OID(0),txt );
|
||||
PG_FREE_IF_COPY(txt,1);
|
||||
prs_setup_firstcall(funcctx, PG_GETARG_OID(0), txt);
|
||||
PG_FREE_IF_COPY(txt, 1);
|
||||
}
|
||||
|
||||
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_DONE(funcctx);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(parse_byname);
|
||||
Datum parse_byname(PG_FUNCTION_ARGS);
|
||||
Datum parse_byname(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
parse_byname(PG_FUNCTION_ARGS) {
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
parse_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
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();
|
||||
prs_setup_firstcall(funcctx, name2id_prs( name ),txt );
|
||||
PG_FREE_IF_COPY(name,0);
|
||||
PG_FREE_IF_COPY(txt,1);
|
||||
prs_setup_firstcall(funcctx, name2id_prs(name), txt);
|
||||
PG_FREE_IF_COPY(name, 0);
|
||||
PG_FREE_IF_COPY(txt, 1);
|
||||
}
|
||||
|
||||
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_DONE(funcctx);
|
||||
}
|
||||
|
||||
|
||||
PG_FUNCTION_INFO_V1(parse_current);
|
||||
Datum parse_current(PG_FUNCTION_ARGS);
|
||||
Datum parse_current(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
parse_current(PG_FUNCTION_ARGS) {
|
||||
FuncCallContext *funcctx;
|
||||
Datum result;
|
||||
parse_current(PG_FUNCTION_ARGS)
|
||||
{
|
||||
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();
|
||||
if ( current_parser_id==InvalidOid )
|
||||
current_parser_id = name2id_prs( char2text("default") );
|
||||
prs_setup_firstcall(funcctx, current_parser_id,txt );
|
||||
PG_FREE_IF_COPY(txt,0);
|
||||
if (current_parser_id == InvalidOid)
|
||||
current_parser_id = name2id_prs(char2text("default"));
|
||||
prs_setup_firstcall(funcctx, current_parser_id, txt);
|
||||
PG_FREE_IF_COPY(txt, 0);
|
||||
}
|
||||
|
||||
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_DONE(funcctx);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(headline);
|
||||
Datum headline(PG_FUNCTION_ARGS);
|
||||
Datum headline(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
headline(PG_FUNCTION_ARGS) {
|
||||
TSCfgInfo *cfg=findcfg(PG_GETARG_OID(0));
|
||||
text *in = PG_GETARG_TEXT_P(1);
|
||||
headline(PG_FUNCTION_ARGS)
|
||||
{
|
||||
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)));
|
||||
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;
|
||||
text *out;
|
||||
text *out;
|
||||
WParserInfo *prsobj = findprs(cfg->prs_id);
|
||||
|
||||
memset(&prs,0,sizeof(HLPRSTEXT));
|
||||
memset(&prs, 0, sizeof(HLPRSTEXT));
|
||||
prs.lenwords = 32;
|
||||
prs.words = (HLWORD *) palloc(sizeof(HLWORD) * prs.lenwords);
|
||||
hlparsetext(cfg, &prs, query, VARDATA(in), VARSIZE(in) - VARHDRSZ);
|
||||
|
||||
|
||||
FunctionCall3(
|
||||
&(prsobj->headline_info),
|
||||
PointerGetDatum(&prs),
|
||||
PointerGetDatum(opt),
|
||||
PointerGetDatum(query)
|
||||
);
|
||||
&(prsobj->headline_info),
|
||||
PointerGetDatum(&prs),
|
||||
PointerGetDatum(opt),
|
||||
PointerGetDatum(query)
|
||||
);
|
||||
|
||||
out = genhl(&prs);
|
||||
|
||||
PG_FREE_IF_COPY(in,1);
|
||||
PG_FREE_IF_COPY(query,2);
|
||||
if ( opt ) PG_FREE_IF_COPY(opt,3);
|
||||
PG_FREE_IF_COPY(in, 1);
|
||||
PG_FREE_IF_COPY(query, 2);
|
||||
if (opt)
|
||||
PG_FREE_IF_COPY(opt, 3);
|
||||
pfree(prs.words);
|
||||
pfree(prs.startsel);
|
||||
pfree(prs.stopsel);
|
||||
|
@ -495,35 +548,34 @@ headline(PG_FUNCTION_ARGS) {
|
|||
|
||||
|
||||
PG_FUNCTION_INFO_V1(headline_byname);
|
||||
Datum headline_byname(PG_FUNCTION_ARGS);
|
||||
Datum headline_byname(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
headline_byname(PG_FUNCTION_ARGS) {
|
||||
text *cfg=PG_GETARG_TEXT_P(0);
|
||||
headline_byname(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *cfg = PG_GETARG_TEXT_P(0);
|
||||
|
||||
Datum out=DirectFunctionCall4(
|
||||
headline,
|
||||
ObjectIdGetDatum(name2id_cfg( cfg ) ),
|
||||
PG_GETARG_DATUM(1),
|
||||
PG_GETARG_DATUM(2),
|
||||
( PG_NARGS()>3 ) ? PG_GETARG_DATUM(3) : PointerGetDatum(NULL)
|
||||
Datum out = DirectFunctionCall4(
|
||||
headline,
|
||||
ObjectIdGetDatum(name2id_cfg(cfg)),
|
||||
PG_GETARG_DATUM(1),
|
||||
PG_GETARG_DATUM(2),
|
||||
(PG_NARGS() > 3) ? PG_GETARG_DATUM(3) : PointerGetDatum(NULL)
|
||||
);
|
||||
|
||||
PG_FREE_IF_COPY(cfg,0);
|
||||
PG_RETURN_DATUM(out);
|
||||
PG_FREE_IF_COPY(cfg, 0);
|
||||
PG_RETURN_DATUM(out);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(headline_current);
|
||||
Datum headline_current(PG_FUNCTION_ARGS);
|
||||
Datum headline_current(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
headline_current(PG_FUNCTION_ARGS) {
|
||||
headline_current(PG_FUNCTION_ARGS)
|
||||
{
|
||||
PG_RETURN_DATUM(DirectFunctionCall4(
|
||||
headline,
|
||||
ObjectIdGetDatum(get_currcfg()),
|
||||
PG_GETARG_DATUM(0),
|
||||
PG_GETARG_DATUM(1),
|
||||
( PG_NARGS()>2 ) ? PG_GETARG_DATUM(2) : PointerGetDatum(NULL)
|
||||
));
|
||||
headline,
|
||||
ObjectIdGetDatum(get_currcfg()),
|
||||
PG_GETARG_DATUM(0),
|
||||
PG_GETARG_DATUM(1),
|
||||
(PG_NARGS() > 2) ? PG_GETARG_DATUM(2) : PointerGetDatum(NULL)
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,26 +3,28 @@
|
|||
#include "postgres.h"
|
||||
#include "fmgr.h"
|
||||
|
||||
typedef struct {
|
||||
Oid prs_id;
|
||||
FmgrInfo start_info;
|
||||
FmgrInfo getlexeme_info;
|
||||
FmgrInfo end_info;
|
||||
FmgrInfo headline_info;
|
||||
Oid lextype;
|
||||
void *prs;
|
||||
} WParserInfo;
|
||||
typedef struct
|
||||
{
|
||||
Oid prs_id;
|
||||
FmgrInfo start_info;
|
||||
FmgrInfo getlexeme_info;
|
||||
FmgrInfo end_info;
|
||||
FmgrInfo headline_info;
|
||||
Oid lextype;
|
||||
void *prs;
|
||||
} WParserInfo;
|
||||
|
||||
void init_prs(Oid id, WParserInfo *prs);
|
||||
WParserInfo* findprs(Oid id);
|
||||
Oid name2id_prs(text *name);
|
||||
void reset_prs(void);
|
||||
void init_prs(Oid id, WParserInfo * prs);
|
||||
WParserInfo *findprs(Oid id);
|
||||
Oid name2id_prs(text *name);
|
||||
void reset_prs(void);
|
||||
|
||||
|
||||
typedef struct {
|
||||
int lexid;
|
||||
char *alias;
|
||||
char *descr;
|
||||
} LexDescr;
|
||||
typedef struct
|
||||
{
|
||||
int lexid;
|
||||
char *alias;
|
||||
char *descr;
|
||||
} LexDescr;
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* default word parser
|
||||
/*
|
||||
* default word parser
|
||||
* Teodor Sigaev <teodor@sigaev.ru>
|
||||
*/
|
||||
#include <errno.h>
|
||||
|
@ -17,40 +17,44 @@
|
|||
#include "wordparser/deflex.h"
|
||||
|
||||
PG_FUNCTION_INFO_V1(prsd_lextype);
|
||||
Datum prsd_lextype(PG_FUNCTION_ARGS);
|
||||
Datum prsd_lextype(PG_FUNCTION_ARGS);
|
||||
|
||||
Datum
|
||||
prsd_lextype(PG_FUNCTION_ARGS) {
|
||||
LexDescr *descr=(LexDescr*)palloc(sizeof(LexDescr)*(LASTNUM+1));
|
||||
int i;
|
||||
Datum
|
||||
prsd_lextype(PG_FUNCTION_ARGS)
|
||||
{
|
||||
LexDescr *descr = (LexDescr *) palloc(sizeof(LexDescr) * (LASTNUM + 1));
|
||||
int i;
|
||||
|
||||
for(i=1;i<=LASTNUM;i++) {
|
||||
descr[i-1].lexid = i;
|
||||
descr[i-1].alias = pstrdup(tok_alias[i]);
|
||||
descr[i-1].descr = pstrdup(lex_descr[i]);
|
||||
for (i = 1; i <= LASTNUM; i++)
|
||||
{
|
||||
descr[i - 1].lexid = 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_FUNCTION_INFO_V1(prsd_start);
|
||||
Datum prsd_start(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
prsd_start(PG_FUNCTION_ARGS) {
|
||||
start_parse_str( (char*)PG_GETARG_POINTER(0), PG_GETARG_INT32(1) );
|
||||
Datum prsd_start(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
prsd_start(PG_FUNCTION_ARGS)
|
||||
{
|
||||
start_parse_str((char *) PG_GETARG_POINTER(0), PG_GETARG_INT32(1));
|
||||
PG_RETURN_POINTER(NULL);
|
||||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(prsd_getlexeme);
|
||||
Datum prsd_getlexeme(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
prsd_getlexeme(PG_FUNCTION_ARGS) {
|
||||
Datum prsd_getlexeme(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
prsd_getlexeme(PG_FUNCTION_ARGS)
|
||||
{
|
||||
/* ParserState *p=(ParserState*)PG_GETARG_POINTER(0); */
|
||||
char **t=(char**)PG_GETARG_POINTER(1);
|
||||
int *tlen=(int*)PG_GETARG_POINTER(2);
|
||||
int type=tsearch2_yylex();
|
||||
char **t = (char **) PG_GETARG_POINTER(1);
|
||||
int *tlen = (int *) PG_GETARG_POINTER(2);
|
||||
int type = tsearch2_yylex();
|
||||
|
||||
*t = token;
|
||||
*tlen = tokenlen;
|
||||
|
@ -58,34 +62,39 @@ prsd_getlexeme(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(prsd_end);
|
||||
Datum prsd_end(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
prsd_end(PG_FUNCTION_ARGS) {
|
||||
Datum prsd_end(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
prsd_end(PG_FUNCTION_ARGS)
|
||||
{
|
||||
/* ParserState *p=(ParserState*)PG_GETARG_POINTER(0); */
|
||||
end_parse();
|
||||
PG_RETURN_VOID();
|
||||
}
|
||||
|
||||
#define LEAVETOKEN(x) ( (x)==12 )
|
||||
#define COMPLEXTOKEN(x) ( (x)==5 || (x)==15 || (x)==16 || (x)==17 )
|
||||
#define ENDPUNCTOKEN(x) ( (x)==12 )
|
||||
#define COMPLEXTOKEN(x) ( (x)==5 || (x)==15 || (x)==16 || (x)==17 )
|
||||
#define ENDPUNCTOKEN(x) ( (x)==12 )
|
||||
|
||||
|
||||
#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 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) )
|
||||
|
||||
typedef struct {
|
||||
HLWORD *words;
|
||||
int len;
|
||||
} hlCheck;
|
||||
typedef struct
|
||||
{
|
||||
HLWORD *words;
|
||||
int len;
|
||||
} hlCheck;
|
||||
|
||||
static bool
|
||||
checkcondition_HL(void *checkval, ITEM *val) {
|
||||
int i;
|
||||
for(i=0;i<((hlCheck*)checkval)->len;i++) {
|
||||
if ( ((hlCheck*)checkval)->words[i].item==val )
|
||||
checkcondition_HL(void *checkval, ITEM * val)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ((hlCheck *) checkval)->len; i++)
|
||||
{
|
||||
if (((hlCheck *) checkval)->words[i].item == val)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -93,21 +102,28 @@ checkcondition_HL(void *checkval, ITEM *val) {
|
|||
|
||||
|
||||
static bool
|
||||
hlCover(HLPRSTEXT *prs, QUERYTYPE *query, int *p, int *q) {
|
||||
int i,j;
|
||||
ITEM *item=GETQUERY(query);
|
||||
int pos=*p;
|
||||
*q=0;
|
||||
*p=0x7fffffff;
|
||||
hlCover(HLPRSTEXT * prs, QUERYTYPE * query, int *p, int *q)
|
||||
{
|
||||
int i,
|
||||
j;
|
||||
ITEM *item = GETQUERY(query);
|
||||
int pos = *p;
|
||||
|
||||
for(j=0;j<query->size;j++) {
|
||||
if ( item->type != VAL ) {
|
||||
*q = 0;
|
||||
*p = 0x7fffffff;
|
||||
|
||||
for (j = 0; j < query->size; j++)
|
||||
{
|
||||
if (item->type != VAL)
|
||||
{
|
||||
item++;
|
||||
continue;
|
||||
}
|
||||
for(i=pos;i<prs->curwords;i++) {
|
||||
if ( prs->words[i].item == item ) {
|
||||
if ( i>*q)
|
||||
for (i = pos; i < prs->curwords; i++)
|
||||
{
|
||||
if (prs->words[i].item == item)
|
||||
{
|
||||
if (i > *q)
|
||||
*q = i;
|
||||
break;
|
||||
}
|
||||
|
@ -115,32 +131,39 @@ hlCover(HLPRSTEXT *prs, QUERYTYPE *query, int *p, int *q) {
|
|||
item++;
|
||||
}
|
||||
|
||||
if ( *q==0 )
|
||||
if (*q == 0)
|
||||
return false;
|
||||
|
||||
item=GETQUERY(query);
|
||||
for(j=0;j<query->size;j++) {
|
||||
if ( item->type != VAL ) {
|
||||
item = GETQUERY(query);
|
||||
for (j = 0; j < query->size; j++)
|
||||
{
|
||||
if (item->type != VAL)
|
||||
{
|
||||
item++;
|
||||
continue;
|
||||
}
|
||||
for(i=*q;i>=pos;i--) {
|
||||
if ( prs->words[i].item == item ) {
|
||||
if ( i<*p )
|
||||
*p=i;
|
||||
for (i = *q; i >= pos; i--)
|
||||
{
|
||||
if (prs->words[i].item == item)
|
||||
{
|
||||
if (i < *p)
|
||||
*p = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
item++;
|
||||
}
|
||||
}
|
||||
|
||||
if ( *p<=*q ) {
|
||||
hlCheck ch={ &(prs->words[*p]), *q-*p+1 };
|
||||
if ( TS_execute(GETQUERY(query), &ch, false, checkcondition_HL) ) {
|
||||
if (*p <= *q)
|
||||
{
|
||||
hlCheck ch = {&(prs->words[*p]), *q - *p + 1};
|
||||
|
||||
if (TS_execute(GETQUERY(query), &ch, false, checkcondition_HL))
|
||||
return true;
|
||||
} else {
|
||||
else
|
||||
{
|
||||
(*p)++;
|
||||
return hlCover(prs,query,p,q);
|
||||
return hlCover(prs, query, p, q);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -148,45 +171,54 @@ hlCover(HLPRSTEXT *prs, QUERYTYPE *query, int *p, int *q) {
|
|||
}
|
||||
|
||||
PG_FUNCTION_INFO_V1(prsd_headline);
|
||||
Datum prsd_headline(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
prsd_headline(PG_FUNCTION_ARGS) {
|
||||
HLPRSTEXT *prs=(HLPRSTEXT*)PG_GETARG_POINTER(0);
|
||||
text *opt=(text*)PG_GETARG_POINTER(1); /* can't be toasted */
|
||||
QUERYTYPE *query=(QUERYTYPE*)PG_GETARG_POINTER(2); /* can't be toasted */
|
||||
Datum prsd_headline(PG_FUNCTION_ARGS);
|
||||
Datum
|
||||
prsd_headline(PG_FUNCTION_ARGS)
|
||||
{
|
||||
HLPRSTEXT *prs = (HLPRSTEXT *) PG_GETARG_POINTER(0);
|
||||
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 */
|
||||
int min_words=15;
|
||||
int max_words=35;
|
||||
int shortword=3;
|
||||
int min_words = 15;
|
||||
int max_words = 35;
|
||||
int shortword = 3;
|
||||
|
||||
int p=0,q=0;
|
||||
int bestb=-1,beste=-1;
|
||||
int bestlen=-1;
|
||||
int pose=0, poslen, curlen;
|
||||
int p = 0,
|
||||
q = 0;
|
||||
int bestb = -1,
|
||||
beste = -1;
|
||||
int bestlen = -1;
|
||||
int pose = 0,
|
||||
poslen,
|
||||
curlen;
|
||||
|
||||
int i;
|
||||
int i;
|
||||
|
||||
/*config*/
|
||||
prs->startsel=NULL;
|
||||
prs->stopsel=NULL;
|
||||
if ( opt ) {
|
||||
Map *map,*mptr;
|
||||
|
||||
parse_cfgdict(opt,&map);
|
||||
mptr=map;
|
||||
/* config */
|
||||
prs->startsel = NULL;
|
||||
prs->stopsel = NULL;
|
||||
if (opt)
|
||||
{
|
||||
Map *map,
|
||||
*mptr;
|
||||
|
||||
parse_cfgdict(opt, &map);
|
||||
mptr = map;
|
||||
|
||||
while (mptr && mptr->key)
|
||||
{
|
||||
if (strcasecmp(mptr->key, "MaxWords") == 0)
|
||||
max_words = pg_atoi(mptr->value, 4, 1);
|
||||
else if (strcasecmp(mptr->key, "MinWords") == 0)
|
||||
min_words = pg_atoi(mptr->value, 4, 1);
|
||||
else if (strcasecmp(mptr->key, "ShortWord") == 0)
|
||||
shortword = pg_atoi(mptr->value, 4, 1);
|
||||
else if (strcasecmp(mptr->key, "StartSel") == 0)
|
||||
prs->startsel = pstrdup(mptr->value);
|
||||
else if (strcasecmp(mptr->key, "StopSel") == 0)
|
||||
prs->stopsel = pstrdup(mptr->value);
|
||||
|
||||
while(mptr && mptr->key) {
|
||||
if ( strcasecmp(mptr->key,"MaxWords")==0 )
|
||||
max_words=pg_atoi(mptr->value,4,1);
|
||||
else if ( strcasecmp(mptr->key,"MinWords")==0 )
|
||||
min_words=pg_atoi(mptr->value,4,1);
|
||||
else if ( strcasecmp(mptr->key,"ShortWord")==0 )
|
||||
shortword=pg_atoi(mptr->value,4,1);
|
||||
else if ( strcasecmp(mptr->key,"StartSel")==0 )
|
||||
prs->startsel=pstrdup(mptr->value);
|
||||
else if ( strcasecmp(mptr->key,"StopSel")==0 )
|
||||
prs->stopsel=pstrdup(mptr->value);
|
||||
|
||||
pfree(mptr->key);
|
||||
pfree(mptr->value);
|
||||
|
||||
|
@ -194,104 +226,118 @@ prsd_headline(PG_FUNCTION_ARGS) {
|
|||
}
|
||||
pfree(map);
|
||||
|
||||
if ( min_words >= max_words )
|
||||
if (min_words >= max_words)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("must be MinWords < MaxWords")));
|
||||
if ( min_words<=0 )
|
||||
if (min_words <= 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("must be MinWords > 0")));
|
||||
if ( shortword<0 )
|
||||
if (shortword < 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||
errmsg("must be ShortWord >= 0")));
|
||||
}
|
||||
|
||||
while( hlCover(prs,query,&p,&q) ) {
|
||||
while (hlCover(prs, query, &p, &q))
|
||||
{
|
||||
/* find cover len in words */
|
||||
curlen=0;
|
||||
poslen=0;
|
||||
for(i=p;i<=q && curlen < max_words ; i++) {
|
||||
if ( !NONWORDTOKEN(prs->words[i].type) )
|
||||
curlen = 0;
|
||||
poslen = 0;
|
||||
for (i = p; i <= q && curlen < max_words; i++)
|
||||
{
|
||||
if (!NONWORDTOKEN(prs->words[i].type))
|
||||
curlen++;
|
||||
if ( prs->words[i].item && !prs->words[i].repeated )
|
||||
poslen++;
|
||||
pose=i;
|
||||
if (prs->words[i].item && !prs->words[i].repeated)
|
||||
poslen++;
|
||||
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 */
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( curlen < max_words ) { /* find good end */
|
||||
for(i=i-1 ;i<prs->curwords && curlen<max_words; i++) {
|
||||
if ( i!=q ) {
|
||||
if ( !NONWORDTOKEN(prs->words[i].type) )
|
||||
if (curlen < max_words)
|
||||
{ /* find good end */
|
||||
for (i = i - 1; i < prs->curwords && curlen < max_words; i++)
|
||||
{
|
||||
if (i != q)
|
||||
{
|
||||
if (!NONWORDTOKEN(prs->words[i].type))
|
||||
curlen++;
|
||||
if ( prs->words[i].item && !prs->words[i].repeated )
|
||||
if (prs->words[i].item && !prs->words[i].repeated)
|
||||
poslen++;
|
||||
}
|
||||
pose=i;
|
||||
if ( NOENDTOKEN(prs->words[i].type) || prs->words[i].len <= shortword )
|
||||
pose = i;
|
||||
if (NOENDTOKEN(prs->words[i].type) || prs->words[i].len <= shortword)
|
||||
continue;
|
||||
if ( curlen>=min_words )
|
||||
if (curlen >= min_words)
|
||||
break;
|
||||
}
|
||||
} else { /* shorter cover :((( */
|
||||
for(;curlen>min_words;i--) {
|
||||
if ( !NONWORDTOKEN(prs->words[i].type) )
|
||||
}
|
||||
else
|
||||
{ /* shorter cover :((( */
|
||||
for (; curlen > min_words; i--)
|
||||
{
|
||||
if (!NONWORDTOKEN(prs->words[i].type))
|
||||
curlen--;
|
||||
if ( prs->words[i].item && !prs->words[i].repeated )
|
||||
if (prs->words[i].item && !prs->words[i].repeated)
|
||||
poslen--;
|
||||
pose=i;
|
||||
if ( NOENDTOKEN(prs->words[i].type) || prs->words[i].len <= shortword )
|
||||
pose = i;
|
||||
if (NOENDTOKEN(prs->words[i].type) || prs->words[i].len <= shortword)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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) &&
|
||||
(NOENDTOKEN(prs->words[beste].type) || prs->words[beste].len <= shortword) ) ) {
|
||||
bestb=p; beste=pose;
|
||||
bestlen=poslen;
|
||||
}
|
||||
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) &&
|
||||
(NOENDTOKEN(prs->words[beste].type) || prs->words[beste].len <= shortword)))
|
||||
{
|
||||
bestb = p;
|
||||
beste = pose;
|
||||
bestlen = poslen;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
if ( bestlen<0 ) {
|
||||
curlen=0;
|
||||
poslen=0;
|
||||
for(i=0;i<prs->curwords && curlen<min_words ; i++) {
|
||||
if ( !NONWORDTOKEN(prs->words[i].type) )
|
||||
if (bestlen < 0)
|
||||
{
|
||||
curlen = 0;
|
||||
poslen = 0;
|
||||
for (i = 0; i < prs->curwords && curlen < min_words; i++)
|
||||
{
|
||||
if (!NONWORDTOKEN(prs->words[i].type))
|
||||
curlen++;
|
||||
pose=i;
|
||||
pose = i;
|
||||
}
|
||||
bestb=0; beste=pose;
|
||||
bestb = 0;
|
||||
beste = pose;
|
||||
}
|
||||
|
||||
for(i=bestb;i<=beste;i++) {
|
||||
if ( prs->words[i].item )
|
||||
prs->words[i].selected=1;
|
||||
if ( prs->words[i].repeated )
|
||||
prs->words[i].skip=1;
|
||||
if ( HLIDIGNORE(prs->words[i].type) )
|
||||
prs->words[i].replace=1;
|
||||
for (i = bestb; i <= beste; i++)
|
||||
{
|
||||
if (prs->words[i].item)
|
||||
prs->words[i].selected = 1;
|
||||
if (prs->words[i].repeated)
|
||||
prs->words[i].skip = 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)
|
||||
prs->startsel=pstrdup("<b>");
|
||||
prs->startsel = pstrdup("<b>");
|
||||
if (!prs->stopsel)
|
||||
prs->stopsel=pstrdup("</b>");
|
||||
prs->startsellen=strlen(prs->startsel);
|
||||
prs->stopsellen=strlen(prs->stopsel);
|
||||
prs->stopsel = pstrdup("</b>");
|
||||
prs->startsellen = strlen(prs->startsel);
|
||||
prs->stopsellen = strlen(prs->stopsel);
|
||||
|
||||
PG_RETURN_POINTER(prs);
|
||||
}
|
||||
|
||||
|
|
|
@ -87,10 +87,10 @@ pgxml_parse(PG_FUNCTION_ARGS)
|
|||
doctree = xmlParseMemory((char *) VARDATA(t), docsize);
|
||||
if (doctree == NULL)
|
||||
{
|
||||
xmlCleanupParser();
|
||||
xmlCleanupParser();
|
||||
PG_RETURN_BOOL(false); /* i.e. not well-formed */
|
||||
}
|
||||
xmlCleanupParser();
|
||||
xmlCleanupParser();
|
||||
xmlFreeDoc(doctree);
|
||||
PG_RETURN_BOOL(true);
|
||||
}
|
||||
|
@ -202,8 +202,8 @@ pgxml_xpath(PG_FUNCTION_ARGS)
|
|||
|
||||
doctree = xmlParseMemory((char *) VARDATA(t), docsize);
|
||||
if (doctree == NULL)
|
||||
{ /* not well-formed */
|
||||
xmlCleanupParser();
|
||||
{ /* not well-formed */
|
||||
xmlCleanupParser();
|
||||
PG_RETURN_NULL();
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
* The old interface functions have been converted to macros
|
||||
|
@ -617,7 +617,7 @@ heap_formtuple(TupleDesc tupleDescriptor,
|
|||
td->t_natts = numberOfAttributes;
|
||||
td->t_hoff = hoff;
|
||||
|
||||
if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
|
||||
if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */
|
||||
td->t_infomask = HEAP_HASOID;
|
||||
|
||||
DataFill((char *) td + hoff,
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* 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)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("index tuple requires %lu bytes, maximum size is %lu",
|
||||
(unsigned long) size,
|
||||
(unsigned long) INDEX_SIZE_MASK)));
|
||||
errmsg("index tuple requires %lu bytes, maximum size is %lu",
|
||||
(unsigned long) size,
|
||||
(unsigned long) INDEX_SIZE_MASK)));
|
||||
|
||||
infomask |= size;
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* 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,
|
||||
TupleDesc typeinfo);
|
||||
TupleDesc typeinfo);
|
||||
static void printtup(HeapTuple tuple, TupleDesc typeinfo,
|
||||
DestReceiver *self);
|
||||
DestReceiver *self);
|
||||
static void printtup_20(HeapTuple tuple, TupleDesc typeinfo,
|
||||
DestReceiver *self);
|
||||
DestReceiver *self);
|
||||
static void printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo,
|
||||
DestReceiver *self);
|
||||
DestReceiver *self);
|
||||
static void printtup_shutdown(DestReceiver *self);
|
||||
static void printtup_destroy(DestReceiver *self);
|
||||
|
||||
|
@ -81,8 +81,8 @@ printtup_create_DR(CommandDest dest, Portal portal)
|
|||
else
|
||||
{
|
||||
/*
|
||||
* In protocol 2.0 the Bind message does not exist, so there is
|
||||
* no way for the columns to have different print formats; it's
|
||||
* In protocol 2.0 the Bind message does not exist, so there is no
|
||||
* way for the columns to have different print formats; it's
|
||||
* sufficient to look at the first one.
|
||||
*/
|
||||
if (portal->formats && portal->formats[0] != 0)
|
||||
|
@ -111,12 +111,13 @@ static void
|
|||
printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
|
||||
{
|
||||
DR_printtup *myState = (DR_printtup *) self;
|
||||
Portal portal = myState->portal;
|
||||
Portal portal = myState->portal;
|
||||
|
||||
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.
|
||||
*/
|
||||
|
@ -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,
|
||||
* then we send back the tuple descriptor of the tuples.
|
||||
* If this is a retrieve, and we are supposed to emit row
|
||||
* descriptions, then we send back the tuple descriptor of the tuples.
|
||||
*/
|
||||
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.
|
||||
* 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
|
||||
* 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);
|
||||
* send zeroes for the format codes in that case.
|
||||
*/
|
||||
|
@ -176,14 +177,14 @@ SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist, int16 *formats)
|
|||
int i;
|
||||
StringInfoData buf;
|
||||
|
||||
pq_beginmessage(&buf, 'T'); /* tuple descriptor message type */
|
||||
pq_sendint(&buf, natts, 2); /* # of attrs in tuples */
|
||||
pq_beginmessage(&buf, 'T'); /* tuple descriptor message type */
|
||||
pq_sendint(&buf, natts, 2); /* # of attrs in tuples */
|
||||
|
||||
for (i = 0; i < natts; ++i)
|
||||
{
|
||||
Oid atttypid = attrs[i]->atttypid;
|
||||
int32 atttypmod = attrs[i]->atttypmod;
|
||||
Oid basetype;
|
||||
Oid atttypid = attrs[i]->atttypid;
|
||||
int32 atttypmod = attrs[i]->atttypmod;
|
||||
Oid basetype;
|
||||
|
||||
pq_sendstring(&buf, NameStr(attrs[i]->attname));
|
||||
/* 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
|
||||
* avoid memory leakage inside the type's output routine.
|
||||
* If we have a toasted datum, forcibly detoast it here to avoid
|
||||
* memory leakage inside the type's output routine.
|
||||
*/
|
||||
if (thisState->typisvarlena)
|
||||
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
||||
|
@ -347,7 +348,7 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||
|
||||
outputbytes = DatumGetByteaP(FunctionCall2(&thisState->finfo,
|
||||
attr,
|
||||
ObjectIdGetDatum(thisState->typelem)));
|
||||
ObjectIdGetDatum(thisState->typelem)));
|
||||
/* We assume the result will not have been toasted */
|
||||
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
|
||||
pq_sendbytes(&buf, VARDATA(outputbytes),
|
||||
|
@ -424,8 +425,8 @@ printtup_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||
Assert(thisState->format == 0);
|
||||
|
||||
/*
|
||||
* If we have a toasted datum, forcibly detoast it here to
|
||||
* avoid memory leakage inside the type's output routine.
|
||||
* If we have a toasted datum, forcibly detoast it here to avoid
|
||||
* memory leakage inside the type's output routine.
|
||||
*/
|
||||
if (thisState->typisvarlena)
|
||||
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
||||
|
@ -536,9 +537,10 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||
continue;
|
||||
getTypeOutputInfo(typeinfo->attrs[i]->atttypid,
|
||||
&typoutput, &typelem, &typisvarlena);
|
||||
|
||||
/*
|
||||
* If we have a toasted datum, forcibly detoast it here to
|
||||
* avoid memory leakage inside the type's output routine.
|
||||
* If we have a toasted datum, forcibly detoast it here to avoid
|
||||
* memory leakage inside the type's output routine.
|
||||
*/
|
||||
if (typisvarlena)
|
||||
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
||||
|
@ -547,7 +549,7 @@ debugtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||
|
||||
value = DatumGetCString(OidFunctionCall3(typoutput,
|
||||
attr,
|
||||
ObjectIdGetDatum(typelem),
|
||||
ObjectIdGetDatum(typelem),
|
||||
Int32GetDatum(typeinfo->attrs[i]->atttypmod)));
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* If we have a toasted datum, forcibly detoast it here to
|
||||
* avoid memory leakage inside the type's output routine.
|
||||
* If we have a toasted datum, forcibly detoast it here to avoid
|
||||
* memory leakage inside the type's output routine.
|
||||
*/
|
||||
if (thisState->typisvarlena)
|
||||
attr = PointerGetDatum(PG_DETOAST_DATUM(origattr));
|
||||
|
@ -637,7 +639,7 @@ printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
|
|||
|
||||
outputbytes = DatumGetByteaP(FunctionCall2(&thisState->finfo,
|
||||
attr,
|
||||
ObjectIdGetDatum(thisState->typelem)));
|
||||
ObjectIdGetDatum(thisState->typelem)));
|
||||
/* We assume the result will not have been toasted */
|
||||
pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
|
||||
pq_sendbytes(&buf, VARDATA(outputbytes),
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* 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,
|
||||
key,
|
||||
s->numberOfKeys * sizeof(ScanKeyData));
|
||||
|
||||
/*
|
||||
* Play games here with the scan key to use the Consistent
|
||||
* function for all comparisons: 1) the sk_procedure field
|
||||
* will now be used to hold the strategy number 2) the
|
||||
* sk_func field will point to the Consistent function
|
||||
* function for all comparisons: 1) the sk_procedure field will
|
||||
* now be used to hold the strategy number 2) the sk_func field
|
||||
* will point to the Consistent function
|
||||
*/
|
||||
for (i = 0; i < s->numberOfKeys; i++)
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* On IEEE-float machines, minus zero and zero have different bit patterns
|
||||
* but should compare as equal. We must ensure that they have the same
|
||||
* hash value, which is most easily done this way:
|
||||
* On IEEE-float machines, minus zero and zero have different bit
|
||||
* patterns but should compare as equal. We must ensure that they
|
||||
* have the same hash value, which is most easily done this way:
|
||||
*/
|
||||
if (key == (float4) 0)
|
||||
PG_RETURN_UINT32(0);
|
||||
|
@ -76,9 +76,9 @@ hashfloat8(PG_FUNCTION_ARGS)
|
|||
float8 key = PG_GETARG_FLOAT8(0);
|
||||
|
||||
/*
|
||||
* On IEEE-float machines, minus zero and zero have different bit patterns
|
||||
* but should compare as equal. We must ensure that they have the same
|
||||
* hash value, which is most easily done this way:
|
||||
* On IEEE-float machines, minus zero and zero have different bit
|
||||
* patterns but should compare as equal. We must ensure that they
|
||||
* have the same hash value, which is most easily done this way:
|
||||
*/
|
||||
if (key == (float8) 0)
|
||||
PG_RETURN_UINT32(0);
|
||||
|
@ -121,9 +121,9 @@ hashtext(PG_FUNCTION_ARGS)
|
|||
Datum result;
|
||||
|
||||
/*
|
||||
* Note: this is currently identical in behavior to hashvarlena,
|
||||
* but it seems likely that we may need to do something different
|
||||
* in non-C locales. (See also hashbpchar, if so.)
|
||||
* Note: this is currently identical in behavior to hashvarlena, but
|
||||
* it seems likely that we may need to do something different in non-C
|
||||
* locales. (See also hashbpchar, if so.)
|
||||
*/
|
||||
result = hash_any((unsigned char *) VARDATA(key),
|
||||
VARSIZE(key) - VARHDRSZ);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
* Overflow pages look like ordinary relation pages.
|
||||
|
@ -205,8 +205,8 @@ _hash_getovfladdr(Relation rel, Buffer *metabufp)
|
|||
if (++splitnum >= NCACHED)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
||||
errmsg("out of overflow pages in hash index \"%s\"",
|
||||
RelationGetRelationName(rel))));
|
||||
errmsg("out of overflow pages in hash index \"%s\"",
|
||||
RelationGetRelationName(rel))));
|
||||
metap->hashm_ovflpoint = splitnum;
|
||||
metap->hashm_spares[splitnum] = metap->hashm_spares[splitnum - 1];
|
||||
metap->hashm_spares[splitnum - 1]--;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
|
@ -1132,6 +1132,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid)
|
|||
xlhdr.t_natts = tup->t_data->t_natts;
|
||||
xlhdr.t_infomask = tup->t_data->t_infomask;
|
||||
xlhdr.t_hoff = tup->t_data->t_hoff;
|
||||
|
||||
/*
|
||||
* 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
|
||||
|
@ -1149,9 +1150,9 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid)
|
|||
rdata[2].next = NULL;
|
||||
|
||||
/*
|
||||
* If this is the single and first tuple on page, we can reinit the
|
||||
* page instead of restoring the whole thing. Set flag, and hide
|
||||
* buffer references from XLogInsert.
|
||||
* If this is the single and first tuple on page, we can reinit
|
||||
* the page instead of restoring the whole thing. Set flag, and
|
||||
* hide buffer references from XLogInsert.
|
||||
*/
|
||||
if (ItemPointerGetOffsetNumber(&(tup->t_self)) == 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
|
||||
* 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.
|
||||
*/
|
||||
rdata[1].buffer = buffer;
|
||||
|
@ -1991,9 +1992,10 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
|||
2 * sizeof(TransactionId));
|
||||
hsize += 2 * sizeof(TransactionId);
|
||||
}
|
||||
|
||||
/*
|
||||
* As with insert records, we need not store the rdata[2] segment
|
||||
* if we decide to store the whole buffer instead.
|
||||
* As with insert records, we need not store the rdata[2] segment if
|
||||
* we decide to store the whole buffer instead.
|
||||
*/
|
||||
rdata[2].buffer = newbuf;
|
||||
rdata[2].data = (char *) &xlhdr;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* short-circuited by index_getnext, the effective position restoration
|
||||
* is done by restoring unique_tuple_pos.
|
||||
* short-circuited by index_getnext, the effective position
|
||||
* restoration is done by restoring unique_tuple_pos.
|
||||
*/
|
||||
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
|
||||
* to make the index AM look through any additional tuples. (This can
|
||||
* If we already got a tuple and it must be unique, there's no need to
|
||||
* make the index AM look through any additional tuples. (This can
|
||||
* save a useful amount of work in scenarios where there are many dead
|
||||
* tuples due to heavy update activity.)
|
||||
*
|
||||
* 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
|
||||
* resources before returning NULL; if we fail to do so then a multi-index
|
||||
* scan can easily run the system out of free buffers. We can release
|
||||
* index-level resources fairly cheaply by calling index_rescan. This
|
||||
* means there are two persistent states as far as the index AM is
|
||||
* concerned: on-tuple and rescanned. If we are actually asked to
|
||||
* re-fetch the single tuple, we have to go through a fresh indexscan
|
||||
* startup, which penalizes that (infrequent) case.
|
||||
* resources before returning NULL; if we fail to do so then a
|
||||
* multi-index scan can easily run the system out of free buffers. We
|
||||
* can release index-level resources fairly cheaply by calling
|
||||
* index_rescan. This means there are two persistent states as far as
|
||||
* the index AM is concerned: on-tuple and rescanned. If we are
|
||||
* actually asked to re-fetch the single tuple, we have to go through
|
||||
* a fresh indexscan startup, which penalizes that (infrequent) case.
|
||||
*/
|
||||
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))
|
||||
{
|
||||
|
@ -459,22 +459,23 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
|
|||
if (new_tuple_pos == 0)
|
||||
{
|
||||
/*
|
||||
* We are moving onto the unique tuple from having been off it.
|
||||
* We just fall through and let the index AM do the work. Note
|
||||
* we should get the right answer regardless of scan direction.
|
||||
* We are moving onto the unique tuple from having been off
|
||||
* it. We just fall through and let the index AM do the work.
|
||||
* 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
|
||||
{
|
||||
/*
|
||||
* Moving off the tuple; must do amrescan to release index-level
|
||||
* pins before we return NULL. Since index_rescan will reset
|
||||
* my state, must save and restore...
|
||||
* Moving off the tuple; must do amrescan to release
|
||||
* index-level pins before we return NULL. Since index_rescan
|
||||
* 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->got_tuple = true;
|
||||
|
@ -631,7 +632,7 @@ index_bulk_delete(Relation indexRelation,
|
|||
*/
|
||||
IndexBulkDeleteResult *
|
||||
index_vacuum_cleanup(Relation indexRelation,
|
||||
IndexVacuumCleanupInfo *info,
|
||||
IndexVacuumCleanupInfo * info,
|
||||
IndexBulkDeleteResult *stats)
|
||||
{
|
||||
RegProcedure procedure;
|
||||
|
@ -649,7 +650,7 @@ index_vacuum_cleanup(Relation indexRelation,
|
|||
DatumGetPointer(OidFunctionCall3(procedure,
|
||||
PointerGetDatum(indexRelation),
|
||||
PointerGetDatum((Pointer) info),
|
||||
PointerGetDatum((Pointer) stats)));
|
||||
PointerGetDatum((Pointer) stats)));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
* current page; else someone else's _bt_check_unique scan
|
||||
* could fail to see our insertion. write locks on intermediate
|
||||
* dead pages won't do because we don't know when they will get
|
||||
* de-linked from the tree.
|
||||
* could fail to see our insertion. write locks on
|
||||
* intermediate dead pages won't do because we don't know when
|
||||
* they will get de-linked from the tree.
|
||||
*/
|
||||
Buffer rbuf = InvalidBuffer;
|
||||
|
||||
|
@ -523,9 +523,10 @@ _bt_insertonpg(Relation rel,
|
|||
/*
|
||||
* 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
|
||||
* have been the "fast root". We need to ensure that the fast root
|
||||
* link points at or above the current page. We can safely acquire
|
||||
* a lock on the metapage here --- see comments for _bt_newroot().
|
||||
* have been the "fast root". We need to ensure that the fast
|
||||
* root link points at or above the current page. We can safely
|
||||
* acquire a lock on the metapage here --- see comments for
|
||||
* _bt_newroot().
|
||||
*/
|
||||
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
|
||||
* 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
|
||||
* 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)
|
||||
{
|
||||
/*
|
||||
* Here we have to do something Lehman and Yao don't talk about:
|
||||
* deal with a root split and construction of a new root. If our
|
||||
* stack is empty then we have just split a node on what had been
|
||||
* the root level when we descended the tree. If it was still the
|
||||
* root then we perform a new-root construction. If it *wasn't*
|
||||
* the root anymore, search to find the next higher level that
|
||||
* someone constructed meanwhile, and find the right place to insert
|
||||
* as for the normal case.
|
||||
* Here we have to do something Lehman and Yao don't talk about: deal
|
||||
* with a root split and construction of a new root. If our stack is
|
||||
* empty then we have just split a node on what had been the root
|
||||
* level when we descended the tree. If it was still the root then we
|
||||
* perform a new-root construction. If it *wasn't* the root anymore,
|
||||
* search to find the next higher level that someone constructed
|
||||
* meanwhile, and find the right place to insert as for the normal
|
||||
* case.
|
||||
*
|
||||
* If we have to search for the parent level, we do so by
|
||||
* re-descending from the root. This is not super-efficient,
|
||||
* but it's rare enough not to matter. (This path is also taken
|
||||
* when called from WAL recovery --- we have no stack in that case.)
|
||||
* If we have to search for the parent level, we do so by re-descending
|
||||
* from the root. This is not super-efficient, but it's rare enough
|
||||
* not to matter. (This path is also taken when called from WAL
|
||||
* recovery --- we have no stack in that case.)
|
||||
*/
|
||||
if (is_root)
|
||||
{
|
||||
|
@ -1222,9 +1223,9 @@ _bt_insert_parent(Relation rel,
|
|||
/*
|
||||
* Find the parent buffer and get the parent page.
|
||||
*
|
||||
* Oops - if we were moved right then we need to change stack
|
||||
* item! We want to find parent pointing to where we are,
|
||||
* right ? - vadim 05/27/97
|
||||
* Oops - if we were moved right then we need to change stack item!
|
||||
* We want to find parent pointing to where we are, right ? -
|
||||
* vadim 05/27/97
|
||||
*/
|
||||
ItemPointerSet(&(stack->bts_btitem.bti_itup.t_tid),
|
||||
bknum, P_HIKEY);
|
||||
|
@ -1296,16 +1297,16 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
|
|||
|
||||
/*
|
||||
* start = InvalidOffsetNumber means "search the whole page".
|
||||
* We need this test anyway due to possibility that
|
||||
* page has a high key now when it didn't before.
|
||||
* We need this test anyway due to possibility that page has a
|
||||
* high key now when it didn't before.
|
||||
*/
|
||||
if (start < minoff)
|
||||
start = minoff;
|
||||
|
||||
/*
|
||||
* These loops will check every item on the page --- but in an
|
||||
* order that's attuned to the probability of where it actually
|
||||
* is. Scan to the right first, then to the left.
|
||||
* order that's attuned to the probability of where it
|
||||
* actually is. Scan to the right first, then to the left.
|
||||
*/
|
||||
for (offnum = start;
|
||||
offnum <= maxoff;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* guarantee no deadlocks, we have to release the metadata
|
||||
* page and start all over again. (Is that really true?
|
||||
* But it's hardly worth trying to optimize this case.)
|
||||
* page and start all over again. (Is that really true? But
|
||||
* it's hardly worth trying to optimize this case.)
|
||||
*/
|
||||
_bt_relbuf(rel, metabuf);
|
||||
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
|
||||
* type on the new root page. Since this is the first page in
|
||||
* the tree, it's a leaf as well as the root.
|
||||
* type on the new root page. Since this is the first page in the
|
||||
* tree, it's a leaf as well as the root.
|
||||
*/
|
||||
rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
|
||||
rootblkno = BufferGetBlockNumber(rootbuf);
|
||||
|
@ -240,7 +240,7 @@ _bt_getroot(Relation rel, int access)
|
|||
_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,
|
||||
* 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
|
||||
* lock set on the metadata page. Return the root page's buffer.
|
||||
* By here, we have a pin and read lock on the root page, and no lock
|
||||
* set on the metadata page. Return the root page's buffer.
|
||||
*/
|
||||
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
|
||||
* 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
|
||||
* 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
|
||||
* 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.)
|
||||
|
@ -406,9 +406,9 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
|
|||
* First see if the FSM knows of any free pages.
|
||||
*
|
||||
* 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
|
||||
* could have been re-used between the time the last VACUUM scanned
|
||||
* it and the time the VACUUM made its FSM updates.)
|
||||
* that the page is still free. (For example, an already-free
|
||||
* page could have been re-used between the time the last VACUUM
|
||||
* scanned it and the time the VACUUM made its FSM updates.)
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
|
@ -431,10 +431,10 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
|
|||
/*
|
||||
* Extend the relation by one page.
|
||||
*
|
||||
* We have to use a lock to ensure no one else is extending the rel at
|
||||
* the same time, else we will both try to initialize the same new
|
||||
* page. We can skip locking for new or temp relations, however,
|
||||
* since no one else could be accessing them.
|
||||
* We have to use a lock to ensure no one else is extending the rel
|
||||
* at the same time, else we will both try to initialize the same
|
||||
* new page. We can skip locking for new or temp relations,
|
||||
* however, since no one else could be accessing them.
|
||||
*/
|
||||
needLock = !(rel->rd_isnew || rel->rd_istemp);
|
||||
|
||||
|
@ -444,8 +444,8 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
|
|||
buf = ReadBuffer(rel, P_NEW);
|
||||
|
||||
/*
|
||||
* Release the file-extension lock; it's now OK for someone else to
|
||||
* extend the relation some more.
|
||||
* Release the file-extension lock; it's now OK for someone else
|
||||
* to extend the relation some more.
|
||||
*/
|
||||
if (needLock)
|
||||
UnlockPage(rel, 0, ExclusiveLock);
|
||||
|
@ -484,7 +484,7 @@ _bt_relbuf(Relation rel, Buffer buf)
|
|||
* and a pin on the buffer.
|
||||
*
|
||||
* 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
|
||||
* guaranteeing correctness after a crash.
|
||||
*/
|
||||
|
@ -534,13 +534,14 @@ _bt_page_recyclable(Page page)
|
|||
BTPageOpaque opaque;
|
||||
|
||||
/*
|
||||
* It's possible to find an all-zeroes page in an index --- for example,
|
||||
* a backend might successfully extend the relation one page and then
|
||||
* crash before it is able to make a WAL entry for adding the page.
|
||||
* If we find a zeroed page then reclaim it.
|
||||
* It's possible to find an all-zeroes page in an index --- for
|
||||
* example, a backend might successfully extend the relation one page
|
||||
* and then crash before it is able to make a WAL entry for adding the
|
||||
* page. If we find a zeroed page then reclaim it.
|
||||
*/
|
||||
if (PageIsNew(page))
|
||||
return true;
|
||||
|
||||
/*
|
||||
* Otherwise, recycle if deleted and too old to have any processes
|
||||
* interested in it.
|
||||
|
@ -565,7 +566,7 @@ _bt_page_recyclable(Page page)
|
|||
* mistake. On exit, metapage data is correct and we no longer have
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* deleting the page it points to.
|
||||
*
|
||||
|
@ -646,9 +647,7 @@ _bt_delitems(Relation rel, Buffer buf,
|
|||
* adjusting item numbers for previous deletions.
|
||||
*/
|
||||
for (i = nitems - 1; i >= 0; i--)
|
||||
{
|
||||
PageIndexTupleDelete(page, itemnos[i]);
|
||||
}
|
||||
|
||||
/* XLOG stuff */
|
||||
if (!rel->rd_istemp)
|
||||
|
@ -666,8 +665,8 @@ _bt_delitems(Relation rel, Buffer buf,
|
|||
rdata[0].next = &(rdata[1]);
|
||||
|
||||
/*
|
||||
* The target-offsets array is not in the buffer, but pretend
|
||||
* that it is. When XLogInsert stores the whole buffer, the offsets
|
||||
* The target-offsets array is not in the buffer, but pretend that
|
||||
* it is. When XLogInsert stores the whole buffer, the offsets
|
||||
* array need not be stored too.
|
||||
*/
|
||||
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
|
||||
* 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.
|
||||
*
|
||||
* Returns the number of pages successfully deleted (zero on failure; could
|
||||
|
@ -714,7 +713,7 @@ _bt_delitems(Relation rel, Buffer buf,
|
|||
int
|
||||
_bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||
{
|
||||
BlockNumber target,
|
||||
BlockNumber target,
|
||||
leftsib,
|
||||
rightsib,
|
||||
parent;
|
||||
|
@ -740,17 +739,18 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||
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.
|
||||
*/
|
||||
page = BufferGetPage(buf);
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
if (P_RIGHTMOST(opaque) || P_ISROOT(opaque) || P_ISDELETED(opaque) ||
|
||||
P_FIRSTDATAKEY(opaque) <= PageGetMaxOffsetNumber(page))
|
||||
P_FIRSTDATAKEY(opaque) <= PageGetMaxOffsetNumber(page))
|
||||
{
|
||||
_bt_relbuf(rel, buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save info about page, including a copy of its high key (it must
|
||||
* have one, being non-rightmost).
|
||||
|
@ -760,12 +760,13 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||
leftsib = opaque->btpo_prev;
|
||||
itemid = PageGetItemId(page, P_HIKEY);
|
||||
targetkey = CopyBTItem((BTItem) PageGetItem(page, itemid));
|
||||
|
||||
/*
|
||||
* 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;
|
||||
* this will give us a link to either the current parent or someplace
|
||||
* to its left (if there are multiple equal high keys). To avoid
|
||||
* deadlocks, we'd better drop the target page lock first.
|
||||
* Use the standard search mechanism to search for the page's high
|
||||
* key; this will give us a link to either the current parent or
|
||||
* someplace to its left (if there are multiple equal high keys). To
|
||||
* avoid deadlocks, we'd better drop the target page lock first.
|
||||
*/
|
||||
_bt_relbuf(rel, buf);
|
||||
/* 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);
|
||||
/* don't need a pin on that either */
|
||||
_bt_relbuf(rel, lbuf);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
for (;;)
|
||||
|
@ -789,10 +792,12 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||
stack = stack->bts_parent;
|
||||
ilevel++;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* target page. The sibling that was current a moment ago could have
|
||||
* split, so we may have to move right. This search could fail if
|
||||
|
@ -823,21 +828,24 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||
}
|
||||
else
|
||||
lbuf = InvalidBuffer;
|
||||
|
||||
/*
|
||||
* Next write-lock the target page itself. It should be okay to take just
|
||||
* a write lock not a superexclusive lock, since no scans would stop on an
|
||||
* empty page.
|
||||
* Next write-lock the target page itself. It should be okay to take
|
||||
* just a write lock not a superexclusive lock, since no scans would
|
||||
* stop on an empty page.
|
||||
*/
|
||||
buf = _bt_getbuf(rel, target, BT_WRITE);
|
||||
page = BufferGetPage(buf);
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
|
||||
/*
|
||||
* Check page is still empty etc, else abandon deletion. The empty check
|
||||
* is necessary since someone else might have inserted into it while
|
||||
* we didn't have it locked; the others are just for paranoia's sake.
|
||||
* Check page is still empty etc, else abandon deletion. The empty
|
||||
* check is necessary since someone else might have inserted into it
|
||||
* 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) ||
|
||||
P_FIRSTDATAKEY(opaque) <= PageGetMaxOffsetNumber(page))
|
||||
P_FIRSTDATAKEY(opaque) <= PageGetMaxOffsetNumber(page))
|
||||
{
|
||||
_bt_relbuf(rel, buf);
|
||||
if (BufferIsValid(lbuf))
|
||||
|
@ -846,14 +854,17 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||
}
|
||||
if (opaque->btpo_prev != leftsib)
|
||||
elog(ERROR, "left link changed unexpectedly");
|
||||
|
||||
/*
|
||||
* And next write-lock the (current) right sibling.
|
||||
*/
|
||||
rightsib = opaque->btpo_next;
|
||||
rbuf = _bt_getbuf(rel, rightsib, BT_WRITE);
|
||||
|
||||
/*
|
||||
* 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),
|
||||
target, P_HIKEY);
|
||||
|
@ -863,10 +874,11 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||
RelationGetRelationName(rel));
|
||||
parent = stack->bts_blkno;
|
||||
poffset = stack->bts_offset;
|
||||
|
||||
/*
|
||||
* 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
|
||||
* changes to half-dead status.
|
||||
* delete, unless it's also the only child --- in which case the
|
||||
* parent changes to half-dead status.
|
||||
*/
|
||||
page = BufferGetPage(pbuf);
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
|
@ -893,12 +905,13 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||
if (OffsetNumberNext(P_FIRSTDATAKEY(opaque)) == maxoff)
|
||||
parent_one_child = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
* (In 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
|
||||
* daunting.)
|
||||
* then the rightsib is a candidate to become the new fast root. (In
|
||||
* 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 daunting.)
|
||||
*
|
||||
* We can safely acquire a lock on the metapage here --- see comments for
|
||||
* _bt_newroot().
|
||||
|
@ -914,12 +927,13 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||
metabuf = _bt_getbuf(rel, BTREE_METAPAGE, BT_WRITE);
|
||||
metapg = BufferGetPage(metabuf);
|
||||
metad = BTPageGetMeta(metapg);
|
||||
|
||||
/*
|
||||
* The expected case here is btm_fastlevel == targetlevel+1;
|
||||
* if the fastlevel is <= targetlevel, something is wrong, and we
|
||||
* choose to overwrite it to fix it.
|
||||
* if the fastlevel is <= targetlevel, something is wrong, and
|
||||
* we choose to overwrite it to fix it.
|
||||
*/
|
||||
if (metad->btm_fastlevel > targetlevel+1)
|
||||
if (metad->btm_fastlevel > targetlevel + 1)
|
||||
{
|
||||
/* no update wanted */
|
||||
_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
|
||||
* delete the target's downlink and the *following* key. Easiest way is
|
||||
* to copy the right sibling's downlink over the target downlink, and then
|
||||
* delete the following item.
|
||||
* delete the target's downlink and the *following* key. Easiest way
|
||||
* is to copy the right sibling's downlink over the target downlink,
|
||||
* and then delete the following item.
|
||||
*/
|
||||
page = BufferGetPage(pbuf);
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
|
@ -950,7 +964,7 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||
}
|
||||
else
|
||||
{
|
||||
OffsetNumber nextoffset;
|
||||
OffsetNumber nextoffset;
|
||||
|
||||
itemid = PageGetItemId(page, poffset);
|
||||
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
|
||||
* continue to point to the siblings.
|
||||
* Update siblings' side-links. Note the target page's side-links
|
||||
* will continue to point to the siblings.
|
||||
*/
|
||||
if (BufferIsValid(lbuf))
|
||||
{
|
||||
|
@ -1096,10 +1110,11 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
|||
_bt_wrtbuf(rel, lbuf);
|
||||
|
||||
/*
|
||||
* If parent became half dead, recurse to try to delete it. Otherwise,
|
||||
* if right sibling is empty and is now the last child of the parent,
|
||||
* recurse to try to delete it. (These cases cannot apply at the same
|
||||
* time, though the second case might itself recurse to the first.)
|
||||
* If parent became half dead, recurse to try to delete it.
|
||||
* Otherwise, if right sibling is empty and is now the last child of
|
||||
* the parent, recurse to try to delete it. (These cases cannot apply
|
||||
* at the same time, though the second case might itself recurse to
|
||||
* the first.)
|
||||
*/
|
||||
if (parent_half_dead)
|
||||
{
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* 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
|
||||
* on a leaf page. We issue just one _bt_delitems() call per page,
|
||||
* so as to minimize WAL traffic.
|
||||
* on a leaf page. We issue just one _bt_delitems() call per page, so
|
||||
* as to minimize WAL traffic.
|
||||
*
|
||||
* Note that we exclusive-lock every leaf page containing data items,
|
||||
* in sequence left to right. It sounds attractive to only exclusive-lock
|
||||
* those containing items we need to delete, but unfortunately that
|
||||
* is not safe: we could then pass a stopped indexscan, which could
|
||||
* in rare cases lead to deleting the item it needs to find when it
|
||||
* resumes. (See _bt_restscan --- this could only happen if an indexscan
|
||||
* stops on a deletable item and then a page split moves that item
|
||||
* into a page further to its right, which the indexscan will have no
|
||||
* pin on.) We can skip obtaining exclusive lock on empty pages
|
||||
* though, since no indexscan could be stopped on those.
|
||||
* Note that we exclusive-lock every leaf page containing data items, in
|
||||
* sequence left to right. It sounds attractive to only
|
||||
* exclusive-lock those containing items we need to delete, but
|
||||
* unfortunately that is not safe: we could then pass a stopped
|
||||
* indexscan, which could in rare cases lead to deleting the item it
|
||||
* needs to find when it resumes. (See _bt_restscan --- this could
|
||||
* only happen if an indexscan stops on a deletable item and then a
|
||||
* page split moves that item into a page further to its right, which
|
||||
* the indexscan will have no pin on.) We can skip obtaining
|
||||
* exclusive lock on empty pages though, since no indexscan could be
|
||||
* stopped on those.
|
||||
*/
|
||||
buf = _bt_get_endpoint(rel, 0, false);
|
||||
if (BufferIsValid(buf)) /* check for empty index */
|
||||
|
@ -604,7 +605,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
|||
OffsetNumber offnum,
|
||||
minoff,
|
||||
maxoff;
|
||||
BlockNumber nextpage;
|
||||
BlockNumber nextpage;
|
||||
|
||||
CHECK_FOR_INTERRUPTS();
|
||||
|
||||
|
@ -622,12 +623,14 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
|||
*/
|
||||
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
|
||||
LockBufferForCleanup(buf);
|
||||
|
||||
/*
|
||||
* Recompute minoff/maxoff, both of which could have changed
|
||||
* while we weren't holding the lock.
|
||||
* Recompute minoff/maxoff, both of which could have
|
||||
* changed while we weren't holding the lock.
|
||||
*/
|
||||
minoff = P_FIRSTDATAKEY(opaque);
|
||||
maxoff = PageGetMaxOffsetNumber(page);
|
||||
|
||||
/*
|
||||
* Scan over all items to see which ones need deleted
|
||||
* according to the callback function.
|
||||
|
@ -640,7 +643,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
|||
ItemPointer htup;
|
||||
|
||||
btitem = (BTItem) PageGetItem(page,
|
||||
PageGetItemId(page, offnum));
|
||||
PageGetItemId(page, offnum));
|
||||
htup = &(btitem->bti_itup.t_tid);
|
||||
if (callback(htup, callback_state))
|
||||
{
|
||||
|
@ -651,6 +654,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
|||
num_index_tuples += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If we need to delete anything, do it and write the buffer;
|
||||
* else just release the buffer.
|
||||
|
@ -662,9 +666,7 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
|||
_bt_wrtbuf(rel, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
_bt_relbuf(rel, buf);
|
||||
}
|
||||
/* And advance to next page, if any */
|
||||
if (nextpage == P_NONE)
|
||||
break;
|
||||
|
@ -712,7 +714,7 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
/* No point in remembering more than MaxFSMPages pages */
|
||||
maxFreePages = MaxFSMPages;
|
||||
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));
|
||||
nFreePages = 0;
|
||||
|
||||
|
@ -728,10 +730,10 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
* after we start the scan will not be examined; this should be fine,
|
||||
* 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;
|
||||
Page page;
|
||||
Buffer buf;
|
||||
Page page;
|
||||
BTPageOpaque opaque;
|
||||
|
||||
buf = _bt_getbuf(rel, blkno, BT_READ);
|
||||
|
@ -753,7 +755,7 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
P_FIRSTDATAKEY(opaque) > PageGetMaxOffsetNumber(page))
|
||||
{
|
||||
/* Empty, try to delete */
|
||||
int ndel;
|
||||
int ndel;
|
||||
|
||||
/* Run pagedel in a temp context to avoid memory leakage */
|
||||
MemoryContextReset(mycontext);
|
||||
|
@ -768,7 +770,7 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
/*
|
||||
* During VACUUM FULL it's okay to recycle deleted pages
|
||||
* 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
|
||||
* might have recursed to; this seems reasonable in the name
|
||||
* 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
|
||||
* end of the index. In a normal vacuum it'd be unsafe to do this
|
||||
* except by acquiring exclusive lock on the index and then rechecking
|
||||
* all the pages; doesn't seem worth it.
|
||||
* During VACUUM FULL, we truncate off any recyclable pages at the end
|
||||
* of the index. In a normal vacuum it'd be unsafe to do this except
|
||||
* by acquiring exclusive lock on the index and then rechecking all
|
||||
* the pages; doesn't seem worth it.
|
||||
*/
|
||||
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--;
|
||||
pages_deleted--;
|
||||
|
@ -810,9 +812,10 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
* Okay to truncate.
|
||||
*
|
||||
* First, flush any shared buffers for the blocks we intend to
|
||||
* delete. FlushRelationBuffers is a bit more than we need for
|
||||
* this, since it will also write out dirty buffers for blocks we
|
||||
* aren't deleting, but it's the closest thing in bufmgr's API.
|
||||
* delete. FlushRelationBuffers is a bit more than we need
|
||||
* for this, since it will also write out dirty buffers for
|
||||
* blocks we aren't deleting, but it's the closest thing in
|
||||
* bufmgr's API.
|
||||
*/
|
||||
i = FlushRelationBuffers(rel, new_pages);
|
||||
if (i < 0)
|
||||
|
@ -822,7 +825,8 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
* Do the physical truncation.
|
||||
*/
|
||||
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;
|
||||
num_pages = new_pages;
|
||||
}
|
||||
|
@ -856,7 +860,7 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
|||
* 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
|
||||
* 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
|
||||
* current position is updated to point at it.
|
||||
*/
|
||||
|
@ -877,8 +881,8 @@ _bt_restscan(IndexScanDesc scan)
|
|||
BlockNumber blkno;
|
||||
|
||||
/*
|
||||
* Reacquire read lock on the buffer. (We should still have
|
||||
* a reference-count pin on it, so need not get that.)
|
||||
* Reacquire read lock on the buffer. (We should still have a
|
||||
* reference-count pin on it, so need not get that.)
|
||||
*/
|
||||
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
|
||||
* move right. We are careful here to pin and read-lock the next
|
||||
* non-dead page before releasing the current one. This ensures that
|
||||
* a concurrent btbulkdelete scan cannot pass our position --- if it
|
||||
* did, it might be able to reach and delete our target item before
|
||||
* we can find it again.
|
||||
* move right. We are careful here to pin and read-lock the next
|
||||
* non-dead page before releasing the current one. This ensures
|
||||
* that a concurrent btbulkdelete scan cannot pass our position
|
||||
* --- if it did, it might be able to reach and delete our target
|
||||
* item before we can find it again.
|
||||
*/
|
||||
if (P_RIGHTMOST(opaque))
|
||||
elog(ERROR, "failed to re-find previous key in \"%s\"",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* 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
|
||||
* its pointer in the parent (or metapage). If it has, we may need
|
||||
* to move right to its new sibling. Do that.
|
||||
* its pointer in the parent (or metapage). If it has, we may
|
||||
* need to move right to its new sibling. Do that.
|
||||
*/
|
||||
*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);
|
||||
|
||||
/*
|
||||
* We need to save the location of the index entry we chose in
|
||||
* the parent page on a stack. In case we split the tree, we'll
|
||||
* use the stack to work back up to the parent page. We also save
|
||||
* the actual downlink (TID) to uniquely identify the index entry,
|
||||
* in case it moves right while we're working lower in the
|
||||
* tree. See the paper by Lehman and Yao for how this is detected
|
||||
* and handled. (We use the child link to disambiguate duplicate
|
||||
* keys in the index -- Lehman and Yao disallow duplicate keys.)
|
||||
* We need to save the location of the index entry we chose in the
|
||||
* parent page on a stack. In case we split the tree, we'll use
|
||||
* the stack to work back up to the parent page. We also save the
|
||||
* actual downlink (TID) to uniquely identify the index entry, in
|
||||
* case it moves right while we're working lower in the tree. See
|
||||
* the paper by Lehman and Yao for how this is detected and
|
||||
* handled. (We use the child link to disambiguate duplicate keys
|
||||
* in the index -- Lehman and Yao disallow duplicate keys.)
|
||||
*/
|
||||
new_stack = (BTStack) palloc(sizeof(BTStackData));
|
||||
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.)
|
||||
* 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
|
||||
* a dead page.
|
||||
* We also have to move right if we followed a link that brought us to a
|
||||
* dead page.
|
||||
*/
|
||||
while (!P_RIGHTMOST(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
|
||||
* 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
|
||||
* pages is greater than or equal to scan key.
|
||||
* less than the scan key and we know that everything on later pages
|
||||
* is greater than or equal to scan key.
|
||||
*
|
||||
* 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
|
||||
|
@ -851,7 +851,8 @@ _bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
|||
}
|
||||
}
|
||||
}
|
||||
else /* backwards scan */
|
||||
else
|
||||
/* backwards scan */
|
||||
{
|
||||
if (offnum > P_FIRSTDATAKEY(opaque))
|
||||
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
|
||||
* complex than the walk-right case because of the possibility
|
||||
* that the page to our left splits while we are in flight to it,
|
||||
* plus the possibility that the page we were on gets deleted
|
||||
* after we leave it. See nbtree/README for details.
|
||||
* that the page to our left splits while we are in flight to
|
||||
* it, plus the possibility that the page we were on gets
|
||||
* deleted after we leave it. See nbtree/README for details.
|
||||
*/
|
||||
for (;;)
|
||||
{
|
||||
|
@ -877,10 +878,11 @@ _bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
|||
}
|
||||
page = BufferGetPage(*bufP);
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(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
|
||||
* and do it all again.
|
||||
* Done if it's not half-dead and not empty. Else loop
|
||||
* back and do it all again.
|
||||
*/
|
||||
if (!P_IGNORE(opaque))
|
||||
{
|
||||
|
@ -946,17 +948,18 @@ _bt_walk_left(Relation rel, Buffer buf)
|
|||
buf = _bt_getbuf(rel, blkno, BT_READ);
|
||||
page = BufferGetPage(buf);
|
||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
|
||||
/*
|
||||
* If this isn't the page we want, walk right till we find
|
||||
* what we want --- but go no more than four hops (an
|
||||
* arbitrary limit). If we don't find the correct page by then,
|
||||
* the most likely bet is that the original page got deleted
|
||||
* and isn't in the sibling chain at all anymore, not that its
|
||||
* left sibling got split more than four times.
|
||||
* If this isn't the page we want, walk right till we find what we
|
||||
* want --- but go no more than four hops (an arbitrary limit).
|
||||
* If we don't find the correct page by then, the most likely bet
|
||||
* is that the original page got deleted and isn't in the sibling
|
||||
* chain at all anymore, not that its left sibling got split more
|
||||
* than four times.
|
||||
*
|
||||
* Note that it is correct to test P_ISDELETED not P_IGNORE
|
||||
* here, because half-dead pages are still in the sibling
|
||||
* chain. Caller must reject half-dead pages if wanted.
|
||||
* Note that it is correct to test P_ISDELETED not P_IGNORE here,
|
||||
* because half-dead pages are still in the sibling chain. Caller
|
||||
* must reject half-dead pages if wanted.
|
||||
*/
|
||||
tries = 0;
|
||||
for (;;)
|
||||
|
@ -983,8 +986,8 @@ _bt_walk_left(Relation rel, Buffer buf)
|
|||
if (P_ISDELETED(opaque))
|
||||
{
|
||||
/*
|
||||
* It was deleted. Move right to first nondeleted page
|
||||
* (there must be one); that is the page that has acquired the
|
||||
* It was deleted. Move right to first nondeleted page (there
|
||||
* must be one); that is the page that has acquired the
|
||||
* deleted one's keyspace, so stepping left from it will take
|
||||
* us where we want to be.
|
||||
*/
|
||||
|
@ -1001,18 +1004,18 @@ _bt_walk_left(Relation rel, Buffer buf)
|
|||
if (!P_ISDELETED(opaque))
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now return to top of loop, resetting obknum to
|
||||
* point to this nondeleted page, and try again.
|
||||
* Now return to top of loop, resetting obknum to point to
|
||||
* this nondeleted page, and try again.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
* It wasn't deleted; the explanation had better be
|
||||
* that the page to the left got split or deleted.
|
||||
* Without this check, we'd go into an infinite loop
|
||||
* if there's anything wrong.
|
||||
* It wasn't deleted; the explanation had better be that the
|
||||
* page to the left got split or deleted. Without this check,
|
||||
* we'd go into an infinite loop if there's anything wrong.
|
||||
*/
|
||||
if (opaque->btpo_prev == lblkno)
|
||||
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
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
@ -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;
|
||||
* otherwise better descend from true root. (There is no point in being
|
||||
* smarter about intermediate levels.)
|
||||
* otherwise better descend from true root. (There is no point in
|
||||
* being smarter about intermediate levels.)
|
||||
*/
|
||||
if (level == 0)
|
||||
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
|
||||
* (there must be one). Also, if we want the rightmost page,
|
||||
* step right if needed to get to it (this could happen if the
|
||||
* page split since we obtained a pointer to it).
|
||||
* (there must be one). Also, if we want the rightmost page, step
|
||||
* right if needed to get to it (this could happen if the page
|
||||
* split since we obtained a pointer to it).
|
||||
*/
|
||||
while (P_IGNORE(opaque) ||
|
||||
(rightmost && !P_RIGHTMOST(opaque)))
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* 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,
|
||||
uint32 level);
|
||||
uint32 level);
|
||||
static BTPageState *_bt_pagestate(Relation index, uint32 level);
|
||||
static void _bt_slideleft(Relation index, Buffer buf, Page page);
|
||||
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);
|
||||
nopaque->btpo_prev = BufferGetBlockNumber(obuf);
|
||||
nopaque->btpo_next = P_NONE; /* redundant */
|
||||
nopaque->btpo_next = P_NONE; /* redundant */
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* 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
|
||||
{
|
||||
RelFileNode node; /* the index */
|
||||
BlockNumber leftblk; /* left half of split */
|
||||
BlockNumber rightblk; /* right half of split */
|
||||
BlockNumber leftblk; /* left half of split */
|
||||
BlockNumber rightblk; /* right half of split */
|
||||
bool is_root; /* we split the root */
|
||||
} bt_incomplete_split;
|
||||
} bt_incomplete_split;
|
||||
|
||||
static List *incomplete_splits;
|
||||
|
||||
|
@ -107,7 +107,7 @@ _bt_restore_page(Page page, char *from, int len)
|
|||
}
|
||||
|
||||
static void
|
||||
_bt_restore_meta(Relation reln, XLogRecPtr lsn,
|
||||
_bt_restore_meta(Relation reln, XLogRecPtr lsn,
|
||||
BlockNumber root, uint32 level,
|
||||
BlockNumber fastroot, uint32 fastlevel)
|
||||
{
|
||||
|
@ -172,7 +172,7 @@ btree_xlog_insert(bool redo, bool isleaf, bool ismeta,
|
|||
if (!redo || !(record->xl_info & XLR_BKP_BLOCK_1))
|
||||
{
|
||||
buffer = XLogReadBuffer(false, reln,
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)));
|
||||
if (!BufferIsValid(buffer))
|
||||
elog(PANIC, "btree_insert_%sdo: block unfound", (redo) ? "re" : "un");
|
||||
page = (Page) BufferGetPage(buffer);
|
||||
|
@ -183,13 +183,11 @@ btree_xlog_insert(bool redo, bool isleaf, bool ismeta,
|
|||
if (redo)
|
||||
{
|
||||
if (XLByteLE(lsn, PageGetLSN(page)))
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (PageAddItem(page, (Item) datapos, datalen,
|
||||
ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
|
||||
ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
|
||||
LP_USED) == InvalidOffsetNumber)
|
||||
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");
|
||||
|
||||
if (!P_ISLEAF(pageop))
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
forget_matching_split(reln, xlrec->target.node,
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)),
|
||||
ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)),
|
||||
ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
|
||||
false);
|
||||
}
|
||||
}
|
||||
|
@ -238,9 +232,9 @@ btree_xlog_split(bool redo, bool onleft, bool isroot,
|
|||
{
|
||||
xl_btree_split *xlrec = (xl_btree_split *) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
BlockNumber targetblk;
|
||||
BlockNumber leftsib;
|
||||
BlockNumber rightsib;
|
||||
BlockNumber targetblk;
|
||||
BlockNumber leftsib;
|
||||
BlockNumber rightsib;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
BTPageOpaque pageop;
|
||||
|
@ -338,9 +332,7 @@ btree_xlog_split(bool redo, bool onleft, bool isroot,
|
|||
elog(PANIC, "btree_split_redo: uninitialized next right page");
|
||||
|
||||
if (XLByteLE(lsn, PageGetLSN(page)))
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
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)
|
||||
{
|
||||
forget_matching_split(reln, xlrec->target.node,
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)),
|
||||
ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
|
||||
ItemPointerGetBlockNumber(&(xlrec->target.tid)),
|
||||
ItemPointerGetOffsetNumber(&(xlrec->target.tid)),
|
||||
false);
|
||||
}
|
||||
|
||||
|
@ -422,10 +414,10 @@ btree_xlog_delete_page(bool redo, bool ismeta,
|
|||
{
|
||||
xl_btree_delete_page *xlrec = (xl_btree_delete_page *) XLogRecGetData(record);
|
||||
Relation reln;
|
||||
BlockNumber parent;
|
||||
BlockNumber target;
|
||||
BlockNumber leftsib;
|
||||
BlockNumber rightsib;
|
||||
BlockNumber parent;
|
||||
BlockNumber target;
|
||||
BlockNumber leftsib;
|
||||
BlockNumber rightsib;
|
||||
Buffer buffer;
|
||||
Page page;
|
||||
BTPageOpaque pageop;
|
||||
|
@ -451,9 +443,7 @@ btree_xlog_delete_page(bool redo, bool ismeta,
|
|||
if (PageIsNew((PageHeader) page))
|
||||
elog(PANIC, "btree_delete_page_redo: uninitialized parent page");
|
||||
if (XLByteLE(lsn, PageGetLSN(page)))
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
OffsetNumber poffset;
|
||||
|
@ -469,7 +459,7 @@ btree_xlog_delete_page(bool redo, bool ismeta,
|
|||
{
|
||||
ItemId itemid;
|
||||
BTItem btitem;
|
||||
OffsetNumber nextoffset;
|
||||
OffsetNumber nextoffset;
|
||||
|
||||
itemid = PageGetItemId(page, poffset);
|
||||
btitem = (BTItem) PageGetItem(page, itemid);
|
||||
|
@ -494,9 +484,7 @@ btree_xlog_delete_page(bool redo, bool ismeta,
|
|||
if (PageIsNew((PageHeader) page))
|
||||
elog(PANIC, "btree_delete_page_redo: uninitialized right sibling");
|
||||
if (XLByteLE(lsn, PageGetLSN(page)))
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
|
@ -520,9 +508,7 @@ btree_xlog_delete_page(bool redo, bool ismeta,
|
|||
if (PageIsNew((PageHeader) page))
|
||||
elog(PANIC, "btree_delete_page_redo: uninitialized left sibling");
|
||||
if (XLByteLE(lsn, PageGetLSN(page)))
|
||||
{
|
||||
UnlockAndReleaseBuffer(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
pageop = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||
|
@ -799,116 +785,116 @@ btree_desc(char *buf, uint8 xl_info, char *rec)
|
|||
switch (info)
|
||||
{
|
||||
case XLOG_BTREE_INSERT_LEAF:
|
||||
{
|
||||
xl_btree_insert *xlrec = (xl_btree_insert *) rec;
|
||||
{
|
||||
xl_btree_insert *xlrec = (xl_btree_insert *) rec;
|
||||
|
||||
strcat(buf, "insert: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
break;
|
||||
}
|
||||
strcat(buf, "insert: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
break;
|
||||
}
|
||||
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: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
break;
|
||||
}
|
||||
strcat(buf, "insert_upper: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
break;
|
||||
}
|
||||
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: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
break;
|
||||
}
|
||||
strcat(buf, "insert_meta: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
break;
|
||||
}
|
||||
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: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
sprintf(buf + strlen(buf), "; oth %u; rgh %u",
|
||||
xlrec->otherblk, xlrec->rightblk);
|
||||
break;
|
||||
}
|
||||
strcat(buf, "split_l: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
sprintf(buf + strlen(buf), "; oth %u; rgh %u",
|
||||
xlrec->otherblk, xlrec->rightblk);
|
||||
break;
|
||||
}
|
||||
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: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
sprintf(buf + strlen(buf), "; oth %u; rgh %u",
|
||||
xlrec->otherblk, xlrec->rightblk);
|
||||
break;
|
||||
}
|
||||
strcat(buf, "split_r: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
sprintf(buf + strlen(buf), "; oth %u; rgh %u",
|
||||
xlrec->otherblk, xlrec->rightblk);
|
||||
break;
|
||||
}
|
||||
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: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
sprintf(buf + strlen(buf), "; oth %u; rgh %u",
|
||||
xlrec->otherblk, xlrec->rightblk);
|
||||
break;
|
||||
}
|
||||
strcat(buf, "split_l_root: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
sprintf(buf + strlen(buf), "; oth %u; rgh %u",
|
||||
xlrec->otherblk, xlrec->rightblk);
|
||||
break;
|
||||
}
|
||||
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: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
sprintf(buf + strlen(buf), "; oth %u; rgh %u",
|
||||
xlrec->otherblk, xlrec->rightblk);
|
||||
break;
|
||||
}
|
||||
strcat(buf, "split_r_root: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
sprintf(buf + strlen(buf), "; oth %u; rgh %u",
|
||||
xlrec->otherblk, xlrec->rightblk);
|
||||
break;
|
||||
}
|
||||
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",
|
||||
xlrec->node.tblNode, xlrec->node.relNode, xlrec->block);
|
||||
break;
|
||||
}
|
||||
sprintf(buf + strlen(buf), "delete: node %u/%u; blk %u",
|
||||
xlrec->node.tblNode, xlrec->node.relNode, xlrec->block);
|
||||
break;
|
||||
}
|
||||
case XLOG_BTREE_DELETE_PAGE:
|
||||
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: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
sprintf(buf + strlen(buf), "; dead %u; left %u; right %u",
|
||||
xlrec->deadblk, xlrec->leftblk, xlrec->rightblk);
|
||||
break;
|
||||
}
|
||||
strcat(buf, "delete_page: ");
|
||||
out_target(buf, &(xlrec->target));
|
||||
sprintf(buf + strlen(buf), "; dead %u; left %u; right %u",
|
||||
xlrec->deadblk, xlrec->leftblk, xlrec->rightblk);
|
||||
break;
|
||||
}
|
||||
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",
|
||||
xlrec->node.tblNode, xlrec->node.relNode,
|
||||
xlrec->rootblk, xlrec->level);
|
||||
break;
|
||||
}
|
||||
sprintf(buf + strlen(buf), "newroot: node %u/%u; root %u lev %u",
|
||||
xlrec->node.tblNode, xlrec->node.relNode,
|
||||
xlrec->rootblk, xlrec->level);
|
||||
break;
|
||||
}
|
||||
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",
|
||||
xlrec->node.tblNode, xlrec->node.relNode,
|
||||
xlrec->meta.root, xlrec->meta.level,
|
||||
xlrec->meta.fastroot, xlrec->meta.fastlevel);
|
||||
break;
|
||||
}
|
||||
sprintf(buf + strlen(buf), "newmeta: node %u/%u; root %u lev %u fast %u lev %u",
|
||||
xlrec->node.tblNode, xlrec->node.relNode,
|
||||
xlrec->meta.root, xlrec->meta.level,
|
||||
xlrec->meta.fastroot, xlrec->meta.fastlevel);
|
||||
break;
|
||||
}
|
||||
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",
|
||||
xlrec->node.tblNode, xlrec->node.relNode,
|
||||
xlrec->blkno);
|
||||
break;
|
||||
}
|
||||
sprintf(buf + strlen(buf), "newpage: node %u/%u; page %u",
|
||||
xlrec->node.tblNode, xlrec->node.relNode,
|
||||
xlrec->blkno);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
strcat(buf, "UNKNOWN");
|
||||
break;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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));
|
||||
|
||||
/*
|
||||
* Scans on internal pages use different operators than they
|
||||
* do on leaf pages. For example, if the user wants all boxes
|
||||
* that exactly match (x1,y1,x2,y2), then on internal pages we
|
||||
* need to find all boxes that contain (x1,y1,x2,y2).
|
||||
* Scans on internal pages use different operators than they do on
|
||||
* leaf pages. For example, if the user wants all boxes that
|
||||
* exactly match (x1,y1,x2,y2), then on internal pages we need to
|
||||
* find all boxes that contain (x1,y1,x2,y2).
|
||||
*/
|
||||
for (i = 0; i < s->numberOfKeys; i++)
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* 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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -73,7 +73,7 @@
|
|||
|
||||
static SlruCtlData ClogCtlData;
|
||||
static SlruCtl ClogCtl = &ClogCtlData;
|
||||
|
||||
|
||||
|
||||
static int ZeroCLOGPage(int pageno, bool writeXlog);
|
||||
static bool CLOGPagePrecedes(int page1, int page2);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* 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"
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
|||
#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},
|
||||
{"Transaction", xact_redo, xact_undo, xact_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},
|
||||
{"Heap", heap_redo, heap_undo, heap_desc, NULL, NULL},
|
||||
{"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},
|
||||
{"Rtree", rtree_redo, rtree_undo, rtree_desc, NULL, NULL},
|
||||
{"Gist", gist_redo, gist_undo, gist_desc, NULL, NULL},
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
|
||||
* 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_DIRTY, /* page is valid but needs write */
|
||||
SLRU_PAGE_WRITE_IN_PROGRESS /* page is being written out */
|
||||
} SlruPageStatus;
|
||||
} SlruPageStatus;
|
||||
|
||||
/*
|
||||
* Shared-memory state
|
||||
|
@ -117,7 +117,7 @@ typedef struct SlruSharedData
|
|||
* swapping out the latest page.
|
||||
*/
|
||||
int latest_page_number;
|
||||
} SlruSharedData;
|
||||
} SlruSharedData;
|
||||
typedef SlruSharedData *SlruShared;
|
||||
|
||||
|
||||
|
@ -145,7 +145,7 @@ typedef enum
|
|||
SLRU_SEEK_FAILED,
|
||||
SLRU_READ_FAILED,
|
||||
SLRU_WRITE_FAILED
|
||||
} SlruErrorCause;
|
||||
} SlruErrorCause;
|
||||
static SlruErrorCause slru_errcause;
|
||||
static int slru_errno;
|
||||
|
||||
|
@ -166,9 +166,9 @@ SimpleLruShmemSize(void)
|
|||
{
|
||||
return MAXALIGN(sizeof(SlruSharedData)) + BLCKSZ * NUM_CLOG_BUFFERS
|
||||
#ifdef EXEC_BACKEND
|
||||
+ MAXALIGN(sizeof(SlruLockData))
|
||||
+ MAXALIGN(sizeof(SlruLockData))
|
||||
#endif
|
||||
;
|
||||
;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -183,12 +183,14 @@ SimpleLruInit(SlruCtl ctl, const char *name, const char *subdir)
|
|||
shared = (SlruShared) ptr;
|
||||
|
||||
#ifdef EXEC_BACKEND
|
||||
|
||||
/*
|
||||
* Locks are in shared memory
|
||||
*/
|
||||
locks = (SlruLock)(ptr + MAXALIGN(sizeof(SlruSharedData)) +
|
||||
BLCKSZ * NUM_CLOG_BUFFERS);
|
||||
locks = (SlruLock) (ptr + MAXALIGN(sizeof(SlruSharedData)) +
|
||||
BLCKSZ * NUM_CLOG_BUFFERS);
|
||||
#else
|
||||
|
||||
/*
|
||||
* Locks are in private memory
|
||||
*/
|
||||
|
@ -199,7 +201,7 @@ SimpleLruInit(SlruCtl ctl, const char *name, const char *subdir)
|
|||
|
||||
|
||||
if (!IsUnderPostmaster)
|
||||
/* Initialize locks and shared memory area */
|
||||
/* Initialize locks and shared memory area */
|
||||
{
|
||||
char *bufptr;
|
||||
int slotno;
|
||||
|
@ -210,8 +212,8 @@ SimpleLruInit(SlruCtl ctl, const char *name, const char *subdir)
|
|||
|
||||
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++)
|
||||
{
|
||||
locks->BufferLocks[slotno] = LWLockAssign();
|
||||
|
@ -247,7 +249,7 @@ int
|
|||
SimpleLruZeroPage(SlruCtl ctl, int pageno)
|
||||
{
|
||||
int slotno;
|
||||
SlruShared shared = (SlruShared) ctl->shared;
|
||||
SlruShared shared = (SlruShared) ctl->shared;
|
||||
|
||||
/* Find a suitable buffer slot for the page */
|
||||
slotno = SlruSelectLRUPage(ctl, pageno);
|
||||
|
@ -285,7 +287,7 @@ SimpleLruZeroPage(SlruCtl ctl, int pageno)
|
|||
char *
|
||||
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 */
|
||||
for (;;)
|
||||
|
@ -383,7 +385,7 @@ SimpleLruWritePage(SlruCtl ctl, int slotno)
|
|||
{
|
||||
int pageno;
|
||||
bool ok;
|
||||
SlruShared shared = (SlruShared) ctl->shared;
|
||||
SlruShared shared = (SlruShared) ctl->shared;
|
||||
|
||||
/* Do nothing if page does not need writing */
|
||||
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
|
||||
* 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
|
||||
* SimpleLruZeroPage is called for the first page of a segment. However,
|
||||
* if after a crash and restart the REDO logic elects to replay the
|
||||
* log from a checkpoint before the latest one, then it's possible
|
||||
* that we will get commands to set transaction status of transactions
|
||||
* that have already been truncated from the commit log. Easiest way
|
||||
* to deal with that is to accept references to nonexistent files here
|
||||
* and in SlruPhysicalReadPage.)
|
||||
* SimpleLruZeroPage is called for the first page of a segment.
|
||||
* However, if after a crash and restart the REDO logic elects to
|
||||
* replay the log from a checkpoint before the latest one, then it's
|
||||
* possible that we will get commands to set transaction status of
|
||||
* transactions that have already been truncated from the commit log.
|
||||
* Easiest way to deal with that is to accept references to
|
||||
* nonexistent files here and in SlruPhysicalReadPage.)
|
||||
*/
|
||||
fd = BasicOpenFile(path, O_RDWR | PG_BINARY, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0)
|
||||
|
@ -608,37 +610,37 @@ SlruReportIOError(SlruCtl ctl, int pageno, TransactionId xid)
|
|||
case SLRU_OPEN_FAILED:
|
||||
ereport(ERROR,
|
||||
(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",
|
||||
path)));
|
||||
break;
|
||||
case SLRU_CREATE_FAILED:
|
||||
ereport(ERROR,
|
||||
(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",
|
||||
path)));
|
||||
break;
|
||||
case SLRU_SEEK_FAILED:
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not access status of transaction %u", xid),
|
||||
errdetail("lseek of file \"%s\", offset %u failed: %m",
|
||||
path, offset)));
|
||||
errmsg("could not access status of transaction %u", xid),
|
||||
errdetail("lseek of file \"%s\", offset %u failed: %m",
|
||||
path, offset)));
|
||||
break;
|
||||
case SLRU_READ_FAILED:
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not access status of transaction %u", xid),
|
||||
errdetail("read of file \"%s\", offset %u failed: %m",
|
||||
path, offset)));
|
||||
errmsg("could not access status of transaction %u", xid),
|
||||
errdetail("read of file \"%s\", offset %u failed: %m",
|
||||
path, offset)));
|
||||
break;
|
||||
case SLRU_WRITE_FAILED:
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not access status of transaction %u", xid),
|
||||
errdetail("write of file \"%s\", offset %u failed: %m",
|
||||
path, offset)));
|
||||
errmsg("could not access status of transaction %u", xid),
|
||||
errdetail("write of file \"%s\", offset %u failed: %m",
|
||||
path, offset)));
|
||||
break;
|
||||
default:
|
||||
/* can't get here, we trust */
|
||||
|
@ -665,6 +667,7 @@ static int
|
|||
SlruSelectLRUPage(SlruCtl ctl, int pageno)
|
||||
{
|
||||
SlruShared shared = (SlruShared) ctl->shared;
|
||||
|
||||
/* Outer loop handles restart after I/O */
|
||||
for (;;)
|
||||
{
|
||||
|
@ -689,7 +692,7 @@ SlruSelectLRUPage(SlruCtl ctl, int pageno)
|
|||
if (shared->page_status[slotno] == SLRU_PAGE_EMPTY)
|
||||
return slotno;
|
||||
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;
|
||||
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
|
||||
* 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
|
||||
* the read to complete.
|
||||
* read-busy page. In that case we use SimpleLruReadPage to wait
|
||||
* for the read to complete.
|
||||
*/
|
||||
if (shared->page_status[bestslot] == SLRU_PAGE_READ_IN_PROGRESS)
|
||||
(void) SimpleLruReadPage(ctl, shared->page_number[bestslot],
|
||||
InvalidTransactionId, false);
|
||||
InvalidTransactionId, false);
|
||||
else
|
||||
SimpleLruWritePage(ctl, bestslot);
|
||||
|
||||
|
@ -747,10 +750,11 @@ SimpleLruFlush(SlruCtl ctl, bool checkpoint)
|
|||
for (slotno = 0; slotno < NUM_CLOG_BUFFERS; slotno++)
|
||||
{
|
||||
SimpleLruWritePage(ctl, slotno);
|
||||
|
||||
/*
|
||||
* When called during a checkpoint,
|
||||
* we cannot assert that the slot is clean now, since another
|
||||
* process might have re-dirtied it already. That's okay.
|
||||
* When called during a checkpoint, we cannot assert that the slot
|
||||
* is clean now, since another process might have re-dirtied it
|
||||
* already. That's okay.
|
||||
*/
|
||||
Assert(checkpoint ||
|
||||
shared->page_status[slotno] == SLRU_PAGE_EMPTY ||
|
||||
|
@ -792,10 +796,10 @@ SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
|
|||
CreateCheckPoint(false, true);
|
||||
|
||||
/*
|
||||
* Scan shared memory and remove any pages preceding the cutoff
|
||||
* page, to ensure we won't rewrite them later. (Any dirty pages
|
||||
* should have been flushed already during the checkpoint, we're just
|
||||
* being extra careful here.)
|
||||
* Scan shared memory and remove any pages preceding the cutoff page,
|
||||
* to ensure we won't rewrite them later. (Any dirty pages should
|
||||
* have been flushed already during the checkpoint, we're just being
|
||||
* extra careful here.)
|
||||
*/
|
||||
LWLockAcquire(ctl->locks->ControlLock, LW_EXCLUSIVE);
|
||||
|
||||
|
@ -870,7 +874,7 @@ SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
|
|||
if (cldir == NULL)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not open directory \"%s\": %m", ctl->Dir)));
|
||||
errmsg("could not open directory \"%s\": %m", ctl->Dir)));
|
||||
|
||||
errno = 0;
|
||||
while ((clde = readdir(cldir)) != NULL)
|
||||
|
@ -898,7 +902,7 @@ SlruScanDirectory(SlruCtl ctl, int cutoffPage, bool doDeletions)
|
|||
if (errno)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read directory \"%s\": %m", ctl->Dir)));
|
||||
errmsg("could not read directory \"%s\": %m", ctl->Dir)));
|
||||
closedir(cldir);
|
||||
|
||||
return found;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
* Transaction aborts can now occur two ways:
|
||||
|
@ -92,7 +92,7 @@
|
|||
* AbortTransactionBlock
|
||||
*
|
||||
* 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
|
||||
* the StartTransactionCommand() and CommitTransactionCommand().
|
||||
*
|
||||
|
@ -197,8 +197,8 @@ static TransactionStateData CurrentTransactionStateData = {
|
|||
0, /* scan command id */
|
||||
0x0, /* start time */
|
||||
TRANS_DEFAULT, /* transaction state */
|
||||
TBLOCK_DEFAULT /* transaction block state from
|
||||
the client perspective */
|
||||
TBLOCK_DEFAULT /* transaction block state from the client
|
||||
* perspective */
|
||||
};
|
||||
|
||||
TransactionState CurrentTransactionState = &CurrentTransactionStateData;
|
||||
|
@ -359,7 +359,7 @@ GetCurrentTransactionStartTimeUsec(int *msec)
|
|||
* TransactionIdIsCurrentTransactionId
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
* appears either in permanent rels or in local temporary rels.
|
||||
* We test this by seeing if we made transaction-controlled
|
||||
* entries *OR* local-rel tuple updates. Note that if we made
|
||||
* only the latter, we have not emitted an XLOG record for our
|
||||
* commit, and so in the event of a crash the clog update might be
|
||||
* lost. This is okay because no one else will ever care whether
|
||||
* we committed.
|
||||
* appears either in permanent rels or in local temporary rels. We
|
||||
* test this by seeing if we made transaction-controlled entries
|
||||
* *OR* local-rel tuple updates. Note that if we made only the
|
||||
* latter, we have not emitted an XLOG record for our commit, and
|
||||
* so in the event of a crash the clog update might be lost. This
|
||||
* is okay because no one else will ever care whether we
|
||||
* committed.
|
||||
*/
|
||||
if (MyLastRecPtr.xrecoff != 0 || MyXactMadeTempRelUpdate)
|
||||
TransactionIdCommit(xid);
|
||||
|
@ -755,9 +755,9 @@ AtAbort_Memory(void)
|
|||
{
|
||||
/*
|
||||
* Make sure we are in a valid context (not a child of
|
||||
* TopTransactionContext...). Note that it is possible for this
|
||||
* code to be called when we aren't in a transaction at all; go
|
||||
* directly to TopMemoryContext in that case.
|
||||
* TopTransactionContext...). Note that it is possible for this code
|
||||
* to be called when we aren't in a transaction at all; go directly to
|
||||
* TopMemoryContext in that case.
|
||||
*/
|
||||
if (TopTransactionContext != NULL)
|
||||
{
|
||||
|
@ -891,8 +891,8 @@ CommitTransaction(void)
|
|||
DeferredTriggerEndXact();
|
||||
|
||||
/*
|
||||
* Similarly, let ON COMMIT management do its thing before we start
|
||||
* to commit.
|
||||
* Similarly, let ON COMMIT management do its thing before we start to
|
||||
* commit.
|
||||
*/
|
||||
PreCommit_on_commit_actions();
|
||||
|
||||
|
@ -953,10 +953,10 @@ CommitTransaction(void)
|
|||
* noncritical resource releasing.
|
||||
*
|
||||
* The ordering of operations is not entirely random. The idea is:
|
||||
* release resources visible to other backends (eg, files, buffer pins);
|
||||
* then release locks; then release backend-local resources. We want
|
||||
* to release locks at the point where any backend waiting for us will
|
||||
* see our transaction as being fully cleaned up.
|
||||
* release resources visible to other backends (eg, files, buffer
|
||||
* pins); then release locks; then release backend-local resources.
|
||||
* We want to release locks at the point where any backend waiting for
|
||||
* us will see our transaction as being fully cleaned up.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
|
@ -1194,8 +1194,8 @@ StartTransactionCommand(void)
|
|||
}
|
||||
|
||||
/*
|
||||
* We must switch to TopTransactionContext before returning. This
|
||||
* is already done if we called StartTransaction, otherwise not.
|
||||
* We must switch to TopTransactionContext before returning. This is
|
||||
* already done if we called StartTransaction, otherwise not.
|
||||
*/
|
||||
Assert(TopTransactionContext != NULL);
|
||||
MemoryContextSwitchTo(TopTransactionContext);
|
||||
|
@ -1370,9 +1370,10 @@ PreventTransactionChain(void *stmtNode, const char *stmtType)
|
|||
if (IsTransactionBlock())
|
||||
ereport(ERROR,
|
||||
(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",
|
||||
stmtType)));
|
||||
|
||||
/*
|
||||
* Are we inside a function call? If the statement's parameter block
|
||||
* was allocated in QueryContext, assume it is an interactive command.
|
||||
|
@ -1381,8 +1382,8 @@ PreventTransactionChain(void *stmtNode, const char *stmtType)
|
|||
if (!MemoryContextContains(QueryContext, stmtNode))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_ACTIVE_SQL_TRANSACTION),
|
||||
/* translator: %s represents an SQL statement name */
|
||||
errmsg("%s cannot be executed from a function", stmtType)));
|
||||
/* translator: %s represents an SQL statement name */
|
||||
errmsg("%s cannot be executed from a function", stmtType)));
|
||||
/* If we got past IsTransactionBlock test, should be in default state */
|
||||
if (CurrentTransactionState->blockState != TBLOCK_DEFAULT)
|
||||
elog(ERROR, "cannot prevent transaction chain");
|
||||
|
@ -1414,6 +1415,7 @@ RequireTransactionChain(void *stmtNode, const char *stmtType)
|
|||
*/
|
||||
if (IsTransactionBlock())
|
||||
return;
|
||||
|
||||
/*
|
||||
* Are we inside a function call? If the statement's parameter block
|
||||
* was allocated in QueryContext, assume it is an interactive command.
|
||||
|
@ -1423,7 +1425,7 @@ RequireTransactionChain(void *stmtNode, const char *stmtType)
|
|||
return;
|
||||
ereport(ERROR,
|
||||
(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",
|
||||
stmtType)));
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
|
||||
* 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)
|
||||
ereport(PANIC,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("close of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg)));
|
||||
errmsg("close of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg)));
|
||||
openLogFile = -1;
|
||||
}
|
||||
XLByteToPrevSeg(LogwrtResult.Write, openLogId, openLogSeg);
|
||||
|
@ -1162,8 +1162,8 @@ XLogWrite(XLogwrtRqst WriteRqst)
|
|||
if (close(openLogFile) != 0)
|
||||
ereport(PANIC,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("close of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg)));
|
||||
errmsg("close of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg)));
|
||||
openLogFile = -1;
|
||||
}
|
||||
if (openLogFile < 0)
|
||||
|
@ -1266,7 +1266,7 @@ XLogFlush(XLogRecPtr record)
|
|||
XLogCtlInsert *Insert = &XLogCtl->Insert;
|
||||
uint32 freespace = INSERT_FREESPACE(Insert);
|
||||
|
||||
if (freespace < SizeOfXLogRecord) /* buffer is full */
|
||||
if (freespace < SizeOfXLogRecord) /* buffer is full */
|
||||
WriteRqstPtr = XLogCtl->xlblocks[Insert->curridx];
|
||||
else
|
||||
{
|
||||
|
@ -1449,8 +1449,8 @@ XLogFileInit(uint32 log, uint32 seg,
|
|||
if (fd < 0)
|
||||
ereport(PANIC,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("open of \"%s\" (log file %u, segment %u) failed: %m",
|
||||
path, log, seg)));
|
||||
errmsg("open of \"%s\" (log file %u, segment %u) failed: %m",
|
||||
path, log, seg)));
|
||||
|
||||
return (fd);
|
||||
}
|
||||
|
@ -1563,14 +1563,14 @@ XLogFileOpen(uint32 log, uint32 seg, bool econt)
|
|||
{
|
||||
ereport(LOG,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("open of \"%s\" (log file %u, segment %u) failed: %m",
|
||||
path, log, seg)));
|
||||
errmsg("open of \"%s\" (log file %u, segment %u) failed: %m",
|
||||
path, log, seg)));
|
||||
return (fd);
|
||||
}
|
||||
ereport(PANIC,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("open of \"%s\" (log file %u, segment %u) failed: %m",
|
||||
path, log, seg)));
|
||||
errmsg("open of \"%s\" (log file %u, segment %u) failed: %m",
|
||||
path, log, seg)));
|
||||
}
|
||||
|
||||
return (fd);
|
||||
|
@ -1621,8 +1621,8 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr)
|
|||
if (xldir == NULL)
|
||||
ereport(PANIC,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not open transaction log directory \"%s\": %m",
|
||||
XLogDir)));
|
||||
errmsg("could not open transaction log directory \"%s\": %m",
|
||||
XLogDir)));
|
||||
|
||||
sprintf(lastoff, "%08X%08X", log, seg);
|
||||
|
||||
|
@ -1654,15 +1654,15 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr)
|
|||
true))
|
||||
{
|
||||
ereport(LOG,
|
||||
(errmsg("recycled transaction log file \"%s\"",
|
||||
xlde->d_name)));
|
||||
(errmsg("recycled transaction log file \"%s\"",
|
||||
xlde->d_name)));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No need for any more future segments... */
|
||||
ereport(LOG,
|
||||
(errmsg("removing transaction log file \"%s\"",
|
||||
xlde->d_name)));
|
||||
(errmsg("removing transaction log file \"%s\"",
|
||||
xlde->d_name)));
|
||||
unlink(path);
|
||||
}
|
||||
}
|
||||
|
@ -1672,8 +1672,8 @@ MoveOfflineLogs(uint32 log, uint32 seg, XLogRecPtr endptr)
|
|||
if (errno)
|
||||
ereport(PANIC,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not read transaction log directory \"%s\": %m",
|
||||
XLogDir)));
|
||||
errmsg("could not read transaction log directory \"%s\": %m",
|
||||
XLogDir)));
|
||||
closedir(xldir);
|
||||
}
|
||||
|
||||
|
@ -1746,8 +1746,8 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
|
|||
if (!EQ_CRC64(record->xl_crc, crc))
|
||||
{
|
||||
ereport(emode,
|
||||
(errmsg("bad resource manager data checksum in record at %X/%X",
|
||||
recptr.xlogid, recptr.xrecoff)));
|
||||
(errmsg("bad resource manager data checksum in record at %X/%X",
|
||||
recptr.xlogid, recptr.xrecoff)));
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
@ -1769,8 +1769,8 @@ RecordIsValid(XLogRecord *record, XLogRecPtr recptr, int emode)
|
|||
if (!EQ_CRC64(cbuf, crc))
|
||||
{
|
||||
ereport(emode,
|
||||
(errmsg("bad checksum of backup block %d in record at %X/%X",
|
||||
i + 1, recptr.xlogid, recptr.xrecoff)));
|
||||
(errmsg("bad checksum of backup block %d in record at %X/%X",
|
||||
i + 1, recptr.xlogid, recptr.xrecoff)));
|
||||
return (false);
|
||||
}
|
||||
blk += sizeof(BkpBlock) + BLCKSZ;
|
||||
|
@ -1931,7 +1931,7 @@ got_record:;
|
|||
{
|
||||
ereport(emode,
|
||||
(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;
|
||||
}
|
||||
nextRecord = NULL;
|
||||
|
@ -2063,7 +2063,7 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode, bool checkSUI)
|
|||
{
|
||||
ereport(emode,
|
||||
(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)));
|
||||
return false;
|
||||
}
|
||||
|
@ -2084,7 +2084,7 @@ ValidXLOGHeader(XLogPageHeader hdr, int emode, bool checkSUI)
|
|||
hdr->xlp_sui > lastReadSUI + 512)
|
||||
{
|
||||
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",
|
||||
hdr->xlp_sui, lastReadSUI,
|
||||
readId, readSeg, readOff)));
|
||||
|
@ -2235,8 +2235,8 @@ ReadControlFile(void)
|
|||
ereport(FATAL,
|
||||
(errmsg("database files are incompatible with server"),
|
||||
errdetail("The database cluster was initialized with PG_CONTROL_VERSION %d,"
|
||||
" but the server was compiled with PG_CONTROL_VERSION %d.",
|
||||
ControlFile->pg_control_version, PG_CONTROL_VERSION),
|
||||
" but the server was compiled with PG_CONTROL_VERSION %d.",
|
||||
ControlFile->pg_control_version, PG_CONTROL_VERSION),
|
||||
errhint("It looks like you need to initdb.")));
|
||||
/* Now check the CRC. */
|
||||
INIT_CRC64(crc);
|
||||
|
@ -2265,75 +2265,75 @@ ReadControlFile(void)
|
|||
ereport(FATAL,
|
||||
(errmsg("database files are incompatible with server"),
|
||||
errdetail("The database cluster was initialized with CATALOG_VERSION_NO %d,"
|
||||
" but the server was compiled with CATALOG_VERSION_NO %d.",
|
||||
ControlFile->catalog_version_no, CATALOG_VERSION_NO),
|
||||
" but the server was compiled with CATALOG_VERSION_NO %d.",
|
||||
ControlFile->catalog_version_no, CATALOG_VERSION_NO),
|
||||
errhint("It looks like you need to initdb.")));
|
||||
if (ControlFile->blcksz != BLCKSZ)
|
||||
ereport(FATAL,
|
||||
(errmsg("database files are incompatible with server"),
|
||||
errdetail("The database cluster was initialized with BLCKSZ %d,"
|
||||
" but the server was compiled with BLCKSZ %d.",
|
||||
ControlFile->blcksz, BLCKSZ),
|
||||
errhint("It looks like you need to recompile or initdb.")));
|
||||
errdetail("The database cluster was initialized with BLCKSZ %d,"
|
||||
" but the server was compiled with BLCKSZ %d.",
|
||||
ControlFile->blcksz, BLCKSZ),
|
||||
errhint("It looks like you need to recompile or initdb.")));
|
||||
if (ControlFile->relseg_size != RELSEG_SIZE)
|
||||
ereport(FATAL,
|
||||
(errmsg("database files are incompatible with server"),
|
||||
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),
|
||||
errhint("It looks like you need to recompile or initdb.")));
|
||||
errhint("It looks like you need to recompile or initdb.")));
|
||||
if (ControlFile->nameDataLen != NAMEDATALEN)
|
||||
ereport(FATAL,
|
||||
(errmsg("database files are incompatible with server"),
|
||||
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),
|
||||
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)
|
||||
ereport(FATAL,
|
||||
(errmsg("database files are incompatible with server"),
|
||||
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),
|
||||
errhint("It looks like you need to recompile or initdb.")));
|
||||
errhint("It looks like you need to recompile or initdb.")));
|
||||
|
||||
#ifdef HAVE_INT64_TIMESTAMP
|
||||
if (ControlFile->enableIntTimes != TRUE)
|
||||
ereport(FATAL,
|
||||
(errmsg("database files are incompatible with server"),
|
||||
errdetail("The database cluster was initialized without HAVE_INT64_TIMESTAMP"
|
||||
" but the server was compiled with HAVE_INT64_TIMESTAMP."),
|
||||
errhint("It looks like you need to recompile or initdb.")));
|
||||
" but the server was compiled with HAVE_INT64_TIMESTAMP."),
|
||||
errhint("It looks like you need to recompile or initdb.")));
|
||||
#else
|
||||
if (ControlFile->enableIntTimes != FALSE)
|
||||
ereport(FATAL,
|
||||
(errmsg("database files are incompatible with server"),
|
||||
errdetail("The database cluster was initialized with HAVE_INT64_TIMESTAMP"
|
||||
" but the server was compiled without HAVE_INT64_TIMESTAMP."),
|
||||
errhint("It looks like you need to recompile or initdb.")));
|
||||
" but the server was compiled without HAVE_INT64_TIMESTAMP."),
|
||||
errhint("It looks like you need to recompile or initdb.")));
|
||||
#endif
|
||||
|
||||
if (ControlFile->localeBuflen != LOCALE_NAME_BUFLEN)
|
||||
ereport(FATAL,
|
||||
(errmsg("database files are incompatible with server"),
|
||||
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),
|
||||
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)
|
||||
ereport(FATAL,
|
||||
(errmsg("database files are incompatible with operating system"),
|
||||
errdetail("The database cluster was initialized with LC_COLLATE \"%s\","
|
||||
" which is not recognized by setlocale().",
|
||||
ControlFile->lc_collate),
|
||||
errhint("It looks like you need to initdb or install locale support.")));
|
||||
(errmsg("database files are incompatible with operating system"),
|
||||
errdetail("The database cluster was initialized with LC_COLLATE \"%s\","
|
||||
" which is not recognized by setlocale().",
|
||||
ControlFile->lc_collate),
|
||||
errhint("It looks like you need to initdb or install locale support.")));
|
||||
if (setlocale(LC_CTYPE, ControlFile->lc_ctype) == NULL)
|
||||
ereport(FATAL,
|
||||
(errmsg("database files are incompatible with operating system"),
|
||||
errdetail("The database cluster was initialized with LC_CTYPE \"%s\","
|
||||
" which is not recognized by setlocale().",
|
||||
ControlFile->lc_ctype),
|
||||
errhint("It looks like you need to initdb or install locale support.")));
|
||||
(errmsg("database files are incompatible with operating system"),
|
||||
errdetail("The database cluster was initialized with LC_CTYPE \"%s\","
|
||||
" which is not recognized by setlocale().",
|
||||
ControlFile->lc_ctype),
|
||||
errhint("It looks like you need to initdb or install locale support.")));
|
||||
|
||||
/* Make the fixed locale settings visible as GUC variables, too */
|
||||
SetConfigOption("lc_collate", ControlFile->lc_collate,
|
||||
|
@ -2602,10 +2602,10 @@ StartupXLOG(void)
|
|||
str_time(ControlFile->time))));
|
||||
else if (ControlFile->state == DB_IN_RECOVERY)
|
||||
ereport(LOG,
|
||||
(errmsg("database system was interrupted while in recovery at %s",
|
||||
str_time(ControlFile->time)),
|
||||
errhint("This probably means that some data is corrupted and"
|
||||
" you will have to use the last backup for recovery.")));
|
||||
(errmsg("database system was interrupted while in recovery at %s",
|
||||
str_time(ControlFile->time)),
|
||||
errhint("This probably means that some data is corrupted and"
|
||||
" you will have to use the last backup for recovery.")));
|
||||
else if (ControlFile->state == DB_IN_PRODUCTION)
|
||||
ereport(LOG,
|
||||
(errmsg("database system was interrupted at %s",
|
||||
|
@ -2637,12 +2637,12 @@ StartupXLOG(void)
|
|||
checkPointLoc = ControlFile->prevCheckPoint;
|
||||
ereport(LOG,
|
||||
(errmsg("using previous checkpoint record at %X/%X",
|
||||
checkPointLoc.xlogid, checkPointLoc.xrecoff)));
|
||||
checkPointLoc.xlogid, checkPointLoc.xrecoff)));
|
||||
InRecovery = true; /* force recovery even if SHUTDOWNED */
|
||||
}
|
||||
else
|
||||
ereport(PANIC,
|
||||
(errmsg("could not locate a valid checkpoint record")));
|
||||
(errmsg("could not locate a valid checkpoint record")));
|
||||
}
|
||||
LastRec = RecPtr = checkPointLoc;
|
||||
memcpy(&checkPoint, XLogRecGetData(record), sizeof(CheckPoint));
|
||||
|
@ -2665,11 +2665,12 @@ StartupXLOG(void)
|
|||
ShmemVariableCache->oidCount = 0;
|
||||
|
||||
/*
|
||||
* If it was a shutdown checkpoint, then any following WAL entries were
|
||||
* created under the next StartUpID; if it was a regular checkpoint then
|
||||
* any following WAL entries were created under the same StartUpID.
|
||||
* We must replay WAL entries using the same StartUpID they were created
|
||||
* under, so temporarily adopt that SUI (see also xlog_redo()).
|
||||
* If it was a shutdown checkpoint, then any following WAL entries
|
||||
* were created under the next StartUpID; if it was a regular
|
||||
* checkpoint then any following WAL entries were created under the
|
||||
* same StartUpID. We must replay WAL entries using the same StartUpID
|
||||
* they were created under, so temporarily adopt that SUI (see also
|
||||
* xlog_redo()).
|
||||
*/
|
||||
if (wasShutdown)
|
||||
ThisStartUpID = checkPoint.ThisStartUpID + 1;
|
||||
|
@ -2690,7 +2691,7 @@ StartupXLOG(void)
|
|||
{
|
||||
if (wasShutdown)
|
||||
ereport(PANIC,
|
||||
(errmsg("invalid redo/undo record in shutdown checkpoint")));
|
||||
(errmsg("invalid redo/undo record in shutdown checkpoint")));
|
||||
InRecovery = true;
|
||||
}
|
||||
else if (ControlFile->state != DB_SHUTDOWNED)
|
||||
|
@ -2699,7 +2700,7 @@ StartupXLOG(void)
|
|||
/* REDO */
|
||||
if (InRecovery)
|
||||
{
|
||||
int rmid;
|
||||
int rmid;
|
||||
|
||||
ereport(LOG,
|
||||
(errmsg("database system was not properly shut down; "
|
||||
|
@ -2791,8 +2792,8 @@ StartupXLOG(void)
|
|||
|
||||
/*
|
||||
* Tricky point here: readBuf contains the *last* block that the
|
||||
* LastRec record spans, not the one it starts in. The last block
|
||||
* is indeed the one we want to use.
|
||||
* LastRec record spans, not the one it starts in. The last block is
|
||||
* indeed the one we want to use.
|
||||
*/
|
||||
Assert(readOff == (XLogCtl->xlblocks[0].xrecoff - BLCKSZ) % XLogSegSize);
|
||||
memcpy((char *) Insert->currpage, readBuf, BLCKSZ);
|
||||
|
@ -2818,11 +2819,12 @@ StartupXLOG(void)
|
|||
else
|
||||
{
|
||||
/*
|
||||
* Whenever Write.LogwrtResult points to exactly the end of a page,
|
||||
* Write.curridx must point to the *next* page (see XLogWrite()).
|
||||
* Whenever Write.LogwrtResult points to exactly the end of a
|
||||
* page, Write.curridx must point to the *next* page (see
|
||||
* XLogWrite()).
|
||||
*
|
||||
* Note: it might seem we should do AdvanceXLInsertBuffer() here,
|
||||
* but we can't since we haven't yet determined the correct StartUpID
|
||||
* Note: it might seem we should do AdvanceXLInsertBuffer() here, but
|
||||
* 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
|
||||
* insert a log record will advance the insert state.
|
||||
*/
|
||||
|
@ -2859,7 +2861,7 @@ StartupXLOG(void)
|
|||
|
||||
if (InRecovery)
|
||||
{
|
||||
int rmid;
|
||||
int rmid;
|
||||
|
||||
/*
|
||||
* Allow resource managers to do any required cleanup.
|
||||
|
@ -2885,14 +2887,15 @@ StartupXLOG(void)
|
|||
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
|
||||
* the records following it will use SUI one more than what is shown
|
||||
* in the checkpoint's ThisStartUpID.
|
||||
* the records following it will use SUI one more than what is
|
||||
* shown in the checkpoint's ThisStartUpID.
|
||||
*
|
||||
* In case we had to use the secondary checkpoint, make sure that
|
||||
* it will still be shown as the secondary checkpoint after this
|
||||
* In case we had to use the secondary checkpoint, make sure that it
|
||||
* will still be shown as the secondary checkpoint after this
|
||||
* CreateCheckPoint operation; we don't want the broken primary
|
||||
* checkpoint to become prevCheckPoint...
|
||||
*/
|
||||
|
@ -2907,10 +2910,10 @@ StartupXLOG(void)
|
|||
else
|
||||
{
|
||||
/*
|
||||
* If we are not doing recovery, then we saw a checkpoint with nothing
|
||||
* after it, and we can safely use StartUpID equal to one more than
|
||||
* the checkpoint's SUI. But just for paranoia's sake, check against
|
||||
* pg_control too.
|
||||
* If we are not doing recovery, then we saw a checkpoint with
|
||||
* nothing after it, and we can safely use StartUpID equal to one
|
||||
* more than the checkpoint's SUI. But just for paranoia's sake,
|
||||
* check against pg_control too.
|
||||
*/
|
||||
ThisStartUpID = checkPoint.ThisStartUpID;
|
||||
if (ThisStartUpID < ControlFile->checkPointCopy.ThisStartUpID)
|
||||
|
@ -2923,7 +2926,8 @@ StartupXLOG(void)
|
|||
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++;
|
||||
XLogCtl->ThisStartUpID = ThisStartUpID;
|
||||
|
@ -2973,9 +2977,9 @@ ReadCheckpointRecord(XLogRecPtr RecPtr,
|
|||
if (!XRecOffIsValid(RecPtr.xrecoff))
|
||||
{
|
||||
ereport(LOG,
|
||||
/* translator: %s is "primary" or "secondary" */
|
||||
/* translator: %s is "primary" or "secondary" */
|
||||
(errmsg("invalid %s checkpoint link in control file",
|
||||
(whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
|
||||
(whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -2984,34 +2988,34 @@ ReadCheckpointRecord(XLogRecPtr RecPtr,
|
|||
if (record == NULL)
|
||||
{
|
||||
ereport(LOG,
|
||||
/* translator: %s is "primary" or "secondary" */
|
||||
/* translator: %s is "primary" or "secondary" */
|
||||
(errmsg("invalid %s checkpoint record",
|
||||
(whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
|
||||
(whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
|
||||
return NULL;
|
||||
}
|
||||
if (record->xl_rmid != RM_XLOG_ID)
|
||||
{
|
||||
ereport(LOG,
|
||||
/* translator: %s is "primary" or "secondary" */
|
||||
(errmsg("invalid resource manager id in %s checkpoint record",
|
||||
(whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
|
||||
/* translator: %s is "primary" or "secondary" */
|
||||
(errmsg("invalid resource manager id in %s checkpoint record",
|
||||
(whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
|
||||
return NULL;
|
||||
}
|
||||
if (record->xl_info != XLOG_CHECKPOINT_SHUTDOWN &&
|
||||
record->xl_info != XLOG_CHECKPOINT_ONLINE)
|
||||
{
|
||||
ereport(LOG,
|
||||
/* translator: %s is "primary" or "secondary" */
|
||||
/* translator: %s is "primary" or "secondary" */
|
||||
(errmsg("invalid xl_info in %s checkpoint record",
|
||||
(whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
|
||||
(whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
|
||||
return NULL;
|
||||
}
|
||||
if (record->xl_len != sizeof(CheckPoint))
|
||||
{
|
||||
ereport(LOG,
|
||||
/* translator: %s is "primary" or "secondary" */
|
||||
/* translator: %s is "primary" or "secondary" */
|
||||
(errmsg("invalid length of %s checkpoint record",
|
||||
(whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
|
||||
(whichChkpt == 1) ? gettext("primary") : gettext("secondary"))));
|
||||
return NULL;
|
||||
}
|
||||
return record;
|
||||
|
@ -3112,10 +3116,11 @@ CreateCheckPoint(bool shutdown, bool force)
|
|||
if (MyXactMadeXLogEntry)
|
||||
ereport(ERROR,
|
||||
(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
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* If this isn't a shutdown or forced checkpoint, and we have not inserted
|
||||
* any XLOG records since the start of the last checkpoint, skip the
|
||||
* checkpoint. The idea here is to avoid inserting duplicate checkpoints
|
||||
* when the system is idle. That wastes log space, and more importantly it
|
||||
* exposes us to possible loss of both current and previous checkpoint
|
||||
* records if the machine crashes just as we're writing the update.
|
||||
* (Perhaps it'd make even more sense to checkpoint only when the previous
|
||||
* checkpoint record is in a different xlog page?)
|
||||
* If this isn't a shutdown or forced checkpoint, and we have not
|
||||
* inserted any XLOG records since the start of the last checkpoint,
|
||||
* skip the checkpoint. The idea here is to avoid inserting duplicate
|
||||
* checkpoints when the system is idle. That wastes log space, and
|
||||
* more importantly it exposes us to possible loss of both current and
|
||||
* previous checkpoint records if the machine crashes just as we're
|
||||
* writing the update. (Perhaps it'd make even more sense to
|
||||
* 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
|
||||
* 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;
|
||||
* this must be done while holding the insert lock AND the info_lck.
|
||||
*
|
||||
* Note: if we fail to complete the checkpoint, RedoRecPtr will be
|
||||
* left pointing past where it really needs to point. This is okay;
|
||||
* the only consequence is that XLogInsert might back up whole buffers
|
||||
* that it didn't really need to. We can't postpone advancing RedoRecPtr
|
||||
* because XLogInserts that happen while we are dumping buffers must
|
||||
* assume that their buffer changes are not included in the checkpoint.
|
||||
* Note: if we fail to complete the checkpoint, RedoRecPtr will be left
|
||||
* pointing past where it really needs to point. This is okay; the
|
||||
* only consequence is that XLogInsert might back up whole buffers
|
||||
* that it didn't really need to. We can't postpone advancing
|
||||
* RedoRecPtr because XLogInserts that happen while we are dumping
|
||||
* buffers must assume that their buffer changes are not included in
|
||||
* the checkpoint.
|
||||
*/
|
||||
{
|
||||
/* 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)
|
||||
ereport(PANIC,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("fsync of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg)));
|
||||
errmsg("fsync of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg)));
|
||||
if (open_sync_bit != new_sync_bit)
|
||||
{
|
||||
if (close(openLogFile) != 0)
|
||||
ereport(PANIC,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("close of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg)));
|
||||
errmsg("close of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg)));
|
||||
openLogFile = -1;
|
||||
}
|
||||
}
|
||||
|
@ -3570,16 +3577,16 @@ issue_xlog_fsync(void)
|
|||
if (pg_fsync(openLogFile) != 0)
|
||||
ereport(PANIC,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("fsync of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg)));
|
||||
errmsg("fsync of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg)));
|
||||
break;
|
||||
#ifdef HAVE_FDATASYNC
|
||||
case SYNC_METHOD_FDATASYNC:
|
||||
if (pg_fdatasync(openLogFile) != 0)
|
||||
ereport(PANIC,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("fdatasync of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg)));
|
||||
errmsg("fdatasync of log file %u, segment %u failed: %m",
|
||||
openLogId, openLogSeg)));
|
||||
break;
|
||||
#endif
|
||||
case SYNC_METHOD_OPEN:
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* 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 (!IsUnderPostmaster /* when exec || ExecBackend */)
|
||||
if (!IsUnderPostmaster /* when exec || ExecBackend */ )
|
||||
MemoryContextInit();
|
||||
|
||||
/*
|
||||
|
@ -247,7 +247,7 @@ BootstrapMain(int argc, char *argv[])
|
|||
|
||||
/* Set defaults, to be overriden by explicit options below */
|
||||
dbname = NULL;
|
||||
if (!IsUnderPostmaster /* when exec || ExecBackend*/)
|
||||
if (!IsUnderPostmaster /* when exec || ExecBackend */ )
|
||||
{
|
||||
InitializeGUCOptions();
|
||||
potential_DataDir = getenv("PGDATA"); /* Null if no PGDATA
|
||||
|
@ -285,22 +285,22 @@ BootstrapMain(int argc, char *argv[])
|
|||
xlogop = atoi(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
{
|
||||
/* indicates fork from postmaster */
|
||||
{
|
||||
/* indicates fork from postmaster */
|
||||
#ifdef EXEC_BACKEND
|
||||
char *p;
|
||||
char *p;
|
||||
|
||||
sscanf(optarg, "%d,%p,", &UsedShmemSegID, &UsedShmemSegAddr);
|
||||
p = strchr(optarg, ',');
|
||||
if (p)
|
||||
p = strchr(p+1, ',');
|
||||
if (p)
|
||||
dbname = strdup(p+1);
|
||||
sscanf(optarg, "%d,%p,", &UsedShmemSegID, &UsedShmemSegAddr);
|
||||
p = strchr(optarg, ',');
|
||||
if (p)
|
||||
p = strchr(p + 1, ',');
|
||||
if (p)
|
||||
dbname = strdup(p + 1);
|
||||
#else
|
||||
dbname = strdup(optarg);
|
||||
dbname = strdup(optarg);
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'B':
|
||||
SetConfigOption("shared_buffers", optarg, PGC_POSTMASTER, PGC_S_ARGV);
|
||||
break;
|
||||
|
@ -346,12 +346,10 @@ BootstrapMain(int argc, char *argv[])
|
|||
usage();
|
||||
|
||||
|
||||
if (IsUnderPostmaster && ExecBackend && MyProc /* ordinary backend */)
|
||||
{
|
||||
if (IsUnderPostmaster && ExecBackend && MyProc /* ordinary backend */ )
|
||||
AttachSharedMemoryAndSemaphores();
|
||||
}
|
||||
|
||||
if (!IsUnderPostmaster /* when exec || ExecBackend*/)
|
||||
|
||||
if (!IsUnderPostmaster /* when exec || ExecBackend */ )
|
||||
{
|
||||
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
|
||||
* semaphores (just to prove we can do it with the current GUC settings).
|
||||
* So, quit now.
|
||||
* semaphores (just to prove we can do it with the current GUC
|
||||
* settings). So, quit now.
|
||||
*/
|
||||
if (xlogop == BS_XLOG_NOP)
|
||||
proc_exit(0);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
* See acl.h.
|
||||
|
@ -97,37 +97,40 @@ merge_acl_with_grant(Acl *old_acl, bool is_grant,
|
|||
|
||||
if (grantee->username)
|
||||
{
|
||||
aclitem.ai_grantee = get_usesysid(grantee->username);
|
||||
aclitem. ai_grantee = get_usesysid(grantee->username);
|
||||
|
||||
idtype = ACL_IDTYPE_UID;
|
||||
}
|
||||
else if (grantee->groupname)
|
||||
{
|
||||
aclitem.ai_grantee = get_grosysid(grantee->groupname);
|
||||
aclitem. ai_grantee = get_grosysid(grantee->groupname);
|
||||
|
||||
idtype = ACL_IDTYPE_GID;
|
||||
}
|
||||
else
|
||||
{
|
||||
aclitem.ai_grantee = ACL_ID_WORLD;
|
||||
aclitem. ai_grantee = ACL_ID_WORLD;
|
||||
|
||||
idtype = ACL_IDTYPE_WORLD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Grant options can only be granted to individual users, not
|
||||
* groups or public. The reason is that if a user would
|
||||
* re-grant a privilege that he held through a group having a
|
||||
* grant option, and later the user is removed from the group,
|
||||
* the situation is impossible to clean up.
|
||||
* groups or public. The reason is that if a user would re-grant
|
||||
* a privilege that he held through a group having a grant option,
|
||||
* and later the user is removed from the group, the situation is
|
||||
* impossible to clean up.
|
||||
*/
|
||||
if (is_grant && idtype != ACL_IDTYPE_UID && grant_option)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
||||
errmsg("grant options can only be granted to individual users")));
|
||||
|
||||
aclitem.ai_grantor = GetUserId();
|
||||
aclitem. ai_grantor = GetUserId();
|
||||
|
||||
ACLITEM_SET_PRIVS_IDTYPE(aclitem,
|
||||
(is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
|
||||
(grant_option || !is_grant) ? privileges : ACL_NO_RIGHTS,
|
||||
(is_grant || !grant_option) ? privileges : ACL_NO_RIGHTS,
|
||||
(grant_option || !is_grant) ? privileges : ACL_NO_RIGHTS,
|
||||
idtype);
|
||||
|
||||
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,
|
||||
stmt->grantees, privileges,
|
||||
stmt->grant_option, stmt->behavior);
|
||||
stmt->grant_option, stmt->behavior);
|
||||
|
||||
/* finished building new ACL value, now insert it */
|
||||
MemSet(values, 0, sizeof(values));
|
||||
|
@ -346,7 +349,7 @@ ExecuteGrantStmt_Database(GrantStmt *stmt)
|
|||
|
||||
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
||||
stmt->grantees, privileges,
|
||||
stmt->grant_option, stmt->behavior);
|
||||
stmt->grant_option, stmt->behavior);
|
||||
|
||||
/* finished building new ACL value, now insert it */
|
||||
MemSet(values, 0, sizeof(values));
|
||||
|
@ -443,7 +446,7 @@ ExecuteGrantStmt_Function(GrantStmt *stmt)
|
|||
|
||||
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
||||
stmt->grantees, privileges,
|
||||
stmt->grant_option, stmt->behavior);
|
||||
stmt->grant_option, stmt->behavior);
|
||||
|
||||
/* finished building new ACL value, now insert it */
|
||||
MemSet(values, 0, sizeof(values));
|
||||
|
@ -543,7 +546,7 @@ ExecuteGrantStmt_Language(GrantStmt *stmt)
|
|||
|
||||
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
||||
stmt->grantees, privileges,
|
||||
stmt->grant_option, stmt->behavior);
|
||||
stmt->grant_option, stmt->behavior);
|
||||
|
||||
/* finished building new ACL value, now insert it */
|
||||
MemSet(values, 0, sizeof(values));
|
||||
|
@ -619,7 +622,7 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
|
|||
pg_namespace_tuple = (Form_pg_namespace) GETSTRUCT(tuple);
|
||||
|
||||
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)
|
||||
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE,
|
||||
nspname);
|
||||
|
@ -640,7 +643,7 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
|
|||
|
||||
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
|
||||
stmt->grantees, privileges,
|
||||
stmt->grant_option, stmt->behavior);
|
||||
stmt->grant_option, stmt->behavior);
|
||||
|
||||
/* finished building new ACL value, now insert it */
|
||||
MemSet(values, 0, sizeof(values));
|
||||
|
@ -805,7 +808,7 @@ in_group(AclId uid, AclId gid)
|
|||
static AclResult
|
||||
aclcheck(Acl *acl, AclId userid, AclMode mode)
|
||||
{
|
||||
AclItem *aidat;
|
||||
AclItem *aidat;
|
||||
int i,
|
||||
num;
|
||||
|
||||
|
@ -833,10 +836,10 @@ aclcheck(Acl *acl, AclId userid, AclMode mode)
|
|||
if (aidat[i].ai_privs & mode)
|
||||
return ACLCHECK_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* See if he has the permission via any group (do this in a
|
||||
* separate pass to avoid expensive(?) lookups in pg_group)
|
||||
* See if he has the permission via any group (do this in a separate
|
||||
* pass to avoid expensive(?) lookups in pg_group)
|
||||
*/
|
||||
for (i = 0; i < num; i++)
|
||||
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.
|
||||
*/
|
||||
|
||||
static const char * const no_priv_msg[MAX_ACL_KIND] =
|
||||
static const char *const no_priv_msg[MAX_ACL_KIND] =
|
||||
{
|
||||
/* ACL_KIND_CLASS */
|
||||
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")
|
||||
};
|
||||
|
||||
static const char * const not_owner_msg[MAX_ACL_KIND] =
|
||||
static const char *const not_owner_msg[MAX_ACL_KIND] =
|
||||
{
|
||||
/* ACL_KIND_CLASS */
|
||||
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))
|
||||
ereport(ERROR,
|
||||
(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
|
||||
|
@ -1124,7 +1127,7 @@ pg_proc_aclcheck(Oid proc_oid, AclId userid, AclMode mode)
|
|||
if (!HeapTupleIsValid(tuple))
|
||||
ereport(ERROR,
|
||||
(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,
|
||||
&isNull);
|
||||
|
@ -1179,7 +1182,7 @@ pg_language_aclcheck(Oid lang_oid, AclId userid, AclMode mode)
|
|||
if (!HeapTupleIsValid(tuple))
|
||||
ereport(ERROR,
|
||||
(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,
|
||||
&isNull);
|
||||
|
@ -1288,7 +1291,7 @@ pg_class_ownercheck(Oid class_oid, AclId userid)
|
|||
if (!HeapTupleIsValid(tuple))
|
||||
ereport(ERROR,
|
||||
(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;
|
||||
|
||||
|
@ -1344,7 +1347,7 @@ pg_oper_ownercheck(Oid oper_oid, AclId userid)
|
|||
if (!HeapTupleIsValid(tuple))
|
||||
ereport(ERROR,
|
||||
(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;
|
||||
|
||||
|
@ -1372,7 +1375,7 @@ pg_proc_ownercheck(Oid proc_oid, AclId userid)
|
|||
if (!HeapTupleIsValid(tuple))
|
||||
ereport(ERROR,
|
||||
(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;
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* 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,
|
||||
ObjectAddresses *oktodelete,
|
||||
Relation depRel);
|
||||
ObjectAddresses *oktodelete,
|
||||
Relation depRel);
|
||||
static bool recursiveDeletion(const ObjectAddress *object,
|
||||
DropBehavior behavior,
|
||||
int msglevel,
|
||||
|
@ -102,11 +102,11 @@ static bool recursiveDeletion(const ObjectAddress *object,
|
|||
ObjectAddresses *oktodelete,
|
||||
Relation depRel);
|
||||
static bool deleteDependentObjects(const ObjectAddress *object,
|
||||
const char *objDescription,
|
||||
DropBehavior behavior,
|
||||
int msglevel,
|
||||
ObjectAddresses *oktodelete,
|
||||
Relation depRel);
|
||||
const char *objDescription,
|
||||
DropBehavior behavior,
|
||||
int msglevel,
|
||||
ObjectAddresses *oktodelete,
|
||||
Relation depRel);
|
||||
static void doDeletion(const ObjectAddress *object);
|
||||
static bool find_expr_references_walker(Node *node,
|
||||
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,
|
||||
ObjectAddresses *addrs);
|
||||
static bool object_address_present(const ObjectAddress *object,
|
||||
ObjectAddresses *addrs);
|
||||
ObjectAddresses *addrs);
|
||||
static void term_object_addresses(ObjectAddresses *addrs);
|
||||
static void init_object_classes(void);
|
||||
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
|
||||
* dependencies from the target object. These should be deleted silently,
|
||||
* even if the actual deletion pass first reaches one of them via a
|
||||
* non-auto dependency.
|
||||
* dependencies from the target object. These should be deleted
|
||||
* silently, even if the actual deletion pass first reaches one of
|
||||
* them via a non-auto dependency.
|
||||
*/
|
||||
init_object_addresses(&oktodelete);
|
||||
|
||||
|
@ -170,8 +170,8 @@ performDeletion(const ObjectAddress *object,
|
|||
NULL, &oktodelete, depRel))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
|
||||
errmsg("cannot drop %s because other objects depend on it",
|
||||
objDescription),
|
||||
errmsg("cannot drop %s because other objects depend on it",
|
||||
objDescription),
|
||||
errhint("Use DROP ... CASCADE to drop the dependent objects too.")));
|
||||
|
||||
term_object_addresses(&oktodelete);
|
||||
|
@ -184,7 +184,7 @@ performDeletion(const ObjectAddress *object,
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* 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
|
||||
* dependencies from the target object. These should be deleted silently,
|
||||
* even if the actual deletion pass first reaches one of them via a
|
||||
* non-auto dependency.
|
||||
* dependencies from the target object. These should be deleted
|
||||
* silently, even if the actual deletion pass first reaches one of
|
||||
* them via a non-auto dependency.
|
||||
*/
|
||||
init_object_addresses(&oktodelete);
|
||||
|
||||
|
@ -266,9 +266,9 @@ findAutoDeletableObjects(const ObjectAddress *object,
|
|||
ObjectAddress otherObject;
|
||||
|
||||
/*
|
||||
* If this object is already in oktodelete, then we already visited it;
|
||||
* don't do so again (this prevents infinite recursion if there's a loop
|
||||
* in pg_depend). Otherwise, add it.
|
||||
* If this object is already in oktodelete, then we already visited
|
||||
* it; don't do so again (this prevents infinite recursion if there's
|
||||
* a loop in pg_depend). Otherwise, add it.
|
||||
*/
|
||||
if (object_address_present(object, oktodelete))
|
||||
return;
|
||||
|
@ -276,8 +276,8 @@ findAutoDeletableObjects(const ObjectAddress *object,
|
|||
|
||||
/*
|
||||
* 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
|
||||
* referencing object.
|
||||
* that depend on it. For each one that is AUTO or INTERNAL, visit
|
||||
* the referencing object.
|
||||
*
|
||||
* When dropping a whole object (subId = 0), find pg_depend records for
|
||||
* its sub-objects too.
|
||||
|
@ -319,6 +319,7 @@ findAutoDeletableObjects(const ObjectAddress *object,
|
|||
findAutoDeletableObjects(&otherObject, oktodelete, depRel);
|
||||
break;
|
||||
case DEPENDENCY_PIN:
|
||||
|
||||
/*
|
||||
* For a PIN dependency we just ereport immediately; there
|
||||
* won't be any others to examine, and we aren't ever
|
||||
|
@ -461,11 +462,11 @@ recursiveDeletion(const ObjectAddress *object,
|
|||
char *otherObjDesc = getObjectDescription(&otherObject);
|
||||
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
|
||||
errmsg("cannot drop %s because %s requires it",
|
||||
objDescription, otherObjDesc),
|
||||
errhint("You may drop %s instead.",
|
||||
otherObjDesc)));
|
||||
(errcode(ERRCODE_DEPENDENT_OBJECTS_STILL_EXIST),
|
||||
errmsg("cannot drop %s because %s requires it",
|
||||
objDescription, otherObjDesc),
|
||||
errhint("You may drop %s instead.",
|
||||
otherObjDesc)));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -559,10 +560,9 @@ recursiveDeletion(const ObjectAddress *object,
|
|||
/*
|
||||
* Step 2: scan pg_depend records that link to this object, showing
|
||||
* the things that depend on it. Recursively delete those things.
|
||||
* Note it's important to delete the dependent objects
|
||||
* before the referenced one, since the deletion routines might do
|
||||
* things like try to update the pg_class record when deleting a check
|
||||
* constraint.
|
||||
* Note it's important to delete the dependent objects before the
|
||||
* referenced one, since the deletion routines might do things like
|
||||
* try to update the pg_class record when deleting a check constraint.
|
||||
*/
|
||||
if (!deleteDependentObjects(object, objDescription,
|
||||
behavior, msglevel,
|
||||
|
@ -674,11 +674,12 @@ deleteDependentObjects(const ObjectAddress *object,
|
|||
switch (foundDep->deptype)
|
||||
{
|
||||
case DEPENDENCY_NORMAL:
|
||||
|
||||
/*
|
||||
* Perhaps there was another dependency path that would
|
||||
* have allowed silent deletion of the otherObject, had
|
||||
* we only taken that path first.
|
||||
* In that case, act like this link is AUTO, too.
|
||||
* have allowed silent deletion of the otherObject, had we
|
||||
* only taken that path first. In that case, act like this
|
||||
* link is AUTO, too.
|
||||
*/
|
||||
if (object_address_present(&otherObject, oktodelete))
|
||||
ereport(DEBUG2,
|
||||
|
@ -872,7 +873,7 @@ recordDependencyOnExpr(const ObjectAddress *depender,
|
|||
* recordDependencyOnSingleRelExpr - find expression dependencies
|
||||
*
|
||||
* 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
|
||||
* relation (or its component columns) will be marked with 'self_behavior',
|
||||
* whereas 'behavior' is used for everything else.
|
||||
|
@ -1001,7 +1002,7 @@ find_expr_references_walker(Node *node,
|
|||
else if (rte->rtekind == RTE_JOIN)
|
||||
{
|
||||
/* 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 */
|
||||
save_rtables = context->rtables;
|
||||
|
@ -1026,7 +1027,7 @@ find_expr_references_walker(Node *node,
|
|||
}
|
||||
if (IsA(node, OpExpr))
|
||||
{
|
||||
OpExpr *opexpr = (OpExpr *) node;
|
||||
OpExpr *opexpr = (OpExpr *) node;
|
||||
|
||||
add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
|
||||
&context->addrs);
|
||||
|
@ -1034,7 +1035,7 @@ find_expr_references_walker(Node *node,
|
|||
}
|
||||
if (IsA(node, DistinctExpr))
|
||||
{
|
||||
DistinctExpr *distinctexpr = (DistinctExpr *) node;
|
||||
DistinctExpr *distinctexpr = (DistinctExpr *) node;
|
||||
|
||||
add_object_address(OCLASS_OPERATOR, distinctexpr->opno, 0,
|
||||
&context->addrs);
|
||||
|
@ -1042,7 +1043,7 @@ find_expr_references_walker(Node *node,
|
|||
}
|
||||
if (IsA(node, ScalarArrayOpExpr))
|
||||
{
|
||||
ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
|
||||
ScalarArrayOpExpr *opexpr = (ScalarArrayOpExpr *) node;
|
||||
|
||||
add_object_address(OCLASS_OPERATOR, opexpr->opno, 0,
|
||||
&context->addrs);
|
||||
|
@ -1066,7 +1067,7 @@ find_expr_references_walker(Node *node,
|
|||
}
|
||||
if (IsA(node, SubLink))
|
||||
{
|
||||
SubLink *sublink = (SubLink *) node;
|
||||
SubLink *sublink = (SubLink *) node;
|
||||
List *opid;
|
||||
|
||||
foreach(opid, sublink->operOids)
|
||||
|
@ -1092,7 +1093,8 @@ find_expr_references_walker(Node *node,
|
|||
* Add whole-relation refs for each plain relation mentioned in
|
||||
* the subquery's rtable. (Note: query_tree_walker takes care of
|
||||
* 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)
|
||||
{
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
|
@ -418,8 +418,8 @@ CheckAttributeType(const char *attname, Oid atttypid)
|
|||
* Warn user, but don't fail, if column to be created has UNKNOWN type
|
||||
* (usually as a result of a 'retrieve into' - jolly)
|
||||
*
|
||||
* Refuse any attempt to create a pseudo-type column or one that uses
|
||||
* a standalone composite type. (Eventually we should probably refuse
|
||||
* Refuse any attempt to create a pseudo-type column or one that uses a
|
||||
* standalone composite type. (Eventually we should probably refuse
|
||||
* all references to complex types, but for now there's still some
|
||||
* Berkeley-derived code that thinks it can do this...)
|
||||
*/
|
||||
|
@ -439,7 +439,7 @@ CheckAttributeType(const char *attname, Oid atttypid)
|
|||
}
|
||||
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)
|
||||
ereport(ERROR,
|
||||
|
@ -975,12 +975,13 @@ RemoveAttributeById(Oid relid, AttrNumber attnum)
|
|||
attStruct->attisdropped = true;
|
||||
|
||||
/*
|
||||
* Set the type OID to invalid. A dropped attribute's type link cannot
|
||||
* be relied on (once the attribute is dropped, the type might be too).
|
||||
* Fortunately we do not need the type row --- the only really essential
|
||||
* information is the type's typlen and typalign, which are preserved in
|
||||
* the attribute's attlen and attalign. We set atttypid to zero here
|
||||
* as a means of catching code that incorrectly expects it to be valid.
|
||||
* Set the type OID to invalid. A dropped attribute's type link
|
||||
* cannot be relied on (once the attribute is dropped, the type might
|
||||
* be too). Fortunately we do not need the type row --- the only
|
||||
* really essential information is the type's typlen and typalign,
|
||||
* which are preserved in the attribute's attlen and attalign. We set
|
||||
* atttypid to zero here as a means of catching code that incorrectly
|
||||
* expects it to be valid.
|
||||
*/
|
||||
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 */
|
||||
ccbin, /* Binary form check constraint */
|
||||
ccsrc); /* Source form check constraint */
|
||||
|
@ -1568,8 +1569,8 @@ AddRelationRawConstraints(Relation rel,
|
|||
if (strcmp(cdef2->name, ccname) == 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
||||
errmsg("CHECK constraint \"%s\" already exists",
|
||||
ccname)));
|
||||
errmsg("CHECK constraint \"%s\" already exists",
|
||||
ccname)));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1639,7 +1640,7 @@ AddRelationRawConstraints(Relation rel,
|
|||
if (pstate->p_hasSubLinks)
|
||||
ereport(ERROR,
|
||||
(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)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_GROUPING_ERROR),
|
||||
|
@ -1750,7 +1751,7 @@ cookDefault(ParseState *pstate,
|
|||
if (contain_var_clause(expr))
|
||||
ereport(ERROR,
|
||||
(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.
|
||||
|
@ -1773,9 +1774,9 @@ cookDefault(ParseState *pstate,
|
|||
errmsg("cannot use aggregate in DEFAULT clause")));
|
||||
|
||||
/*
|
||||
* Coerce the expression to the correct type and typmod, if given. This
|
||||
* should match the parser's processing of non-defaulted expressions ---
|
||||
* see updateTargetListEntry().
|
||||
* Coerce the expression to the correct type and typmod, if given.
|
||||
* This should match the parser's processing of non-defaulted
|
||||
* expressions --- see updateTargetListEntry().
|
||||
*/
|
||||
if (OidIsValid(atttypid))
|
||||
{
|
||||
|
@ -1793,7 +1794,7 @@ cookDefault(ParseState *pstate,
|
|||
attname,
|
||||
format_type_be(atttypid),
|
||||
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;
|
||||
|
@ -1952,7 +1953,7 @@ RelationTruncateIndexes(Oid heapId)
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
heapRelation = heap_open(heapId, NoLock);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
|
@ -65,8 +65,8 @@
|
|||
|
||||
/* non-export function prototypes */
|
||||
static TupleDesc ConstructTupleDescriptor(Relation heapRelation,
|
||||
IndexInfo *indexInfo,
|
||||
Oid *classObjectId);
|
||||
IndexInfo *indexInfo,
|
||||
Oid *classObjectId);
|
||||
static void UpdateRelationRelation(Relation indexRelation);
|
||||
static void InitializeAttributeOids(Relation indexRelation,
|
||||
int numatts, Oid indexoid);
|
||||
|
@ -124,7 +124,7 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
for (i = 0; i < numatts; i++)
|
||||
|
@ -149,7 +149,7 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||
* here we are indexing on a system attribute (-1...-n)
|
||||
*/
|
||||
from = SystemAttributeDefinition(atnum,
|
||||
heapRelation->rd_rel->relhasoids);
|
||||
heapRelation->rd_rel->relhasoids);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -162,8 +162,8 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||
}
|
||||
|
||||
/*
|
||||
* now that we've determined the "from", let's copy the tuple desc
|
||||
* data...
|
||||
* now that we've determined the "from", let's copy the tuple
|
||||
* desc data...
|
||||
*/
|
||||
memcpy(to, from, ATTRIBUTE_TUPLE_SIZE);
|
||||
|
||||
|
@ -185,7 +185,7 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||
/* Expressional index */
|
||||
Node *indexkey;
|
||||
|
||||
if (indexprs == NIL) /* shouldn't happen */
|
||||
if (indexprs == NIL) /* shouldn't happen */
|
||||
elog(ERROR, "too few entries in indexprs list");
|
||||
indexkey = (Node *) lfirst(indexprs);
|
||||
indexprs = lnext(indexprs);
|
||||
|
@ -197,7 +197,8 @@ ConstructTupleDescriptor(Relation heapRelation,
|
|||
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);
|
||||
tuple = SearchSysCache(TYPEOID,
|
||||
|
@ -534,7 +535,7 @@ index_create(Oid heapRelationId,
|
|||
if (shared_relation && IsUnderPostmaster)
|
||||
ereport(ERROR,
|
||||
(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))
|
||||
ereport(ERROR,
|
||||
|
@ -668,7 +669,7 @@ index_create(Oid heapRelationId,
|
|||
' ',
|
||||
' ',
|
||||
' ',
|
||||
InvalidOid, /* no associated index */
|
||||
InvalidOid, /* no associated index */
|
||||
NULL, /* no check constraint */
|
||||
NULL,
|
||||
NULL);
|
||||
|
@ -709,7 +710,7 @@ index_create(Oid heapRelationId,
|
|||
if (indexInfo->ii_Expressions)
|
||||
{
|
||||
recordDependencyOnSingleRelExpr(&myself,
|
||||
(Node *) indexInfo->ii_Expressions,
|
||||
(Node *) indexInfo->ii_Expressions,
|
||||
heapRelationId,
|
||||
DEPENDENCY_NORMAL,
|
||||
DEPENDENCY_AUTO);
|
||||
|
@ -719,7 +720,7 @@ index_create(Oid heapRelationId,
|
|||
if (indexInfo->ii_Predicate)
|
||||
{
|
||||
recordDependencyOnSingleRelExpr(&myself,
|
||||
(Node *) indexInfo->ii_Predicate,
|
||||
(Node *) indexInfo->ii_Predicate,
|
||||
heapRelationId,
|
||||
DEPENDENCY_NORMAL,
|
||||
DEPENDENCY_AUTO);
|
||||
|
@ -831,8 +832,8 @@ index_drop(Oid indexId)
|
|||
|
||||
/*
|
||||
* We are presently too lazy to attempt to compute the new correct
|
||||
* value of relhasindex (the next VACUUM will fix it if necessary).
|
||||
* So there is no need to update the pg_class tuple for the owning
|
||||
* value of relhasindex (the next VACUUM will fix it if necessary). So
|
||||
* 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
|
||||
* owning relation to ensure other backends update their relcache
|
||||
* lists of indexes.
|
||||
|
@ -958,7 +959,7 @@ FormIndexDatum(IndexInfo *indexInfo,
|
|||
if (indexprs == NIL)
|
||||
elog(ERROR, "wrong number of index expressions");
|
||||
iDatum = ExecEvalExprSwitchContext((ExprState *) lfirst(indexprs),
|
||||
GetPerTupleExprContext(estate),
|
||||
GetPerTupleExprContext(estate),
|
||||
&isNull,
|
||||
NULL);
|
||||
indexprs = lnext(indexprs);
|
||||
|
@ -1160,7 +1161,7 @@ setNewRelfilenode(Relation relation)
|
|||
if (!in_place_upd)
|
||||
{
|
||||
tuple = SearchSysCacheCopy(RELOID,
|
||||
ObjectIdGetDatum(RelationGetRelid(relation)),
|
||||
ObjectIdGetDatum(RelationGetRelid(relation)),
|
||||
0, 0, 0);
|
||||
}
|
||||
else
|
||||
|
@ -1170,7 +1171,7 @@ setNewRelfilenode(Relation relation)
|
|||
ScanKeyEntryInitialize(&key[0], 0,
|
||||
ObjectIdAttributeNumber,
|
||||
F_OIDEQ,
|
||||
ObjectIdGetDatum(RelationGetRelid(relation)));
|
||||
ObjectIdGetDatum(RelationGetRelid(relation)));
|
||||
|
||||
pg_class_scan = heap_beginscan(pg_class, SnapshotNow, 1, key);
|
||||
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
|
||||
* unnecessary update is not just a tiny performance improvement;
|
||||
* it also reduces the window wherein concurrent CREATE INDEX commands
|
||||
* Update statistics in pg_class, if they changed. (Avoiding an
|
||||
* unnecessary update is not just a tiny performance improvement; it
|
||||
* also reduces the window wherein concurrent CREATE INDEX commands
|
||||
* may conflict.)
|
||||
*/
|
||||
rd_rel = (Form_pg_class) GETSTRUCT(tuple);
|
||||
|
@ -1338,8 +1339,9 @@ UpdateStats(Oid relid, double reltuples)
|
|||
if (in_place_upd)
|
||||
{
|
||||
/*
|
||||
* At bootstrap time, we don't need to worry about concurrency or
|
||||
* visibility of changes, so we cheat. Also cheat if REINDEX.
|
||||
* At bootstrap time, we don't need to worry about concurrency
|
||||
* or visibility of changes, so we cheat. Also cheat if
|
||||
* REINDEX.
|
||||
*/
|
||||
LockBuffer(pg_class_scan->rs_cbuf, BUFFER_LOCK_EXCLUSIVE);
|
||||
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
|
||||
* 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?)
|
||||
*/
|
||||
whichRel->rd_rel->relpages = (int32) relpages;
|
||||
|
@ -1454,8 +1456,8 @@ IndexBuildHeapScan(Relation heapRelation,
|
|||
heapDescriptor = RelationGetDescr(heapRelation);
|
||||
|
||||
/*
|
||||
* Need an EState for evaluation of index expressions
|
||||
* and partial-index predicates.
|
||||
* Need an EState for evaluation of index expressions and
|
||||
* partial-index predicates.
|
||||
*/
|
||||
estate = CreateExecutorState();
|
||||
econtext = GetPerTupleExprContext(estate);
|
||||
|
@ -1463,7 +1465,8 @@ IndexBuildHeapScan(Relation heapRelation,
|
|||
/*
|
||||
* If this is a predicate (partial) index, we will need to evaluate
|
||||
* 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)
|
||||
{
|
||||
|
@ -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
|
||||
* the relcache can't cope with changing its relfilenode.
|
||||
*
|
||||
* In either of these cases, we are definitely processing a system
|
||||
* index, so we'd better be ignoring system indexes.
|
||||
* In either of these cases, we are definitely processing a system index,
|
||||
* so we'd better be ignoring system indexes.
|
||||
*/
|
||||
if (iRel->rd_rel->relisshared)
|
||||
{
|
||||
if (!IsIgnoringSystemIndexes())
|
||||
ereport(ERROR,
|
||||
(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;
|
||||
}
|
||||
if (iRel->rd_isnailed)
|
||||
|
@ -1757,7 +1760,7 @@ reindex_index(Oid indexId, bool force, bool inplace)
|
|||
if (!IsIgnoringSystemIndexes())
|
||||
ereport(ERROR,
|
||||
(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;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* 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)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cross-database references are not implemented")));
|
||||
errmsg("cross-database references are not implemented")));
|
||||
}
|
||||
|
||||
if (relation->schemaname)
|
||||
|
@ -217,7 +217,7 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation)
|
|||
if (strcmp(newRelation->catalogname, get_database_name(MyDatabaseId)) != 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cross-database references are not implemented")));
|
||||
errmsg("cross-database references are not implemented")));
|
||||
}
|
||||
|
||||
if (newRelation->istemp)
|
||||
|
@ -226,7 +226,7 @@ RangeVarGetCreationNamespace(const RangeVar *newRelation)
|
|||
if (newRelation->schemaname)
|
||||
ereport(ERROR,
|
||||
(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 */
|
||||
if (!OidIsValid(myTempNamespace))
|
||||
InitTempTableNamespace();
|
||||
|
@ -1057,7 +1057,7 @@ OpclassIsVisible(Oid opcid)
|
|||
Oid
|
||||
ConversionGetConid(const char *conname)
|
||||
{
|
||||
Oid conid;
|
||||
Oid conid;
|
||||
List *lptr;
|
||||
|
||||
recomputeNamespacePath();
|
||||
|
@ -1115,11 +1115,11 @@ ConversionIsVisible(Oid conid)
|
|||
/*
|
||||
* 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
|
||||
* path. So we must do a slow check to see if this conversion would
|
||||
* be found by ConversionGetConid.
|
||||
* path. So we must do a slow check to see if this conversion
|
||||
* would be found by ConversionGetConid.
|
||||
*/
|
||||
char *conname = NameStr(conform->conname);
|
||||
|
||||
|
||||
visible = (ConversionGetConid(conname) == conid);
|
||||
}
|
||||
|
||||
|
@ -1164,13 +1164,13 @@ DeconstructQualifiedName(List *names,
|
|||
if (strcmp(catalogname, get_database_name(MyDatabaseId)) != 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cross-database references are not implemented")));
|
||||
errmsg("cross-database references are not implemented")));
|
||||
break;
|
||||
default:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("improper qualified name (too many dotted names): %s",
|
||||
NameListToString(names))));
|
||||
errmsg("improper qualified name (too many dotted names): %s",
|
||||
NameListToString(names))));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1281,8 +1281,8 @@ makeRangeVarFromNameList(List *names)
|
|||
default:
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("improper relation name (too many dotted names): %s",
|
||||
NameListToString(names))));
|
||||
errmsg("improper relation name (too many dotted names): %s",
|
||||
NameListToString(names))));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1720,8 +1720,8 @@ RemoveTempRelations(Oid tempNamespaceId)
|
|||
|
||||
/*
|
||||
* 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
|
||||
* a waste of cycles). We do this by finding everything that has a
|
||||
* the namespace itself (deleting it only to recreate it later would
|
||||
* be a waste of cycles). We do this by finding everything that has a
|
||||
* dependency on the namespace.
|
||||
*/
|
||||
object.classId = get_system_catalog_relid(NamespaceRelationName);
|
||||
|
@ -1797,7 +1797,7 @@ assign_search_path(const char *newval, bool doit, bool interactive)
|
|||
0, 0, 0))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_SCHEMA),
|
||||
errmsg("schema \"%s\" does not exist", curname)));
|
||||
errmsg("schema \"%s\" does not exist", curname)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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"
|
||||
|
||||
|
||||
static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
|
||||
Oid *rettype);
|
||||
static Oid lookup_agg_function(List *fnName, int nargs, Oid *input_types,
|
||||
Oid *rettype);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -79,7 +79,7 @@ AggregateCreate(const char *aggName,
|
|||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("cannot determine transition datatype"),
|
||||
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 */
|
||||
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)
|
||||
* must exactly match declared transtype.
|
||||
*
|
||||
* In the non-polymorphic-transtype case, it might be okay to allow
|
||||
* a rettype that's binary-coercible to transtype, but I'm not quite
|
||||
* In the non-polymorphic-transtype case, it might be okay to allow a
|
||||
* rettype that's binary-coercible to transtype, but I'm not quite
|
||||
* convinced that it's either safe or useful. When transtype is
|
||||
* polymorphic we *must* demand exact equality.
|
||||
*/
|
||||
|
@ -151,9 +151,9 @@ AggregateCreate(const char *aggName,
|
|||
Assert(OidIsValid(finaltype));
|
||||
|
||||
/*
|
||||
* If finaltype (i.e. aggregate return type) is polymorphic,
|
||||
* basetype must be polymorphic also, else parser will fail to deduce
|
||||
* result type. (Note: given the previous test on transtype and basetype,
|
||||
* If finaltype (i.e. aggregate return type) is polymorphic, basetype
|
||||
* must be polymorphic also, else parser will fail to deduce result
|
||||
* type. (Note: given the previous test on transtype and basetype,
|
||||
* this cannot happen, unless someone has snuck a finalfn definition
|
||||
* into the catalogs that itself violates the rule against polymorphic
|
||||
* result with no polymorphic input.)
|
||||
|
@ -163,8 +163,8 @@ AggregateCreate(const char *aggName,
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("cannot determine result datatype"),
|
||||
errdetail("An aggregate returning ANYARRAY or ANYELEMENT "
|
||||
"must have one of them as its base type.")));
|
||||
errdetail("An aggregate returning ANYARRAY or ANYELEMENT "
|
||||
"must have one of them as its base type.")));
|
||||
|
||||
/*
|
||||
* Everything looks okay. Try to create the pg_proc entry for the
|
||||
|
@ -278,21 +278,21 @@ lookup_agg_function(List *fnName,
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_FUNCTION),
|
||||
errmsg("function %s does not exist",
|
||||
func_signature_string(fnName, nargs, input_types))));
|
||||
func_signature_string(fnName, nargs, input_types))));
|
||||
if (retset)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
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
|
||||
* can check. Otherwise, enforce consistency, and possibly refine
|
||||
* the result type.
|
||||
* If the given type(s) are all polymorphic, there's nothing we can
|
||||
* check. Otherwise, enforce consistency, and possibly refine the
|
||||
* result type.
|
||||
*/
|
||||
if ((input_types[0] == ANYARRAYOID || input_types[0] == ANYELEMENTOID) &&
|
||||
(nargs == 1 ||
|
||||
(input_types[1] == ANYARRAYOID || input_types[1] == ANYELEMENTOID)))
|
||||
(input_types[1] == ANYARRAYOID || input_types[1] == ANYELEMENTOID)))
|
||||
{
|
||||
/* nothing to check here */
|
||||
}
|
||||
|
@ -305,8 +305,8 @@ lookup_agg_function(List *fnName,
|
|||
}
|
||||
|
||||
/*
|
||||
* func_get_detail will find functions requiring run-time argument type
|
||||
* coercion, but nodeAgg.c isn't prepared to deal with that
|
||||
* func_get_detail will find functions requiring run-time argument
|
||||
* type coercion, but nodeAgg.c isn't prepared to deal with that
|
||||
*/
|
||||
if (true_oid_array[0] != ANYARRAYOID &&
|
||||
true_oid_array[0] != ANYELEMENTOID &&
|
||||
|
@ -314,7 +314,7 @@ lookup_agg_function(List *fnName,
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
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 &&
|
||||
true_oid_array[1] != ANYARRAYOID &&
|
||||
|
@ -323,7 +323,7 @@ lookup_agg_function(List *fnName,
|
|||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
ObjectAddress domobject;
|
||||
ObjectAddress domobject;
|
||||
|
||||
domobject.classId = RelOid_pg_type;
|
||||
domobject.objectId = domainId;
|
||||
|
@ -234,8 +234,8 @@ CreateConstraintEntry(const char *constraintName,
|
|||
if (OidIsValid(indexRelId))
|
||||
{
|
||||
/*
|
||||
* Register normal dependency on the unique index that supports
|
||||
* a foreign-key constraint.
|
||||
* Register normal dependency on the unique index that supports a
|
||||
* foreign-key constraint.
|
||||
*/
|
||||
ObjectAddress relobject;
|
||||
|
||||
|
@ -438,8 +438,8 @@ RemoveConstraintById(Oid conId)
|
|||
Relation rel;
|
||||
|
||||
/*
|
||||
* If the constraint is for a relation, open and exclusive-lock the
|
||||
* relation it's for.
|
||||
* If the constraint is for a relation, open and exclusive-lock
|
||||
* the relation it's for.
|
||||
*/
|
||||
rel = heap_open(con->conrelid, AccessExclusiveLock);
|
||||
|
||||
|
@ -463,7 +463,7 @@ RemoveConstraintById(Oid conId)
|
|||
con->conrelid);
|
||||
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",
|
||||
RelationGetRelationName(rel));
|
||||
classForm->relchecks--;
|
||||
|
@ -483,16 +483,15 @@ RemoveConstraintById(Oid conId)
|
|||
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,
|
||||
* but we have no such concept at the moment.
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR, "constraint %u is not of a known type", conId);
|
||||
}
|
||||
|
||||
/* Fry the constraint itself */
|
||||
simple_heap_delete(conDesc, &tup->t_self);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue