1 -- Functions for term normalisation and access to the 'word' table.
 
   3 CREATE OR REPLACE FUNCTION transliteration(text) RETURNS text
 
   4   AS '{modulepath}/nominatim.so', 'transliteration'
 
   5 LANGUAGE c IMMUTABLE STRICT;
 
   8 CREATE OR REPLACE FUNCTION gettokenstring(text) RETURNS text
 
   9   AS '{modulepath}/nominatim.so', 'gettokenstring'
 
  10 LANGUAGE c IMMUTABLE STRICT;
 
  13 CREATE OR REPLACE FUNCTION make_standard_name(name TEXT) RETURNS TEXT
 
  18   o := public.gettokenstring(public.transliteration(name));
 
  19   RETURN trim(substr(o,1,length(o)));
 
  22 LANGUAGE plpgsql IMMUTABLE;
 
  24 -- returns NULL if the word is too common
 
  25 CREATE OR REPLACE FUNCTION getorcreate_word_id(lookup_word TEXT) 
 
  30   return_word_id INTEGER;
 
  33   lookup_token := trim(lookup_word);
 
  34   SELECT min(word_id), max(search_name_count) FROM word
 
  35     WHERE word_token = lookup_token and class is null and type is null
 
  36     INTO return_word_id, count;
 
  37   IF return_word_id IS NULL THEN
 
  38     return_word_id := nextval('seq_word');
 
  39     INSERT INTO word VALUES (return_word_id, lookup_token, null, null, null, null, 0);
 
  41     IF count > get_maxwordfreq() THEN
 
  42       return_word_id := NULL;
 
  45   RETURN return_word_id;
 
  51 CREATE OR REPLACE FUNCTION getorcreate_housenumber_id(lookup_word TEXT)
 
  56   return_word_id INTEGER;
 
  58   lookup_token := ' ' || trim(lookup_word);
 
  59   SELECT min(word_id) FROM word
 
  60     WHERE word_token = lookup_token and class='place' and type='house'
 
  62   IF return_word_id IS NULL THEN
 
  63     return_word_id := nextval('seq_word');
 
  64     INSERT INTO word VALUES (return_word_id, lookup_token, null,
 
  65                              'place', 'house', null, 0);
 
  67   RETURN return_word_id;
 
  73 CREATE OR REPLACE FUNCTION getorcreate_postcode_id(postcode TEXT)
 
  79   return_word_id INTEGER;
 
  81   lookup_word := upper(trim(postcode));
 
  82   lookup_token := ' ' || make_standard_name(lookup_word);
 
  83   SELECT min(word_id) FROM word
 
  84     WHERE word_token = lookup_token and class='place' and type='postcode'
 
  86   IF return_word_id IS NULL THEN
 
  87     return_word_id := nextval('seq_word');
 
  88     INSERT INTO word VALUES (return_word_id, lookup_token, lookup_word,
 
  89                              'place', 'postcode', null, 0);
 
  91   RETURN return_word_id;
 
  97 CREATE OR REPLACE FUNCTION getorcreate_country(lookup_word TEXT,
 
  98                                                lookup_country_code varchar(2))
 
 103   return_word_id INTEGER;
 
 105   lookup_token := ' '||trim(lookup_word);
 
 106   SELECT min(word_id) FROM word
 
 107     WHERE word_token = lookup_token and country_code=lookup_country_code
 
 109   IF return_word_id IS NULL THEN
 
 110     return_word_id := nextval('seq_word');
 
 111     INSERT INTO word VALUES (return_word_id, lookup_token, null,
 
 112                              null, null, lookup_country_code, 0);
 
 114   RETURN return_word_id;
 
 120 CREATE OR REPLACE FUNCTION getorcreate_amenity(lookup_word TEXT, normalized_word TEXT,
 
 121                                                lookup_class text, lookup_type text)
 
 126   return_word_id INTEGER;
 
 128   lookup_token := ' '||trim(lookup_word);
 
 129   SELECT min(word_id) FROM word
 
 130   WHERE word_token = lookup_token and word = normalized_word
 
 131         and class = lookup_class and type = lookup_type
 
 133   IF return_word_id IS NULL THEN
 
 134     return_word_id := nextval('seq_word');
 
 135     INSERT INTO word VALUES (return_word_id, lookup_token, normalized_word,
 
 136                              lookup_class, lookup_type, null, 0);
 
 138   RETURN return_word_id;
 
 144 CREATE OR REPLACE FUNCTION getorcreate_amenityoperator(lookup_word TEXT,
 
 145                                                        normalized_word TEXT,
 
 153   return_word_id INTEGER;
 
 155   lookup_token := ' '||trim(lookup_word);
 
 156   SELECT min(word_id) FROM word
 
 157   WHERE word_token = lookup_token and word = normalized_word
 
 158         and class = lookup_class and type = lookup_type and operator = op
 
 160   IF return_word_id IS NULL THEN
 
 161     return_word_id := nextval('seq_word');
 
 162     INSERT INTO word VALUES (return_word_id, lookup_token, normalized_word,
 
 163                              lookup_class, lookup_type, null, 0, op);
 
 165   RETURN return_word_id;
 
 171 CREATE OR REPLACE FUNCTION getorcreate_name_id(lookup_word TEXT, src_word TEXT)
 
 176   nospace_lookup_token TEXT;
 
 177   return_word_id INTEGER;
 
 179   lookup_token := ' '||trim(lookup_word);
 
 180   SELECT min(word_id) FROM word
 
 181   WHERE word_token = lookup_token and class is null and type is null
 
 183   IF return_word_id IS NULL THEN
 
 184     return_word_id := nextval('seq_word');
 
 185     INSERT INTO word VALUES (return_word_id, lookup_token, src_word,
 
 186                              null, null, null, 0);
 
 188   RETURN return_word_id;
 
 194 CREATE OR REPLACE FUNCTION getorcreate_name_id(lookup_word TEXT)
 
 199   RETURN getorcreate_name_id(lookup_word, '');
 
 204 -- Normalize a string and lookup its word ids (partial words).
 
 205 CREATE OR REPLACE FUNCTION addr_ids_from_name(lookup_word TEXT)
 
 210   return_word_id INTEGER[];
 
 212   lookup_token := make_standard_name(lookup_word);
 
 213   SELECT array_agg(word_id) FROM word
 
 214     WHERE word_token = lookup_token and class is null and type is null
 
 216   RETURN return_word_id;
 
 219 LANGUAGE plpgsql STABLE;
 
 222 -- Normalize a string and look up its name ids (full words).
 
 223 CREATE OR REPLACE FUNCTION word_ids_from_name(lookup_word TEXT)
 
 228   return_word_ids INTEGER[];
 
 230   lookup_token := ' '|| make_standard_name(lookup_word);
 
 231   SELECT array_agg(word_id) FROM word
 
 232     WHERE word_token = lookup_token and class is null and type is null
 
 233     INTO return_word_ids;
 
 234   RETURN return_word_ids;
 
 237 LANGUAGE plpgsql STABLE STRICT;
 
 240 CREATE OR REPLACE FUNCTION create_country(src HSTORE, country_code varchar(2))
 
 250   FOR item IN SELECT (each(src)).* LOOP
 
 252     s := make_standard_name(item.value);
 
 253     w := getorcreate_country(s, country_code);
 
 255     words := regexp_split_to_array(item.value, E'[,;()]');
 
 256     IF array_upper(words, 1) != 1 THEN
 
 257       FOR j IN 1..array_upper(words, 1) LOOP
 
 258         s := make_standard_name(words[j]);
 
 260           w := getorcreate_country(s, country_code);
 
 270 CREATE OR REPLACE FUNCTION make_keywords(src HSTORE)
 
 281   result := '{}'::INTEGER[];
 
 283   FOR item IN SELECT (each(src)).* LOOP
 
 285     s := make_standard_name(item.value);
 
 286     w := getorcreate_name_id(s, item.value);
 
 288     IF not(ARRAY[w] <@ result) THEN
 
 289       result := result || w;
 
 292     w := getorcreate_word_id(s);
 
 294     IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
 
 295       result := result || w;
 
 298     words := string_to_array(s, ' ');
 
 299     IF array_upper(words, 1) IS NOT NULL THEN
 
 300       FOR j IN 1..array_upper(words, 1) LOOP
 
 301         IF (words[j] != '') THEN
 
 302           w = getorcreate_word_id(words[j]);
 
 303           IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
 
 304             result := result || w;
 
 310     words := regexp_split_to_array(item.value, E'[,;()]');
 
 311     IF array_upper(words, 1) != 1 THEN
 
 312       FOR j IN 1..array_upper(words, 1) LOOP
 
 313         s := make_standard_name(words[j]);
 
 315           w := getorcreate_word_id(s);
 
 316           IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
 
 317             result := result || w;
 
 323     s := regexp_replace(item.value, '市$', '');
 
 324     IF s != item.value THEN
 
 325       s := make_standard_name(s);
 
 327         w := getorcreate_name_id(s, item.value);
 
 328         IF NOT (ARRAY[w] <@ result) THEN
 
 329           result := result || w;
 
 342 CREATE OR REPLACE FUNCTION make_keywords(src TEXT)
 
 353   result := '{}'::INTEGER[];
 
 355   s := make_standard_name(src);
 
 356   w := getorcreate_name_id(s, src);
 
 358   IF NOT (ARRAY[w] <@ result) THEN
 
 359     result := result || w;
 
 362   w := getorcreate_word_id(s);
 
 364   IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
 
 365     result := result || w;
 
 368   words := string_to_array(s, ' ');
 
 369   IF array_upper(words, 1) IS NOT NULL THEN
 
 370     FOR j IN 1..array_upper(words, 1) LOOP
 
 371       IF (words[j] != '') THEN
 
 372         w = getorcreate_word_id(words[j]);
 
 373         IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
 
 374           result := result || w;
 
 380   words := regexp_split_to_array(src, E'[,;()]');
 
 381   IF array_upper(words, 1) != 1 THEN
 
 382     FOR j IN 1..array_upper(words, 1) LOOP
 
 383       s := make_standard_name(words[j]);
 
 385         w := getorcreate_word_id(s);
 
 386         IF w IS NOT NULL AND NOT (ARRAY[w] <@ result) THEN
 
 387           result := result || w;
 
 393   s := regexp_replace(src, '市$', '');
 
 395     s := make_standard_name(s);
 
 397       w := getorcreate_name_id(s, src);
 
 398       IF NOT (ARRAY[w] <@ result) THEN
 
 399         result := result || w;