3 namespace Nominatim\Setup;
5 require_once(CONST_LibDir.'/Shell.php');
9 protected $iCacheMemory;
10 protected $iInstances;
14 protected $sIgnoreErrors;
15 protected $bEnableDiffUpdates;
16 protected $bEnableDebugStatements;
17 protected $bNoPartitions;
19 protected $oDB = null;
20 protected $oNominatimCmd;
22 public function __construct(array $aCMDResult)
24 // by default, use all but one processor, but never more than 15.
25 $this->iInstances = isset($aCMDResult['threads'])
26 ? $aCMDResult['threads']
27 : (min(16, getProcessorCount()) - 1);
29 if ($this->iInstances < 1) {
30 $this->iInstances = 1;
31 warn('resetting threads to '.$this->iInstances);
34 if (isset($aCMDResult['osm2pgsql-cache'])) {
35 $this->iCacheMemory = $aCMDResult['osm2pgsql-cache'];
36 } elseif (getSetting('FLATNODE_FILE')) {
37 // When flatnode files are enabled then disable cache per default.
38 $this->iCacheMemory = 0;
40 // Otherwise: Assume we can steal all the cache memory in the box.
41 $this->iCacheMemory = getCacheMemoryMB();
44 // parse database string
45 $this->aDSNInfo = \Nominatim\DB::parseDSN(getSetting('DATABASE_DSN'));
46 if (!isset($this->aDSNInfo['port'])) {
47 $this->aDSNInfo['port'] = 5432;
50 // setting member variables based on command line options stored in $aCMDResult
51 $this->bQuiet = isset($aCMDResult['quiet']) && $aCMDResult['quiet'];
52 $this->bVerbose = $aCMDResult['verbose'];
54 //setting default values which are not set by the update.php array
55 if (isset($aCMDResult['ignore-errors'])) {
56 $this->sIgnoreErrors = $aCMDResult['ignore-errors'];
58 $this->sIgnoreErrors = false;
60 if (isset($aCMDResult['enable-debug-statements'])) {
61 $this->bEnableDebugStatements = $aCMDResult['enable-debug-statements'];
63 $this->bEnableDebugStatements = false;
65 if (isset($aCMDResult['no-partitions'])) {
66 $this->bNoPartitions = $aCMDResult['no-partitions'];
68 $this->bNoPartitions = false;
70 if (isset($aCMDResult['enable-diff-updates'])) {
71 $this->bEnableDiffUpdates = $aCMDResult['enable-diff-updates'];
73 $this->bEnableDiffUpdates = false;
76 $this->bDrop = isset($aCMDResult['drop']) && $aCMDResult['drop'];
78 $this->oNominatimCmd = new \Nominatim\Shell(getSetting('NOMINATIM_TOOL'));
80 $this->oNominatimCmd->addParams('--quiet');
82 if ($this->bVerbose) {
83 $this->oNominatimCmd->addParams('--verbose');
87 public function importData($sOSMFile)
91 if (!file_exists(getOsm2pgsqlBinary())) {
92 echo "Check NOMINATIM_OSM2PGSQL_BINARY in your local .env file.\n";
93 echo "Normally you should not need to set this manually.\n";
94 fail("osm2pgsql not found in '".getOsm2pgsqlBinary()."'");
97 $oCmd = new \Nominatim\Shell(getOsm2pgsqlBinary());
98 $oCmd->addParams('--style', getImportStyle());
100 if (getSetting('FLATNODE_FILE')) {
101 $oCmd->addParams('--flat-nodes', getSetting('FLATNODE_FILE'));
103 if (getSetting('TABLESPACE_OSM_DATA')) {
104 $oCmd->addParams('--tablespace-slim-data', getSetting('TABLESPACE_OSM_DATA'));
106 if (getSetting('TABLESPACE_OSM_INDEX')) {
107 $oCmd->addParams('--tablespace-slim-index', getSetting('TABLESPACE_OSM_INDEX'));
109 if (getSetting('TABLESPACE_PLACE_DATA')) {
110 $oCmd->addParams('--tablespace-main-data', getSetting('TABLESPACE_PLACE_DATA'));
112 if (getSetting('TABLESPACE_PLACE_INDEX')) {
113 $oCmd->addParams('--tablespace-main-index', getSetting('TABLESPACE_PLACE_INDEX'));
115 $oCmd->addParams('--latlong', '--slim', '--create');
116 $oCmd->addParams('--output', 'gazetteer');
117 $oCmd->addParams('--hstore');
118 $oCmd->addParams('--number-processes', 1);
119 $oCmd->addParams('--with-forward-dependencies', 'false');
120 $oCmd->addParams('--log-progress', 'true');
121 $oCmd->addParams('--cache', $this->iCacheMemory);
122 $oCmd->addParams('--port', $this->aDSNInfo['port']);
124 if (isset($this->aDSNInfo['username'])) {
125 $oCmd->addParams('--username', $this->aDSNInfo['username']);
127 if (isset($this->aDSNInfo['password'])) {
128 $oCmd->addEnvPair('PGPASSWORD', $this->aDSNInfo['password']);
130 if (isset($this->aDSNInfo['hostspec'])) {
131 $oCmd->addParams('--host', $this->aDSNInfo['hostspec']);
133 $oCmd->addParams('--database', $this->aDSNInfo['database']);
134 $oCmd->addParams($sOSMFile);
137 if (!$this->sIgnoreErrors && !$this->db()->getRow('select * from place limit 1')) {
142 $this->dropTable('planet_osm_nodes');
143 $this->removeFlatnodeFile();
147 public function createFunctions()
149 info('Create Functions');
151 // Try accessing the C module, so we know early if something is wrong
152 $this->checkModulePresence(); // raises exception on failure
154 $this->createSqlFunctions();
157 public function createTables($bReverseOnly = false)
159 info('Create Tables');
161 $sTemplate = file_get_contents(CONST_SqlDir.'/tables.sql');
162 $sTemplate = $this->replaceSqlPatterns($sTemplate);
164 $this->pgsqlRunScript($sTemplate, false);
167 $this->dropTable('search_name');
170 (clone($this->oNominatimCmd))->addParams('refresh', '--address-levels')->run();
173 public function createTableTriggers()
175 info('Create Tables');
177 $sTemplate = file_get_contents(CONST_SqlDir.'/table-triggers.sql');
178 $sTemplate = $this->replaceSqlPatterns($sTemplate);
180 $this->pgsqlRunScript($sTemplate, false);
183 public function createPartitionTables()
185 info('Create Partition Tables');
187 $sTemplate = file_get_contents(CONST_SqlDir.'/partition-tables.src.sql');
188 $sTemplate = $this->replaceSqlPatterns($sTemplate);
190 $this->pgsqlRunPartitionScript($sTemplate);
193 public function createPartitionFunctions()
195 info('Create Partition Functions');
196 $this->createSqlFunctions(); // also create partition functions
199 public function importWikipediaArticles()
201 $sWikiArticlePath = getSetting('WIKIPEDIA_DATA_PATH', CONST_InstallDir);
202 $sWikiArticlesFile = $sWikiArticlePath.'/wikimedia-importance.sql.gz';
203 if (file_exists($sWikiArticlesFile)) {
204 info('Importing wikipedia articles and redirects');
205 $this->dropTable('wikipedia_article');
206 $this->dropTable('wikipedia_redirect');
207 $this->pgsqlRunScriptFile($sWikiArticlesFile);
209 warn('wikipedia importance dump file not found - places will have default importance');
213 public function loadData($bDisableTokenPrecalc)
215 info('Drop old Data');
219 $oDB->exec('TRUNCATE word');
221 $oDB->exec('TRUNCATE placex');
223 $oDB->exec('TRUNCATE location_property_osmline');
225 $oDB->exec('TRUNCATE place_addressline');
227 $oDB->exec('TRUNCATE location_area');
229 if (!$this->dbReverseOnly()) {
230 $oDB->exec('TRUNCATE search_name');
233 $oDB->exec('TRUNCATE search_name_blank');
235 $oDB->exec('DROP SEQUENCE seq_place');
237 $oDB->exec('CREATE SEQUENCE seq_place start 100000');
240 $sSQL = 'select distinct partition from country_name';
241 $aPartitions = $oDB->getCol($sSQL);
243 if (!$this->bNoPartitions) $aPartitions[] = 0;
244 foreach ($aPartitions as $sPartition) {
245 $oDB->exec('TRUNCATE location_road_'.$sPartition);
249 // used by getorcreate_word_id to ignore frequent partial words
250 $sSQL = 'CREATE OR REPLACE FUNCTION get_maxwordfreq() RETURNS integer AS ';
251 $sSQL .= '$$ SELECT '.getSetting('MAX_WORD_FREQUENCY').' as maxwordfreq; $$ LANGUAGE SQL IMMUTABLE';
255 // pre-create the word list
256 if (!$bDisableTokenPrecalc) {
257 info('Loading word list');
258 $this->pgsqlRunScriptFile(CONST_DataDir.'/words.sql');
262 $sColumns = 'osm_type, osm_id, class, type, name, admin_level, address, extratags, geometry';
264 $aDBInstances = array();
265 $iLoadThreads = max(1, $this->iInstances - 1);
266 for ($i = 0; $i < $iLoadThreads; $i++) {
267 // https://secure.php.net/manual/en/function.pg-connect.php
268 $DSN = getSetting('DATABASE_DSN');
269 $DSN = preg_replace('/^pgsql:/', '', $DSN);
270 $DSN = preg_replace('/;/', ' ', $DSN);
271 $aDBInstances[$i] = pg_connect($DSN, PGSQL_CONNECT_FORCE_NEW);
272 pg_ping($aDBInstances[$i]);
275 for ($i = 0; $i < $iLoadThreads; $i++) {
276 $sSQL = "INSERT INTO placex ($sColumns) SELECT $sColumns FROM place WHERE osm_id % $iLoadThreads = $i";
277 $sSQL .= " and not (class='place' and type='houses' and osm_type='W'";
278 $sSQL .= " and ST_GeometryType(geometry) = 'ST_LineString')";
279 $sSQL .= ' and ST_IsValid(geometry)';
280 if ($this->bVerbose) echo "$sSQL\n";
281 if (!pg_send_query($aDBInstances[$i], $sSQL)) {
282 fail(pg_last_error($aDBInstances[$i]));
286 // last thread for interpolation lines
287 // https://secure.php.net/manual/en/function.pg-connect.php
288 $DSN = getSetting('DATABASE_DSN');
289 $DSN = preg_replace('/^pgsql:/', '', $DSN);
290 $DSN = preg_replace('/;/', ' ', $DSN);
291 $aDBInstances[$iLoadThreads] = pg_connect($DSN, PGSQL_CONNECT_FORCE_NEW);
292 pg_ping($aDBInstances[$iLoadThreads]);
293 $sSQL = 'insert into location_property_osmline';
294 $sSQL .= ' (osm_id, address, linegeo)';
295 $sSQL .= ' SELECT osm_id, address, geometry from place where ';
296 $sSQL .= "class='place' and type='houses' and osm_type='W' and ST_GeometryType(geometry) = 'ST_LineString'";
297 if ($this->bVerbose) echo "$sSQL\n";
298 if (!pg_send_query($aDBInstances[$iLoadThreads], $sSQL)) {
299 fail(pg_last_error($aDBInstances[$iLoadThreads]));
303 for ($i = 0; $i <= $iLoadThreads; $i++) {
304 while (($hPGresult = pg_get_result($aDBInstances[$i])) !== false) {
305 $resultStatus = pg_result_status($hPGresult);
306 // PGSQL_EMPTY_QUERY, PGSQL_COMMAND_OK, PGSQL_TUPLES_OK,
307 // PGSQL_COPY_OUT, PGSQL_COPY_IN, PGSQL_BAD_RESPONSE,
308 // PGSQL_NONFATAL_ERROR and PGSQL_FATAL_ERROR
309 // echo 'Query result ' . $i . ' is: ' . $resultStatus . "\n";
310 if ($resultStatus != PGSQL_COMMAND_OK && $resultStatus != PGSQL_TUPLES_OK) {
311 $resultError = pg_result_error($hPGresult);
312 echo '-- error text ' . $i . ': ' . $resultError . "\n";
318 fail('SQL errors loading placex and/or location_property_osmline tables');
321 for ($i = 0; $i < $this->iInstances; $i++) {
322 pg_close($aDBInstances[$i]);
326 info('Reanalysing database');
327 $this->pgsqlRunScript('ANALYSE');
329 $sDatabaseDate = getDatabaseDate($oDB);
330 $oDB->exec('TRUNCATE import_status');
331 if (!$sDatabaseDate) {
332 warn('could not determine database date.');
334 $sSQL = "INSERT INTO import_status (lastimportdate) VALUES('".$sDatabaseDate."')";
336 echo "Latest data imported from $sDatabaseDate.\n";
340 public function importTigerData($sTigerPath)
342 info('Import Tiger data');
344 $aFilenames = glob($sTigerPath.'/*.sql');
345 info('Found '.count($aFilenames).' SQL files in path '.$sTigerPath);
346 if (empty($aFilenames)) {
347 warn('Tiger data import selected but no files found in path '.$sTigerPath);
350 $sTemplate = file_get_contents(CONST_SqlDir.'/tiger_import_start.sql');
351 $sTemplate = $this->replaceSqlPatterns($sTemplate);
353 $this->pgsqlRunScript($sTemplate, false);
355 $aDBInstances = array();
356 for ($i = 0; $i < $this->iInstances; $i++) {
357 // https://secure.php.net/manual/en/function.pg-connect.php
358 $DSN = getSetting('DATABASE_DSN');
359 $DSN = preg_replace('/^pgsql:/', '', $DSN);
360 $DSN = preg_replace('/;/', ' ', $DSN);
361 $aDBInstances[$i] = pg_connect($DSN, PGSQL_CONNECT_FORCE_NEW | PGSQL_CONNECT_ASYNC);
362 pg_ping($aDBInstances[$i]);
365 foreach ($aFilenames as $sFile) {
367 $hFile = fopen($sFile, 'r');
368 $sSQL = fgets($hFile, 100000);
371 for ($i = 0; $i < $this->iInstances; $i++) {
372 if (!pg_connection_busy($aDBInstances[$i])) {
373 while (pg_get_result($aDBInstances[$i]));
374 $sSQL = fgets($hFile, 100000);
376 if (!pg_send_query($aDBInstances[$i], $sSQL)) fail(pg_last_error($aDBInstances[$i]));
378 if ($iLines == 1000) {
391 for ($i = 0; $i < $this->iInstances; $i++) {
392 if (pg_connection_busy($aDBInstances[$i])) $bAnyBusy = true;
399 for ($i = 0; $i < $this->iInstances; $i++) {
400 pg_close($aDBInstances[$i]);
403 info('Creating indexes on Tiger data');
404 $sTemplate = file_get_contents(CONST_SqlDir.'/tiger_import_finish.sql');
405 $sTemplate = $this->replaceSqlPatterns($sTemplate);
407 $this->pgsqlRunScript($sTemplate, false);
410 public function calculatePostcodes($bCMDResultAll)
412 info('Calculate Postcodes');
413 $this->pgsqlRunScriptFile(CONST_SqlDir.'/postcode_tables.sql');
415 $sPostcodeFilename = CONST_InstallDir.'/gb_postcode_data.sql.gz';
416 if (file_exists($sPostcodeFilename)) {
417 $this->pgsqlRunScriptFile($sPostcodeFilename);
419 warn('optional external GB postcode table file ('.$sPostcodeFilename.') not found. Skipping.');
422 $sPostcodeFilename = CONST_InstallDir.'/us_postcode_data.sql.gz';
423 if (file_exists($sPostcodeFilename)) {
424 $this->pgsqlRunScriptFile($sPostcodeFilename);
426 warn('optional external US postcode table file ('.$sPostcodeFilename.') not found. Skipping.');
430 $this->db()->exec('TRUNCATE location_postcode');
432 $sSQL = 'INSERT INTO location_postcode';
433 $sSQL .= ' (place_id, indexed_status, country_code, postcode, geometry) ';
434 $sSQL .= "SELECT nextval('seq_place'), 1, country_code,";
435 $sSQL .= " upper(trim (both ' ' from address->'postcode')) as pc,";
436 $sSQL .= ' ST_Centroid(ST_Collect(ST_Centroid(geometry)))';
437 $sSQL .= ' FROM placex';
438 $sSQL .= " WHERE address ? 'postcode' AND address->'postcode' NOT SIMILAR TO '%(,|;)%'";
439 $sSQL .= ' AND geometry IS NOT null';
440 $sSQL .= ' GROUP BY country_code, pc';
441 $this->db()->exec($sSQL);
443 // only add postcodes that are not yet available in OSM
444 $sSQL = 'INSERT INTO location_postcode';
445 $sSQL .= ' (place_id, indexed_status, country_code, postcode, geometry) ';
446 $sSQL .= "SELECT nextval('seq_place'), 1, 'us', postcode,";
447 $sSQL .= ' ST_SetSRID(ST_Point(x,y),4326)';
448 $sSQL .= ' FROM us_postcode WHERE postcode NOT IN';
449 $sSQL .= ' (SELECT postcode FROM location_postcode';
450 $sSQL .= " WHERE country_code = 'us')";
451 $this->db()->exec($sSQL);
453 // add missing postcodes for GB (if available)
454 $sSQL = 'INSERT INTO location_postcode';
455 $sSQL .= ' (place_id, indexed_status, country_code, postcode, geometry) ';
456 $sSQL .= "SELECT nextval('seq_place'), 1, 'gb', postcode, geometry";
457 $sSQL .= ' FROM gb_postcode WHERE postcode NOT IN';
458 $sSQL .= ' (SELECT postcode FROM location_postcode';
459 $sSQL .= " WHERE country_code = 'gb')";
460 $this->db()->exec($sSQL);
462 if (!$bCMDResultAll) {
463 $sSQL = "DELETE FROM word WHERE class='place' and type='postcode'";
464 $sSQL .= 'and word NOT IN (SELECT postcode FROM location_postcode)';
465 $this->db()->exec($sSQL);
468 $sSQL = 'SELECT count(getorcreate_postcode_id(v)) FROM ';
469 $sSQL .= '(SELECT distinct(postcode) as v FROM location_postcode) p';
470 $this->db()->exec($sSQL);
473 public function index($bIndexNoanalyse)
475 $this->checkModulePresence(); // raises exception on failure
477 $oBaseCmd = (clone $this->oNominatimCmd)->addParams('index');
479 info('Index ranks 0 - 4');
480 $oCmd = (clone $oBaseCmd)->addParams('--maxrank', 4);
482 $iStatus = $oCmd->run();
484 fail('error status ' . $iStatus . ' running nominatim!');
486 if (!$bIndexNoanalyse) $this->pgsqlRunScript('ANALYSE');
488 info('Index administrative boundaries');
489 $oCmd = (clone $oBaseCmd)->addParams('--boundaries-only');
490 $iStatus = $oCmd->run();
492 fail('error status ' . $iStatus . ' running nominatim!');
495 info('Index ranks 5 - 25');
496 $oCmd = (clone $oBaseCmd)->addParams('--no-boundaries', '--minrank', 5, '--maxrank', 25);
497 $iStatus = $oCmd->run();
499 fail('error status ' . $iStatus . ' running nominatim!');
502 if (!$bIndexNoanalyse) $this->pgsqlRunScript('ANALYSE');
504 info('Index ranks 26 - 30');
505 $oCmd = (clone $oBaseCmd)->addParams('--no-boundaries', '--minrank', 26);
506 $iStatus = $oCmd->run();
508 fail('error status ' . $iStatus . ' running nominatim!');
511 info('Index postcodes');
512 $sSQL = 'UPDATE location_postcode SET indexed_status = 0';
513 $this->db()->exec($sSQL);
516 public function createSearchIndices()
518 info('Create Search indices');
520 $sSQL = 'SELECT relname FROM pg_class, pg_index ';
521 $sSQL .= 'WHERE pg_index.indisvalid = false AND pg_index.indexrelid = pg_class.oid';
522 $aInvalidIndices = $this->db()->getCol($sSQL);
524 foreach ($aInvalidIndices as $sIndexName) {
525 info("Cleaning up invalid index $sIndexName");
526 $this->db()->exec("DROP INDEX $sIndexName;");
529 $sTemplate = file_get_contents(CONST_SqlDir.'/indices.src.sql');
531 $sTemplate .= file_get_contents(CONST_SqlDir.'/indices_updates.src.sql');
533 if (!$this->dbReverseOnly()) {
534 $sTemplate .= file_get_contents(CONST_SqlDir.'/indices_search.src.sql');
536 $sTemplate = $this->replaceSqlPatterns($sTemplate);
538 $this->pgsqlRunScript($sTemplate);
541 public function createCountryNames()
543 info('Create search index for default country names');
545 $this->pgsqlRunScript("select getorcreate_country(make_standard_name('uk'), 'gb')");
546 $this->pgsqlRunScript("select getorcreate_country(make_standard_name('united states'), 'us')");
547 $this->pgsqlRunScript('select count(*) from (select getorcreate_country(make_standard_name(country_code), country_code) from country_name where country_code is not null) as x');
548 $this->pgsqlRunScript("select count(*) from (select getorcreate_country(make_standard_name(name->'name'), country_code) from country_name where name ? 'name') as x");
549 $sSQL = 'select count(*) from (select getorcreate_country(make_standard_name(v),'
550 .'country_code) from (select country_code, skeys(name) as k, svals(name) as v from country_name) x where k ';
551 $sLanguages = getSetting('LANGUAGES');
555 foreach (explode(',', $sLanguages) as $sLang) {
556 $sSQL .= $sDelim."'name:$sLang'";
561 // all include all simple name tags
562 $sSQL .= "like 'name:%'";
565 $this->pgsqlRunScript($sSQL);
568 public function drop()
570 (clone($this->oNominatimCmd))->addParams('freeze')->run();
574 * Setup the directory for the API scripts.
578 public function setupWebsite()
580 (clone($this->oNominatimCmd))->addParams('refresh', '--website')->run();
584 * Return the connection to the database.
586 * @return Database object.
588 * Creates a new connection if none exists yet. Otherwise reuses the
589 * already established connection.
591 private function db()
593 if (is_null($this->oDB)) {
594 $this->oDB = new \Nominatim\DB();
595 $this->oDB->connect();
601 private function removeFlatnodeFile()
603 $sFName = getSetting('FLATNODE_FILE');
604 if ($sFName && file_exists($sFName)) {
605 if ($this->bVerbose) echo 'Deleting '.$sFName."\n";
610 private function pgsqlRunScript($sScript, $bfatal = true)
620 private function createSqlFunctions()
622 $oCmd = (clone($this->oNominatimCmd))
623 ->addParams('refresh', '--functions');
625 if (!$this->bEnableDiffUpdates) {
626 $oCmd->addParams('--no-diff-updates');
629 if ($this->bEnableDebugStatements) {
630 $oCmd->addParams('--enable-debug-statements');
636 private function pgsqlRunPartitionScript($sTemplate)
638 $sSQL = 'select distinct partition from country_name';
639 $aPartitions = $this->db()->getCol($sSQL);
640 if (!$this->bNoPartitions) $aPartitions[] = 0;
642 preg_match_all('#^-- start(.*?)^-- end#ms', $sTemplate, $aMatches, PREG_SET_ORDER);
643 foreach ($aMatches as $aMatch) {
645 foreach ($aPartitions as $sPartitionName) {
646 $sResult .= str_replace('-partition-', $sPartitionName, $aMatch[1]);
648 $sTemplate = str_replace($aMatch[0], $sResult, $sTemplate);
651 $this->pgsqlRunScript($sTemplate);
654 private function pgsqlRunScriptFile($sFilename)
656 if (!file_exists($sFilename)) fail('unable to find '.$sFilename);
658 $oCmd = (new \Nominatim\Shell('psql'))
659 ->addParams('--port', $this->aDSNInfo['port'])
660 ->addParams('--dbname', $this->aDSNInfo['database']);
662 if (!$this->bVerbose) {
663 $oCmd->addParams('--quiet');
665 if (isset($this->aDSNInfo['hostspec'])) {
666 $oCmd->addParams('--host', $this->aDSNInfo['hostspec']);
668 if (isset($this->aDSNInfo['username'])) {
669 $oCmd->addParams('--username', $this->aDSNInfo['username']);
671 if (isset($this->aDSNInfo['password'])) {
672 $oCmd->addEnvPair('PGPASSWORD', $this->aDSNInfo['password']);
675 if (preg_match('/\\.gz$/', $sFilename)) {
676 $aDescriptors = array(
677 0 => array('pipe', 'r'),
678 1 => array('pipe', 'w'),
679 2 => array('file', '/dev/null', 'a')
681 $oZcatCmd = new \Nominatim\Shell('zcat', $sFilename);
683 $hGzipProcess = proc_open($oZcatCmd->escapedCmd(), $aDescriptors, $ahGzipPipes);
684 if (!is_resource($hGzipProcess)) fail('unable to start zcat');
685 $aReadPipe = $ahGzipPipes[1];
686 fclose($ahGzipPipes[0]);
688 $oCmd->addParams('--file', $sFilename);
689 $aReadPipe = array('pipe', 'r');
691 $aDescriptors = array(
693 1 => array('pipe', 'w'),
694 2 => array('file', '/dev/null', 'a')
698 $hProcess = proc_open($oCmd->escapedCmd(), $aDescriptors, $ahPipes, null, $oCmd->aEnv);
699 if (!is_resource($hProcess)) fail('unable to start pgsql');
700 // TODO: error checking
701 while (!feof($ahPipes[1])) {
702 echo fread($ahPipes[1], 4096);
705 $iReturn = proc_close($hProcess);
707 fail("pgsql returned with error code ($iReturn)");
710 fclose($ahGzipPipes[1]);
711 proc_close($hGzipProcess);
715 private function replaceSqlPatterns($sSql)
717 $sSql = str_replace('{www-user}', getSetting('DATABASE_WEBUSER'), $sSql);
720 '{ts:address-data}' => getSetting('TABLESPACE_ADDRESS_DATA'),
721 '{ts:address-index}' => getSetting('TABLESPACE_ADDRESS_INDEX'),
722 '{ts:search-data}' => getSetting('TABLESPACE_SEARCH_DATA'),
723 '{ts:search-index}' => getSetting('TABLESPACE_SEARCH_INDEX'),
724 '{ts:aux-data}' => getSetting('TABLESPACE_AUX_DATA'),
725 '{ts:aux-index}' => getSetting('TABLESPACE_AUX_INDEX')
728 foreach ($aPatterns as $sPattern => $sTablespace) {
730 $sSql = str_replace($sPattern, 'TABLESPACE "'.$sTablespace.'"', $sSql);
732 $sSql = str_replace($sPattern, '', $sSql);
740 * Drop table with the given name if it exists.
742 * @param string $sName Name of table to remove.
746 private function dropTable($sName)
748 if ($this->bVerbose) echo "Dropping table $sName\n";
749 $this->db()->deleteTable($sName);
753 * Check if the database is in reverse-only mode.
755 * @return True if there is no search_name table and infrastructure.
757 private function dbReverseOnly()
759 return !($this->db()->tableExists('search_name'));
763 * Try accessing the C module, so we know early if something is wrong.
765 * Raises Nominatim\DatabaseError on failure
767 private function checkModulePresence()
769 $sModulePath = getSetting('DATABASE_MODULE_PATH', CONST_InstallDir.'/module');
770 $sSQL = "CREATE FUNCTION nominatim_test_import_func(text) RETURNS text AS '";
771 $sSQL .= $sModulePath . "/nominatim.so', 'transliteration' LANGUAGE c IMMUTABLE STRICT";
772 $sSQL .= ';DROP FUNCTION nominatim_test_import_func(text);';
774 $oDB = new \Nominatim\DB();
776 $oDB->exec($sSQL, null, 'Database server failed to load '.$sModulePath.'/nominatim.so module');