4 require_once(dirname(dirname(__FILE__)).'/lib/init-cmd.php');
5 ini_set('memory_limit', '800M');
8 "Create and setup nominatim search system",
9 array('help', 'h', 0, 1, 0, 0, false, 'Show Help'),
10 array('quiet', 'q', 0, 1, 0, 0, 'bool', 'Quiet output'),
11 array('verbose', 'v', 0, 1, 0, 0, 'bool', 'Verbose output'),
13 array('osm-file', '', 0, 1, 1, 1, 'realpath', 'File to import'),
14 array('threads', '', 0, 1, 1, 1, 'int', 'Number of threads (where possible)'),
16 array('all', '', 0, 1, 0, 0, 'bool', 'Do the complete process'),
18 array('create-db', '', 0, 1, 0, 0, 'bool', 'Create nominatim db'),
19 array('setup-db', '', 0, 1, 0, 0, 'bool', 'Build a blank nominatim db'),
20 array('import-data', '', 0, 1, 0, 0, 'bool', 'Import a osm file'),
21 array('create-functions', '', 0, 1, 0, 0, 'bool', 'Create functions'),
22 array('create-tables', '', 0, 1, 0, 0, 'bool', 'Create main tables'),
23 array('create-partitions', '', 0, 1, 0, 0, 'bool', 'Create required partition tables and triggers'),
24 array('load-data', '', 0, 1, 0, 0, 'bool', 'Copy data to live tables from import table'),
25 array('import-tiger-data', '', 0, 1, 0, 0, 'bool', 'Import tiger data (not included in \'all\')'),
26 array('calculate-postcodes', '', 0, 1, 0, 0, 'bool', 'Calculate postcode centroids'),
27 array('index', '', 0, 1, 0, 0, 'bool', 'Index the data'),
29 getCmdOpt($_SERVER['argv'], $aCMDOptions, $aCMDResult, true, true);
31 $bDidSomething = false;
33 // This is a pretty hard core defult - the number of processors in the box - 1
34 $iInstances = isset($aCMDResult['threads'])?$aCMDResult['threads']:(getProcessorCount()-1);
38 echo "WARNING: resetting threads to $iInstances\n";
40 if ($iInstances > getProcessorCount())
42 $iInstances = getProcessorCount();
43 echo "WARNING: resetting threads to $iInstances\n";
46 if ($aCMDResult['create-db'] || $aCMDResult['all'])
48 $bDidSomething = true;
49 $oDB =& DB::connect(CONST_Database_DSN, false);
50 if (!PEAR::isError($oDB))
52 fail('database already exists');
54 passthru('createdb nominatim');
57 if ($aCMDResult['create-db'] || $aCMDResult['all'])
59 $bDidSomething = true;
60 // TODO: path detection, detection memory, etc.
63 passthru('createlang plpgsql nominatim');
64 pgsqlRunScriptFile(CONST_Path_Postgresql_Contrib.'/_int.sql');
65 pgsqlRunScriptFile(CONST_Path_Postgresql_Contrib.'/hstore.sql');
66 pgsqlRunScriptFile(CONST_Path_Postgresql_Postgis.'/postgis.sql');
67 pgsqlRunScriptFile(CONST_Path_Postgresql_Postgis.'/spatial_ref_sys.sql');
68 pgsqlRunScriptFile(CONST_BasePath.'/data/country_name.sql');
69 pgsqlRunScriptFile(CONST_BasePath.'/data/country_naturalearthdata.sql');
70 pgsqlRunScriptFile(CONST_BasePath.'/data/country_osm_grid.sql');
71 pgsqlRunScriptFile(CONST_BasePath.'/data/gb_postcode.sql');
72 pgsqlRunScriptFile(CONST_BasePath.'/data/us_statecounty.sql');
73 pgsqlRunScriptFile(CONST_BasePath.'/data/us_state.sql');
74 pgsqlRunScriptFile(CONST_BasePath.'/data/us_postcode.sql');
75 pgsqlRunScriptFile(CONST_BasePath.'/data/worldboundaries.sql');
78 if ($aCMDResult['import-data'] || $aCMDResult['all'])
80 $bDidSomething = true;
81 passthru(CONST_BasePath.'/osm2pgsql/osm2pgsql -lsc -O gazetteer -C 10000 --hstore -d nominatim '.$aCMDResult['osm-file']);
84 $x = $oDB->getRow('select * from place limit 1');
85 if (!$x || PEAR::isError($x)) fail('No Data');
88 if ($aCMDResult['create-functions'] || $aCMDResult['all'])
90 $bDidSomething = true;
91 if (!file_exists(CONST_BasePath.'/module/nominatim.so')) fail("nominatim module not built");
92 $sTemplate = file_get_contents(CONST_BasePath.'/sql/functions.sql');
93 $sTemplate = str_replace('{modulepath}',CONST_BasePath.'/module', $sTemplate);
94 pgsqlRunScript($sTemplate);
97 if ($aCMDResult['create-tables'] || $aCMDResult['all'])
99 $bDidSomething = true;
100 pgsqlRunScriptFile(CONST_BasePath.'/sql/tables.sql');
102 // re-run the functions
103 $sTemplate = file_get_contents(CONST_BasePath.'/sql/functions.sql');
104 $sTemplate = str_replace('{modulepath}',CONST_BasePath.'/module', $sTemplate);
105 pgsqlRunScript($sTemplate);
108 if ($aCMDResult['create-partitions'] || $aCMDResult['all'])
110 $bDidSomething = true;
112 $sSQL = 'select partition from country_name order by country_code';
113 $aPartitions = $oDB->getCol($sSQL);
114 if (PEAR::isError($aPartitions))
116 fail($aPartitions->getMessage());
120 $sTemplate = file_get_contents(CONST_BasePath.'/sql/partitions.src.sql');
121 preg_match_all('#^-- start(.*?)^-- end#ms', $sTemplate, $aMatches, PREG_SET_ORDER);
122 foreach($aMatches as $aMatch)
125 foreach($aPartitions as $sPartitionName)
127 $sResult .= str_replace('-partition-', $sPartitionName, $aMatch[1]);
129 $sTemplate = str_replace($aMatch[0], $sResult, $sTemplate);
132 pgsqlRunScript($sTemplate);
135 if ($aCMDResult['load-data'] || $aCMDResult['all'])
137 $bDidSomething = true;
140 if (!pg_query($oDB->connection, 'TRUNCATE word')) fail(pg_last_error($oDB->connection));
142 if (!pg_query($oDB->connection, 'TRUNCATE placex')) fail(pg_last_error($oDB->connection));
144 if (!pg_query($oDB->connection, 'TRUNCATE place_addressline')) fail(pg_last_error($oDB->connection));
146 if (!pg_query($oDB->connection, 'TRUNCATE place_boundingbox')) fail(pg_last_error($oDB->connection));
148 if (!pg_query($oDB->connection, 'TRUNCATE location_area')) fail(pg_last_error($oDB->connection));
150 if (!pg_query($oDB->connection, 'TRUNCATE search_name')) fail(pg_last_error($oDB->connection));
152 if (!pg_query($oDB->connection, 'TRUNCATE search_name_blank')) fail(pg_last_error($oDB->connection));
154 if (!pg_query($oDB->connection, 'DROP SEQUENCE seq_place')) fail(pg_last_error($oDB->connection));
156 if (!pg_query($oDB->connection, 'CREATE SEQUENCE seq_place start 100000')) fail(pg_last_error($oDB->connection));
159 $aDBInstances = array();
160 for($i = 0; $i < $iInstances; $i++)
162 $aDBInstances[$i] =& getDB(true);
163 $sSQL = 'insert into placex (osm_type, osm_id, class, type, name, admin_level, ';
164 $sSQL .= 'housenumber, street, isin, postcode, country_code, extratags, ';
165 $sSQL .= 'geometry) select * from place where osm_id % '.$iInstances.' = '.$i;
166 if ($aCMDResult['verbose']) echo "$sSQL\n";
167 if (!pg_send_query($aDBInstances[$i]->connection, $sSQL)) fail(pg_last_error($oDB->connection));
173 for($i = 0; $i < $iInstances; $i++)
175 if (pg_connection_busy($aDBInstances[$i]->connection)) $bAnyBusy = true;
183 if ($aCMDResult['import-tiger-data'])
185 $bDidSomething = true;
187 $aDBInstances = array();
188 for($i = 0; $i < $iInstances; $i++)
190 $aDBInstances[$i] =& getDB(true);
193 foreach(glob(CONST_BasePath.'/data/tiger2009/*.sql') as $sFile)
196 if ((int)basename($sFile) <= 53033) continue;
197 $hFile = fopen($sFile, "r");
198 $sSQL = fgets($hFile, 100000);
203 for($i = 0; $i < $iInstances; $i++)
205 if (!pg_connection_busy($aDBInstances[$i]->connection))
207 while(pg_get_result($aDBInstances[$i]->connection));
208 $sSQL = fgets($hFile, 100000);
210 if (!pg_send_query($aDBInstances[$i]->connection, $sSQL)) fail(pg_last_error($oDB->connection));
228 for($i = 0; $i < $iInstances; $i++)
230 if (pg_connection_busy($aDBInstances[$i]->connection)) $bAnyBusy = true;
238 if ($aCMDResult['calculate-postcodes'] || $aCMDResult['all'])
241 if (!pg_query($oDB->connection, 'DELETE from placex where osm_type=\'P\'')) fail(pg_last_error($oDB->connection));
242 $sSQL = "insert into placex (osm_type,osm_id,class,type,postcode,country_code,geometry) ";
243 $sSQL .= "select 'P',nextval('seq_postcodes'),'place','postcode',postcode,country_code,";
244 $sSQL .= "ST_SetSRID(ST_Point(x,y),4326) as geometry from (select country_code,postcode,";
245 $sSQL .= "avg(st_x(st_centroid(geometry))) as x,avg(st_y(st_centroid(geometry))) as y ";
246 $sSQL .= "from place where postcode is not null group by country_code,postcode) as x";
247 if (!pg_query($oDB->connection, $sSQL)) fail(pg_last_error($oDB->connection));
249 $sSQL = "insert into placex (osm_type,osm_id,class,type,postcode,country_code,geometry) ";
250 $sSQL .= "select 'P',nextval('seq_postcodes'),'place','postcode',postcode,'us',";
251 $sSQL .= "ST_SetSRID(ST_Point(x,y),4326) as geometry from us_postcode";
252 if (!pg_query($oDB->connection, $sSQL)) fail(pg_last_error($oDB->connection));
255 if ($aCMDResult['index'] || $aCMDResult['all'])
257 $bDidSomething = true;
258 passthru(CONST_BasePath.'/nominatim/nominatim -i -d nominatim -t '.$iInstances);
263 showUsage($aCMDOptions, true);
266 function pgsqlRunScriptFile($sFilename)
268 if (!file_exists($sFilename)) fail('unable to find '.$sFilename);
270 // Convert database DSN to psql paramaters
271 $aDSNInfo = DB::parseDSN(CONST_Database_DSN);
272 $sCMD = 'psql -f '.$sFilename.' '.$aDSNInfo['database'];
274 $aDescriptors = array(
275 0 => array('pipe', 'r'),
276 1 => array('pipe', 'w'),
277 2 => array('file', '/dev/null', 'a')
280 $hProcess = proc_open($sCMD, $aDescriptors, $ahPipes);
281 if (!is_resource($hProcess)) fail('unable to start pgsql');
285 // TODO: error checking
286 while(!feof($ahPipes[1]))
288 echo fread($ahPipes[1], 4096);
292 proc_close($hProcess);
295 function pgsqlRunScript($sScript)
297 // Convert database DSN to psql paramaters
298 $aDSNInfo = DB::parseDSN(CONST_Database_DSN);
299 $sCMD = 'psql '.$aDSNInfo['database'];
301 $aDescriptors = array(
302 0 => array('pipe', 'r'),
303 1 => array('pipe', 'w'),
304 2 => array('file', '/dev/null', 'a')
307 $hProcess = proc_open($sCMD, $aDescriptors, $ahPipes);
308 if (!is_resource($hProcess)) fail('unable to start pgsql');
310 fwrite($ahPipes[0], $sScript);
313 // TODO: error checking
314 while(!feof($ahPipes[1]))
316 echo fread($ahPipes[1], 4096);
320 proc_close($hProcess);