]> git.openstreetmap.org Git - nominatim.git/blob - utils/setup.php
calculate importance from wikipedia
[nominatim.git] / utils / setup.php
1 #!/usr/bin/php -Cq
2 <?php
3
4         require_once(dirname(dirname(__FILE__)).'/lib/init-cmd.php');
5         ini_set('memory_limit', '800M');
6
7         $aCMDOptions = array(
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'),
12
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)'),
15
16                 array('all', '', 0, 1, 0, 0, 'bool', 'Do the complete process'),
17
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('osm2pgsql-cache', '', 0, 1, 1, 1, 'int', 'Cache size used by osm2pgsql'),
22                 array('create-functions', '', 0, 1, 0, 0, 'bool', 'Create functions'),
23                 array('create-minimal-tables', '', 0, 1, 0, 0, 'bool', 'Create minimal main tables'),
24                 array('create-tables', '', 0, 1, 0, 0, 'bool', 'Create main tables'),
25                 array('create-partitions', '', 0, 1, 0, 0, 'bool', 'Create required partition tables and triggers'),
26                 array('import-wikipedia-articles', '', 0, 1, 0, 0, 'bool', 'Import wikipedia article dump'),
27                 array('load-data', '', 0, 1, 0, 0, 'bool', 'Copy data to live tables from import table'),
28                 array('import-tiger-data', '', 0, 1, 0, 0, 'bool', 'Import tiger data (not included in \'all\')'),
29                 array('calculate-postcodes', '', 0, 1, 0, 0, 'bool', 'Calculate postcode centroids'),
30                 array('create-roads', '', 0, 1, 0, 0, 'bool', 'Calculate postcode centroids'),
31                 array('osmosis-init', '', 0, 1, 0, 0, 'bool', 'Generate default osmosis configuration'),
32                 array('osmosis-init-date', '', 0, 1, 1, 1, 'string', 'Generate default osmosis configuration'),
33                 array('index', '', 0, 1, 0, 0, 'bool', 'Index the data'),
34                 array('index-output', '', 0, 1, 1, 1, 'string', 'File to dump index information to'),
35                 array('create-search-indices', '', 0, 1, 0, 0, 'bool', 'Create additional indices required for search and update'),
36                 array('create-website', '', 0, 1, 1, 1, 'realpath', 'Create symlinks to setup web directory'),
37         );
38         getCmdOpt($_SERVER['argv'], $aCMDOptions, $aCMDResult, true, true);
39
40         $bDidSomething = false;
41
42         // This is a pretty hard core defult - the number of processors in the box - 1
43         $iInstances = isset($aCMDResult['threads'])?$aCMDResult['threads']:(getProcessorCount()-1);
44         if ($iInstances < 1)
45         {
46                 $iInstances = 1;
47                 echo "WARNING: resetting threads to $iInstances\n";
48         }
49         if ($iInstances > getProcessorCount())
50         {
51                 $iInstances = getProcessorCount();
52                 echo "WARNING: resetting threads to $iInstances\n";
53         }
54
55         // Assume we can steal all the cache memory in the box (unless told otherwise)
56         $iCacheMemory = (isset($aCMDResult['osm2pgsql-cache'])?$aCMDResult['osm2pgsql-cache']:getCacheMemoryMB());
57         if ($iCacheMemory > getTotalMemoryMB())
58         {
59                 $iCacheMemory = getCacheMemoryMB();
60                 echo "WARNING: resetting cache memory to $iCacheMemory\n";
61         }
62
63         if (isset($aCMDResult['osm-file']) && !isset($aCMDResult['osmosis-init-date']))
64         {
65                 $sBaseFile = basename($aCMDResult['osm-file']);
66                 if (preg_match('#^planet-([0-9]{2})([0-9]{2})([0-9]{2})[.]#', $sBaseFile, $aMatch))
67                 {
68                         $iTime = mktime(0, 0, 0, $aMatch[2], $aMatch[3], '20'.$aMatch[1]);
69                         $iTime -= (60*60*24);
70                         $aCMDResult['osmosis-init-date'] = date('Y-m-d', $iTime).'T22:00:00Z';
71                 }
72         }
73         $aDSNInfo = DB::parseDSN(CONST_Database_DSN);
74         if (!isset($aDSNInfo['port']) || !$aDSNInfo['port']) $aDSNInfo['port'] = 5432;
75
76         if ($aCMDResult['create-db'] || $aCMDResult['all'])
77         {
78                 echo "Create DB\n";
79                 $bDidSomething = true;
80                 $oDB =& DB::connect(CONST_Database_DSN, false);
81                 if (!PEAR::isError($oDB))
82                 {
83                         fail('database already exists ('.CONST_Database_DSN.')');
84                 }
85                 passthru('createdb -E UTF-8 '.$aDSNInfo['database']);
86         }
87
88         if ($aCMDResult['create-db'] || $aCMDResult['all'])
89         {
90                 echo "Create DB (2)\n";
91                 $bDidSomething = true;
92                 // TODO: path detection, detection memory, etc.
93
94                 $oDB =& getDB();
95                 passthru('createlang plpgsql '.$aDSNInfo['database']);
96                 $pgver = (float) CONST_Postgresql_Version;
97                 if ($pgver < 9.1) {
98                         pgsqlRunScriptFile(CONST_Path_Postgresql_Contrib.'/hstore.sql');
99                 } else {
100                         pgsqlRunScript('CREATE EXTENSION hstore');
101                 }
102                 pgsqlRunScriptFile(CONST_Path_Postgresql_Postgis.'/postgis.sql');
103                 pgsqlRunScriptFile(CONST_Path_Postgresql_Postgis.'/spatial_ref_sys.sql');
104                 pgsqlRunScriptFile(CONST_BasePath.'/data/country_name.sql');
105                 pgsqlRunScriptFile(CONST_BasePath.'/data/country_naturalearthdata.sql');
106                 pgsqlRunScriptFile(CONST_BasePath.'/data/country_osm_grid.sql');
107                 pgsqlRunScriptFile(CONST_BasePath.'/data/gb_postcode.sql');
108                 pgsqlRunScriptFile(CONST_BasePath.'/data/us_statecounty.sql');
109                 pgsqlRunScriptFile(CONST_BasePath.'/data/us_state.sql');
110                 pgsqlRunScriptFile(CONST_BasePath.'/data/us_postcode.sql');
111                 pgsqlRunScriptFile(CONST_BasePath.'/data/worldboundaries.sql');
112         }
113
114         if ($aCMDResult['import-data'] || $aCMDResult['all'])
115         {
116                 echo "Import\n";
117                 $bDidSomething = true;
118
119                 $osm2pgsql = CONST_Osm2pgsql_Binary;
120                 if (!file_exists($osm2pgsql)) fail("please download and build osm2pgsql");
121                 $osm2pgsql .= ' -lsc -O gazetteer --hstore';
122                 $osm2pgsql .= ' -C '.$iCacheMemory;
123                 $osm2pgsql .= ' -d '.$aDSNInfo['database'].' '.$aCMDResult['osm-file'];
124                 passthru($osm2pgsql);
125
126                 $oDB =& getDB();
127                 $x = $oDB->getRow('select * from place limit 1');
128                 if (!$x || PEAR::isError($x)) fail('No Data');
129         }
130
131         if ($aCMDResult['create-functions'] || $aCMDResult['all'])
132         {
133                 echo "Functions\n";
134                 $bDidSomething = true;
135                 if (!file_exists(CONST_BasePath.'/module/nominatim.so')) fail("nominatim module not built");
136                 $sTemplate = file_get_contents(CONST_BasePath.'/sql/functions.sql');
137                 $sTemplate = str_replace('{modulepath}',CONST_BasePath.'/module', $sTemplate);
138                 pgsqlRunScript($sTemplate);
139         }
140
141         if ($aCMDResult['create-minimal-tables'])
142         {
143                 echo "Minimal Tables\n";
144                 $bDidSomething = true;
145                 pgsqlRunScriptFile(CONST_BasePath.'/sql/tables-minimal.sql');
146
147                 $sScript = '';
148
149                 // Backstop the import process - easliest possible import id
150                 $sScript .= "insert into import_npi_log values (18022);\n";
151
152                 $hFile = @fopen(CONST_BasePath.'/settings/partitionedtags.def', "r");
153                 if (!$hFile) fail('unable to open list of partitions: '.CONST_BasePath.'/settings/partitionedtags.def');
154
155                 while (($sLine = fgets($hFile, 4096)) !== false && $sLine && substr($sLine,0,1) !='#')
156                 {
157                         list($sClass, $sType) = explode(' ', trim($sLine));
158                         $sScript .= "create table place_classtype_".$sClass."_".$sType." as ";
159                         $sScript .= "select place_id as place_id,geometry as centroid from placex limit 0;\n";
160
161                         $sScript .= "CREATE INDEX idx_place_classtype_".$sClass."_".$sType."_centroid ";
162                         $sScript .= "ON place_classtype_".$sClass."_".$sType." USING GIST (centroid);\n";
163
164                         $sScript .= "CREATE INDEX idx_place_classtype_".$sClass."_".$sType."_place_id ";
165                         $sScript .= "ON place_classtype_".$sClass."_".$sType." USING btree(place_id);\n";
166                 }
167                 fclose($hFile);
168                 pgsqlRunScript($sScript);
169         }
170
171         if ($aCMDResult['create-tables'] || $aCMDResult['all'])
172         {
173                 echo "Tables\n";
174                 $bDidSomething = true;
175                 pgsqlRunScriptFile(CONST_BasePath.'/sql/tables.sql');
176
177                 // re-run the functions
178                 $sTemplate = file_get_contents(CONST_BasePath.'/sql/functions.sql');
179                 $sTemplate = str_replace('{modulepath}',CONST_BasePath.'/module', $sTemplate);
180                 pgsqlRunScript($sTemplate);
181         }
182
183         if ($aCMDResult['create-partitions'] || $aCMDResult['all'])
184         {
185                 echo "Partitions\n";
186                 $bDidSomething = true;
187                 $oDB =& getDB();
188                 $sSQL = 'select partition from country_name order by country_code';
189                 $aPartitions = $oDB->getCol($sSQL);
190                 if (PEAR::isError($aPartitions))
191                 {
192                         fail($aPartitions->getMessage());
193                 }
194                 $aPartitions[] = 0;
195
196                 $sTemplate = file_get_contents(CONST_BasePath.'/sql/partitions.src.sql');
197                 preg_match_all('#^-- start(.*?)^-- end#ms', $sTemplate, $aMatches, PREG_SET_ORDER);
198                 foreach($aMatches as $aMatch)
199                 {
200                         $sResult = '';
201                         foreach($aPartitions as $sPartitionName)
202                         {
203                                 $sResult .= str_replace('-partition-', $sPartitionName, $aMatch[1]);
204                         }
205                         $sTemplate = str_replace($aMatch[0], $sResult, $sTemplate);
206                 }
207
208                 pgsqlRunScript($sTemplate);
209         }
210
211         if ($aCMDResult['import-wikipedia-articles'] || $aCMDResult['all'])
212         {
213                 $bDidSomething = true;
214                 $sWikiArticlesFile = CONST_BasePath.'/data/wikipedia_article.sql.bin';
215                 $sWikiRedirectsFile = CONST_BasePath.'/data/wikipedia_redirect.sql.bin';
216                 if (file_exists($sWikiArticlesFile))
217                 {
218                         echo "Importing wikipedia articles...";
219                         pgsqlRunRestoreData($sWikiArticlesFile);
220                         echo "...done\n";
221                 }
222                 else
223                 {
224                         echo "WARNING: wikipedia article dump file not found - places will have default importance\n";
225                 }
226                 if (file_exists($sWikiRedirectsFile))
227                 {
228                         echo "Importing wikipedia redirects...";
229                         pgsqlRunRestoreData($sWikiRedirectsFile);
230                         echo "...done\n";
231                 }
232                 else
233                 {
234                         echo "WARNING: wikipedia redirect dump file not found - some place importance values may be missing\n";
235                 }
236         }
237
238
239         if ($aCMDResult['load-data'] || $aCMDResult['all'])
240         {
241                 echo "Load Data\n";
242                 $bDidSomething = true;
243
244                 $oDB =& getDB();
245                 if (!pg_query($oDB->connection, 'TRUNCATE word')) fail(pg_last_error($oDB->connection));
246                 echo '.';
247                 if (!pg_query($oDB->connection, 'TRUNCATE placex')) fail(pg_last_error($oDB->connection));
248                 echo '.';
249                 if (!pg_query($oDB->connection, 'TRUNCATE place_addressline')) fail(pg_last_error($oDB->connection));
250                 echo '.';
251                 if (!pg_query($oDB->connection, 'TRUNCATE place_boundingbox')) fail(pg_last_error($oDB->connection));
252                 echo '.';
253                 if (!pg_query($oDB->connection, 'TRUNCATE location_area')) fail(pg_last_error($oDB->connection));
254                 echo '.';
255                 if (!pg_query($oDB->connection, 'TRUNCATE search_name')) fail(pg_last_error($oDB->connection));
256                 echo '.';
257                 if (!pg_query($oDB->connection, 'TRUNCATE search_name_blank')) fail(pg_last_error($oDB->connection));
258                 echo '.';
259                 if (!pg_query($oDB->connection, 'DROP SEQUENCE seq_place')) fail(pg_last_error($oDB->connection));
260                 echo '.';
261                 if (!pg_query($oDB->connection, 'CREATE SEQUENCE seq_place start 100000')) fail(pg_last_error($oDB->connection));
262                 echo '.';
263
264                 $aDBInstances = array();
265                 for($i = 0; $i < $iInstances; $i++)
266                 {
267                         $aDBInstances[$i] =& getDB(true);
268                         $sSQL = 'insert into placex (osm_type, osm_id, class, type, name, admin_level, ';
269                         $sSQL .= 'housenumber, street, isin, postcode, country_code, extratags, ';
270                         $sSQL .= 'geometry) select * from place where osm_id % '.$iInstances.' = '.$i;
271                         if ($aCMDResult['verbose']) echo "$sSQL\n";
272                         if (!pg_send_query($aDBInstances[$i]->connection, $sSQL)) fail(pg_last_error($oDB->connection));
273                 }
274                 $bAnyBusy = true;
275                 while($bAnyBusy)
276                 {
277                         $bAnyBusy = false;
278                         for($i = 0; $i < $iInstances; $i++)
279                         {
280                                 if (pg_connection_busy($aDBInstances[$i]->connection)) $bAnyBusy = true;
281                         }
282                         sleep(1);
283                         echo '.';
284                 }
285                 echo "\n";
286                 echo "Reanalysing database...\n";
287                 pgsqlRunScript('ANALYSE');
288         }
289
290         if ($aCMDResult['create-roads'])
291         {
292                 $bDidSomething = true;
293
294                 $oDB =& getDB();
295                 $aDBInstances = array();
296                 for($i = 0; $i < $iInstances; $i++)
297                 {
298                         $aDBInstances[$i] =& getDB(true);
299                         if (!pg_query($aDBInstances[$i]->connection, 'set enable_bitmapscan = off')) fail(pg_last_error($oDB->connection));
300                         $sSQL = 'select count(*) from (select insertLocationRoad(partition, place_id, country_code, geometry) from ';
301                         $sSQL .= 'placex where osm_id % '.$iInstances.' = '.$i.' and rank_search between 26 and 27 and class = \'highway\') as x ';
302                         if ($aCMDResult['verbose']) echo "$sSQL\n";
303                         if (!pg_send_query($aDBInstances[$i]->connection, $sSQL)) fail(pg_last_error($oDB->connection));
304                 }
305                 $bAnyBusy = true;
306                 while($bAnyBusy)
307                 {
308                         $bAnyBusy = false;
309                         for($i = 0; $i < $iInstances; $i++)
310                         {
311                                 if (pg_connection_busy($aDBInstances[$i]->connection)) $bAnyBusy = true;
312                         }
313                         sleep(1);
314                         echo '.';
315                 }
316                 echo "\n";
317         }
318
319         if ($aCMDResult['import-tiger-data'])
320         {
321                 $bDidSomething = true;
322
323                 $aDBInstances = array();
324                 for($i = 0; $i < $iInstances; $i++)
325                 {
326                         $aDBInstances[$i] =& getDB(true);
327                 }
328
329                 foreach(glob(CONST_BasePath.'/data/tiger2011/*.sql') as $sFile)
330                 {
331                         echo $sFile.': ';
332                         $hFile = fopen($sFile, "r");
333                         $sSQL = fgets($hFile, 100000);
334                         $iLines = 0;
335
336                         while(true)
337                         {
338                                 for($i = 0; $i < $iInstances; $i++)
339                                 {
340                                         if (!pg_connection_busy($aDBInstances[$i]->connection))
341                                         {
342                                                 while(pg_get_result($aDBInstances[$i]->connection));
343                                                 $sSQL = fgets($hFile, 100000);
344                                                 if (!$sSQL) break 2;
345                                                 if (!pg_send_query($aDBInstances[$i]->connection, $sSQL)) fail(pg_last_error($oDB->connection));
346                                                 $iLines++;
347                                                 if ($iLines == 1000)
348                                                 {
349                                                         echo ".";
350                                                         $iLines = 0;
351                                                 }
352                                         }
353                                 }
354                                 usleep(10);
355                         }
356
357                         fclose($hFile);
358
359                         $bAnyBusy = true;
360                         while($bAnyBusy)
361                         {
362                                 $bAnyBusy = false;
363                                 for($i = 0; $i < $iInstances; $i++)
364                                 {
365                                         if (pg_connection_busy($aDBInstances[$i]->connection)) $bAnyBusy = true;
366                                 }
367                                 usleep(10);
368                         }
369                         echo "\n";
370                 }
371         }
372
373         if ($aCMDResult['calculate-postcodes'] || $aCMDResult['all'])
374         {
375                 $bDidSomething = true;
376                 $oDB =& getDB();
377                 if (!pg_query($oDB->connection, 'DELETE from placex where osm_type=\'P\'')) fail(pg_last_error($oDB->connection));
378                 $sSQL = "insert into placex (osm_type,osm_id,class,type,postcode,country_code,geometry) ";
379                 $sSQL .= "select 'P',nextval('seq_postcodes'),'place','postcode',postcode,country_code,";
380                 $sSQL .= "ST_SetSRID(ST_Point(x,y),4326) as geometry from (select country_code,postcode,";
381                 $sSQL .= "avg(st_x(st_centroid(geometry))) as x,avg(st_y(st_centroid(geometry))) as y ";
382                 $sSQL .= "from placex where postcode is not null group by country_code,postcode) as x";
383                 if (!pg_query($oDB->connection, $sSQL)) fail(pg_last_error($oDB->connection));
384
385                 $sSQL = "insert into placex (osm_type,osm_id,class,type,postcode,country_code,geometry) ";
386                 $sSQL .= "select 'P',nextval('seq_postcodes'),'place','postcode',postcode,'us',";
387                 $sSQL .= "ST_SetSRID(ST_Point(x,y),4326) as geometry from us_postcode";
388                 if (!pg_query($oDB->connection, $sSQL)) fail(pg_last_error($oDB->connection));
389         }
390
391         if (($aCMDResult['osmosis-init'] || $aCMDResult['all']) && isset($aCMDResult['osmosis-init-date']))
392         {
393                 $bDidSomething = true;
394                 $oDB =& getDB();
395
396                 if (!file_exists(CONST_Osmosis_Binary)) fail("please download osmosis");
397                 if (file_exists(CONST_BasePath.'/settings/configuration.txt')) echo "settings/configuration.txt already exists\n";
398                 else passthru(CONST_Osmosis_Binary.' --read-replication-interval-init '.CONST_BasePath.'/settings');
399
400                 $sDate = $aCMDResult['osmosis-init-date'];
401                 $aDate = date_parse_from_format("Y-m-d\TH-i", $sDate);
402                 $sURL = 'http://toolserver.org/~mazder/replicate-sequences/?';
403                 $sURL .= 'Y='.$aDate['year'].'&m='.$aDate['month'].'&d='.$aDate['day'];
404                 $sURL .= '&H='.$aDate['hour'].'&i='.$aDate['minute'].'&s=0';
405                 $sURL .= '&stream=minute';
406                 echo "Getting state file: $sURL\n";
407                 $sStateFile = file_get_contents($sURL);
408                 if (!$sStateFile || strlen($sStateFile) > 1000) fail("unable to obtain state file");
409                 file_put_contents(CONST_BasePath.'/settings/state.txt', $sStateFile);
410                 echo "Updating DB status\n";
411                 pg_query($oDB->connection, 'TRUNCATE import_status');
412                 $sSQL = "INSERT INTO import_status VALUES('".$sDate."')";
413                 pg_query($oDB->connection, $sSQL);
414
415         }
416
417         if ($aCMDResult['index'] || $aCMDResult['all'])
418         {
419                 $bDidSomething = true;
420                 $sOutputFile = '';
421                 if (isset($aCMDResult['index-output'])) $sOutputFile = ' -F '.$aCMDResult['index-output'];
422                 $sBaseCmd = CONST_BasePath.'/nominatim/nominatim -i -d '.$aDSNInfo['database'].' -t '.$iInstances.$sOutputFile;
423                 passthru($sBaseCmd.' -R 4');
424                 pgsqlRunScript('ANALYSE');
425                 passthru($sBaseCmd.' -r 5 -R 25');
426                 pgsqlRunScript('ANALYSE');
427                 passthru($sBaseCmd.' -r 26');
428         }
429
430         if ($aCMDResult['create-search-indices'] || $aCMDResult['all'])
431         {
432                 echo "Search indices\n";
433                 $bDidSomething = true;
434                 $oDB =& getDB();
435                 $sSQL = 'select partition from country_name order by country_code';
436                 $aPartitions = $oDB->getCol($sSQL);
437                 if (PEAR::isError($aPartitions))
438                 {
439                         fail($aPartitions->getMessage());
440                 }
441                 $aPartitions[] = 0;
442
443                 $sTemplate = file_get_contents(CONST_BasePath.'/sql/indices.src.sql');
444                 preg_match_all('#^-- start(.*?)^-- end#ms', $sTemplate, $aMatches, PREG_SET_ORDER);
445                 foreach($aMatches as $aMatch)
446                 {
447                         $sResult = '';
448                         foreach($aPartitions as $sPartitionName)
449                         {
450                                 $sResult .= str_replace('-partition-', $sPartitionName, $aMatch[1]);
451                         }
452                         $sTemplate = str_replace($aMatch[0], $sResult, $sTemplate);
453                 }
454
455                 pgsqlRunScript($sTemplate);
456         }
457
458         if (isset($aCMDResult['create-website']))
459         {
460                 $bDidSomething = true;
461                 $sTargetDir = $aCMDResult['create-website'];
462                 if (!is_dir($sTargetDir)) fail('please specify a directory to setup');
463                 @symlink(CONST_BasePath.'/website/details.php', $sTargetDir.'/details.php');
464                 @symlink(CONST_BasePath.'/website/reverse.php', $sTargetDir.'/reverse.php');
465                 @symlink(CONST_BasePath.'/website/search.php', $sTargetDir.'/search.php');
466                 @symlink(CONST_BasePath.'/website/search.php', $sTargetDir.'/index.php');
467                 @symlink(CONST_BasePath.'/website/images', $sTargetDir.'/images');
468                 @symlink(CONST_BasePath.'/website/js', $sTargetDir.'/js');
469                 echo "Symlinks created\n";
470         }
471
472         if (!$bDidSomething)
473         {
474                 showUsage($aCMDOptions, true);
475         }
476
477         function pgsqlRunScriptFile($sFilename)
478         {
479                 if (!file_exists($sFilename)) fail('unable to find '.$sFilename);
480
481                 // Convert database DSN to psql paramaters
482                 $aDSNInfo = DB::parseDSN(CONST_Database_DSN);
483                 if (!isset($aDSNInfo['port']) || !$aDSNInfo['port']) $aDSNInfo['port'] = 5432;
484                 $sCMD = 'psql -p '.$aDSNInfo['port'].' -d '.$aDSNInfo['database'].' -f '.$sFilename;
485
486                 $aDescriptors = array(
487                         0 => array('pipe', 'r'),
488                         1 => array('pipe', 'w'),
489                         2 => array('file', '/dev/null', 'a')
490                 );
491                 $ahPipes = null;
492                 $hProcess = proc_open($sCMD, $aDescriptors, $ahPipes);
493                 if (!is_resource($hProcess)) fail('unable to start pgsql');
494
495                 fclose($ahPipes[0]);
496
497                 // TODO: error checking
498                 while(!feof($ahPipes[1]))
499                 {
500                         echo fread($ahPipes[1], 4096);
501                 }
502                 fclose($ahPipes[1]);
503
504                 proc_close($hProcess);
505         }
506
507         function pgsqlRunScript($sScript)
508         {
509                 // Convert database DSN to psql paramaters
510                 $aDSNInfo = DB::parseDSN(CONST_Database_DSN);
511                 if (!isset($aDSNInfo['port']) || !$aDSNInfo['port']) $aDSNInfo['port'] = 5432;
512                 $sCMD = 'psql -p '.$aDSNInfo['port'].' -d '.$aDSNInfo['database'];
513                 $aDescriptors = array(
514                         0 => array('pipe', 'r'),
515                         1 => STDOUT, 
516                         2 => STDERR
517                 );
518                 $ahPipes = null;
519                 $hProcess = @proc_open($sCMD, $aDescriptors, $ahPipes);
520                 if (!is_resource($hProcess)) fail('unable to start pgsql');
521
522                 while(strlen($sScript))
523                 {
524                         $written = fwrite($ahPipes[0], $sScript);
525                         $sScript = substr($sScript, $written);
526                 }
527                 fclose($ahPipes[0]);
528                 proc_close($hProcess);
529         }
530
531         function pgsqlRunRestoreData($sDumpFile)
532         {
533                 // Convert database DSN to psql paramaters
534                 $aDSNInfo = DB::parseDSN(CONST_Database_DSN);
535                 if (!isset($aDSNInfo['port']) || !$aDSNInfo['port']) $aDSNInfo['port'] = 5432;
536                 $sCMD = 'pg_restore -p '.$aDSNInfo['port'].' -d '.$aDSNInfo['database'].' -Fc -a '.$sDumpFile;
537
538                 $aDescriptors = array(
539                         0 => array('pipe', 'r'),
540                         1 => array('pipe', 'w'),
541                         2 => array('file', '/dev/null', 'a')
542                 );
543                 $ahPipes = null;
544                 $hProcess = proc_open($sCMD, $aDescriptors, $ahPipes);
545                 if (!is_resource($hProcess)) fail('unable to start pg_restore');
546
547                 fclose($ahPipes[0]);
548
549                 // TODO: error checking
550                 while(!feof($ahPipes[1]))
551                 {
552                         echo fread($ahPipes[1], 4096);
553                 }
554                 fclose($ahPipes[1]);
555
556                 proc_close($hProcess);
557         }