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