Header And Logo

PostgreSQL
| The world's most advanced open source database.

Data Structures | Typedefs | Functions | Variables

ts_cache.h File Reference

#include "utils/guc.h"
Include dependency graph for ts_cache.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  TSAnyCacheEntry
struct  TSParserCacheEntry
struct  TSDictionaryCacheEntry
struct  ListDictionary
struct  TSConfigCacheEntry

Typedefs

typedef struct TSAnyCacheEntry TSAnyCacheEntry
typedef struct TSParserCacheEntry TSParserCacheEntry
typedef struct
TSDictionaryCacheEntry 
TSDictionaryCacheEntry

Functions

TSParserCacheEntrylookup_ts_parser_cache (Oid prsId)
TSDictionaryCacheEntrylookup_ts_dictionary_cache (Oid dictId)
TSConfigCacheEntrylookup_ts_config_cache (Oid cfgId)
Oid getTSCurrentConfig (bool emitError)
bool check_TSCurrentConfig (char **newval, void **extra, GucSource source)
void assign_TSCurrentConfig (const char *newval, void *extra)

Variables

char * TSCurrentConfig

Typedef Documentation


Function Documentation

void assign_TSCurrentConfig ( const char *  newval,
void *  extra 
)

Definition at line 654 of file ts_cache.c.

References TSCurrentConfigCache.

{
    /* Just reset the cache to force a lookup on first use */
    TSCurrentConfigCache = InvalidOid;
}

bool check_TSCurrentConfig ( char **  newval,
void **  extra,
GucSource  source 
)

Definition at line 591 of file ts_cache.c.

References buf, elog, ereport, errcode(), errmsg(), ERROR, free, get_namespace_name(), get_ts_config_oid(), GETSTRUCT, HeapTupleIsValid, IsTransactionState(), NameStr, NOTICE, ObjectIdGetDatum, OidIsValid, pfree(), PGC_S_TEST, quote_qualified_identifier(), ReleaseSysCache(), SearchSysCache1, stringToQualifiedNameList(), TSCONFIGOID, and catclist::tuple.

{
    /*
     * If we aren't inside a transaction, we cannot do database access so
     * cannot verify the config name.  Must accept it on faith.
     */
    if (IsTransactionState())
    {
        Oid         cfgId;
        HeapTuple   tuple;
        Form_pg_ts_config cfg;
        char       *buf;

        cfgId = get_ts_config_oid(stringToQualifiedNameList(*newval), true);

        /*
         * When source == PGC_S_TEST, we are checking the argument of an ALTER
         * DATABASE SET or ALTER USER SET command.  It could be that the
         * intended use of the setting is for some other database, so we
         * should not error out if the text search configuration is not
         * present in the current database.  We issue a NOTICE instead.
         */
        if (!OidIsValid(cfgId))
        {
            if (source == PGC_S_TEST)
            {
                ereport(NOTICE,
                        (errcode(ERRCODE_UNDEFINED_OBJECT),
                         errmsg("text search configuration \"%s\" does not exist", *newval)));
                return true;
            }
            else
                return false;
        }

        /*
         * Modify the actually stored value to be fully qualified, to ensure
         * later changes of search_path don't affect it.
         */
        tuple = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgId));
        if (!HeapTupleIsValid(tuple))
            elog(ERROR, "cache lookup failed for text search configuration %u",
                 cfgId);
        cfg = (Form_pg_ts_config) GETSTRUCT(tuple);

        buf = quote_qualified_identifier(get_namespace_name(cfg->cfgnamespace),
                                         NameStr(cfg->cfgname));

        ReleaseSysCache(tuple);

        /* GUC wants it malloc'd not palloc'd */
        free(*newval);
        *newval = strdup(buf);
        pfree(buf);
        if (!*newval)
            return false;
    }

    return true;
}

Oid getTSCurrentConfig ( bool  emitError  ) 

Definition at line 560 of file ts_cache.c.

References elog, ERROR, get_ts_config_oid(), init_ts_config_cache(), NULL, OidIsValid, stringToQualifiedNameList(), TSCurrentConfig, and TSCurrentConfigCache.

Referenced by get_current_ts_config(), plainto_tsquery(), to_tsquery(), to_tsvector(), ts_headline(), and ts_headline_opt().

{
    /* if we have a cached value, return it */
    if (OidIsValid(TSCurrentConfigCache))
        return TSCurrentConfigCache;

    /* fail if GUC hasn't been set up yet */
    if (TSCurrentConfig == NULL || *TSCurrentConfig == '\0')
    {
        if (emitError)
            elog(ERROR, "text search configuration isn't set");
        else
            return InvalidOid;
    }

    if (TSConfigCacheHash == NULL)
    {
        /* First time through: initialize the tsconfig inval callback */
        init_ts_config_cache();
    }

    /* Look up the config */
    TSCurrentConfigCache =
        get_ts_config_oid(stringToQualifiedNameList(TSCurrentConfig),
                          !emitError);

    return TSCurrentConfigCache;
}

TSConfigCacheEntry* lookup_ts_config_cache ( Oid  cfgId  ) 

Definition at line 389 of file ts_cache.c.

References AccessShareLock, Anum_pg_ts_config_map_mapcfg, Assert, BTEqualStrategyNumber, CacheMemoryContext, TSConfigCacheEntry::cfgId, ListDictionary::dictIds, elog, ERROR, ForwardScanDirection, GETSTRUCT, hash_search(), heap_close, heap_open(), HeapTupleIsValid, i, index_close(), index_open(), init_ts_config_cache(), TSConfigCacheEntry::isvalid, ListDictionary::len, TSConfigCacheEntry::lenmap, TSConfigCacheEntry::map, MAXDICTSPERTT, MAXTOKENTYPE, MemoryContextAlloc(), MemSet, NULL, ObjectIdGetDatum, OidIsValid, pfree(), TSConfigCacheEntry::prsId, ReleaseSysCache(), ScanKeyInit(), SearchSysCache1, SnapshotNow, systable_beginscan_ordered(), systable_endscan_ordered(), systable_getnext_ordered(), TSConfigMapIndexId, TSConfigMapRelationId, and TSCONFIGOID.

Referenced by hlparsetext(), parsetext(), and ts_headline_byid_opt().

{
    TSConfigCacheEntry *entry;

    if (TSConfigCacheHash == NULL)
    {
        /* First time through: initialize the hash table */
        init_ts_config_cache();
    }

    /* Check single-entry cache */
    if (lastUsedConfig && lastUsedConfig->cfgId == cfgId &&
        lastUsedConfig->isvalid)
        return lastUsedConfig;

    /* Try to look up an existing entry */
    entry = (TSConfigCacheEntry *) hash_search(TSConfigCacheHash,
                                               (void *) &cfgId,
                                               HASH_FIND, NULL);
    if (entry == NULL || !entry->isvalid)
    {
        /*
         * If we didn't find one, we want to make one. But first look up the
         * object to be sure the OID is real.
         */
        HeapTuple   tp;
        Form_pg_ts_config cfg;
        Relation    maprel;
        Relation    mapidx;
        ScanKeyData mapskey;
        SysScanDesc mapscan;
        HeapTuple   maptup;
        ListDictionary maplists[MAXTOKENTYPE + 1];
        Oid         mapdicts[MAXDICTSPERTT];
        int         maxtokentype;
        int         ndicts;
        int         i;

        tp = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgId));
        if (!HeapTupleIsValid(tp))
            elog(ERROR, "cache lookup failed for text search configuration %u",
                 cfgId);
        cfg = (Form_pg_ts_config) GETSTRUCT(tp);

        /*
         * Sanity checks
         */
        if (!OidIsValid(cfg->cfgparser))
            elog(ERROR, "text search configuration %u has no parser", cfgId);

        if (entry == NULL)
        {
            bool        found;

            /* Now make the cache entry */
            entry = (TSConfigCacheEntry *)
                hash_search(TSConfigCacheHash,
                            (void *) &cfgId,
                            HASH_ENTER, &found);
            Assert(!found);     /* it wasn't there a moment ago */
        }
        else
        {
            /* Cleanup old contents */
            if (entry->map)
            {
                for (i = 0; i < entry->lenmap; i++)
                    if (entry->map[i].dictIds)
                        pfree(entry->map[i].dictIds);
                pfree(entry->map);
            }
        }

        MemSet(entry, 0, sizeof(TSConfigCacheEntry));
        entry->cfgId = cfgId;
        entry->prsId = cfg->cfgparser;

        ReleaseSysCache(tp);

        /*
         * Scan pg_ts_config_map to gather dictionary list for each token type
         *
         * Because the index is on (mapcfg, maptokentype, mapseqno), we will
         * see the entries in maptokentype order, and in mapseqno order for
         * each token type, even though we didn't explicitly ask for that.
         */
        MemSet(maplists, 0, sizeof(maplists));
        maxtokentype = 0;
        ndicts = 0;

        ScanKeyInit(&mapskey,
                    Anum_pg_ts_config_map_mapcfg,
                    BTEqualStrategyNumber, F_OIDEQ,
                    ObjectIdGetDatum(cfgId));

        maprel = heap_open(TSConfigMapRelationId, AccessShareLock);
        mapidx = index_open(TSConfigMapIndexId, AccessShareLock);
        mapscan = systable_beginscan_ordered(maprel, mapidx,
                                             SnapshotNow, 1, &mapskey);

        while ((maptup = systable_getnext_ordered(mapscan, ForwardScanDirection)) != NULL)
        {
            Form_pg_ts_config_map cfgmap = (Form_pg_ts_config_map) GETSTRUCT(maptup);
            int         toktype = cfgmap->maptokentype;

            if (toktype <= 0 || toktype > MAXTOKENTYPE)
                elog(ERROR, "maptokentype value %d is out of range", toktype);
            if (toktype < maxtokentype)
                elog(ERROR, "maptokentype entries are out of order");
            if (toktype > maxtokentype)
            {
                /* starting a new token type, but first save the prior data */
                if (ndicts > 0)
                {
                    maplists[maxtokentype].len = ndicts;
                    maplists[maxtokentype].dictIds = (Oid *)
                        MemoryContextAlloc(CacheMemoryContext,
                                           sizeof(Oid) * ndicts);
                    memcpy(maplists[maxtokentype].dictIds, mapdicts,
                           sizeof(Oid) * ndicts);
                }
                maxtokentype = toktype;
                mapdicts[0] = cfgmap->mapdict;
                ndicts = 1;
            }
            else
            {
                /* continuing data for current token type */
                if (ndicts >= MAXDICTSPERTT)
                    elog(ERROR, "too many pg_ts_config_map entries for one token type");
                mapdicts[ndicts++] = cfgmap->mapdict;
            }
        }

        systable_endscan_ordered(mapscan);
        index_close(mapidx, AccessShareLock);
        heap_close(maprel, AccessShareLock);

        if (ndicts > 0)
        {
            /* save the last token type's dictionaries */
            maplists[maxtokentype].len = ndicts;
            maplists[maxtokentype].dictIds = (Oid *)
                MemoryContextAlloc(CacheMemoryContext,
                                   sizeof(Oid) * ndicts);
            memcpy(maplists[maxtokentype].dictIds, mapdicts,
                   sizeof(Oid) * ndicts);
            /* and save the overall map */
            entry->lenmap = maxtokentype + 1;
            entry->map = (ListDictionary *)
                MemoryContextAlloc(CacheMemoryContext,
                                   sizeof(ListDictionary) * entry->lenmap);
            memcpy(entry->map, maplists,
                   sizeof(ListDictionary) * entry->lenmap);
        }

        entry->isvalid = true;
    }

    lastUsedConfig = entry;

    return entry;
}

TSDictionaryCacheEntry* lookup_ts_dictionary_cache ( Oid  dictId  ) 

Definition at line 210 of file ts_cache.c.

References ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), Anum_pg_ts_dict_dictinitoption, Assert, CacheMemoryContext, CacheRegisterSyscacheCallback(), CreateCacheMemoryContext(), DatumGetPointer, deserialize_deflist(), TSDictionaryCacheEntry::dictCtx, TSDictionaryCacheEntry::dictData, TSDictionaryCacheEntry::dictId, elog, HASHCTL::entrysize, ERROR, fmgr_info_cxt(), GETSTRUCT, HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, hash_search(), HeapTupleIsValid, InvalidateTSCacheCallBack(), TSDictionaryCacheEntry::isvalid, HASHCTL::keysize, TSDictionaryCacheEntry::lexize, TSDictionaryCacheEntry::lexizeOid, MemoryContextResetAndDeleteChildren(), MemoryContextSwitchTo(), MemSet, NameStr, NULL, ObjectIdGetDatum, OidFunctionCall1, OidIsValid, PointerGetDatum, ReleaseSysCache(), SearchSysCache1, SysCacheGetAttr(), TSDICTOID, and TSTEMPLATEOID.

Referenced by LexizeExec(), thesaurus_init(), thesaurus_lexize(), ts_lexize(), and unaccent_dict().

{
    TSDictionaryCacheEntry *entry;

    if (TSDictionaryCacheHash == NULL)
    {
        /* First time through: initialize the hash table */
        HASHCTL     ctl;

        MemSet(&ctl, 0, sizeof(ctl));
        ctl.keysize = sizeof(Oid);
        ctl.entrysize = sizeof(TSDictionaryCacheEntry);
        ctl.hash = oid_hash;
        TSDictionaryCacheHash = hash_create("Tsearch dictionary cache", 8,
                                            &ctl, HASH_ELEM | HASH_FUNCTION);
        /* Flush cache on pg_ts_dict and pg_ts_template changes */
        CacheRegisterSyscacheCallback(TSDICTOID, InvalidateTSCacheCallBack,
                                      PointerGetDatum(TSDictionaryCacheHash));
        CacheRegisterSyscacheCallback(TSTEMPLATEOID, InvalidateTSCacheCallBack,
                                      PointerGetDatum(TSDictionaryCacheHash));

        /* Also make sure CacheMemoryContext exists */
        if (!CacheMemoryContext)
            CreateCacheMemoryContext();
    }

    /* Check single-entry cache */
    if (lastUsedDictionary && lastUsedDictionary->dictId == dictId &&
        lastUsedDictionary->isvalid)
        return lastUsedDictionary;

    /* Try to look up an existing entry */
    entry = (TSDictionaryCacheEntry *) hash_search(TSDictionaryCacheHash,
                                                   (void *) &dictId,
                                                   HASH_FIND, NULL);
    if (entry == NULL || !entry->isvalid)
    {
        /*
         * If we didn't find one, we want to make one. But first look up the
         * object to be sure the OID is real.
         */
        HeapTuple   tpdict,
                    tptmpl;
        Form_pg_ts_dict dict;
        Form_pg_ts_template template;
        MemoryContext saveCtx;

        tpdict = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
        if (!HeapTupleIsValid(tpdict))
            elog(ERROR, "cache lookup failed for text search dictionary %u",
                 dictId);
        dict = (Form_pg_ts_dict) GETSTRUCT(tpdict);

        /*
         * Sanity checks
         */
        if (!OidIsValid(dict->dicttemplate))
            elog(ERROR, "text search dictionary %u has no template", dictId);

        /*
         * Retrieve dictionary's template
         */
        tptmpl = SearchSysCache1(TSTEMPLATEOID,
                                 ObjectIdGetDatum(dict->dicttemplate));
        if (!HeapTupleIsValid(tptmpl))
            elog(ERROR, "cache lookup failed for text search template %u",
                 dict->dicttemplate);
        template = (Form_pg_ts_template) GETSTRUCT(tptmpl);

        /*
         * Sanity checks
         */
        if (!OidIsValid(template->tmpllexize))
            elog(ERROR, "text search template %u has no lexize method",
                 template->tmpllexize);

        if (entry == NULL)
        {
            bool        found;

            /* Now make the cache entry */
            entry = (TSDictionaryCacheEntry *)
                hash_search(TSDictionaryCacheHash,
                            (void *) &dictId,
                            HASH_ENTER, &found);
            Assert(!found);     /* it wasn't there a moment ago */

            /* Create private memory context the first time through */
            saveCtx = AllocSetContextCreate(CacheMemoryContext,
                                            NameStr(dict->dictname),
                                            ALLOCSET_SMALL_MINSIZE,
                                            ALLOCSET_SMALL_INITSIZE,
                                            ALLOCSET_SMALL_MAXSIZE);
        }
        else
        {
            /* Clear the existing entry's private context */
            saveCtx = entry->dictCtx;
            MemoryContextResetAndDeleteChildren(saveCtx);
        }

        MemSet(entry, 0, sizeof(TSDictionaryCacheEntry));
        entry->dictId = dictId;
        entry->dictCtx = saveCtx;

        entry->lexizeOid = template->tmpllexize;

        if (OidIsValid(template->tmplinit))
        {
            List       *dictoptions;
            Datum       opt;
            bool        isnull;
            MemoryContext oldcontext;

            /*
             * Init method runs in dictionary's private memory context, and we
             * make sure the options are stored there too
             */
            oldcontext = MemoryContextSwitchTo(entry->dictCtx);

            opt = SysCacheGetAttr(TSDICTOID, tpdict,
                                  Anum_pg_ts_dict_dictinitoption,
                                  &isnull);
            if (isnull)
                dictoptions = NIL;
            else
                dictoptions = deserialize_deflist(opt);

            entry->dictData =
                DatumGetPointer(OidFunctionCall1(template->tmplinit,
                                              PointerGetDatum(dictoptions)));

            MemoryContextSwitchTo(oldcontext);
        }

        ReleaseSysCache(tptmpl);
        ReleaseSysCache(tpdict);

        fmgr_info_cxt(entry->lexizeOid, &entry->lexize, entry->dictCtx);

        entry->isvalid = true;
    }

    lastUsedDictionary = entry;

    return entry;
}

TSParserCacheEntry* lookup_ts_parser_cache ( Oid  prsId  ) 

Definition at line 111 of file ts_cache.c.

References Assert, CacheMemoryContext, CacheRegisterSyscacheCallback(), CreateCacheMemoryContext(), elog, TSParserCacheEntry::endOid, HASHCTL::entrysize, ERROR, fmgr_info_cxt(), GETSTRUCT, HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, hash_search(), TSParserCacheEntry::headlineOid, HeapTupleIsValid, InvalidateTSCacheCallBack(), TSParserCacheEntry::isvalid, HASHCTL::keysize, TSParserCacheEntry::lextypeOid, MemSet, NULL, ObjectIdGetDatum, OidIsValid, PointerGetDatum, TSParserCacheEntry::prsend, TSParserCacheEntry::prsheadline, TSParserCacheEntry::prsId, TSParserCacheEntry::prsstart, TSParserCacheEntry::prstoken, ReleaseSysCache(), SearchSysCache1, TSParserCacheEntry::startOid, TSParserCacheEntry::tokenOid, and TSPARSEROID.

Referenced by getTokenTypes(), hlparsetext(), parsetext(), prs_setup_firstcall(), ts_headline_byid_opt(), and tt_setup_firstcall().

{
    TSParserCacheEntry *entry;

    if (TSParserCacheHash == NULL)
    {
        /* First time through: initialize the hash table */
        HASHCTL     ctl;

        MemSet(&ctl, 0, sizeof(ctl));
        ctl.keysize = sizeof(Oid);
        ctl.entrysize = sizeof(TSParserCacheEntry);
        ctl.hash = oid_hash;
        TSParserCacheHash = hash_create("Tsearch parser cache", 4,
                                        &ctl, HASH_ELEM | HASH_FUNCTION);
        /* Flush cache on pg_ts_parser changes */
        CacheRegisterSyscacheCallback(TSPARSEROID, InvalidateTSCacheCallBack,
                                      PointerGetDatum(TSParserCacheHash));

        /* Also make sure CacheMemoryContext exists */
        if (!CacheMemoryContext)
            CreateCacheMemoryContext();
    }

    /* Check single-entry cache */
    if (lastUsedParser && lastUsedParser->prsId == prsId &&
        lastUsedParser->isvalid)
        return lastUsedParser;

    /* Try to look up an existing entry */
    entry = (TSParserCacheEntry *) hash_search(TSParserCacheHash,
                                               (void *) &prsId,
                                               HASH_FIND, NULL);
    if (entry == NULL || !entry->isvalid)
    {
        /*
         * If we didn't find one, we want to make one. But first look up the
         * object to be sure the OID is real.
         */
        HeapTuple   tp;
        Form_pg_ts_parser prs;

        tp = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(prsId));
        if (!HeapTupleIsValid(tp))
            elog(ERROR, "cache lookup failed for text search parser %u",
                 prsId);
        prs = (Form_pg_ts_parser) GETSTRUCT(tp);

        /*
         * Sanity checks
         */
        if (!OidIsValid(prs->prsstart))
            elog(ERROR, "text search parser %u has no prsstart method", prsId);
        if (!OidIsValid(prs->prstoken))
            elog(ERROR, "text search parser %u has no prstoken method", prsId);
        if (!OidIsValid(prs->prsend))
            elog(ERROR, "text search parser %u has no prsend method", prsId);

        if (entry == NULL)
        {
            bool        found;

            /* Now make the cache entry */
            entry = (TSParserCacheEntry *)
                hash_search(TSParserCacheHash,
                            (void *) &prsId,
                            HASH_ENTER, &found);
            Assert(!found);     /* it wasn't there a moment ago */
        }

        MemSet(entry, 0, sizeof(TSParserCacheEntry));
        entry->prsId = prsId;
        entry->startOid = prs->prsstart;
        entry->tokenOid = prs->prstoken;
        entry->endOid = prs->prsend;
        entry->headlineOid = prs->prsheadline;
        entry->lextypeOid = prs->prslextype;

        ReleaseSysCache(tp);

        fmgr_info_cxt(entry->startOid, &entry->prsstart, CacheMemoryContext);
        fmgr_info_cxt(entry->tokenOid, &entry->prstoken, CacheMemoryContext);
        fmgr_info_cxt(entry->endOid, &entry->prsend, CacheMemoryContext);
        if (OidIsValid(entry->headlineOid))
            fmgr_info_cxt(entry->headlineOid, &entry->prsheadline,
                          CacheMemoryContext);

        entry->isvalid = true;
    }

    lastUsedParser = entry;

    return entry;
}


Variable Documentation

Definition at line 74 of file ts_cache.c.

Referenced by getTSCurrentConfig().