Header And Logo

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

Data Structures | Functions

dict_synonym.c File Reference

#include "postgres.h"
#include "commands/defrem.h"
#include "tsearch/ts_locale.h"
#include "tsearch/ts_utils.h"
Include dependency graph for dict_synonym.c:

Go to the source code of this file.

Data Structures

struct  Syn
struct  DictSyn

Functions

static char * findwrd (char *in, char **end, uint16 *flags)
static int compareSyn (const void *a, const void *b)
Datum dsynonym_init (PG_FUNCTION_ARGS)
Datum dsynonym_lexize (PG_FUNCTION_ARGS)

Function Documentation

static int compareSyn ( const void *  a,
const void *  b 
) [static]

Definition at line 84 of file dict_synonym.c.

Referenced by dsynonym_init().

{
    return strcmp(((const Syn *) a)->in, ((const Syn *) b)->in);
}

Datum dsynonym_init ( PG_FUNCTION_ARGS   ) 

Definition at line 91 of file dict_synonym.c.

References DictSyn::case_sensitive, compareSyn(), cur, defGetBoolean(), defGetString(), DefElem::defname, end, ereport, errcode(), errmsg(), ERROR, filename, findwrd(), Syn::flags, get_tsearch_config_filename(), Syn::in, DictSyn::len, lfirst, lowerstr(), NULL, Syn::out, Syn::outlen, palloc(), palloc0(), pfree(), PG_GETARG_POINTER, PG_RETURN_POINTER, pg_strcasecmp(), pstrdup(), qsort, repalloc(), DictSyn::syn, tsearch_readline(), tsearch_readline_begin(), and tsearch_readline_end().

{
    List       *dictoptions = (List *) PG_GETARG_POINTER(0);
    DictSyn    *d;
    ListCell   *l;
    char       *filename = NULL;
    bool        case_sensitive = false;
    tsearch_readline_state trst;
    char       *starti,
               *starto,
               *end = NULL;
    int         cur = 0;
    char       *line = NULL;
    uint16      flags = 0;

    foreach(l, dictoptions)
    {
        DefElem    *defel = (DefElem *) lfirst(l);

        if (pg_strcasecmp("Synonyms", defel->defname) == 0)
            filename = defGetString(defel);
        else if (pg_strcasecmp("CaseSensitive", defel->defname) == 0)
            case_sensitive = defGetBoolean(defel);
        else
            ereport(ERROR,
                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                     errmsg("unrecognized synonym parameter: \"%s\"",
                            defel->defname)));
    }

    if (!filename)
        ereport(ERROR,
                (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
                 errmsg("missing Synonyms parameter")));

    filename = get_tsearch_config_filename(filename, "syn");

    if (!tsearch_readline_begin(&trst, filename))
        ereport(ERROR,
                (errcode(ERRCODE_CONFIG_FILE_ERROR),
                 errmsg("could not open synonym file \"%s\": %m",
                        filename)));

    d = (DictSyn *) palloc0(sizeof(DictSyn));

    while ((line = tsearch_readline(&trst)) != NULL)
    {
        starti = findwrd(line, &end, NULL);
        if (!starti)
        {
            /* Empty line */
            goto skipline;
        }
        if (*end == '\0')
        {
            /* A line with only one word. Ignore silently. */
            goto skipline;
        }
        *end = '\0';

        starto = findwrd(end + 1, &end, &flags);
        if (!starto)
        {
            /* A line with only one word (+whitespace). Ignore silently. */
            goto skipline;
        }
        *end = '\0';

        /*
         * starti now points to the first word, and starto to the second word
         * on the line, with a \0 terminator at the end of both words.
         */

        if (cur >= d->len)
        {
            if (d->len == 0)
            {
                d->len = 64;
                d->syn = (Syn *) palloc(sizeof(Syn) * d->len);
            }
            else
            {
                d->len *= 2;
                d->syn = (Syn *) repalloc(d->syn, sizeof(Syn) * d->len);
            }
        }

        if (case_sensitive)
        {
            d->syn[cur].in = pstrdup(starti);
            d->syn[cur].out = pstrdup(starto);
        }
        else
        {
            d->syn[cur].in = lowerstr(starti);
            d->syn[cur].out = lowerstr(starto);
        }

        d->syn[cur].outlen = strlen(starto);
        d->syn[cur].flags = flags;

        cur++;

skipline:
        pfree(line);
    }

    tsearch_readline_end(&trst);

    d->len = cur;
    qsort(d->syn, d->len, sizeof(Syn), compareSyn);

    d->case_sensitive = case_sensitive;

    PG_RETURN_POINTER(d);
}

Datum dsynonym_lexize ( PG_FUNCTION_ARGS   ) 

Definition at line 209 of file dict_synonym.c.

References DictSyn::case_sensitive, Syn::flags, TSLexeme::flags, Syn::in, DictSyn::len, TSLexeme::lexeme, lowerstr_with_len(), NULL, Syn::out, Syn::outlen, palloc0(), pfree(), PG_GETARG_INT32, PG_GETARG_POINTER, PG_RETURN_POINTER, pnstrdup(), and DictSyn::syn.

{
    DictSyn    *d = (DictSyn *) PG_GETARG_POINTER(0);
    char       *in = (char *) PG_GETARG_POINTER(1);
    int32       len = PG_GETARG_INT32(2);
    Syn         key,
               *found;
    TSLexeme   *res;

    /* note: d->len test protects against Solaris bsearch-of-no-items bug */
    if (len <= 0 || d->len <= 0)
        PG_RETURN_POINTER(NULL);

    if (d->case_sensitive)
        key.in = pnstrdup(in, len);
    else
        key.in = lowerstr_with_len(in, len);

    key.out = NULL;

    found = (Syn *) bsearch(&key, d->syn, d->len, sizeof(Syn), compareSyn);
    pfree(key.in);

    if (!found)
        PG_RETURN_POINTER(NULL);

    res = palloc0(sizeof(TSLexeme) * 2);
    res[0].lexeme = pnstrdup(found->out, found->outlen);
    res[0].flags = found->flags;

    PG_RETURN_POINTER(res);
}

static char* findwrd ( char *  in,
char **  end,
uint16 flags 
) [static]

Definition at line 43 of file dict_synonym.c.

References pg_mblen(), t_iseq, and t_isspace.

Referenced by dsynonym_init().

{
    char       *start;
    char       *lastchar;

    /* Skip leading spaces */
    while (*in && t_isspace(in))
        in += pg_mblen(in);

    /* Return NULL on empty lines */
    if (*in == '\0')
    {
        *end = NULL;
        return NULL;
    }

    lastchar = start = in;

    /* Find end of word */
    while (*in && !t_isspace(in))
    {
        lastchar = in;
        in += pg_mblen(in);
    }

    if (in - lastchar == 1 && t_iseq(lastchar, '*') && flags)
    {
        *flags = TSL_PREFIX;
        *end = lastchar;
    }
    else
    {
        if (flags)
            *flags = 0;
        *end = in;
    }

    return start;
}