postgresql/contrib/tsearch2/dict.c

276 lines
6.0 KiB
C
Raw Normal View History

2003-07-21 18:27:44 +08:00
/*
* interface functions to dictionary
* Teodor Sigaev <teodor@sigaev.ru>
*/
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "postgres.h"
#include "fmgr.h"
#include "utils/array.h"
#include "catalog/pg_type.h"
#include "executor/spi.h"
#include "dict.h"
#include "common.h"
#include "snmap.h"
/*********top interface**********/
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;
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 )
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));
}
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
ts_error(ERROR, "No dictionary with id %d", id);
SPI_finish();
}
typedef struct {
DictInfo *last_dict;
int len;
int reallen;
DictInfo *list;
SNMap name2id_map;
} DictList;
static DictList DList = {NULL,0,0,NULL,{0,0,NULL}};
void
reset_dict(void) {
freeSNMap( &(DList.name2id_map) );
/* XXX need to free DList.list[*].dictionary */
if ( DList.list )
free(DList.list);
memset(&DList,0,sizeof(DictList));
}
static int
comparedict(const void *a, const void *b) {
return ((DictInfo*)a)->dict_id - ((DictInfo*)b)->dict_id;
}
DictInfo *
finddict(Oid id) {
/* last used dict */
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;
DList.last_dict = bsearch(&key, DList.list, DList.len, sizeof(DictInfo), comparedict);
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;
}
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!! */;
}
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 );
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 )
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
ts_error(ERROR, "No dictionary with name '%s'", text2char(name));
SPI_finish();
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) {
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)
)
);
PG_FREE_IF_COPY(in, 1);
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) );
ptr++;
}
a = construct_array(
da,
ptr-res,
TEXTOID,
-1,
false,
'i'
);
ptr=res;
while(*ptr) {
pfree( DatumGetPointer(da[ ptr-res ]) );
pfree( *ptr );
ptr++;
}
pfree(res);
pfree(da);
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;
strdup("simple");
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
PG_RETURN_NULL();
}
static Oid currect_dictionary_id=0;
PG_FUNCTION_INFO_V1(set_curdict);
Datum set_curdict(PG_FUNCTION_ARGS);
Datum
set_curdict(PG_FUNCTION_ARGS) {
finddict(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) {
text *dictname=PG_GETARG_TEXT_P(0);
DirectFunctionCall1(
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 )
elog(ERROR, "No currect dictionary. Execute select set_curdict().");
res = DirectFunctionCall3(
lexize,
ObjectIdGetDatum(currect_dictionary_id),
PG_GETARG_DATUM(0),
(Datum)0
);
if (res)
PG_RETURN_DATUM(res);
else
PG_RETURN_NULL();
}