postgresql/contrib/tsearch2/dict.c

348 lines
7.2 KiB
C
Raw Normal View History

/* $PostgreSQL: pgsql/contrib/tsearch2/dict.c,v 1.12 2006/05/31 14:05:31 teodor Exp $ */
2003-08-04 02:43:34 +02:00
/*
* interface functions to dictionary
2003-07-21 12:27:44 +02:00
* Teodor Sigaev <teodor@sigaev.ru>
*/
#include "postgres.h"
2003-07-21 12:27:44 +02:00
#include <ctype.h>
#include "catalog/pg_type.h"
#include "executor/spi.h"
#include "fmgr.h"
#include "utils/array.h"
#include "utils/memutils.h"
2003-07-21 12:27:44 +02:00
#include "dict.h"
#include "common.h"
#include "snmap.h"
/*********top interface**********/
void
2003-08-04 02:43:34 +02:00
init_dict(Oid id, DictInfo * dict)
{
Oid arg[1];
2003-08-04 02:43:34 +02:00
bool isnull;
Datum pars[1];
2003-08-04 02:43:34 +02:00
int stat;
2004-08-29 07:07:03 +02:00
void *plan;
char buf[1024];
char *nsp = get_namespace(TSNSP_FunctionOid);
2003-08-04 02:43:34 +02:00
arg[0] = OIDOID;
pars[0] = ObjectIdGetDatum(id);
2003-08-04 02:43:34 +02:00
memset(dict, 0, sizeof(DictInfo));
2003-07-21 12:27:44 +02:00
SPI_connect();
2004-08-29 07:07:03 +02:00
sprintf(buf, "select dict_init, dict_initoption, dict_lexize from %s.pg_ts_dict where oid = $1", nsp);
pfree(nsp);
2004-08-29 07:07:03 +02:00
plan = SPI_prepare(buf, 1, arg);
if (!plan)
ts_error(ERROR, "SPI_prepare() failed");
2003-07-21 12:27:44 +02:00
stat = SPI_execp(plan, pars, " ", 1);
2003-08-04 02:43:34 +02:00
if (stat < 0)
ts_error(ERROR, "SPI_execp return %d", stat);
if (SPI_processed > 0)
{
Datum opt;
Oid oid = InvalidOid;
/* setup dictlexize method */
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);
/* setup and call dictinit method, optinally */
2003-08-04 02:43:34 +02:00
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));
2003-07-21 12:27:44 +02:00
}
2003-08-04 02:43:34 +02:00
dict->dict_id = id;
}
else
2003-07-21 12:27:44 +02:00
ts_error(ERROR, "No dictionary with id %d", id);
SPI_freeplan(plan);
2003-07-21 12:27:44 +02:00
SPI_finish();
}
2003-08-04 02:43:34 +02:00
typedef struct
{
DictInfo *last_dict;
int len;
int reallen;
DictInfo *list;
2003-07-21 12:27:44 +02:00
SNMap name2id_map;
2003-08-04 02:43:34 +02:00
} DictList;
2003-07-21 12:27:44 +02:00
2003-08-04 02:43:34 +02:00
static DictList DList = {NULL, 0, 0, NULL, {0, 0, NULL}};
2003-07-21 12:27:44 +02:00
void
2003-08-04 02:43:34 +02:00
reset_dict(void)
{
freeSNMap(&(DList.name2id_map));
2003-07-21 12:27:44 +02:00
/* XXX need to free DList.list[*].dictionary */
2003-08-04 02:43:34 +02:00
if (DList.list)
2003-07-21 12:27:44 +02:00
free(DList.list);
2003-08-04 02:43:34 +02:00
memset(&DList, 0, sizeof(DictList));
2003-07-21 12:27:44 +02:00
}
static int
2003-08-04 02:43:34 +02:00
comparedict(const void *a, const void *b)
{
2005-10-15 04:49:52 +02:00
if (((DictInfo *) a)->dict_id == ((DictInfo *) b)->dict_id)
return 0;
2005-10-15 04:49:52 +02:00
return (((DictInfo *) a)->dict_id < ((DictInfo *) b)->dict_id) ? -1 : 1;
2003-07-21 12:27:44 +02:00
}
static void
insertdict(Oid id) {
DictInfo newdict;
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;
}
init_dict(id, &newdict);
DList.list[DList.len] = newdict;
DList.len++;
qsort(DList.list, DList.len, sizeof(DictInfo), comparedict);
}
2003-07-21 12:27:44 +02:00
DictInfo *
2003-08-04 02:43:34 +02:00
finddict(Oid id)
{
2003-07-21 12:27:44 +02:00
/* last used dict */
2003-08-04 02:43:34 +02:00
if (DList.last_dict && DList.last_dict->dict_id == id)
2003-07-21 12:27:44 +02:00
return DList.last_dict;
/* already used dict */
2003-08-04 02:43:34 +02:00
if (DList.len != 0)
{
DictInfo key;
key.dict_id = id;
2003-07-21 12:27:44 +02:00
DList.last_dict = bsearch(&key, DList.list, DList.len, sizeof(DictInfo), comparedict);
2003-08-04 02:43:34 +02:00
if (DList.last_dict != NULL)
2003-07-21 12:27:44 +02:00
return DList.last_dict;
}
/* insert new dictionary */
insertdict(id);
2003-08-04 02:43:34 +02:00
return finddict(id); /* qsort changed order!! */ ;
2003-07-21 12:27:44 +02:00
}
Oid
2003-08-04 02:43:34 +02:00
name2id_dict(text *name)
{
Oid arg[1];
2003-08-04 02:43:34 +02:00
bool isnull;
Datum pars[1];
2003-08-04 02:43:34 +02:00
int stat;
Oid id = findSNMap_t(&(DList.name2id_map), name);
2004-08-29 07:07:03 +02:00
void *plan;
char buf[1024],
*nsp;
2003-08-04 02:43:34 +02:00
arg[0] = TEXTOID;
pars[0] = PointerGetDatum(name);
2003-08-04 02:43:34 +02:00
if (id)
2003-07-21 12:27:44 +02:00
return id;
2003-08-04 02:43:34 +02:00
nsp = get_namespace(TSNSP_FunctionOid);
2003-07-21 12:27:44 +02:00
SPI_connect();
2004-08-29 07:07:03 +02:00
sprintf(buf, "select oid from %s.pg_ts_dict where dict_name = $1", nsp);
pfree(nsp);
2004-08-29 07:07:03 +02:00
plan = SPI_prepare(buf, 1, arg);
if (!plan)
ts_error(ERROR, "SPI_prepare() failed");
2003-07-21 12:27:44 +02:00
stat = SPI_execp(plan, pars, " ", 1);
2003-08-04 02:43:34 +02:00
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
2003-07-21 12:27:44 +02:00
ts_error(ERROR, "No dictionary with name '%s'", text2char(name));
SPI_freeplan(plan);
2003-07-21 12:27:44 +02:00
SPI_finish();
2003-08-04 02:43:34 +02:00
addSNMap_t(&(DList.name2id_map), name, id);
2003-07-21 12:27:44 +02:00
return id;
}
/******sql-level interface******/
PG_FUNCTION_INFO_V1(lexize);
2003-08-04 02:43:34 +02:00
Datum lexize(PG_FUNCTION_ARGS);
2003-07-21 12:27:44 +02:00
Datum
2003-08-04 02:43:34 +02:00
lexize(PG_FUNCTION_ARGS)
{
text *in = PG_GETARG_TEXT_P(1);
DictInfo *dict;
2005-10-15 04:49:52 +02:00
TSLexeme *res,
*ptr;
2003-08-04 02:43:34 +02:00
Datum *da;
ArrayType *a;
DictSubState dstate = { false, false, NULL };
2003-08-04 02:43:34 +02:00
SET_FUNCOID();
dict = finddict(PG_GETARG_OID(0));
2003-08-04 02:43:34 +02:00
ptr = res = (TSLexeme *) DatumGetPointer(
FunctionCall4(&(dict->lexize_info),
PointerGetDatum(dict->dictionary),
PointerGetDatum(VARDATA(in)),
Int32GetDatum(VARSIZE(in) - VARHDRSZ),
PointerGetDatum(&dstate)
)
);
if (dstate.getnext) {
dstate.isend = true;
ptr = res = (TSLexeme *) DatumGetPointer(
FunctionCall4(&(dict->lexize_info),
2005-10-15 04:49:52 +02:00
PointerGetDatum(dict->dictionary),
PointerGetDatum(VARDATA(in)),
Int32GetDatum(VARSIZE(in) - VARHDRSZ),
PointerGetDatum(&dstate)
2005-10-15 04:49:52 +02:00
)
2003-08-04 02:43:34 +02:00
);
}
2003-07-21 12:27:44 +02:00
PG_FREE_IF_COPY(in, 1);
2003-08-04 02:43:34 +02:00
if (!res)
{
if (PG_NARGS() > 2)
2003-07-21 12:27:44 +02:00
PG_RETURN_POINTER(NULL);
else
PG_RETURN_NULL();
}
while (ptr->lexeme)
2003-08-04 02:43:34 +02:00
ptr++;
da = (Datum *) palloc(sizeof(Datum) * (ptr - res + 1));
ptr = res;
while (ptr->lexeme)
2003-08-04 02:43:34 +02:00
{
da[ptr - res] = PointerGetDatum(char2text(ptr->lexeme));
2003-07-21 12:27:44 +02:00
ptr++;
}
a = construct_array(
2003-08-04 02:43:34 +02:00
da,
ptr - res,
TEXTOID,
-1,
false,
'i'
);
ptr = res;
while (ptr->lexeme)
2003-08-04 02:43:34 +02:00
{
pfree(DatumGetPointer(da[ptr - res]));
pfree(ptr->lexeme);
2003-07-21 12:27:44 +02:00
ptr++;
}
pfree(res);
pfree(da);
2003-08-04 02:43:34 +02:00
PG_RETURN_POINTER(a);
2003-07-21 12:27:44 +02:00
}
PG_FUNCTION_INFO_V1(lexize_byname);
2003-08-04 02:43:34 +02:00
Datum lexize_byname(PG_FUNCTION_ARGS);
Datum
lexize_byname(PG_FUNCTION_ARGS)
{
text *dictname = PG_GETARG_TEXT_P(0);
Datum res;
2004-08-29 07:07:03 +02:00
SET_FUNCOID();
2003-07-21 12:27:44 +02:00
2003-08-04 02:43:34 +02:00
res = DirectFunctionCall3(
lexize,
ObjectIdGetDatum(name2id_dict(dictname)),
PG_GETARG_DATUM(1),
(Datum) 0
);
2003-07-21 12:27:44 +02:00
PG_FREE_IF_COPY(dictname, 0);
2003-08-04 02:43:34 +02:00
if (res)
PG_RETURN_DATUM(res);
else
2003-07-21 12:27:44 +02:00
PG_RETURN_NULL();
}
2003-08-04 02:43:34 +02:00
static Oid currect_dictionary_id = 0;
2003-07-21 12:27:44 +02:00
PG_FUNCTION_INFO_V1(set_curdict);
2003-08-04 02:43:34 +02:00
Datum set_curdict(PG_FUNCTION_ARGS);
2003-07-21 12:27:44 +02:00
Datum
2003-08-04 02:43:34 +02:00
set_curdict(PG_FUNCTION_ARGS)
{
2004-08-29 07:07:03 +02:00
SET_FUNCOID();
2003-07-21 12:27:44 +02:00
finddict(PG_GETARG_OID(0));
2003-08-04 02:43:34 +02:00
currect_dictionary_id = PG_GETARG_OID(0);
2003-07-21 12:27:44 +02:00
PG_RETURN_VOID();
}
PG_FUNCTION_INFO_V1(set_curdict_byname);
2003-08-04 02:43:34 +02:00
Datum set_curdict_byname(PG_FUNCTION_ARGS);
2003-07-21 12:27:44 +02:00
Datum
2003-08-04 02:43:34 +02:00
set_curdict_byname(PG_FUNCTION_ARGS)
{
text *dictname = PG_GETARG_TEXT_P(0);
2004-08-29 07:07:03 +02:00
SET_FUNCOID();
2003-07-21 12:27:44 +02:00
DirectFunctionCall1(
2003-08-04 02:43:34 +02:00
set_curdict,
ObjectIdGetDatum(name2id_dict(dictname))
);
2003-07-21 12:27:44 +02:00
PG_FREE_IF_COPY(dictname, 0);
PG_RETURN_VOID();
}
PG_FUNCTION_INFO_V1(lexize_bycurrent);
2003-08-04 02:43:34 +02:00
Datum lexize_bycurrent(PG_FUNCTION_ARGS);
Datum
lexize_bycurrent(PG_FUNCTION_ARGS)
{
Datum res;
2004-08-29 07:07:03 +02:00
SET_FUNCOID();
2003-08-04 02:43:34 +02:00
if (currect_dictionary_id == 0)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("no currect dictionary"),
errhint("Execute select set_curdict().")));
2003-07-21 12:27:44 +02:00
res = DirectFunctionCall3(
2003-08-04 02:43:34 +02:00
lexize,
ObjectIdGetDatum(currect_dictionary_id),
PG_GETARG_DATUM(0),
(Datum) 0
);
if (res)
2003-07-21 12:27:44 +02:00
PG_RETURN_DATUM(res);
2003-08-04 02:43:34 +02:00
else
2003-07-21 12:27:44 +02:00
PG_RETURN_NULL();
}