00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "postgres.h"
00015
00016 #include "catalog/namespace.h"
00017 #include "catalog/pg_type.h"
00018 #include "commands/trigger.h"
00019 #include "tsearch/ts_utils.h"
00020 #include "utils/builtins.h"
00021 #include "utils/guc.h"
00022 #include "utils/syscache.h"
00023
00024 PG_MODULE_MAGIC;
00025
00026 static Oid current_dictionary_oid = InvalidOid;
00027 static Oid current_parser_oid = InvalidOid;
00028
00029
00030 #define INSERT_ARGUMENT0(argument, isnull) \
00031 do { \
00032 int i; \
00033 for (i = fcinfo->nargs; i > 0; i--) \
00034 { \
00035 fcinfo->arg[i] = fcinfo->arg[i-1]; \
00036 fcinfo->argnull[i] = fcinfo->argnull[i-1]; \
00037 } \
00038 fcinfo->arg[0] = (argument); \
00039 fcinfo->argnull[0] = (isnull); \
00040 fcinfo->nargs++; \
00041 } while (0)
00042
00043 #define TextGetObjectId(infunction, text) \
00044 DatumGetObjectId(DirectFunctionCall1(infunction, \
00045 CStringGetDatum(text_to_cstring(text))))
00046
00047 #define UNSUPPORTED_FUNCTION(name) \
00048 Datum name(PG_FUNCTION_ARGS); \
00049 Datum \
00050 name(PG_FUNCTION_ARGS) \
00051 { \
00052 ereport(ERROR, \
00053 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),\
00054 errmsg("function %s is no longer supported", \
00055 format_procedure(fcinfo->flinfo->fn_oid)), \
00056 errhint("Switch to new tsearch functionality."))); \
00057 \
00058 PG_RETURN_NULL(); \
00059 } \
00060 PG_FUNCTION_INFO_V1(name)
00061
00062 static Oid GetCurrentDict(void);
00063 static Oid GetCurrentParser(void);
00064
00065 Datum tsa_lexize_byname(PG_FUNCTION_ARGS);
00066 Datum tsa_lexize_bycurrent(PG_FUNCTION_ARGS);
00067 Datum tsa_set_curdict(PG_FUNCTION_ARGS);
00068 Datum tsa_set_curdict_byname(PG_FUNCTION_ARGS);
00069 Datum tsa_token_type_current(PG_FUNCTION_ARGS);
00070 Datum tsa_set_curprs(PG_FUNCTION_ARGS);
00071 Datum tsa_set_curprs_byname(PG_FUNCTION_ARGS);
00072 Datum tsa_parse_current(PG_FUNCTION_ARGS);
00073 Datum tsa_set_curcfg(PG_FUNCTION_ARGS);
00074 Datum tsa_set_curcfg_byname(PG_FUNCTION_ARGS);
00075 Datum tsa_to_tsvector_name(PG_FUNCTION_ARGS);
00076 Datum tsa_to_tsquery_name(PG_FUNCTION_ARGS);
00077 Datum tsa_plainto_tsquery_name(PG_FUNCTION_ARGS);
00078 Datum tsa_headline_byname(PG_FUNCTION_ARGS);
00079 Datum tsa_ts_stat(PG_FUNCTION_ARGS);
00080 Datum tsa_tsearch2(PG_FUNCTION_ARGS);
00081 Datum tsa_rewrite_accum(PG_FUNCTION_ARGS);
00082 Datum tsa_rewrite_finish(PG_FUNCTION_ARGS);
00083
00084 PG_FUNCTION_INFO_V1(tsa_lexize_byname);
00085 PG_FUNCTION_INFO_V1(tsa_lexize_bycurrent);
00086 PG_FUNCTION_INFO_V1(tsa_set_curdict);
00087 PG_FUNCTION_INFO_V1(tsa_set_curdict_byname);
00088 PG_FUNCTION_INFO_V1(tsa_token_type_current);
00089 PG_FUNCTION_INFO_V1(tsa_set_curprs);
00090 PG_FUNCTION_INFO_V1(tsa_set_curprs_byname);
00091 PG_FUNCTION_INFO_V1(tsa_parse_current);
00092 PG_FUNCTION_INFO_V1(tsa_set_curcfg);
00093 PG_FUNCTION_INFO_V1(tsa_set_curcfg_byname);
00094 PG_FUNCTION_INFO_V1(tsa_to_tsvector_name);
00095 PG_FUNCTION_INFO_V1(tsa_to_tsquery_name);
00096 PG_FUNCTION_INFO_V1(tsa_plainto_tsquery_name);
00097 PG_FUNCTION_INFO_V1(tsa_headline_byname);
00098 PG_FUNCTION_INFO_V1(tsa_ts_stat);
00099 PG_FUNCTION_INFO_V1(tsa_tsearch2);
00100 PG_FUNCTION_INFO_V1(tsa_rewrite_accum);
00101 PG_FUNCTION_INFO_V1(tsa_rewrite_finish);
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 UNSUPPORTED_FUNCTION(tsa_dex_init);
00113 UNSUPPORTED_FUNCTION(tsa_dex_lexize);
00114
00115 UNSUPPORTED_FUNCTION(tsa_snb_en_init);
00116 UNSUPPORTED_FUNCTION(tsa_snb_lexize);
00117 UNSUPPORTED_FUNCTION(tsa_snb_ru_init_koi8);
00118 UNSUPPORTED_FUNCTION(tsa_snb_ru_init_utf8);
00119 UNSUPPORTED_FUNCTION(tsa_snb_ru_init);
00120
00121 UNSUPPORTED_FUNCTION(tsa_spell_init);
00122 UNSUPPORTED_FUNCTION(tsa_spell_lexize);
00123
00124 UNSUPPORTED_FUNCTION(tsa_syn_init);
00125 UNSUPPORTED_FUNCTION(tsa_syn_lexize);
00126
00127 UNSUPPORTED_FUNCTION(tsa_thesaurus_init);
00128 UNSUPPORTED_FUNCTION(tsa_thesaurus_lexize);
00129
00130 UNSUPPORTED_FUNCTION(tsa_prsd_start);
00131 UNSUPPORTED_FUNCTION(tsa_prsd_getlexeme);
00132 UNSUPPORTED_FUNCTION(tsa_prsd_end);
00133 UNSUPPORTED_FUNCTION(tsa_prsd_lextype);
00134 UNSUPPORTED_FUNCTION(tsa_prsd_headline);
00135
00136 UNSUPPORTED_FUNCTION(tsa_reset_tsearch);
00137 UNSUPPORTED_FUNCTION(tsa_get_covers);
00138
00139
00140
00141
00142
00143
00144
00145 Datum
00146 tsa_lexize_byname(PG_FUNCTION_ARGS)
00147 {
00148 text *dictname = PG_GETARG_TEXT_PP(0);
00149 Datum arg1 = PG_GETARG_DATUM(1);
00150
00151 return DirectFunctionCall2(ts_lexize,
00152 ObjectIdGetDatum(TextGetObjectId(regdictionaryin, dictname)),
00153 arg1);
00154 }
00155
00156
00157 Datum
00158 tsa_lexize_bycurrent(PG_FUNCTION_ARGS)
00159 {
00160 Datum arg0 = PG_GETARG_DATUM(0);
00161 Oid id = GetCurrentDict();
00162
00163 return DirectFunctionCall2(ts_lexize,
00164 ObjectIdGetDatum(id),
00165 arg0);
00166 }
00167
00168
00169 Datum
00170 tsa_set_curdict(PG_FUNCTION_ARGS)
00171 {
00172 Oid dict_oid = PG_GETARG_OID(0);
00173
00174 if (!SearchSysCacheExists(TSDICTOID,
00175 ObjectIdGetDatum(dict_oid),
00176 0, 0, 0))
00177 elog(ERROR, "cache lookup failed for text search dictionary %u",
00178 dict_oid);
00179
00180 current_dictionary_oid = dict_oid;
00181
00182 PG_RETURN_VOID();
00183 }
00184
00185
00186 Datum
00187 tsa_set_curdict_byname(PG_FUNCTION_ARGS)
00188 {
00189 text *name = PG_GETARG_TEXT_PP(0);
00190 Oid dict_oid;
00191
00192 dict_oid = get_ts_dict_oid(stringToQualifiedNameList(text_to_cstring(name)), false);
00193
00194 current_dictionary_oid = dict_oid;
00195
00196 PG_RETURN_VOID();
00197 }
00198
00199
00200 Datum
00201 tsa_token_type_current(PG_FUNCTION_ARGS)
00202 {
00203 INSERT_ARGUMENT0(ObjectIdGetDatum(GetCurrentParser()), false);
00204 return ts_token_type_byid(fcinfo);
00205 }
00206
00207
00208 Datum
00209 tsa_set_curprs(PG_FUNCTION_ARGS)
00210 {
00211 Oid parser_oid = PG_GETARG_OID(0);
00212
00213 if (!SearchSysCacheExists(TSPARSEROID,
00214 ObjectIdGetDatum(parser_oid),
00215 0, 0, 0))
00216 elog(ERROR, "cache lookup failed for text search parser %u",
00217 parser_oid);
00218
00219 current_parser_oid = parser_oid;
00220
00221 PG_RETURN_VOID();
00222 }
00223
00224
00225 Datum
00226 tsa_set_curprs_byname(PG_FUNCTION_ARGS)
00227 {
00228 text *name = PG_GETARG_TEXT_PP(0);
00229 Oid parser_oid;
00230
00231 parser_oid = get_ts_parser_oid(stringToQualifiedNameList(text_to_cstring(name)), false);
00232
00233 current_parser_oid = parser_oid;
00234
00235 PG_RETURN_VOID();
00236 }
00237
00238
00239 Datum
00240 tsa_parse_current(PG_FUNCTION_ARGS)
00241 {
00242 INSERT_ARGUMENT0(ObjectIdGetDatum(GetCurrentParser()), false);
00243 return ts_parse_byid(fcinfo);
00244 }
00245
00246
00247 Datum
00248 tsa_set_curcfg(PG_FUNCTION_ARGS)
00249 {
00250 Oid arg0 = PG_GETARG_OID(0);
00251 char *name;
00252
00253 name = DatumGetCString(DirectFunctionCall1(regconfigout,
00254 ObjectIdGetDatum(arg0)));
00255
00256 SetConfigOption("default_text_search_config", name,
00257 PGC_USERSET, PGC_S_SESSION);
00258
00259 PG_RETURN_VOID();
00260 }
00261
00262
00263 Datum
00264 tsa_set_curcfg_byname(PG_FUNCTION_ARGS)
00265 {
00266 text *arg0 = PG_GETARG_TEXT_PP(0);
00267 char *name;
00268
00269 name = text_to_cstring(arg0);
00270
00271 SetConfigOption("default_text_search_config", name,
00272 PGC_USERSET, PGC_S_SESSION);
00273
00274 PG_RETURN_VOID();
00275 }
00276
00277
00278 Datum
00279 tsa_to_tsvector_name(PG_FUNCTION_ARGS)
00280 {
00281 text *cfgname = PG_GETARG_TEXT_PP(0);
00282 Datum arg1 = PG_GETARG_DATUM(1);
00283 Oid config_oid;
00284
00285 config_oid = TextGetObjectId(regconfigin, cfgname);
00286
00287 return DirectFunctionCall2(to_tsvector_byid,
00288 ObjectIdGetDatum(config_oid), arg1);
00289 }
00290
00291
00292 Datum
00293 tsa_to_tsquery_name(PG_FUNCTION_ARGS)
00294 {
00295 text *cfgname = PG_GETARG_TEXT_PP(0);
00296 Datum arg1 = PG_GETARG_DATUM(1);
00297 Oid config_oid;
00298
00299 config_oid = TextGetObjectId(regconfigin, cfgname);
00300
00301 return DirectFunctionCall2(to_tsquery_byid,
00302 ObjectIdGetDatum(config_oid), arg1);
00303 }
00304
00305
00306
00307 Datum
00308 tsa_plainto_tsquery_name(PG_FUNCTION_ARGS)
00309 {
00310 text *cfgname = PG_GETARG_TEXT_PP(0);
00311 Datum arg1 = PG_GETARG_DATUM(1);
00312 Oid config_oid;
00313
00314 config_oid = TextGetObjectId(regconfigin, cfgname);
00315
00316 return DirectFunctionCall2(plainto_tsquery_byid,
00317 ObjectIdGetDatum(config_oid), arg1);
00318 }
00319
00320
00321 Datum
00322 tsa_headline_byname(PG_FUNCTION_ARGS)
00323 {
00324 Datum arg0 = PG_GETARG_DATUM(0);
00325 Datum arg1 = PG_GETARG_DATUM(1);
00326 Datum arg2 = PG_GETARG_DATUM(2);
00327 Datum result;
00328 Oid config_oid;
00329
00330
00331 config_oid = DatumGetObjectId(DirectFunctionCall1(regconfigin,
00332 CStringGetDatum(TextDatumGetCString(arg0))));
00333
00334 if (PG_NARGS() == 3)
00335 result = DirectFunctionCall3(ts_headline_byid,
00336 ObjectIdGetDatum(config_oid), arg1, arg2);
00337 else
00338 {
00339 Datum arg3 = PG_GETARG_DATUM(3);
00340
00341 result = DirectFunctionCall4(ts_headline_byid_opt,
00342 ObjectIdGetDatum(config_oid),
00343 arg1, arg2, arg3);
00344 }
00345
00346 return result;
00347 }
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358 Datum
00359 tsa_tsearch2(PG_FUNCTION_ARGS)
00360 {
00361 TriggerData *trigdata;
00362 Trigger *trigger;
00363 char **tgargs,
00364 **tgargs_old;
00365 int i;
00366 Datum res;
00367
00368
00369 if (!CALLED_AS_TRIGGER(fcinfo))
00370 elog(ERROR, "tsvector_update_trigger: not fired by trigger manager");
00371
00372 trigdata = (TriggerData *) fcinfo->context;
00373 trigger = trigdata->tg_trigger;
00374
00375 if (trigger->tgnargs < 2)
00376 elog(ERROR, "TSearch: format tsearch2(tsvector_field, text_field1,...)");
00377
00378
00379 tgargs = (char **) palloc((trigger->tgnargs + 1) * sizeof(char *));
00380 tgargs[0] = trigger->tgargs[0];
00381 for (i = 1; i < trigger->tgnargs; i++)
00382 tgargs[i + 1] = trigger->tgargs[i];
00383
00384 tgargs[1] = pstrdup(GetConfigOptionByName("default_text_search_config",
00385 NULL));
00386 tgargs_old = trigger->tgargs;
00387 trigger->tgargs = tgargs;
00388 trigger->tgnargs++;
00389
00390 res = tsvector_update_trigger_byid(fcinfo);
00391
00392
00393 trigger->tgargs = tgargs_old;
00394 trigger->tgnargs--;
00395
00396 pfree(tgargs[1]);
00397 pfree(tgargs);
00398
00399 return res;
00400 }
00401
00402
00403 Datum
00404 tsa_rewrite_accum(PG_FUNCTION_ARGS)
00405 {
00406 TSQuery acc;
00407 ArrayType *qa;
00408 TSQuery q;
00409 QTNode *qex = NULL,
00410 *subs = NULL,
00411 *acctree = NULL;
00412 bool isfind = false;
00413 Datum *elemsp;
00414 int nelemsp;
00415 MemoryContext aggcontext;
00416 MemoryContext oldcontext;
00417
00418 if (!AggCheckCallContext(fcinfo, &aggcontext))
00419 elog(ERROR, "tsa_rewrite_accum called in non-aggregate context");
00420
00421 if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL)
00422 {
00423 acc = (TSQuery) MemoryContextAlloc(aggcontext, HDRSIZETQ);
00424 SET_VARSIZE(acc, HDRSIZETQ);
00425 acc->size = 0;
00426 }
00427 else
00428 acc = PG_GETARG_TSQUERY(0);
00429
00430 if (PG_ARGISNULL(1) || PG_GETARG_POINTER(1) == NULL)
00431 PG_RETURN_TSQUERY(acc);
00432 else
00433 qa = PG_GETARG_ARRAYTYPE_P_COPY(1);
00434
00435 if (ARR_NDIM(qa) != 1)
00436 elog(ERROR, "array must be one-dimensional, not %d dimensions",
00437 ARR_NDIM(qa));
00438 if (ArrayGetNItems(ARR_NDIM(qa), ARR_DIMS(qa)) != 3)
00439 elog(ERROR, "array must have three elements");
00440 if (ARR_ELEMTYPE(qa) != TSQUERYOID)
00441 elog(ERROR, "array must contain tsquery elements");
00442
00443 deconstruct_array(qa, TSQUERYOID, -1, false, 'i', &elemsp, NULL, &nelemsp);
00444
00445 q = DatumGetTSQuery(elemsp[0]);
00446 if (q->size == 0)
00447 {
00448 pfree(elemsp);
00449 PG_RETURN_POINTER(acc);
00450 }
00451
00452 if (!acc->size)
00453 {
00454 if (VARSIZE(acc) > HDRSIZETQ)
00455 {
00456 pfree(elemsp);
00457 PG_RETURN_POINTER(acc);
00458 }
00459 else
00460 acctree = QT2QTN(GETQUERY(q), GETOPERAND(q));
00461 }
00462 else
00463 acctree = QT2QTN(GETQUERY(acc), GETOPERAND(acc));
00464
00465 QTNTernary(acctree);
00466 QTNSort(acctree);
00467
00468 q = DatumGetTSQuery(elemsp[1]);
00469 if (q->size == 0)
00470 {
00471 pfree(elemsp);
00472 PG_RETURN_POINTER(acc);
00473 }
00474 qex = QT2QTN(GETQUERY(q), GETOPERAND(q));
00475 QTNTernary(qex);
00476 QTNSort(qex);
00477
00478 q = DatumGetTSQuery(elemsp[2]);
00479 if (q->size)
00480 subs = QT2QTN(GETQUERY(q), GETOPERAND(q));
00481
00482 acctree = findsubquery(acctree, qex, subs, &isfind);
00483
00484 if (isfind || !acc->size)
00485 {
00486
00487 if (acctree)
00488 {
00489 QTNBinary(acctree);
00490 oldcontext = MemoryContextSwitchTo(aggcontext);
00491 acc = QTN2QT(acctree);
00492 MemoryContextSwitchTo(oldcontext);
00493 }
00494 else
00495 {
00496 acc = (TSQuery) MemoryContextAlloc(aggcontext, HDRSIZETQ);
00497 SET_VARSIZE(acc, HDRSIZETQ);
00498 acc->size = 0;
00499 }
00500 }
00501
00502 pfree(elemsp);
00503 QTNFree(qex);
00504 QTNFree(subs);
00505 QTNFree(acctree);
00506
00507 PG_RETURN_TSQUERY(acc);
00508 }
00509
00510 Datum
00511 tsa_rewrite_finish(PG_FUNCTION_ARGS)
00512 {
00513 TSQuery acc = PG_GETARG_TSQUERY(0);
00514 TSQuery rewrited;
00515
00516 if (acc == NULL || PG_ARGISNULL(0) || acc->size == 0)
00517 {
00518 rewrited = (TSQuery) palloc(HDRSIZETQ);
00519 SET_VARSIZE(rewrited, HDRSIZETQ);
00520 rewrited->size = 0;
00521 }
00522 else
00523 {
00524 rewrited = (TSQuery) palloc(VARSIZE(acc));
00525 memcpy(rewrited, acc, VARSIZE(acc));
00526 pfree(acc);
00527 }
00528
00529 PG_RETURN_POINTER(rewrited);
00530 }
00531
00532
00533
00534
00535
00536 static Oid
00537 GetCurrentDict(void)
00538 {
00539 if (current_dictionary_oid == InvalidOid)
00540 ereport(ERROR,
00541 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00542 errmsg("no current dictionary"),
00543 errhint("Execute SELECT set_curdict(...).")));
00544
00545 return current_dictionary_oid;
00546 }
00547
00548
00549
00550
00551
00552
00553
00554 static Oid
00555 GetCurrentParser(void)
00556 {
00557 if (current_parser_oid == InvalidOid)
00558 current_parser_oid = get_ts_parser_oid(stringToQualifiedNameList("pg_catalog.default"), false);
00559 return current_parser_oid;
00560 }