aboutsummaryrefslogtreecommitdiff
path: root/contrib/tsearch2/dict.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tsearch2/dict.c')
-rw-r--r--contrib/tsearch2/dict.c275
1 files changed, 275 insertions, 0 deletions
diff --git a/contrib/tsearch2/dict.c b/contrib/tsearch2/dict.c
new file mode 100644
index 00000000000..5c148c43b5a
--- /dev/null
+++ b/contrib/tsearch2/dict.c
@@ -0,0 +1,275 @@
+/*
+ * 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();
+}
+
+