From: Sarah Hoffmann Date: Wed, 2 Nov 2016 18:21:29 +0000 (+0100) Subject: Merge pull request #548 from lonvia/query-ckeck-utf8 X-Git-Tag: v3.0.0~91 X-Git-Url: https://git.openstreetmap.org/nominatim.git/commitdiff_plain/cfb0f3f94ced30b8b44390367e07bc9b0cec787d?hp=7b1f35426dada3eb2d210dfc492e16d2f9a42894 Merge pull request #548 from lonvia/query-ckeck-utf8 check if query is valid unicode string --- diff --git a/docs/Installation.md b/docs/Installation.md index 5a3100e5..678f0556 100644 --- a/docs/Installation.md +++ b/docs/Installation.md @@ -38,7 +38,7 @@ For running Nominatim: * [PostgreSQL](http://www.postgresql.org) (9.1 or later) * [PostGIS](http://postgis.refractions.net) (2.0 or later) - * [PHP](http://php.net) + * [PHP](http://php.net) (5.4 or later) * PHP-pgsql * [PEAR::DB](http://pear.php.net/package/DB) * a webserver (apache or nginx are recommended) diff --git a/lib/Geocode.php b/lib/Geocode.php index ec3ce13b..03df6752 100644 --- a/lib/Geocode.php +++ b/lib/Geocode.php @@ -169,10 +169,10 @@ class Geocode } $this->sViewboxCentreSQL .= ")'::geometry,4326)"; - $this->sViewboxSmallSQL = 'st_buffer('.$this->sViewboxCentreSQL; + $this->sViewboxSmallSQL = 'ST_BUFFER('.$this->sViewboxCentreSQL; $this->sViewboxSmallSQL .= ','.($fRouteWidth/69).')'; - $this->sViewboxLargeSQL = 'st_buffer('.$this->sViewboxCentreSQL; + $this->sViewboxLargeSQL = 'ST_BUFFER('.$this->sViewboxCentreSQL; $this->sViewboxLargeSQL .= ','.($fRouteWidth/30).')'; } @@ -180,14 +180,15 @@ class Geocode { $this->aViewBox = array_map('floatval', $aViewbox); - if ($this->aViewBox[0] < -180 - || $this->aViewBox[2] > 180 - || $this->aViewBox[0] >= $this->aViewBox[2] - || $this->aViewBox[1] < -90 - || $this->aViewBox[3] > 90 - || $this->aViewBox[1] >= $this->aViewBox[3] + $this->aViewBox[0] = max(-180.0, min(180, $this->aViewBox[0])); + $this->aViewBox[1] = max(-90.0, min(90, $this->aViewBox[1])); + $this->aViewBox[2] = max(-180.0, min(180, $this->aViewBox[2])); + $this->aViewBox[3] = max(-90.0, min(90, $this->aViewBox[3])); + + if (abs($this->aViewBox[0] - $this->aViewBox[2]) < 0.000000001 + || abs($this->aViewBox[1] - $this->aViewBox[3]) < 0.000000001 ) { - userError("Bad parameter 'viewbox'. Out of range".$this->aViewBox[0]."|".$this->aViewBox[1]."|".$this->aViewBox[2]."|".$this->aViewBox[3]); + userError("Bad parameter 'viewbox'. Not a box."); } $fHeight = $this->aViewBox[0] - $this->aViewBox[2]; @@ -198,8 +199,20 @@ class Geocode $aBigViewBox[3] = $this->aViewBox[3] - $fWidth; $this->sViewboxCentreSQL = false; - $this->sViewboxSmallSQL = "ST_SetSRID(ST_MakeBox2D(ST_Point(".$this->aViewBox[0].",".$this->aViewBox[1]."),ST_Point(".$this->aViewBox[2].",".$this->aViewBox[3].")),4326)"; - $this->sViewboxLargeSQL = "ST_SetSRID(ST_MakeBox2D(ST_Point(".$aBigViewBox[0].",".$aBigViewBox[1]."),ST_Point(".$aBigViewBox[2].",".$aBigViewBox[3].")),4326)"; + $this->sViewboxSmallSQL = sprintf( + 'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)', + $this->aViewBox[0], + $this->aViewBox[1], + $this->aViewBox[2], + $this->aViewBox[3] + ); + $this->sViewboxLargeSQL = sprintf( + 'ST_SetSRID(ST_MakeBox2D(ST_Point(%F,%F),ST_Point(%F,%F)),4326)', + $aBigViewBox[0], + $aBigViewBox[1], + $aBigViewBox[2], + $aBigViewBox[3] + ); } public function setNearPoint($aNearPoint, $fRadiusDeg = 0.1) @@ -387,34 +400,71 @@ class Geocode $sPlaceIDs = join(',', array_keys($aPlaceIDs)); $sImportanceSQL = ''; - if ($this->sViewboxSmallSQL) $sImportanceSQL .= " case when ST_Contains($this->sViewboxSmallSQL, ST_Collect(centroid)) THEN 1 ELSE 0.75 END * "; - if ($this->sViewboxLargeSQL) $sImportanceSQL .= " case when ST_Contains($this->sViewboxLargeSQL, ST_Collect(centroid)) THEN 1 ELSE 0.75 END * "; - - $sSQL = "select osm_type,osm_id,class,type,admin_level,rank_search,rank_address,min(place_id) as place_id, min(parent_place_id) as parent_place_id, calculated_country_code as country_code,"; - $sSQL .= "get_address_by_language(place_id, -1, $sLanguagePrefArraySQL) as langaddress,"; - $sSQL .= "get_name_by_language(name, $sLanguagePrefArraySQL) as placename,"; - $sSQL .= "get_name_by_language(name, ARRAY['ref']) as ref,"; - if ($this->bIncludeExtraTags) $sSQL .= "hstore_to_json(extratags)::text as extra,"; - if ($this->bIncludeNameDetails) $sSQL .= "hstore_to_json(name)::text as names,"; - $sSQL .= "avg(ST_X(centroid)) as lon,avg(ST_Y(centroid)) as lat, "; - $sSQL .= $sImportanceSQL."coalesce(importance,0.75-(rank_search::float/40)) as importance, "; - $sSQL .= "(select max(p.importance*(p.rank_address+2)) from place_addressline s, placex p where s.place_id = min(CASE WHEN placex.rank_search < 28 THEN placex.place_id ELSE placex.parent_place_id END) and p.place_id = s.address_place_id and s.isaddress and p.importance is not null) as addressimportance, "; - $sSQL .= "(extratags->'place') as extra_place "; - $sSQL .= "from placex where place_id in ($sPlaceIDs) "; - $sSQL .= "and (placex.rank_address between $this->iMinAddressRank and $this->iMaxAddressRank "; - if (14 >= $this->iMinAddressRank && 14 <= $this->iMaxAddressRank) $sSQL .= " OR (extratags->'place') = 'city'"; - if ($this->aAddressRankList) $sSQL .= " OR placex.rank_address in (".join(',', $this->aAddressRankList).")"; - $sSQL .= ") "; - if ($this->sAllowedTypesSQLList) $sSQL .= "and placex.class in $this->sAllowedTypesSQLList "; - $sSQL .= "and linked_place_id is null "; - $sSQL .= "group by osm_type,osm_id,class,type,admin_level,rank_search,rank_address,calculated_country_code,importance"; - if (!$this->bDeDupe) $sSQL .= ",place_id"; - $sSQL .= ",langaddress "; - $sSQL .= ",placename "; - $sSQL .= ",ref "; - if ($this->bIncludeExtraTags) $sSQL .= ",extratags"; - if ($this->bIncludeNameDetails) $sSQL .= ",name"; - $sSQL .= ",extratags->'place' "; + if ($this->sViewboxSmallSQL) $sImportanceSQL .= " CASE WHEN ST_Contains($this->sViewboxSmallSQL, ST_Collect(centroid)) THEN 1 ELSE 0.75 END * "; + if ($this->sViewboxLargeSQL) $sImportanceSQL .= " CASE WHEN ST_Contains($this->sViewboxLargeSQL, ST_Collect(centroid)) THEN 1 ELSE 0.75 END * "; + + $sSQL = "SELECT "; + $sSQL .= " osm_type,"; + $sSQL .= " osm_id,"; + $sSQL .= " class,"; + $sSQL .= " type,"; + $sSQL .= " admin_level,"; + $sSQL .= " rank_search,"; + $sSQL .= " rank_address,"; + $sSQL .= " min(place_id) AS place_id, "; + $sSQL .= " min(parent_place_id) AS parent_place_id, "; + $sSQL .= " calculated_country_code AS country_code, "; + $sSQL .= " get_address_by_language(place_id, -1, $sLanguagePrefArraySQL) AS langaddress,"; + $sSQL .= " get_name_by_language(name, $sLanguagePrefArraySQL) AS placename,"; + $sSQL .= " get_name_by_language(name, ARRAY['ref']) AS ref,"; + if ($this->bIncludeExtraTags) $sSQL .= "hstore_to_json(extratags)::text AS extra,"; + if ($this->bIncludeNameDetails) $sSQL .= "hstore_to_json(name)::text AS names,"; + $sSQL .= " avg(ST_X(centroid)) AS lon, "; + $sSQL .= " avg(ST_Y(centroid)) AS lat, "; + $sSQL .= " ".$sImportanceSQL."COALESCE(importance,0.75-(rank_search::float/40)) AS importance, "; + $sSQL .= " ( "; + $sSQL .= " SELECT max(p.importance*(p.rank_address+2))"; + $sSQL .= " FROM "; + $sSQL .= " place_addressline s, "; + $sSQL .= " placex p"; + $sSQL .= " WHERE s.place_id = min(CASE WHEN placex.rank_search < 28 THEN placex.place_id ELSE placex.parent_place_id END)"; + $sSQL .= " AND p.place_id = s.address_place_id "; + $sSQL .= " AND s.isaddress "; + $sSQL .= " AND p.importance is not null "; + $sSQL .= " ) AS addressimportance, "; + $sSQL .= " (extratags->'place') AS extra_place "; + $sSQL .= " FROM placex"; + $sSQL .= " WHERE place_id in ($sPlaceIDs) "; + $sSQL .= " AND ("; + $sSQL .= " placex.rank_address between $this->iMinAddressRank and $this->iMaxAddressRank "; + if (14 >= $this->iMinAddressRank && 14 <= $this->iMaxAddressRank) { + $sSQL .= " OR (extratags->'place') = 'city'"; + } + if ($this->aAddressRankList) { + $sSQL .= " OR placex.rank_address in (".join(',', $this->aAddressRankList).")"; + } + $sSQL .= " ) "; + if ($this->sAllowedTypesSQLList) { + $sSQL .= "AND placex.class in $this->sAllowedTypesSQLList "; + } + $sSQL .= " AND linked_place_id is null "; + $sSQL .= " GROUP BY "; + $sSQL .= " osm_type, "; + $sSQL .= " osm_id, "; + $sSQL .= " class, "; + $sSQL .= " type, "; + $sSQL .= " admin_level, "; + $sSQL .= " rank_search, "; + $sSQL .= " rank_address, "; + $sSQL .= " calculated_country_code, "; + $sSQL .= " importance, "; + if (!$this->bDeDupe) $sSQL .= "place_id,"; + $sSQL .= " langaddress, "; + $sSQL .= " placename, "; + $sSQL .= " ref, "; + if ($this->bIncludeExtraTags) $sSQL .= "extratags, "; + if ($this->bIncludeNameDetails) $sSQL .= "name, "; + $sSQL .= " extratags->'place' "; if (30 >= $this->iMinAddressRank && 30 <= $this->iMaxAddressRank) { // only Tiger housenumbers and interpolation lines need to be interpolated, because they are saved as lines @@ -427,70 +477,156 @@ class Geocode $sHousenumbers .= "(".$placeID.", ".$housenumber.")"; if ($i<$length) $sHousenumbers .= ", "; } + if (CONST_Use_US_Tiger_Data) { // Tiger search only if a housenumber was searched and if it was found (i.e. aPlaceIDs[placeID] = housenumber != -1) (realized through a join) $sSQL .= " union"; - $sSQL .= " select 'T' as osm_type, place_id as osm_id, 'place' as class, 'house' as type, null as admin_level, 30 as rank_search, 30 as rank_address, min(place_id) as place_id, min(parent_place_id) as parent_place_id, 'us' as country_code"; - $sSQL .= ", get_address_by_language(place_id, housenumber_for_place, $sLanguagePrefArraySQL) as langaddress "; - $sSQL .= ", null as placename"; - $sSQL .= ", null as ref"; - if ($this->bIncludeExtraTags) $sSQL .= ", null as extra"; - if ($this->bIncludeNameDetails) $sSQL .= ", null as names"; - $sSQL .= ", avg(st_x(centroid)) as lon, avg(st_y(centroid)) as lat,"; - $sSQL .= $sImportanceSQL."-1.15 as importance "; - $sSQL .= ", (select max(p.importance*(p.rank_address+2)) from place_addressline s, placex p where s.place_id = min(blub.parent_place_id) and p.place_id = s.address_place_id and s.isaddress and p.importance is not null) as addressimportance "; - $sSQL .= ", null as extra_place "; - $sSQL .= " from (select place_id"; - // interpolate the Tiger housenumbers here - $sSQL .= ", ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) as centroid, parent_place_id, housenumber_for_place"; - $sSQL .= " from (location_property_tiger "; - $sSQL .= " join (values ".$sHousenumbers.") as housenumbers(place_id, housenumber_for_place) using(place_id)) "; - $sSQL .= " where housenumber_for_place>=0 and 30 between $this->iMinAddressRank and $this->iMaxAddressRank) as blub"; //postgres wants an alias here - $sSQL .= " group by place_id, housenumber_for_place"; //is this group by really needed?, place_id + housenumber (in combination) are unique + $sSQL .= " SELECT "; + $sSQL .= " 'T' AS osm_type, "; + $sSQL .= " (SELECT osm_id from placex p WHERE p.place_id=min(blub.parent_place_id)) as osm_id, "; + $sSQL .= " 'place' AS class, "; + $sSQL .= " 'house' AS type, "; + $sSQL .= " null AS admin_level, "; + $sSQL .= " 30 AS rank_search, "; + $sSQL .= " 30 AS rank_address, "; + $sSQL .= " min(place_id) AS place_id, "; + $sSQL .= " min(parent_place_id) AS parent_place_id, "; + $sSQL .= " 'us' AS country_code, "; + $sSQL .= " get_address_by_language(place_id, housenumber_for_place, $sLanguagePrefArraySQL) AS langaddress,"; + $sSQL .= " null AS placename, "; + $sSQL .= " null AS ref, "; + if ($this->bIncludeExtraTags) $sSQL .= "null AS extra,"; + if ($this->bIncludeNameDetails) $sSQL .= "null AS names,"; + $sSQL .= " avg(st_x(centroid)) AS lon, "; + $sSQL .= " avg(st_y(centroid)) AS lat,"; + $sSQL .= " ".$sImportanceSQL."-1.15 AS importance, "; + $sSQL .= " ("; + $sSQL .= " SELECT max(p.importance*(p.rank_address+2))"; + $sSQL .= " FROM "; + $sSQL .= " place_addressline s, "; + $sSQL .= " placex p"; + $sSQL .= " WHERE s.place_id = min(blub.parent_place_id)"; + $sSQL .= " AND p.place_id = s.address_place_id "; + $sSQL .= " AND s.isaddress"; + $sSQL .= " AND p.importance is not null"; + $sSQL .= " ) AS addressimportance, "; + $sSQL .= " null AS extra_place "; + $sSQL .= " FROM ("; + $sSQL .= " SELECT place_id, "; // interpolate the Tiger housenumbers here + $sSQL .= " ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) AS centroid, "; + $sSQL .= " parent_place_id, "; + $sSQL .= " housenumber_for_place"; + $sSQL .= " FROM ("; + $sSQL .= " location_property_tiger "; + $sSQL .= " JOIN (values ".$sHousenumbers.") AS housenumbers(place_id, housenumber_for_place) USING(place_id)) "; + $sSQL .= " WHERE "; + $sSQL .= " housenumber_for_place>=0"; + $sSQL .= " AND 30 between $this->iMinAddressRank AND $this->iMaxAddressRank"; + $sSQL .= " ) AS blub"; //postgres wants an alias here + $sSQL .= " GROUP BY"; + $sSQL .= " place_id, "; + $sSQL .= " housenumber_for_place"; //is this group by really needed?, place_id + housenumber (in combination) are unique if (!$this->bDeDupe) $sSQL .= ", place_id "; } // osmline // interpolation line search only if a housenumber was searched and if it was found (i.e. aPlaceIDs[placeID] = housenumber != -1) (realized through a join) - $sSQL .= " union "; - $sSQL .= "select 'W' as osm_type, place_id as osm_id, 'place' as class, 'house' as type, null as admin_level, 30 as rank_search, 30 as rank_address, min(place_id) as place_id, min(parent_place_id) as parent_place_id, calculated_country_code as country_code, "; - $sSQL .= "get_address_by_language(place_id, housenumber_for_place, $sLanguagePrefArraySQL) as langaddress, "; - $sSQL .= "null as placename, "; - $sSQL .= "null as ref, "; - if ($this->bIncludeExtraTags) $sSQL .= "null as extra, "; - if ($this->bIncludeNameDetails) $sSQL .= "null as names, "; - $sSQL .= " avg(st_x(centroid)) as lon, avg(st_y(centroid)) as lat,"; - $sSQL .= $sImportanceSQL."-0.1 as importance, "; // slightly smaller than the importance for normal houses with rank 30, which is 0 - $sSQL .= " (select max(p.importance*(p.rank_address+2)) from place_addressline s, placex p"; - $sSQL .= " where s.place_id = min(blub.parent_place_id) and p.place_id = s.address_place_id and s.isaddress and p.importance is not null) as addressimportance,"; - $sSQL .= " null as extra_place "; - $sSQL .= " from (select place_id, calculated_country_code "; - // interpolate the housenumbers here - $sSQL .= ", CASE WHEN startnumber != endnumber THEN ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) "; - $sSQL .= " ELSE ST_LineInterpolatePoint(linegeo, 0.5) END as centroid"; - $sSQL .= ", parent_place_id, housenumber_for_place "; - $sSQL .= " from (location_property_osmline "; - $sSQL .= " join (values ".$sHousenumbers.") as housenumbers(place_id, housenumber_for_place) using(place_id)) "; - $sSQL .= " where housenumber_for_place>=0 and 30 between $this->iMinAddressRank and $this->iMaxAddressRank) as blub"; //postgres wants an alias here - $sSQL .= " group by place_id, housenumber_for_place, calculated_country_code "; //is this group by really needed?, place_id + housenumber (in combination) are unique + $sSQL .= " UNION "; + $sSQL .= "SELECT "; + $sSQL .= " 'W' AS osm_type, "; + $sSQL .= " osm_id, "; + $sSQL .= " 'place' AS class, "; + $sSQL .= " 'house' AS type, "; + $sSQL .= " null AS admin_level, "; + $sSQL .= " 30 AS rank_search, "; + $sSQL .= " 30 AS rank_address, "; + $sSQL .= " min(place_id) as place_id, "; + $sSQL .= " min(parent_place_id) AS parent_place_id, "; + $sSQL .= " calculated_country_code AS country_code, "; + $sSQL .= " get_address_by_language(place_id, housenumber_for_place, $sLanguagePrefArraySQL) AS langaddress, "; + $sSQL .= " null AS placename, "; + $sSQL .= " null AS ref, "; + if ($this->bIncludeExtraTags) $sSQL .= "null AS extra, "; + if ($this->bIncludeNameDetails) $sSQL .= "null AS names, "; + $sSQL .= " AVG(st_x(centroid)) AS lon, "; + $sSQL .= " AVG(st_y(centroid)) AS lat, "; + $sSQL .= " ".$sImportanceSQL."-0.1 AS importance, "; // slightly smaller than the importance for normal houses with rank 30, which is 0 + $sSQL .= " ("; + $sSQL .= " SELECT "; + $sSQL .= " MAX(p.importance*(p.rank_address+2)) "; + $sSQL .= " FROM"; + $sSQL .= " place_addressline s, "; + $sSQL .= " placex p"; + $sSQL .= " WHERE s.place_id = min(blub.parent_place_id) "; + $sSQL .= " AND p.place_id = s.address_place_id "; + $sSQL .= " AND s.isaddress "; + $sSQL .= " AND p.importance is not null"; + $sSQL .= " ) AS addressimportance,"; + $sSQL .= " null AS extra_place "; + $sSQL .= " FROM ("; + $sSQL .= " SELECT "; + $sSQL .= " osm_id, "; + $sSQL .= " place_id, "; + $sSQL .= " calculated_country_code, "; + $sSQL .= " CASE "; // interpolate the housenumbers here + $sSQL .= " WHEN startnumber != endnumber "; + $sSQL .= " THEN ST_LineInterpolatePoint(linegeo, (housenumber_for_place-startnumber::float)/(endnumber-startnumber)::float) "; + $sSQL .= " ELSE ST_LineInterpolatePoint(linegeo, 0.5) "; + $sSQL .= " END as centroid, "; + $sSQL .= " parent_place_id, "; + $sSQL .= " housenumber_for_place "; + $sSQL .= " FROM ("; + $sSQL .= " location_property_osmline "; + $sSQL .= " JOIN (values ".$sHousenumbers.") AS housenumbers(place_id, housenumber_for_place) USING(place_id)"; + $sSQL .= " ) "; + $sSQL .= " WHERE housenumber_for_place>=0 "; + $sSQL .= " AND 30 between $this->iMinAddressRank AND $this->iMaxAddressRank"; + $sSQL .= " ) as blub"; //postgres wants an alias here + $sSQL .= " GROUP BY "; + $sSQL .= " osm_id, "; + $sSQL .= " place_id, "; + $sSQL .= " housenumber_for_place, "; + $sSQL .= " calculated_country_code "; //is this group by really needed?, place_id + housenumber (in combination) are unique if (!$this->bDeDupe) $sSQL .= ", place_id "; if (CONST_Use_Aux_Location_data) { - $sSQL .= " union "; - $sSQL .= "select 'L' as osm_type, place_id as osm_id, 'place' as class, 'house' as type, null as admin_level, 0 as rank_search, 0 as rank_address, min(place_id) as place_id, min(parent_place_id) as parent_place_id, 'us' as country_code, "; - $sSQL .= "get_address_by_language(place_id, -1, $sLanguagePrefArraySQL) as langaddress, "; - $sSQL .= "null as placename, "; - $sSQL .= "null as ref, "; - if ($this->bIncludeExtraTags) $sSQL .= "null as extra, "; - if ($this->bIncludeNameDetails) $sSQL .= "null as names, "; - $sSQL .= "avg(ST_X(centroid)) as lon, avg(ST_Y(centroid)) as lat, "; - $sSQL .= $sImportanceSQL."-1.10 as importance, "; - $sSQL .= "(select max(p.importance*(p.rank_address+2)) from place_addressline s, placex p where s.place_id = min(location_property_aux.parent_place_id) and p.place_id = s.address_place_id and s.isaddress and p.importance is not null) as addressimportance, "; - $sSQL .= "null as extra_place "; - $sSQL .= "from location_property_aux where place_id in ($sPlaceIDs) "; - $sSQL .= "and 30 between $this->iMinAddressRank and $this->iMaxAddressRank "; - $sSQL .= "group by place_id"; - if (!$this->bDeDupe) $sSQL .= ", place_id"; - $sSQL .= ", get_address_by_language(place_id, -1, $sLanguagePrefArraySQL) "; + $sSQL .= " UNION "; + $sSQL .= " SELECT "; + $sSQL .= " 'L' AS osm_type, "; + $sSQL .= " place_id AS osm_id, "; + $sSQL .= " 'place' AS class,"; + $sSQL .= " 'house' AS type, "; + $sSQL .= " null AS admin_level, "; + $sSQL .= " 0 AS rank_search,"; + $sSQL .= " 0 AS rank_address, "; + $sSQL .= " min(place_id) AS place_id,"; + $sSQL .= " min(parent_place_id) AS parent_place_id, "; + $sSQL .= " 'us' AS country_code, "; + $sSQL .= " get_address_by_language(place_id, -1, $sLanguagePrefArraySQL) AS langaddress, "; + $sSQL .= " null AS placename, "; + $sSQL .= " null AS ref, "; + if ($this->bIncludeExtraTags) $sSQL .= "null AS extra, "; + if ($this->bIncludeNameDetails) $sSQL .= "null AS names, "; + $sSQL .= " avg(ST_X(centroid)) AS lon, "; + $sSQL .= " avg(ST_Y(centroid)) AS lat, "; + $sSQL .= " ".$sImportanceSQL."-1.10 AS importance, "; + $sSQL .= " ( "; + $sSQL .= " SELECT max(p.importance*(p.rank_address+2))"; + $sSQL .= " FROM "; + $sSQL .= " place_addressline s, "; + $sSQL .= " placex p"; + $sSQL .= " WHERE s.place_id = min(location_property_aux.parent_place_id)"; + $sSQL .= " AND p.place_id = s.address_place_id "; + $sSQL .= " AND s.isaddress"; + $sSQL .= " AND p.importance is not null"; + $sSQL .= " ) AS addressimportance, "; + $sSQL .= " null AS extra_place "; + $sSQL .= " FROM location_property_aux "; + $sSQL .= " WHERE place_id in ($sPlaceIDs) "; + $sSQL .= " AND 30 between $this->iMinAddressRank and $this->iMaxAddressRank "; + $sSQL .= " GROUP BY "; + $sSQL .= " place_id, "; + if (!$this->bDeDupe) $sSQL .= "place_id, "; + $sSQL .= " get_address_by_language(place_id, -1, $sLanguagePrefArraySQL) "; } } @@ -856,9 +992,15 @@ class Geocode foreach ($aSpecialTermsRaw as $aSpecialTerm) { $sQuery = str_replace($aSpecialTerm[0], ' ', $sQuery); - $sToken = chksql($this->oDB->getOne("select make_standard_name('".$aSpecialTerm[1]."') as string")); - $sSQL = 'select * from (select word_id,word_token, word, class, type, country_code, operator'; - $sSQL .= ' from word where word_token in (\' '.$sToken.'\')) as x where (class is not null and class not in (\'place\')) or country_code is not null'; + $sToken = chksql($this->oDB->getOne("SELECT make_standard_name('".$aSpecialTerm[1]."') AS string")); + $sSQL = 'SELECT * '; + $sSQL .= 'FROM ( '; + $sSQL .= ' SELECT word_id, word_token, word, class, type, country_code, operator'; + $sSQL .= ' FROM word '; + $sSQL .= ' WHERE word_token in (\' '.$sToken.'\')'; + $sSQL .= ') AS x '; + $sSQL .= ' WHERE (class is not null AND class not in (\'place\')) '; + $sSQL .= ' OR country_code is not null'; if (CONST_Debug) var_Dump($sSQL); $aSearchWords = chksql($this->oDB->getAll($sSQL)); $aNewSearches = array(); @@ -898,7 +1040,7 @@ class Geocode $aTokens = array(); foreach ($aPhrases as $iPhrase => $sPhrase) { $aPhrase = chksql( - $this->oDB->getRow("select make_standard_name('".pg_escape_string($sPhrase)."') as string"), + $this->oDB->getRow("SELECT make_standard_name('".pg_escape_string($sPhrase)."') as string"), "Cannot normalize query string (is it a UTF-8 string?)" ); if (trim($aPhrase['string'])) { @@ -917,8 +1059,9 @@ class Geocode if (sizeof($aTokens)) { // Check which tokens we have, get the ID numbers - $sSQL = 'select word_id,word_token, word, class, type, country_code, operator, search_name_count'; - $sSQL .= ' from word where word_token in ('.join(',', array_map("getDBQuoted", $aTokens)).')'; + $sSQL = 'SELECT word_id, word_token, word, class, type, country_code, operator, search_name_count'; + $sSQL .= ' FROM word '; + $sSQL .= ' WHERE word_token in ('.join(',', array_map("getDBQuoted", $aTokens)).')'; if (CONST_Debug) var_Dump($sSQL); @@ -1094,11 +1237,11 @@ class Geocode if ($aSearch['sCountryCode'] && !$aSearch['sClass'] && !$aSearch['sHouseNumber']) { // Just looking for a country by code - look it up if (4 >= $this->iMinAddressRank && 4 <= $this->iMaxAddressRank) { - $sSQL = "select place_id from placex where calculated_country_code='".$aSearch['sCountryCode']."' and rank_search = 4"; - if ($sCountryCodesSQL) $sSQL .= " and calculated_country_code in ($sCountryCodesSQL)"; + $sSQL = "SELECT place_id FROM placex WHERE calculated_country_code='".$aSearch['sCountryCode']."' AND rank_search = 4"; + if ($sCountryCodesSQL) $sSQL .= " AND calculated_country_code in ($sCountryCodesSQL)"; if ($bBoundingBoxSearch) - $sSQL .= " and _st_intersects($this->sViewboxSmallSQL, geometry)"; - $sSQL .= " order by st_area(geometry) desc limit 1"; + $sSQL .= " AND _st_intersects($this->sViewboxSmallSQL, geometry)"; + $sSQL .= " ORDER BY st_area(geometry) DESC LIMIT 1"; if (CONST_Debug) var_dump($sSQL); $aPlaceIDs = chksql($this->oDB->getCol($sSQL)); } else { @@ -1108,16 +1251,16 @@ class Geocode if (!$bBoundingBoxSearch && !$aSearch['fLon']) continue; if (!$aSearch['sClass']) continue; - $sSQL = "select count(*) from pg_tables where tablename = 'place_classtype_".$aSearch['sClass']."_".$aSearch['sType']."'"; + $sSQL = "SELECT COUNT(*) FROM pg_tables WHERE tablename = 'place_classtype_".$aSearch['sClass']."_".$aSearch['sType']."'"; if (chksql($this->oDB->getOne($sSQL))) { - $sSQL = "select place_id from place_classtype_".$aSearch['sClass']."_".$aSearch['sType']." ct"; - if ($sCountryCodesSQL) $sSQL .= " join placex using (place_id)"; - $sSQL .= " where st_contains($this->sViewboxSmallSQL, ct.centroid)"; - if ($sCountryCodesSQL) $sSQL .= " and calculated_country_code in ($sCountryCodesSQL)"; + $sSQL = "SELECT place_id FROM place_classtype_".$aSearch['sClass']."_".$aSearch['sType']." ct"; + if ($sCountryCodesSQL) $sSQL .= " JOIN placex USING (place_id)"; + $sSQL .= " WHERE st_contains($this->sViewboxSmallSQL, ct.centroid)"; + if ($sCountryCodesSQL) $sSQL .= " AND calculated_country_code in ($sCountryCodesSQL)"; if (sizeof($this->aExcludePlaceIDs)) { - $sSQL .= " and place_id not in (".join(',', $this->aExcludePlaceIDs).")"; + $sSQL .= " AND place_id not in (".join(',', $this->aExcludePlaceIDs).")"; } - if ($this->sViewboxCentreSQL) $sSQL .= " order by st_distance($this->sViewboxCentreSQL, ct.centroid) asc"; + if ($this->sViewboxCentreSQL) $sSQL .= " ORDER BY ST_Distance($this->sViewboxCentreSQL, ct.centroid) ASC"; $sSQL .= " limit $this->iLimit"; if (CONST_Debug) var_dump($sSQL); $aPlaceIDs = chksql($this->oDB->getCol($sSQL)); @@ -1127,21 +1270,25 @@ class Geocode // expansion in that case. // Also don't expand if bounded results were requested. if (!sizeof($aPlaceIDs) && !sizeof($this->aExcludePlaceIDs) && !$this->bBoundedSearch) { - $sSQL = "select place_id from place_classtype_".$aSearch['sClass']."_".$aSearch['sType']." ct"; + $sSQL = "SELECT place_id FROM place_classtype_".$aSearch['sClass']."_".$aSearch['sType']." ct"; if ($sCountryCodesSQL) $sSQL .= " join placex using (place_id)"; - $sSQL .= " where st_contains($this->sViewboxLargeSQL, ct.centroid)"; - if ($sCountryCodesSQL) $sSQL .= " and calculated_country_code in ($sCountryCodesSQL)"; - if ($this->sViewboxCentreSQL) $sSQL .= " order by st_distance($this->sViewboxCentreSQL, ct.centroid) asc"; - $sSQL .= " limit $this->iLimit"; + $sSQL .= " WHERE ST_Contains($this->sViewboxLargeSQL, ct.centroid)"; + if ($sCountryCodesSQL) $sSQL .= " AND calculated_country_code in ($sCountryCodesSQL)"; + if ($this->sViewboxCentreSQL) $sSQL .= " ORDER BY ST_Distance($this->sViewboxCentreSQL, ct.centroid) ASC"; + $sSQL .= " LIMIT $this->iLimit"; if (CONST_Debug) var_dump($sSQL); $aPlaceIDs = chksql($this->oDB->getCol($sSQL)); } } else { - $sSQL = "select place_id from placex where class='".$aSearch['sClass']."' and type='".$aSearch['sType']."'"; - $sSQL .= " and st_contains($this->sViewboxSmallSQL, geometry) and linked_place_id is null"; - if ($sCountryCodesSQL) $sSQL .= " and calculated_country_code in ($sCountryCodesSQL)"; - if ($this->sViewboxCentreSQL) $sSQL .= " order by st_distance($this->sViewboxCentreSQL, centroid) asc"; - $sSQL .= " limit $this->iLimit"; + $sSQL = "SELECT place_id "; + $sSQL .= "FROM placex "; + $sSQL .= "WHERE class='".$aSearch['sClass']."' "; + $sSQL .= " AND type='".$aSearch['sType']."'"; + $sSQL .= " AND ST_Contains($this->sViewboxSmallSQL, geometry) "; + $sSQL .= " AND linked_place_id is null"; + if ($sCountryCodesSQL) $sSQL .= " AND calculated_country_code in ($sCountryCodesSQL)"; + if ($this->sViewboxCentreSQL) $sSQL .= " ORDER BY ST_Distance($this->sViewboxCentreSQL, centroid) ASC"; + $sSQL .= " LIMIT $this->iLimit"; if (CONST_Debug) var_dump($sSQL); $aPlaceIDs = chksql($this->oDB->getCol($sSQL)); } @@ -1160,12 +1307,25 @@ class Geocode if ($aSearch['sHouseNumber'] && sizeof($aSearch['aAddress'])) { $sHouseNumberRegex = '\\\\m'.$aSearch['sHouseNumber'].'\\\\M'; $aOrder[] = ""; - $aOrder[0] = " (exists(select place_id from placex where parent_place_id = search_name.place_id"; - $aOrder[0] .= " and transliteration(housenumber) ~* E'".$sHouseNumberRegex."' limit 1) "; + $aOrder[0] = " ("; + $aOrder[0] .= " EXISTS("; + $aOrder[0] .= " SELECT place_id "; + $aOrder[0] .= " FROM placex "; + $aOrder[0] .= " WHERE parent_place_id = search_name.place_id"; + $aOrder[0] .= " AND transliteration(housenumber) ~* E'".$sHouseNumberRegex."' "; + $aOrder[0] .= " LIMIT 1"; + $aOrder[0] .= " ) "; // also housenumbers from interpolation lines table are needed - $aOrder[0] .= " or exists(select place_id from location_property_osmline where parent_place_id = search_name.place_id"; - $aOrder[0] .= " and ".intval($aSearch['sHouseNumber']).">=startnumber and ".intval($aSearch['sHouseNumber'])."<=endnumber limit 1))"; - $aOrder[0] .= " desc"; + $aOrder[0] .= " OR EXISTS("; + $aOrder[0] .= " SELECT place_id "; + $aOrder[0] .= " FROM location_property_osmline "; + $aOrder[0] .= " WHERE parent_place_id = search_name.place_id"; + $aOrder[0] .= " AND ".intval($aSearch['sHouseNumber']).">=startnumber "; + $aOrder[0] .= " AND ".intval($aSearch['sHouseNumber'])."<=endnumber "; + $aOrder[0] .= " LIMIT 1"; + $aOrder[0] .= " )"; + $aOrder[0] .= " )"; + $aOrder[0] .= " DESC"; } // TODO: filter out the pointless search terms (2 letter name tokens and less) @@ -1198,7 +1358,13 @@ class Geocode } } if ($aSearch['fLon'] && $aSearch['fLat']) { - $aTerms[] = "ST_DWithin(centroid, ST_SetSRID(ST_Point(".$aSearch['fLon'].",".$aSearch['fLat']."),4326), ".$aSearch['fRadius'].")"; + $aTerms[] = sprintf( + 'ST_DWithin(centroid, ST_SetSRID(ST_Point(%F,%F),4326), %F)', + $aSearch['fLon'], + $aSearch['fLat'], + $aSearch['fRadius'] + ); + $aOrder[] = "ST_Distance(centroid, ST_SetSRID(ST_Point(".$aSearch['fLon'].",".$aSearch['fLat']."),4326)) ASC"; } if (sizeof($this->aExcludePlaceIDs)) { @@ -1209,36 +1375,42 @@ class Geocode } if ($bBoundingBoxSearch) $aTerms[] = "centroid && $this->sViewboxSmallSQL"; - if ($sNearPointSQL) $aOrder[] = "ST_Distance($sNearPointSQL, centroid) asc"; + if ($sNearPointSQL) $aOrder[] = "ST_Distance($sNearPointSQL, centroid) ASC"; if ($aSearch['sHouseNumber']) { $sImportanceSQL = '- abs(26 - address_rank) + 3'; } else { - $sImportanceSQL = '(case when importance = 0 OR importance IS NULL then 0.75-(search_rank::float/40) else importance end)'; + $sImportanceSQL = '(CASE WHEN importance = 0 OR importance IS NULL THEN 0.75-(search_rank::float/40) ELSE importance END)'; } - if ($this->sViewboxSmallSQL) $sImportanceSQL .= " * case when ST_Contains($this->sViewboxSmallSQL, centroid) THEN 1 ELSE 0.5 END"; - if ($this->sViewboxLargeSQL) $sImportanceSQL .= " * case when ST_Contains($this->sViewboxLargeSQL, centroid) THEN 1 ELSE 0.5 END"; + if ($this->sViewboxSmallSQL) $sImportanceSQL .= " * CASE WHEN ST_Contains($this->sViewboxSmallSQL, centroid) THEN 1 ELSE 0.5 END"; + if ($this->sViewboxLargeSQL) $sImportanceSQL .= " * CASE WHEN ST_Contains($this->sViewboxLargeSQL, centroid) THEN 1 ELSE 0.5 END"; $aOrder[] = "$sImportanceSQL DESC"; if (sizeof($aSearch['aFullNameAddress'])) { - $sExactMatchSQL = '(select count(*) from (select unnest(ARRAY['.join($aSearch['aFullNameAddress'], ",").']) INTERSECT select unnest(nameaddress_vector))s) as exactmatch'; + $sExactMatchSQL = ' ( '; + $sExactMatchSQL .= ' SELECT count(*) FROM ( '; + $sExactMatchSQL .= ' SELECT unnest(ARRAY['.join($aSearch['aFullNameAddress'], ",").']) '; + $sExactMatchSQL .= ' INTERSECT '; + $sExactMatchSQL .= ' SELECT unnest(nameaddress_vector)'; + $sExactMatchSQL .= ' ) s'; + $sExactMatchSQL .= ') as exactmatch'; $aOrder[] = 'exactmatch DESC'; } else { $sExactMatchSQL = '0::int as exactmatch'; } if (sizeof($aTerms)) { - $sSQL = "select place_id, "; + $sSQL = "SELECT place_id, "; $sSQL .= $sExactMatchSQL; - $sSQL .= " from search_name"; - $sSQL .= " where ".join(' and ', $aTerms); - $sSQL .= " order by ".join(', ', $aOrder); + $sSQL .= " FROM search_name"; + $sSQL .= " WHERE ".join(' and ', $aTerms); + $sSQL .= " ORDER BY ".join(', ', $aOrder); if ($aSearch['sHouseNumber'] || $aSearch['sClass']) { - $sSQL .= " limit 20"; + $sSQL .= " LIMIT 20"; } elseif (!sizeof($aSearch['aName']) && !sizeof($aSearch['aAddress']) && $aSearch['sClass']) { - $sSQL .= " limit 1"; + $sSQL .= " LIMIT 1"; } else { - $sSQL .= " limit ".$this->iLimit; + $sSQL .= " LIMIT ".$this->iLimit; } if (CONST_Debug) var_dump($sSQL); @@ -1270,40 +1442,48 @@ class Geocode // Now they are indexed, look for a house attached to a street we found $sHouseNumberRegex = '\\\\m'.$aSearch['sHouseNumber'].'\\\\M'; - $sSQL = "select place_id from placex where parent_place_id in (".$sPlaceIDs.") and transliteration(housenumber) ~* E'".$sHouseNumberRegex."'"; + $sSQL = "SELECT place_id FROM placex "; + $sSQL .= "WHERE parent_place_id in (".$sPlaceIDs.") and transliteration(housenumber) ~* E'".$sHouseNumberRegex."'"; if (sizeof($this->aExcludePlaceIDs)) { - $sSQL .= " and place_id not in (".join(',', $this->aExcludePlaceIDs).")"; + $sSQL .= " AND place_id not in (".join(',', $this->aExcludePlaceIDs).")"; } - $sSQL .= " limit $this->iLimit"; + $sSQL .= " LIMIT $this->iLimit"; if (CONST_Debug) var_dump($sSQL); $aPlaceIDs = chksql($this->oDB->getCol($sSQL)); - + // if nothing found, search in the interpolation line table if (!sizeof($aPlaceIDs)) { // do we need to use transliteration and the regex for housenumbers??? //new query for lines, not housenumbers anymore + $sSQL = "SELECT distinct place_id FROM location_property_osmline"; + $sSQL .= " WHERE parent_place_id in (".$sPlaceIDs.") and ("; if ($searchedHousenumber%2 == 0) { //if housenumber is even, look for housenumber in streets with interpolationtype even or all - $sSQL = "select distinct place_id from location_property_osmline where parent_place_id in (".$sPlaceIDs.") and (interpolationtype='even' or interpolationtype='all') and ".$searchedHousenumber.">=startnumber and ".$searchedHousenumber."<=endnumber"; + $sSQL .= "interpolationtype='even'"; } else { //look for housenumber in streets with interpolationtype odd or all - $sSQL = "select distinct place_id from location_property_osmline where parent_place_id in (".$sPlaceIDs.") and (interpolationtype='odd' or interpolationtype='all') and ".$searchedHousenumber.">=startnumber and ".$searchedHousenumber."<=endnumber"; + $sSQL .= "interpolationtype='odd'"; } + $sSQL .= " or interpolationtype='all') and "; + $sSQL .= $searchedHousenumber.">=startnumber and "; + $sSQL .= $searchedHousenumber."<=endnumber"; if (sizeof($this->aExcludePlaceIDs)) { - $sSQL .= " and place_id not in (".join(',', $this->aExcludePlaceIDs).")"; + $sSQL .= " AND place_id not in (".join(',', $this->aExcludePlaceIDs).")"; } //$sSQL .= " limit $this->iLimit"; if (CONST_Debug) var_dump($sSQL); //get place IDs $aPlaceIDs = chksql($this->oDB->getCol($sSQL, 0)); } - + // If nothing found try the aux fallback table if (CONST_Use_Aux_Location_data && !sizeof($aPlaceIDs)) { - $sSQL = "select place_id from location_property_aux where parent_place_id in (".$sPlaceIDs.") and housenumber = '".pg_escape_string($aSearch['sHouseNumber'])."'"; + $sSQL = "SELECT place_id FROM location_property_aux "; + $sSQL .= " WHERE parent_place_id in (".$sPlaceIDs.") "; + $sSQL .= " AND housenumber = '".pg_escape_string($aSearch['sHouseNumber'])."'"; if (sizeof($this->aExcludePlaceIDs)) { - $sSQL .= " and parent_place_id not in (".join(',', $this->aExcludePlaceIDs).")"; + $sSQL .= " AND parent_place_id not in (".join(',', $this->aExcludePlaceIDs).")"; } //$sSQL .= " limit $this->iLimit"; if (CONST_Debug) var_dump($sSQL); @@ -1312,17 +1492,19 @@ class Geocode //if nothing was found in placex or location_property_aux, then search in Tiger data for this housenumber(location_property_tiger) if (CONST_Use_US_Tiger_Data && !sizeof($aPlaceIDs)) { - //new query for lines, not housenumbers anymore + $sSQL = "SELECT distinct place_id FROM location_property_tiger"; + $sSQL .= " WHERE parent_place_id in (".$sPlaceIDs.") and ("; if ($searchedHousenumber%2 == 0) { - //if housenumber is even, look for housenumber in streets with interpolationtype even or all - $sSQL = "select distinct place_id from location_property_tiger where parent_place_id in (".$sPlaceIDs.") and (interpolationtype='even' or interpolationtype='all') and ".$searchedHousenumber.">=startnumber and ".$searchedHousenumber."<=endnumber"; + $sSQL .= "interpolationtype='even'"; } else { - //look for housenumber in streets with interpolationtype odd or all - $sSQL = "select distinct place_id from location_property_tiger where parent_place_id in (".$sPlaceIDs.") and (interpolationtype='odd' or interpolationtype='all') and ".$searchedHousenumber.">=startnumber and ".$searchedHousenumber."<=endnumber"; + $sSQL .= "interpolationtype='odd'"; } + $sSQL .= " or interpolationtype='all') and "; + $sSQL .= $searchedHousenumber.">=startnumber and "; + $sSQL .= $searchedHousenumber."<=endnumber"; if (sizeof($this->aExcludePlaceIDs)) { - $sSQL .= " and place_id not in (".join(',', $this->aExcludePlaceIDs).")"; + $sSQL .= " AND place_id not in (".join(',', $this->aExcludePlaceIDs).")"; } //$sSQL .= " limit $this->iLimit"; if (CONST_Debug) var_dump($sSQL); @@ -1346,19 +1528,25 @@ class Geocode if (!$aSearch['sOperator'] || $aSearch['sOperator'] == 'name') { // If they were searching for a named class (i.e. 'Kings Head pub') then we might have an extra match - $sSQL = "select place_id from placex where place_id in ($sPlaceIDs) and class='".$aSearch['sClass']."' and type='".$aSearch['sType']."'"; - $sSQL .= " and linked_place_id is null"; - if ($sCountryCodesSQL) $sSQL .= " and calculated_country_code in ($sCountryCodesSQL)"; - $sSQL .= " order by rank_search asc limit $this->iLimit"; + $sSQL = "SELECT place_id "; + $sSQL .= " FROM placex "; + $sSQL .= " WHERE place_id in ($sPlaceIDs) "; + $sSQL .= " AND class='".$aSearch['sClass']."' "; + $sSQL .= " AND type='".$aSearch['sType']."'"; + $sSQL .= " AND linked_place_id is null"; + if ($sCountryCodesSQL) $sSQL .= " AND calculated_country_code in ($sCountryCodesSQL)"; + $sSQL .= " ORDER BY rank_search ASC "; + $sSQL .= " LIMIT $this->iLimit"; if (CONST_Debug) var_dump($sSQL); $aClassPlaceIDs = chksql($this->oDB->getCol($sSQL)); } if (!$aSearch['sOperator'] || $aSearch['sOperator'] == 'near') { // & in - $sSQL = "select count(*) from pg_tables where tablename = 'place_classtype_".$aSearch['sClass']."_".$aSearch['sType']."'"; + $sSQL = "SELECT count(*) FROM pg_tables "; + $sSQL .= "WHERE tablename = 'place_classtype_".$aSearch['sClass']."_".$aSearch['sType']."'"; $bCacheTable = chksql($this->oDB->getOne($sSQL)); - $sSQL = "select min(rank_search) from placex where place_id in ($sPlaceIDs)"; + $sSQL = "SELECT min(rank_search) FROM placex WHERE place_id in ($sPlaceIDs)"; if (CONST_Debug) var_dump($sSQL); $this->iMaxRank = ((int)chksql($this->oDB->getOne($sSQL))); @@ -1367,7 +1555,13 @@ class Geocode $sPlaceGeom = false; if ($this->iMaxRank < 9 && $bCacheTable) { // Try and get a polygon to search in instead - $sSQL = "select geometry from placex where place_id in ($sPlaceIDs) and rank_search < $this->iMaxRank + 5 and st_geometrytype(geometry) in ('ST_Polygon','ST_MultiPolygon') order by rank_search asc limit 1"; + $sSQL = "SELECT geometry "; + $sSQL .= " FROM placex"; + $sSQL .= " WHERE place_id in ($sPlaceIDs)"; + $sSQL .= " AND rank_search < $this->iMaxRank + 5"; + $sSQL .= " AND ST_Geometrytype(geometry) in ('ST_Polygon','ST_MultiPolygon')"; + $sSQL .= " ORDER BY rank_search ASC "; + $sSQL .= " LIMIT 1"; if (CONST_Debug) var_dump($sSQL); $sPlaceGeom = chksql($this->oDB->getOne($sSQL)); } @@ -1376,7 +1570,7 @@ class Geocode $sPlaceIDs = false; } else { $this->iMaxRank += 5; - $sSQL = "select place_id from placex where place_id in ($sPlaceIDs) and rank_search < $this->iMaxRank"; + $sSQL = "SELECT place_id FROM placex WHERE place_id in ($sPlaceIDs) and rank_search < $this->iMaxRank"; if (CONST_Debug) var_dump($sSQL); $aPlaceIDs = chksql($this->oDB->getCol($sSQL)); $sPlaceIDs = join(',', $aPlaceIDs); @@ -1419,15 +1613,18 @@ class Geocode if ($sNearPointSQL) $sOrderBySQL = "ST_Distance($sNearPointSQL, l.geometry)"; else $sOrderBySQL = "ST_Distance(l.geometry, f.geometry)"; - $sSQL = "select distinct l.place_id".($sOrderBysSQL?','.$sOrderBysSQL:'')." from placex as l,placex as f where "; - $sSQL .= "f.place_id in ( $sPlaceIDs) and ST_DWithin(l.geometry, f.centroid, $fRange) "; - $sSQL .= "and l.class='".$aSearch['sClass']."' and l.type='".$aSearch['sType']."' "; + $sSQL = "SELECT distinct l.place_id".($sOrderBysSQL?','.$sOrderBysSQL:''); + $sSQL .= " FROM placex as l, placex as f "; + $sSQL .= " WHERE f.place_id in ($sPlaceIDs) "; + $sSQL .= " AND ST_DWithin(l.geometry, f.centroid, $fRange) "; + $sSQL .= " AND l.class='".$aSearch['sClass']."' "; + $sSQL .= " AND l.type='".$aSearch['sType']."' "; if (sizeof($this->aExcludePlaceIDs)) { - $sSQL .= " and l.place_id not in (".join(',', $this->aExcludePlaceIDs).")"; + $sSQL .= " AND l.place_id not in (".join(',', $this->aExcludePlaceIDs).")"; } - if ($sCountryCodesSQL) $sSQL .= " and l.calculated_country_code in ($sCountryCodesSQL)"; - if ($sOrderBy) $sSQL .= "order by ".$OrderBysSQL." asc"; - if ($this->iOffset) $sSQL .= " offset $this->iOffset"; + if ($sCountryCodesSQL) $sSQL .= " AND l.calculated_country_code in ($sCountryCodesSQL)"; + if ($sOrderBy) $sSQL .= "ORDER BY ".$OrderBysSQL." ASC"; + if ($this->iOffset) $sSQL .= " OFFSET $this->iOffset"; $sSQL .= " limit $this->iLimit"; if (CONST_Debug) var_dump($sSQL); $aClassPlaceIDs = array_merge($aClassPlaceIDs, chksql($this->oDB->getCol($sSQL))); @@ -1454,17 +1651,31 @@ class Geocode // Need to verify passes rank limits before dropping out of the loop (yuk!) // reduces the number of place ids, like a filter // rank_address is 30 for interpolated housenumbers - $sSQL = "select place_id from placex where place_id in (".join(',', array_keys($aResultPlaceIDs)).") "; - $sSQL .= "and (placex.rank_address between $this->iMinAddressRank and $this->iMaxAddressRank "; - if (14 >= $this->iMinAddressRank && 14 <= $this->iMaxAddressRank) $sSQL .= " OR (extratags->'place') = 'city'"; - if ($this->aAddressRankList) $sSQL .= " OR placex.rank_address in (".join(',', $this->aAddressRankList).")"; + $sSQL = "SELECT place_id "; + $sSQL .= "FROM placex "; + $sSQL .= "WHERE place_id in (".join(',', array_keys($aResultPlaceIDs)).") "; + $sSQL .= " AND ("; + $sSQL .= " placex.rank_address between $this->iMinAddressRank and $this->iMaxAddressRank "; + if (14 >= $this->iMinAddressRank && 14 <= $this->iMaxAddressRank) { + $sSQL .= " OR (extratags->'place') = 'city'"; + } + if ($this->aAddressRankList) { + $sSQL .= " OR placex.rank_address in (".join(',', $this->aAddressRankList).")"; + } if (CONST_Use_US_Tiger_Data) { - $sSQL .= ") UNION select place_id from location_property_tiger where place_id in (".join(',', array_keys($aResultPlaceIDs)).") "; - $sSQL .= "and (30 between $this->iMinAddressRank and $this->iMaxAddressRank "; + $sSQL .= " ) "; + $sSQL .= "UNION "; + $sSQL .= " SELECT place_id "; + $sSQL .= " FROM location_property_tiger "; + $sSQL .= " WHERE place_id in (".join(',', array_keys($aResultPlaceIDs)).") "; + $sSQL .= " AND (30 between $this->iMinAddressRank and $this->iMaxAddressRank "; if ($this->aAddressRankList) $sSQL .= " OR 30 in (".join(',', $this->aAddressRankList).")"; } - $sSQL .= ") UNION select place_id from location_property_osmline where place_id in (".join(',', array_keys($aResultPlaceIDs)).")"; - $sSQL .= " and (30 between $this->iMinAddressRank and $this->iMaxAddressRank)"; + $sSQL .= ") UNION "; + $sSQL .= " SELECT place_id "; + $sSQL .= " FROM location_property_osmline "; + $sSQL .= " WHERE place_id in (".join(',', array_keys($aResultPlaceIDs)).")"; + $sSQL .= " AND (30 between $this->iMinAddressRank and $this->iMaxAddressRank)"; if (CONST_Debug) var_dump($sSQL); $aFilteredPlaceIDs = chksql($this->oDB->getCol($sSQL)); $tempIDs = array(); diff --git a/lib/PlaceLookup.php b/lib/PlaceLookup.php index 3fd882a7..eff66fd1 100644 --- a/lib/PlaceLookup.php +++ b/lib/PlaceLookup.php @@ -138,7 +138,9 @@ class PlaceLookup // but this will never happen, because if the searched point is that close to the endnumber, the endnumber house will be directly taken from placex (in ReverseGeocode.php line 220) // and not interpolated } else { - $sSQL = "select placex.place_id, partition, osm_type, osm_id, class, type, admin_level, housenumber, street, isin, postcode, country_code, parent_place_id, linked_place_id, rank_address, rank_search, "; + $sSQL = "select placex.place_id, partition, osm_type, osm_id, class,"; + $sSQL .= " type, admin_level, housenumber, street, isin, postcode, country_code,"; + $sSQL .= " parent_place_id, linked_place_id, rank_address, rank_search, "; $sSQL .= " coalesce(importance,0.75-(rank_search::float/40)) as importance, indexed_status, indexed_date, wikipedia, calculated_country_code, "; $sSQL .= " get_address_by_language(place_id, -1, $sLanguagePrefArraySQL) as langaddress,"; $sSQL .= " get_name_by_language(name, $sLanguagePrefArraySQL) as placename,"; diff --git a/lib/init-website.php b/lib/init-website.php index 4ca927cf..967c6cce 100644 --- a/lib/init-website.php +++ b/lib/init-website.php @@ -52,7 +52,8 @@ function failInternalError($sError, $sSQL = false, $vDumpVar = false) echo "

Internal Server Error

"; echo '

Nominatim has encountered an internal error while processing your request. This is most likely because of a bug in the software.

'; echo "

Details: ".$sError,"

"; - echo '

Feel free to file an issue on Github. Please include the error message above and the URL you used.

'; + echo '

Feel free to file an issue on Github. '; + echo 'Please include the error message above and the URL you used.

'; if (CONST_Debug) { echo "

Debugging Information


"; if ($sSQL) { @@ -76,7 +77,8 @@ function userError($sError) echo "

Bad Request

"; echo '

Nominatim has encountered an error with your request.

'; echo "

Details: ".$sError."

"; - echo '

If you feel this error is incorrect feel file an issue on Github. Please include the error message above and the URL you used.

'; + echo '

If you feel this error is incorrect feel file an issue on Github. '; + echo 'Please include the error message above and the URL you used.

'; echo "\n\n"; exit; } diff --git a/lib/lib.php b/lib/lib.php index e14f52f9..de100fdc 100644 --- a/lib/lib.php +++ b/lib/lib.php @@ -494,7 +494,10 @@ function _debugDumpGroupedSearches($aData, $aTokens) } } echo ""; - echo ""; + echo ""; + echo ""; + echo ""; + echo ""; foreach ($aData as $iRank => $aRankedSet) { foreach ($aRankedSet as $aRow) { echo ""; diff --git a/lib/output.php b/lib/output.php index 58f00091..fd6226bc 100644 --- a/lib/output.php +++ b/lib/output.php @@ -9,7 +9,7 @@ function formatOSMType($sType, $bIncludeExternal = true) if (!$bIncludeExternal) return ''; - if ($sType == 'T') return 'tiger'; + if ($sType == 'T') return 'way'; if ($sType == 'I') return 'way'; return ''; diff --git a/lib/template/address-html.php b/lib/template/address-html.php index 4a9f6325..b4c7533e 100644 --- a/lib/template/address-html.php +++ b/lib/template/address-html.php @@ -14,6 +14,7 @@
+ <> max zoom diff --git a/lib/template/search-html.php b/lib/template/search-html.php index 02c338cd..14ebacc8 100644 --- a/lib/template/search-html.php +++ b/lib/template/search-html.php @@ -27,7 +27,7 @@
diff --git a/phpcs.xml b/phpcs.xml index c8b8a80e..9f705d83 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -8,14 +8,10 @@ - - - - - - + + diff --git a/tests-php/Nominatim/NominatimTest.php b/tests-php/Nominatim/NominatimTest.php index a90bbf2e..7822c5dc 100644 --- a/tests-php/Nominatim/NominatimTest.php +++ b/tests-php/Nominatim/NominatimTest.php @@ -186,7 +186,7 @@ class NominatimTest extends \PHPUnit_Framework_TestCase $this->assertEquals( - 65536, + 41226, count(getWordSets(array_fill(0, 18, 'a'), 0)) ); } diff --git a/tests/features/api/regression.feature b/tests/features/api/regression.feature index 34603aec..08156d62 100644 --- a/tests/features/api/regression.feature +++ b/tests/features/api/regression.feature @@ -178,7 +178,7 @@ Feature: API regression tests Scenario: trac #5238 Given the request parameters | bounded | viewbox - | 1 | 0,0,-1,-1 + | 1 | -1,0,0,-1 When sending json search query "sy" Then exactly 0 results are returned diff --git a/tests/features/api/reverse.feature b/tests/features/api/reverse.feature index 56c9670d..7bd12913 100644 --- a/tests/features/api/reverse.feature +++ b/tests/features/api/reverse.feature @@ -28,14 +28,14 @@ Feature: Reverse geocoding Given the request parameters | addressdetails | 1 - When looking up coordinates 40.6863624710666,-112.060005720023 + When looking up jsonv2 coordinates 40.6863624710666,-112.060005720023 And exactly 1 result is returned And result addresses contain | ID | house_number | road | postcode | country_code | 0 | 709. | Kings Estate Drive | 84128 | us And results contain - | osm_type - | tiger + | osm_type | category | type + | way | place | house @Tiger Scenario: No TIGER house number for zoom < 18 diff --git a/tests/features/api/search.feature b/tests/features/api/search.feature index 08b2653c..91050daf 100644 --- a/tests/features/api/search.feature +++ b/tests/features/api/search.feature @@ -61,7 +61,7 @@ Feature: Search queries When sending json search query "3 West Victory Way, Craig" Then results contain | osm_type - | tiger + | way @Tiger Scenario: TIGER house number (road fallback) diff --git a/tests/features/api/search_params.feature b/tests/features/api/search_params.feature index de6bd53d..cd0db091 100644 --- a/tests/features/api/search_params.feature +++ b/tests/features/api/search_params.feature @@ -90,7 +90,7 @@ Feature: Search queries Scenario: bounded search remains within viewbox, even with no results Given the request parameters | bounded | viewbox - | 1 | 43.54285,-5.662003,43.5403125,-5.6563282 + | 1 | 43.5403125,-5.6563282,43.54285,-5.662003 When sending json search query "restaurant" Then less than 1 result is returned diff --git a/tests/features/db/import/interpolation.feature b/tests/features/db/import/interpolation.feature index 1c05a882..6974e7be 100644 --- a/tests/features/db/import/interpolation.feature +++ b/tests/features/db/import/interpolation.feature @@ -207,7 +207,6 @@ Feature: Import of address interpolations | startnumber | endnumber | geometry | 2 | 6 | 0 0, 0 0.001 - Scenario: addr:street on interpolation way Given the scene parallel-road And the place nodes @@ -239,6 +238,18 @@ Feature: Import of address interpolations | object | parent_place_id | startnumber | endnumber | W10 | W2 | 2 | 6 | W11 | W3 | 12 | 16 + When sending query "16 Cloud Street" + Then results contain + | ID | osm_type | osm_id + | 0 | N | 4 + When sending query "14 Cloud Street" + Then results contain + | ID | osm_type | osm_id + | 0 | W | 11 + When sending query "18 Cloud Street" + Then results contain + | ID | osm_type | osm_id + | 0 | W | 3 Scenario: addr:street on housenumber way Given the scene parallel-road @@ -271,6 +282,14 @@ Feature: Import of address interpolations | object | parent_place_id | startnumber | endnumber | W10 | W2 | 2 | 6 | W11 | W3 | 12 | 16 + When sending query "16 Cloud Street" + Then results contain + | ID | osm_type | osm_id + | 0 | N | 4 + When sending query "14 Cloud Street" + Then results contain + | ID | osm_type | osm_id + | 0 | W | 11 Scenario: Geometry of points and way don't match (github #253) Given the place nodes diff --git a/utils/importWikipedia.php b/utils/importWikipedia.php index 6138398b..5271d233 100755 --- a/utils/importWikipedia.php +++ b/utils/importWikipedia.php @@ -307,8 +307,14 @@ function _templatesToProperties($aTemplates) if (isset($aCMDResult['parse-wikipedia'])) { $oDB =& getDB(); - $aArticleNames = $oDB->getCol('select page_title from content where page_namespace = 0 and page_id %10 = '.$aCMDResult['parse-wikipedia'].' and (page_content ilike \'%{{Coord%\' or (page_content ilike \'%lat%\' and page_content ilike \'%lon%\'))'); - // $aArticleNames = $oDB->getCol($sSQL = 'select page_title from content where page_namespace = 0 and (page_content ilike \'%{{Coord%\' or (page_content ilike \'%lat%\' and page_content ilike \'%lon%\')) and page_title in (\'Virginia\')'); + $sSQL = 'select page_title from content where page_namespace = 0 and page_id %10 = '; + $sSQL .= $aCMDResult['parse-wikipedia']; + $sSQL .= ' and (page_content ilike \'%{{Coord%\' or (page_content ilike \'%lat%\' and page_content ilike \'%lon%\'))' + $aArticleNames = $oDB->getCol($sSQL); + /* $aArticleNames = $oDB->getCol($sSQL = 'select page_title from content where page_namespace = 0 + and (page_content ilike \'%{{Coord%\' or (page_content ilike \'%lat%\' + and page_content ilike \'%lon%\')) and page_title in (\'Virginia\')'); + */ foreach ($aArticleNames as $sArticleName) { $sPageText = $oDB->getOne('select page_content from content where page_namespace = 0 and page_title = \''.pg_escape_string($sArticleName).'\''); $aP = _templatesToProperties(_parseWikipediaContent($sPageText)); @@ -520,7 +526,10 @@ if (isset($aCMDResult['link'])) { elseif ($iRank <= 26) $fMaxDist = 0.001; else $fMaxDist = 0.001; } - echo "-- FOUND \"".substr($aNominatRecords[$i]['DISPLAY_NAME'], 0, 50)."\", ".$aNominatRecords[$i]['CLASS'].", ".$aNominatRecords[$i]['TYPE'].", ".$aNominatRecords[$i]['PLACE_RANK'].", ".$aNominatRecords[$i]['OSM_TYPE']." (dist:$fDiff, max:$fMaxDist)\n"; + echo "-- FOUND \"".substr($aNominatRecords[$i]['DISPLAY_NAME'], 0, 50); + echo "\", ".$aNominatRecords[$i]['CLASS'].", ".$aNominatRecords[$i]['TYPE']; + echo ", ".$aNominatRecords[$i]['PLACE_RANK'].", ".$aNominatRecords[$i]['OSM_TYPE']; + echo " (dist:$fDiff, max:$fMaxDist)\n"; if ($fDiff > $fMaxDist) { echo "-- Diff too big $fDiff (max: $fMaxDist)".$aRecord['lat'].','.$aNominatRecords[$i]['LAT'].' & '.$aRecord['lon'].','.$aNominatRecords[$i]['LON']." \n"; } else { diff --git a/utils/setup.php b/utils/setup.php index 9efbcf35..06216587 100755 --- a/utils/setup.php +++ b/utils/setup.php @@ -126,10 +126,10 @@ if ($aCMDResult['setup-db'] || $aCMDResult['all']) { if ($fPostgisVersion < 2.1) { // Functions were renamed in 2.1 and throw an annoying deprecation warning pgsqlRunScript('ALTER FUNCTION st_line_interpolate_point(geometry, double precision) RENAME TO ST_LineInterpolatePoint'); - pgsqlRunScript('ALTER FUNCTION ST_Line_Locate_Point(geometry, double precision) RENAME TO ST_LineLocatePoint'); + pgsqlRunScript('ALTER FUNCTION ST_Line_Locate_Point(geometry, geometry) RENAME TO ST_LineLocatePoint'); } if ($fPostgisVersion < 2.2) { - pgsqlRunScript('ALTER FUNCTION ST_Distance_Spheroid(geometry, double precision) RENAME TO ST_DistanceSpheroid'); + pgsqlRunScript('ALTER FUNCTION ST_Distance_Spheroid(geometry, geometry, spheroid) RENAME TO ST_DistanceSpheroid'); } pgsqlRunScriptFile(CONST_BasePath.'/data/country_name.sql'); @@ -346,7 +346,11 @@ if ($aCMDResult['load-data'] || $aCMDResult['all']) { } // used by getorcreate_word_id to ignore frequent partial words - if (!pg_query($oDB->connection, 'CREATE OR REPLACE FUNCTION get_maxwordfreq() RETURNS integer AS $$ SELECT '.CONST_Max_Word_Frequency.' as maxwordfreq; $$ LANGUAGE SQL IMMUTABLE')) fail(pg_last_error($oDB->connection)); + $sSQL = 'CREATE OR REPLACE FUNCTION get_maxwordfreq() RETURNS integer AS '; + $sSQL .= '$$ SELECT '.CONST_Max_Word_Frequency.' as maxwordfreq; $$ LANGUAGE SQL IMMUTABLE'; + if (!pg_query($oDB->connection, $sSQL)) { + fail(pg_last_error($oDB->connection)); + } echo ".\n"; // pre-create the word list diff --git a/utils/update.php b/utils/update.php index 95e99b9f..232a23c9 100755 --- a/utils/update.php +++ b/utils/update.php @@ -166,12 +166,17 @@ if ($aResult['deduplicate']) { $aPartitions = chksql($oDB->getCol($sSQL)); $aPartitions[] = 0; - $sSQL = "select word_token,count(*) from word where substr(word_token, 1, 1) = ' ' and class is null and type is null and country_code is null group by word_token having count(*) > 1 order by word_token"; + $sSQL = "select word_token,count(*) from word where substr(word_token, 1, 1) = ' '"; + $sSQL .= " and class is null and type is null and country_code is null"; + $sSQL .= " group by word_token having count(*) > 1 order by word_token"; $aDuplicateTokens = chksql($oDB->getAll($sSQL)); foreach ($aDuplicateTokens as $aToken) { if (trim($aToken['word_token']) == '' || trim($aToken['word_token']) == '-') continue; echo "Deduping ".$aToken['word_token']."\n"; - $sSQL = "select word_id,(select count(*) from search_name where nameaddress_vector @> ARRAY[word_id]) as num from word where word_token = '".$aToken['word_token']."' and class is null and type is null and country_code is null order by num desc"; + $sSQL = "select word_id,"; + $sSQL .= " (select count(*) from search_name where nameaddress_vector @> ARRAY[word_id]) as num"; + $sSQL .= " from word where word_token = '".$aToken['word_token']; + $sSQL .= "' and class is null and type is null and country_code is null order by num desc"; $aTokenSet = chksql($oDB->getAll($sSQL)); $aKeep = array_shift($aTokenSet); diff --git a/website/css/common.css b/website/css/common.css index 233af74c..a6d12f4c 100644 --- a/website/css/common.css +++ b/website/css/common.css @@ -29,3 +29,7 @@ header #last-updated { white-space: nowrap; text-align: center; } + +header .dropdown-menu { + z-index: 1001; +} diff --git a/website/css/search.css b/website/css/search.css index d018ab94..eb0d06d7 100644 --- a/website/css/search.css +++ b/website/css/search.css @@ -26,6 +26,12 @@ form label { right: 0 } +#switch-coords { + font-size: 0.8em; + font-weight: bold; + cursor: pointer; +} + .sidebar { width: 25%; padding: 15px; diff --git a/website/deletable.php b/website/deletable.php index d99eb5d1..531bdadb 100755 --- a/website/deletable.php +++ b/website/deletable.php @@ -10,7 +10,10 @@ $sOutputFormat = 'html'; $oDB =& getDB(); -$sSQL = "select placex.place_id, calculated_country_code as country_code, name->'name' as name, i.* from placex, import_polygon_delete i where placex.osm_id = i.osm_id and placex.osm_type = i.osm_type and placex.class = i.class and placex.type = i.type"; +$sSQL = "select placex.place_id, calculated_country_code as country_code,"; +$sSQL .= " name->'name' as name, i.* from placex, import_polygon_delete i"; +$sSQL .= " where placex.osm_id = i.osm_id and placex.osm_type = i.osm_type"; +$sSQL .= " and placex.class = i.class and placex.type = i.type"; $aPolygons = chksql($oDB->getAll($sSQL), "Could not get list of deleted OSM elements."); if (CONST_Debug) { diff --git a/website/details.php b/website/details.php index 9fb8a900..0dc3397a 100755 --- a/website/details.php +++ b/website/details.php @@ -20,12 +20,31 @@ $iOsmId = $oParams->getInt('osmid', -1); $oDB =& getDB(); if ($sOsmType && $iOsmId > 0) { - $sPlaceId = chksql($oDB->getOne("select place_id from placex where osm_type = '".$sOsmType."' and osm_id = ".$iOsmId." order by type = 'postcode' asc")); + $sSQL = sprintf( + "SELECT place_id FROM placex WHERE osm_type='%s' AND osm_id=%d ORDER BY type='postcode' ASC", + $sOsmType, + $iOsmId + ); + $sPlaceId = chksql($oDB->getOne($sSQL)); // Be nice about our error messages for broken geometry if (!$sPlaceId) { - $aPointDetails = chksql($oDB->getRow("select osm_type, osm_id, errormessage, class, type, get_name_by_language(name,$sLanguagePrefArraySQL) as localname, ST_AsText(prevgeometry) as prevgeom, ST_AsText(newgeometry) as newgeom from import_polygon_error where osm_type = '".$sOsmType."' and osm_id = ".$iOsmId." order by updated desc limit 1")); + $sSQL = "SELECT "; + $sSQL .= " osm_type, "; + $sSQL .= " osm_id, "; + $sSQL .= " errormessage, "; + $sSQL .= " class, "; + $sSQL .= " type, "; + $sSQL .= " get_name_by_language(name,$sLanguagePrefArraySQL) AS localname,"; + $sSQL .= " ST_AsText(prevgeometry) AS prevgeom, "; + $sSQL .= " ST_AsText(newgeometry) AS newgeom"; + $sSQL .= " FROM import_polygon_error "; + $sSQL .= " WHERE osm_type = '".$sOsmType."'"; + $sSQL .= " AND osm_id = ".$iOsmId; + $sSQL .= " ORDER BY updated DESC"; + $sSQL .= " LIMIT 1"; + $aPointDetails = chksql($oDB->getRow($sSQL)); if (!PEAR::isError($aPointDetails) && $aPointDetails) { if (preg_match('/\[(-?\d+\.\d+) (-?\d+\.\d+)\]/', $aPointDetails['errormessage'], $aMatches)) { $aPointDetails['error_x'] = $aMatches[1]; @@ -46,26 +65,46 @@ if (!$sPlaceId) userError("Please select a place id"); $iPlaceID = (int)$sPlaceId; if (CONST_Use_US_Tiger_Data) { - $iParentPlaceID = chksql($oDB->getOne('select parent_place_id from location_property_tiger where place_id = '.$iPlaceID)); + $iParentPlaceID = chksql($oDB->getOne('SELECT parent_place_id FROM location_property_tiger WHERE place_id = '.$iPlaceID)); if ($iParentPlaceID) $iPlaceID = $iParentPlaceID; } +// interpolated house numbers +$iParentPlaceID = chksql($oDB->getOne('SELECT parent_place_id FROM location_property_osmline WHERE place_id = '.$iPlaceID)); +if ($iParentPlaceID) $iPlaceID = $iParentPlaceID; + + if (CONST_Use_Aux_Location_data) { - $iParentPlaceID = chksql($oDB->getOne('select parent_place_id from location_property_aux where place_id = '.$iPlaceID)); + $iParentPlaceID = chksql($oDB->getOne('SELECT parent_place_id FROM location_property_aux WHERE place_id = '.$iPlaceID)); if ($iParentPlaceID) $iPlaceID = $iParentPlaceID; } $hLog = logStart($oDB, 'details', $_SERVER['QUERY_STRING'], $aLangPrefOrder); // Get the details for this point -$sSQL = "select place_id, osm_type, osm_id, class, type, name, admin_level, housenumber, street, isin, postcode, calculated_country_code as country_code, importance, wikipedia,"; -$sSQL .= " to_char(indexed_date, 'YYYY-MM-DD HH24:MI') as indexed_date, parent_place_id, rank_address, rank_search, get_searchrank_label(rank_search) as rank_search_label, get_name_by_language(name,$sLanguagePrefArraySQL) as localname, "; -$sSQL .= " ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') as isarea, "; -//$sSQL .= " ST_Area(geometry::geography) as area, "; -$sSQL .= " ST_y(centroid) as lat, ST_x(centroid) as lon,"; -$sSQL .= " case when importance = 0 OR importance IS NULL then 0.75-(rank_search::float/40) else importance end as calculated_importance, "; -$sSQL .= " ST_AsText(CASE WHEN ST_NPoints(geometry) > 5000 THEN ST_SimplifyPreserveTopology(geometry, 0.0001) ELSE geometry END) as outlinestring"; -$sSQL .= " from placex where place_id = $iPlaceID"; +$sSQL = "SELECT place_id, osm_type, osm_id, class, type, name, admin_level,"; +$sSQL .= " housenumber, street, isin, postcode, calculated_country_code AS country_code,"; +$sSQL .= " importance, wikipedia,"; +$sSQL .= " to_char(indexed_date, 'YYYY-MM-DD HH24:MI') AS indexed_date,"; +$sSQL .= " parent_place_id, "; +$sSQL .= " rank_address, "; +$sSQL .= " rank_search, "; +$sSQL .= " get_searchrank_label(rank_search) AS rank_search_label,"; +$sSQL .= " get_name_by_language(name,$sLanguagePrefArraySQL) AS localname, "; +$sSQL .= " ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') AS isarea, "; +//$sSQL .= " ST_Area(geometry::geography) AS area, "; +$sSQL .= " ST_y(centroid) AS lat, "; +$sSQL .= " ST_x(centroid) AS lon,"; +$sSQL .= " CASE "; +$sSQL .= " WHEN importance = 0 OR importance IS NULL THEN 0.75-(rank_search::float/40) "; +$sSQL .= " ELSE importance "; +$sSQL .= " END as calculated_importance, "; +$sSQL .= " ST_AsText(CASE "; +$sSQL .= " WHEN ST_NPoints(geometry) > 5000 THEN ST_SimplifyPreserveTopology(geometry, 0.0001) "; +$sSQL .= " ELSE geometry "; +$sSQL .= " END) as outlinestring"; +$sSQL .= " FROM placex "; +$sSQL .= " WHERE place_id = $iPlaceID"; $aPointDetails = chksql($oDB->getRow($sSQL), "Could not get details of place object."); @@ -85,14 +124,14 @@ if (isset($aClassType[$sPointClassType]) && $aClassType[$sPointClassType]['icon' } // Get all alternative names (languages, etc) -$sSQL = "select (each(name)).key,(each(name)).value from placex where place_id = $iPlaceID order by (each(name)).key"; +$sSQL = "SELECT (each(name)).key,(each(name)).value FROM placex WHERE place_id = $iPlaceID ORDER BY (each(name)).key"; $aPointDetails['aNames'] = $oDB->getAssoc($sSQL); if (PEAR::isError($aPointDetails['aNames'])) { // possible timeout $aPointDetails['aNames'] = []; } // Extra tags -$sSQL = "select (each(extratags)).key,(each(extratags)).value from placex where place_id = $iPlaceID order by (each(extratags)).key"; +$sSQL = "SELECT (each(extratags)).key,(each(extratags)).value FROM placex WHERE place_id = $iPlaceID ORDER BY (each(extratags)).key"; $aPointDetails['aExtraTags'] = $oDB->getAssoc($sSQL); if (PEAR::isError($aPointDetails['aExtraTags'])) { // possible timeout $aPointDetails['aExtraTags'] = []; @@ -102,23 +141,56 @@ if (PEAR::isError($aPointDetails['aExtraTags'])) { // possible timeout $aAddressLines = getAddressDetails($oDB, $sLanguagePrefArraySQL, $iPlaceID, $aPointDetails['country_code'], -1, true); // Linked places -$sSQL = "select placex.place_id, osm_type, osm_id, class, type, housenumber, admin_level, rank_address, ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') as isarea, ST_DistanceSpheroid(geometry, placegeometry, 'SPHEROID[\"WGS 84\",6378137,298.257223563, AUTHORITY[\"EPSG\",\"7030\"]]') as distance, "; -$sSQL .= " get_name_by_language(name,$sLanguagePrefArraySQL) as localname, length(name::text) as namelength "; -$sSQL .= " from placex, (select centroid as placegeometry from placex where place_id = $iPlaceID) as x"; -$sSQL .= " where linked_place_id = $iPlaceID"; -$sSQL .= " order by rank_address asc,rank_search asc,get_name_by_language(name,$sLanguagePrefArraySQL),housenumber"; +$sSQL = "SELECT placex.place_id, osm_type, osm_id, class, type, housenumber,"; +$sSQL .= " admin_level, rank_address, "; +$sSQL .= " ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') AS isarea,"; +$sSQL .= " ST_DistanceSpheroid(geometry, placegeometry, 'SPHEROID[\"WGS 84\",6378137,298.257223563, AUTHORITY[\"EPSG\",\"7030\"]]') AS distance, "; +$sSQL .= " get_name_by_language(name,$sLanguagePrefArraySQL) AS localname, "; +$sSQL .= " length(name::text) AS namelength "; +$sSQL .= " FROM "; +$sSQL .= " placex, "; +$sSQL .= " ( "; +$sSQL .= " SELECT centroid AS placegeometry "; +$sSQL .= " FROM placex "; +$sSQL .= " WHERE place_id = $iPlaceID "; +$sSQL .= " ) AS x"; +$sSQL .= " WHERE linked_place_id = $iPlaceID"; +$sSQL .= " ORDER BY "; +$sSQL .= " rank_address ASC, "; +$sSQL .= " rank_search ASC, "; +$sSQL .= " get_name_by_language(name, $sLanguagePrefArraySQL), "; +$sSQL .= " housenumber"; $aLinkedLines = $oDB->getAll($sSQL); if (PEAR::isError($aLinkedLines)) { // possible timeout $aLinkedLines = []; } // All places this is an imediate parent of -$sSQL = "select obj.place_id, osm_type, osm_id, class, type, housenumber, admin_level, rank_address, ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') as isarea, ST_DistanceSpheroid(geometry, placegeometry, 'SPHEROID[\"WGS 84\",6378137,298.257223563, AUTHORITY[\"EPSG\",\"7030\"]]') as distance, "; -$sSQL .= " get_name_by_language(name,$sLanguagePrefArraySQL) as localname, length(name::text) as namelength "; -$sSQL .= " from (select placex.place_id, osm_type, osm_id, class, type, housenumber, admin_level, rank_address, rank_search, geometry, name from placex "; -$sSQL .= " where parent_place_id = $iPlaceID order by rank_address asc,rank_search asc limit 500) as obj,"; -$sSQL .= " (select centroid as placegeometry from placex where place_id = $iPlaceID) as x"; -$sSQL .= " order by rank_address asc,rank_search asc,localname,housenumber"; +$sSQL = "SELECT obj.place_id, osm_type, osm_id, class, type, housenumber,"; +$sSQL .= " admin_level, rank_address, ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') AS isarea,"; +$sSQL .= " ST_DistanceSpheroid(geometry, placegeometry, 'SPHEROID[\"WGS 84\",6378137,298.257223563, AUTHORITY[\"EPSG\",\"7030\"]]') AS distance, "; +$sSQL .= " get_name_by_language(name,$sLanguagePrefArraySQL) AS localname, "; +$sSQL .= " length(name::text) AS namelength "; +$sSQL .= " FROM "; +$sSQL .= " ( "; +$sSQL .= " SELECT placex.place_id, osm_type, osm_id, class, type, housenumber, admin_level, rank_address, rank_search, geometry, name "; +$sSQL .= " FROM placex "; +$sSQL .= " WHERE parent_place_id = $iPlaceID "; +$sSQL .= " ORDER BY "; +$sSQL .= " rank_address ASC, "; +$sSQL .= " rank_search ASC "; +$sSQL .= " LIMIT 500 "; +$sSQL .= " ) AS obj,"; +$sSQL .= " ( "; +$sSQL .= " SELECT centroid AS placegeometry "; +$sSQL .= " FROM placex "; +$sSQL .= " WHERE place_id = $iPlaceID "; +$sSQL .= " ) AS x"; +$sSQL .= " ORDER BY "; +$sSQL .= " rank_address ASC, "; +$sSQL .= " rank_search ASC, "; +$sSQL .= " localname, "; +$sSQL .= " housenumber"; $aParentOfLines = $oDB->getAll($sSQL); if (PEAR::isError($aParentOfLines)) { // possible timeout $aParentOfLines = []; @@ -127,20 +199,19 @@ if (PEAR::isError($aParentOfLines)) { // possible timeout $aPlaceSearchNameKeywords = false; $aPlaceSearchAddressKeywords = false; if ($oParams->getBool('keywords')) { - $sSQL = "select * from search_name where place_id = $iPlaceID"; + $sSQL = "SELECT * FROM search_name WHERE place_id = $iPlaceID"; $aPlaceSearchName = $oDB->getRow($sSQL); if (PEAR::isError($aPlaceSearchName)) { // possible timeout $aPlaceSearchName = []; } - $sSQL = "select * from word where word_id in (".substr($aPlaceSearchName['name_vector'], 1, -1).")"; + $sSQL = "SELECT * FROM word WHERE word_id in (".substr($aPlaceSearchName['name_vector'], 1, -1).")"; $aPlaceSearchNameKeywords = $oDB->getAll($sSQL); if (PEAR::isError($aPlaceSearchNameKeywords)) { // possible timeout $aPlaceSearchNameKeywords = []; } - - $sSQL = "select * from word where word_id in (".substr($aPlaceSearchName['nameaddress_vector'], 1, -1).")"; + $sSQL = "SELECT * FROM word WHERE word_id in (".substr($aPlaceSearchName['nameaddress_vector'], 1, -1).")"; $aPlaceSearchAddressKeywords = $oDB->getAll($sSQL); if (PEAR::isError($aPlaceSearchAddressKeywords)) { // possible timeout $aPlaceSearchAddressKeywords = []; @@ -150,7 +221,8 @@ if ($oParams->getBool('keywords')) { logEnd($oDB, $hLog, 1); if ($sOutputFormat=='html') { - $sDataDate = chksql($oDB->getOne("select TO_CHAR(lastimportdate - '2 minutes'::interval,'YYYY/MM/DD HH24:MI')||' GMT' from import_status limit 1")); + $sSQL = "SELECT TO_CHAR(lastimportdate - '2 minutes'::interval,'YYYY/MM/DD HH24:MI')||' GMT' FROM import_status LIMIT 1"; + $sDataDate = chksql($oDB->getOne($sSQL)); $sTileURL = CONST_Map_Tile_URL; $sTileAttribution = CONST_Map_Tile_Attribution; } diff --git a/website/hierarchy.php b/website/hierarchy.php index 457f37ca..131a9ca1 100755 --- a/website/hierarchy.php +++ b/website/hierarchy.php @@ -25,7 +25,12 @@ if ($sOsmType && $iOsmId > 0) { // Be nice about our error messages for broken geometry if (!$sPlaceId) { - $aPointDetails = chksql($oDB->getRow("select osm_type, osm_id, errormessage, class, type, get_name_by_language(name,$sLanguagePrefArraySQL) as localname, ST_AsText(prevgeometry) as prevgeom, ST_AsText(newgeometry) as newgeom from import_polygon_error where osm_type = '".$sOsmType."' and osm_id = ".$iOsmId." order by updated desc limit 1")); + $sSQL = "select osm_type, osm_id, errormessage, class, type,"; + $sSQL .= " get_name_by_language(name,$sLanguagePrefArraySQL) as localname,"; + $sSQL .= " ST_AsText(prevgeometry) as prevgeom, ST_AsText(newgeometry) as newgeom"; + $sSQL .= " from import_polygon_error where osm_type = '".$sOsmType; + $sSQL .= "' and osm_id = ".$iOsmId." order by updated desc limit 1"; + $aPointDetails = chksql($oDB->getRow($sSQL)); if ($aPointDetails) { if (preg_match('/\[(-?\d+\.\d+) (-?\d+\.\d+)\]/', $aPointDetails['errormessage'], $aMatches)) { $aPointDetails['error_x'] = $aMatches[1]; @@ -87,7 +92,8 @@ if ($sOutputFormat == 'json') { $aRelatedPlaceIDs = chksql($oDB->getCol($sSQL = "select place_id from placex where linked_place_id = $iPlaceID or place_id = $iPlaceID")); -$sSQL = "select obj.place_id, osm_type, osm_id, class, type, housenumber, admin_level, rank_address, ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') as isarea, st_area(geometry) as area, "; +$sSQL = "select obj.place_id, osm_type, osm_id, class, type, housenumber, admin_level,"; +$sSQL .= " rank_address, ST_GeometryType(geometry) in ('ST_Polygon','ST_MultiPolygon') as isarea, st_area(geometry) as area, "; $sSQL .= " get_name_by_language(name,$sLanguagePrefArraySQL) as localname, length(name::text) as namelength "; $sSQL .= " from (select placex.place_id, osm_type, osm_id, class, type, housenumber, admin_level, rank_address, rank_search, geometry, name from placex "; $sSQL .= " where parent_place_id in (".join(',', $aRelatedPlaceIDs).") and name is not null order by rank_address asc,rank_search asc limit 500) as obj"; diff --git a/website/js/nominatim-ui.js b/website/js/nominatim-ui.js index 7c19b17a..c5e91cf7 100644 --- a/website/js/nominatim-ui.js +++ b/website/js/nominatim-ui.js @@ -72,6 +72,15 @@ jQuery(document).on('ready', function(){ html_viewbox = "viewbox: " + map_viewbox_as_string(); $('#map-position-inner').html([html_center,html_zoom,html_viewbox,html_click,html_mouse].join('
')); + + var reverse_params = { + lat: map.getCenter().lat.toFixed(5), + lon: map.getCenter().lng.toFixed(5), + zoom: map.getZoom(), + format: 'html' + } + $('#switch-to-reverse').attr('href', 'reverse.php?' + $.param(reverse_params)); + $('input#use_viewbox').trigger('change'); } @@ -202,6 +211,14 @@ jQuery(document).on('ready', function(){ $('form input[name=lon]').val( e.latlng.lng); $('form').submit(); }); + + $('#switch-coords').on('click', function(e){ + var lat = $('form input[name=lat]').val(); + var lon = $('form input[name=lon]').val(); + $('form input[name=lat]').val(lon); + $('form input[name=lon]').val(lat); + $('form').submit(); + }); } highlight_result(0, false); diff --git a/wikidata/parse.php b/wikidata/parse.php index 11b30fe1..d8981c6c 100755 --- a/wikidata/parse.php +++ b/wikidata/parse.php @@ -115,8 +115,21 @@ if ($hFile) { } elseif ($aClaim['m'][2] == 'globecoordinate') { // if ($aClaim['m'][3]['globe'] != 'http://www.wikidata.org/entity/Q2') $bFail = true; - fputcsv($hFileEntityProperty, array($iID, $iClaim, $iPID, null, null, "SRID=4326;POINT(".((float) $aClaim['m'][3]['longitude'])." ".((float)$aClaim['m'][3]['latitude']).")", null)); - // echo "insert into entity_property values (nextval('seq_entity_property'),".$iID.",".$iPID.",null,null,ST_SetSRID(ST_MakePoint(".((float)$aClaim['m'][3]['longitude']).", ".((float)$aClaim['m'][3]['latitude'])."),4326));\n"; + fputcsv( + $hFileEntityProperty, + array( + $iID, + $iClaim, + $iPID, + null, + null, + "SRID=4326;POINT(".((float) $aClaim['m'][3]['longitude'])." ".((float)$aClaim['m'][3]['latitude']).")", null + ) + ); + /* echo "insert into entity_property values (nextval('seq_entity_property'),"; + * echo $iID.",".$iPID.",null,null,ST_SetSRID(ST_MakePoint(".((float)$aClaim['m'][3]['longitude']); + * echo ", ".((float)$aClaim['m'][3]['latitude'])."),4326));\n"; + */ } elseif ($aClaim['m'][2] == 'time') { // TODO! /* diff --git a/wikidata/pull_wikipedia_logs.php b/wikidata/pull_wikipedia_logs.php index a7f6a9a3..bdaab52a 100644 --- a/wikidata/pull_wikipedia_logs.php +++ b/wikidata/pull_wikipedia_logs.php @@ -71,7 +71,9 @@ for ($iTimestamp = mktime(0, 0, 0, 5, 1, 2013); $iTimestamp < mktime(0, 0, 0, 6, // Notes: /* - gzip -dc $FILE.gz | grep -e "^en [^ :]\+ [0-9]\+" | sed "s#\(^[a-z]\{2\}\) \([^ :]\+\) \([0-9]\+\) [0-9]\+#update wikipedia_article set hit_count = coalesce(hit_count,0) + \3 where language = '\1' and title = catch_decode_url_part('\2');#g" | /opt/mapquest/stdbase-dev$ + gzip -dc $FILE.gz | grep -e "^en [^ :]\+ [0-9]\+" | + sed "s#\(^[a-z]\{2\}\) \([^ :]\+\) \([0-9]\+\) [0-9]\+#update wikipedia_article set hit_count = coalesce(hit_count,0) + \3 where language = '\1' + and title = catch_decode_url_part('\2');#g" | /opt/mapquest/stdbase-dev$ cat totals.txt | sed "s#\(^[a-z]\{2\}\) \([^ ]\+\) \([0-9]\+\)\$#update entity_link set hits = s,0) + \3 where target = '\1wiki' and value = catch_decode_url_part('\2');#g" cat totals.txt | sed "s#\(^[a-z]\{2\}\) \([^ ]\+\) \([0-9]\+\)\$#update entity_link set hits = coalesce(hits,0) + \3 where target = '\1wiki' and value = catch_decode_url_part('\2');#g" */
rankName TokensName NotAddress TokensAddress Notcountryoperatorclasstypehouse#LatLonRadius
rankName TokensName NotAddress TokensAddress Notcountryoperatorclasstypehouse#LatLonRadius