Datum spell_init(PG_FUNCTION_ARGS) { DictISpell *d; Map *cfg, *pcfg; text *in; bool affloaded = false, dictloaded = false, stoploaded = false; if (PG_ARGISNULL(0) || PG_GETARG_POINTER(0) == NULL) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("ISpell confguration error"))); d = (DictISpell *) malloc(sizeof(DictISpell)); if (!d) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); memset(d, 0, sizeof(DictISpell)); d->stoplist.wordop = lowerstr; in = PG_GETARG_TEXT_P(0); parse_cfgdict(in, &cfg); PG_FREE_IF_COPY(in, 0); pcfg = cfg; while (pcfg->key) { if (pg_strcasecmp("DictFile", pcfg->key) == 0) { if (dictloaded) { freeDictISpell(d); ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("dictionary already loaded"))); } if (NIImportDictionary(&(d->obj), pcfg->value)) { freeDictISpell(d); ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not load dictionary file \"%s\"", pcfg->value))); } dictloaded = true; } else if (pg_strcasecmp("AffFile", pcfg->key) == 0) { if (affloaded) { freeDictISpell(d); ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("affixes already loaded"))); } if (NIImportAffixes(&(d->obj), pcfg->value)) { freeDictISpell(d); ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not load affix file \"%s\"", pcfg->value))); } affloaded = true; } else if (pg_strcasecmp("StopFile", pcfg->key) == 0) { text *tmp = char2text(pcfg->value); if (stoploaded) { freeDictISpell(d); ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("stop words already loaded"))); } readstoplist(tmp, &(d->stoplist)); sortstoplist(&(d->stoplist)); pfree(tmp); stoploaded = true; } else { freeDictISpell(d); ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("unrecognized option: %s => %s", pcfg->key, pcfg->value))); } pfree(pcfg->key); pfree(pcfg->value); pcfg++; } pfree(cfg); if (affloaded && dictloaded) { NISortDictionary(&(d->obj)); NISortAffixes(&(d->obj)); } else if (!affloaded) { freeDictISpell(d); ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("no affixes"))); } else { freeDictISpell(d); ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("no dictionary"))); } PG_RETURN_POINTER(d); }
/* * Initializes the dictionary for use in backends - checks whether such dictionary * and list of stopwords is already used, and if not then parses it and loads it into * the shared segment. * * This is called through dispell_init() which is responsible for proper locking * of the shared memory (using SegmentInfo->lock). */ static void init_shared_dict(DictInfo * info, char * dictFile, char * affFile, char * stopFile) { int size; SharedIspellDict * shdict = NULL; SharedStopList * shstop = NULL; IspellDict * dict; StopList stoplist; /* DICTIONARY + AFFIXES */ /* TODO This should probably check that the filenames are not NULL, and maybe that * it exists. Or maybe that's handled by the NIImport* functions. */ /* lookup if the dictionary (words and affixes) is already loaded in the shared segment */ shdict = get_shared_dict(dictFile, affFile); /* load the dictionary / affixes if not yet defined */ if (shdict == NULL) { dict = (IspellDict *)palloc0(sizeof(IspellDict)); NIStartBuild(dict); NIImportDictionary(dict, get_tsearch_config_filename(dictFile, "dict")); NIImportAffixes(dict, get_tsearch_config_filename(affFile, "affix")); NISortDictionary(dict); NISortAffixes(dict); NIFinishBuild(dict); /* check available space in shared segment */ size = sizeIspellDict(dict, dictFile, affFile); if (size > segment_info->available) elog(ERROR, "shared dictionary %s.dict / %s.affix needs %d B, only %ld B available", dictFile, affFile, size, segment_info->available); /* fine, there's enough space - copy the dictionary */ shdict = copyIspellDict(dict, dictFile, affFile, size, dict->nspell); elog(INFO, "shared dictionary %s.dict / %s.affix loaded, used %d B, %ld B remaining", dictFile, affFile, size, segment_info->available); /* add the new dictionary to the linked list (of SharedIspellDict structures) */ shdict->next = segment_info->dict; segment_info->dict = shdict; } /* STOP WORDS */ /* lookup if the stop words are already loaded in the shared segment, but only if there * actually is a list */ if (stopFile != NULL) { shstop = get_shared_stop_list(stopFile); /* load the stopwords if not yet defined */ if (shstop == NULL) { readstoplist(stopFile, &stoplist, lowerstr); size = sizeStopList(&stoplist, stopFile); if (size > segment_info->available) { elog(ERROR, "shared stoplist %s.stop needs %d B, only %ld B available", stopFile, size, segment_info->available); } /* fine, there's enough space - copy the stoplist */ shstop = copyStopList(&stoplist, stopFile, size); elog(INFO, "shared stoplist %s.stop loaded, used %d B, %ld B remaining", affFile, size, segment_info->available); /* add the new stopword list to the linked list (of SharedStopList structures) */ shstop->next = segment_info->stop; segment_info->stop = shstop; } } /* Now, fill the DictInfo structure for the backend (references to dictionary, * stopwords and the filenames). */ info->dict = shdict; info->stop = shstop; info->lookup = GetCurrentTimestamp(); memcpy(info->dictFile, dictFile, strlen(dictFile) + 1); memcpy(info->affixFile, dictFile, strlen(affFile)+ 1); memcpy(info->stopFile, dictFile, strlen(stopFile) + 1); }