]> git.openstreetmap.org Git - nominatim.git/blob - utils/setup.php
Merge pull request #5 from mfn/improve_errmsg
[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 (PEAR::isError($x)) {
128                         fail($x->getMessage());
129                 }
130                 if (!$x) fail('No Data');
131         }
132
133         if ($aCMDResult['create-functions'] || $aCMDResult['all'])
134         {
135                 echo "Functions\n";
136                 $bDidSomething = true;
137                 if (!file_exists(CONST_BasePath.'/module/nominatim.so')) fail("nominatim module not built");
138                 $sTemplate = file_get_contents(CONST_BasePath.'/sql/functions.sql');
139                 $sTemplate = str_replace('{modulepath}',CONST_BasePath.'/module', $sTemplate);
140                 pgsqlRunScript($sTemplate);
141         }
142
143         if ($aCMDResult['create-minimal-tables'])
144         {
145                 echo "Minimal Tables\n";
146                 $bDidSomething = true;
147                 pgsqlRunScriptFile(CONST_BasePath.'/sql/tables-minimal.sql');
148
149                 $sScript = '';
150
151                 // Backstop the import process - easliest possible import id
152                 $sScript .= "insert into import_npi_log values (18022);\n";
153
154                 $hFile = @fopen(CONST_BasePath.'/settings/partitionedtags.def', "r");
155                 if (!$hFile) fail('unable to open list of partitions: '.CONST_BasePath.'/settings/partitionedtags.def');
156
157                 while (($sLine = fgets($hFile, 4096)) !== false && $sLine && substr($sLine,0,1) !='#')
158                 {
159                         list($sClass, $sType) = explode(' ', trim($sLine));
160                         $sScript .= "create table place_classtype_".$sClass."_".$sType." as ";
161                         $sScript .= "select place_id as place_id,geometry as centroid from placex limit 0;\n";
162
163                         $sScript .= "CREATE INDEX idx_place_classtype_".$sClass."_".$sType."_centroid ";
164                         $sScript .= "ON place_classtype_".$sClass."_".$sType." USING GIST (centroid);\n";
165
166                         $sScript .= "CREATE INDEX idx_place_classtype_".$sClass."_".$sType."_place_id ";
167                         $sScript .= "ON place_classtype_".$sClass."_".$sType." USING btree(place_id);\n";
168                 }
169                 fclose($hFile);
170                 pgsqlRunScript($sScript);
171         }
172
173         if ($aCMDResult['create-tables'] || $aCMDResult['all'])
174         {
175                 echo "Tables\n";
176                 $bDidSomething = true;
177                 pgsqlRunScriptFile(CONST_BasePath.'/sql/tables.sql');
178
179                 // re-run the functions
180                 $sTemplate = file_get_contents(CONST_BasePath.'/sql/functions.sql');
181                 $sTemplate = str_replace('{modulepath}',CONST_BasePath.'/module', $sTemplate);
182                 pgsqlRunScript($sTemplate);
183         }
184
185         if ($aCMDResult['create-partitions'] || $aCMDResult['all'])
186         {
187                 echo "Partitions\n";
188                 $bDidSomething = true;
189                 $oDB =& getDB();
190                 $sSQL = 'select partition from country_name order by country_code';
191                 $aPartitions = $oDB->getCol($sSQL);
192                 if (PEAR::isError($aPartitions))
193                 {
194                         fail($aPartitions->getMessage());
195                 }
196                 $aPartitions[] = 0;
197
198                 $sTemplate = file_get_contents(CONST_BasePath.'/sql/partitions.src.sql');
199                 preg_match_all('#^-- start(.*?)^-- end#ms', $sTemplate, $aMatches, PREG_SET_ORDER);
200                 foreach($aMatches as $aMatch)
201                 {
202                         $sResult = '';
203                         foreach($aPartitions as $sPartitionName)
204                         {
205                                 $sResult .= str_replace('-partition-', $sPartitionName, $aMatch[1]);
206                         }
207                         $sTemplate = str_replace($aMatch[0], $sResult, $sTemplate);
208                 }
209
210                 pgsqlRunScript($sTemplate);
211         }
212
213         if ($aCMDResult['load-data'] || $aCMDResult['all'])
214         {
215                 echo "Load Data\n";
216                 $bDidSomething = true;
217
218                 $oDB =& getDB();
219                 if (!pg_query($oDB->connection, 'TRUNCATE word')) fail(pg_last_error($oDB->connection));
220                 echo '.';
221                 if (!pg_query($oDB->connection, 'TRUNCATE placex')) fail(pg_last_error($oDB->connection));
222                 echo '.';
223                 if (!pg_query($oDB->connection, 'TRUNCATE place_addressline')) fail(pg_last_error($oDB->connection));
224                 echo '.';
225                 if (!pg_query($oDB->connection, 'TRUNCATE place_boundingbox')) fail(pg_last_error($oDB->connection));
226                 echo '.';
227                 if (!pg_query($oDB->connection, 'TRUNCATE location_area')) fail(pg_last_error($oDB->connection));
228                 echo '.';
229                 if (!pg_query($oDB->connection, 'TRUNCATE search_name')) fail(pg_last_error($oDB->connection));
230                 echo '.';
231                 if (!pg_query($oDB->connection, 'TRUNCATE search_name_blank')) fail(pg_last_error($oDB->connection));
232                 echo '.';
233                 if (!pg_query($oDB->connection, 'DROP SEQUENCE seq_place')) fail(pg_last_error($oDB->connection));
234                 echo '.';
235                 if (!pg_query($oDB->connection, 'CREATE SEQUENCE seq_place start 100000')) fail(pg_last_error($oDB->connection));
236                 echo '.';
237
238                 $aDBInstances = array();
239                 for($i = 0; $i < $iInstances; $i++)
240                 {
241                         $aDBInstances[$i] =& getDB(true);
242                         $sSQL = 'insert into placex (osm_type, osm_id, class, type, name, admin_level, ';
243                         $sSQL .= 'housenumber, street, isin, postcode, country_code, extratags, ';
244                         $sSQL .= 'geometry) select * from place where osm_id % '.$iInstances.' = '.$i;
245                         if ($aCMDResult['verbose']) echo "$sSQL\n";
246                         if (!pg_send_query($aDBInstances[$i]->connection, $sSQL)) fail(pg_last_error($oDB->connection));
247                 }
248                 $bAnyBusy = true;
249                 while($bAnyBusy)
250                 {
251                         $bAnyBusy = false;
252                         for($i = 0; $i < $iInstances; $i++)
253                         {
254                                 if (pg_connection_busy($aDBInstances[$i]->connection)) $bAnyBusy = true;
255                         }
256                         sleep(1);
257                         echo '.';
258                 }
259                 echo "\n";
260                 echo "Reanalysing database...\n";
261                 pgsqlRunScript('ANALYSE');
262         }
263
264         if ($aCMDResult['create-roads'])
265         {
266                 $bDidSomething = true;
267
268                 $oDB =& getDB();
269                 $aDBInstances = array();
270                 for($i = 0; $i < $iInstances; $i++)
271                 {
272                         $aDBInstances[$i] =& getDB(true);
273                         if (!pg_query($aDBInstances[$i]->connection, 'set enable_bitmapscan = off')) fail(pg_last_error($oDB->connection));
274                         $sSQL = 'select count(*) from (select insertLocationRoad(partition, place_id, country_code, geometry) from ';
275                         $sSQL .= 'placex where osm_id % '.$iInstances.' = '.$i.' and rank_search between 26 and 27 and class = \'highway\') as x ';
276                         if ($aCMDResult['verbose']) echo "$sSQL\n";
277                         if (!pg_send_query($aDBInstances[$i]->connection, $sSQL)) fail(pg_last_error($oDB->connection));
278                 }
279                 $bAnyBusy = true;
280                 while($bAnyBusy)
281                 {
282                         $bAnyBusy = false;
283                         for($i = 0; $i < $iInstances; $i++)
284                         {
285                                 if (pg_connection_busy($aDBInstances[$i]->connection)) $bAnyBusy = true;
286                         }
287                         sleep(1);
288                         echo '.';
289                 }
290                 echo "\n";
291         }
292
293         if ($aCMDResult['import-tiger-data'])
294         {
295                 $bDidSomething = true;
296
297                 $aDBInstances = array();
298                 for($i = 0; $i < $iInstances; $i++)
299                 {
300                         $aDBInstances[$i] =& getDB(true);
301                 }
302
303                 foreach(glob(CONST_BasePath.'/data/tiger2011/*.sql') as $sFile)
304                 {
305                         echo $sFile.': ';
306                         $hFile = fopen($sFile, "r");
307                         $sSQL = fgets($hFile, 100000);
308                         $iLines = 0;
309
310                         while(true)
311                         {
312                                 for($i = 0; $i < $iInstances; $i++)
313                                 {
314                                         if (!pg_connection_busy($aDBInstances[$i]->connection))
315                                         {
316                                                 while(pg_get_result($aDBInstances[$i]->connection));
317                                                 $sSQL = fgets($hFile, 100000);
318                                                 if (!$sSQL) break 2;
319                                                 if (!pg_send_query($aDBInstances[$i]->connection, $sSQL)) fail(pg_last_error($oDB->connection));
320                                                 $iLines++;
321                                                 if ($iLines == 1000)
322                                                 {
323                                                         echo ".";
324                                                         $iLines = 0;
325                                                 }
326                                         }
327                                 }
328                                 usleep(10);
329                         }
330
331                         fclose($hFile);
332         
333                         $bAnyBusy = true;
334                         while($bAnyBusy)
335                         {
336                                 $bAnyBusy = false;
337                                 for($i = 0; $i < $iInstances; $i++)
338                                 {
339                                         if (pg_connection_busy($aDBInstances[$i]->connection)) $bAnyBusy = true;
340                                 }
341                                 usleep(10);
342                         }
343                         echo "\n";
344                 }
345         }
346
347         if ($aCMDResult['calculate-postcodes'] || $aCMDResult['all'])
348         {
349                 $bDidSomething = true;
350                 $oDB =& getDB();
351                 if (!pg_query($oDB->connection, 'DELETE from placex where osm_type=\'P\'')) fail(pg_last_error($oDB->connection));
352                 $sSQL = "insert into placex (osm_type,osm_id,class,type,postcode,country_code,geometry) ";
353                 $sSQL .= "select 'P',nextval('seq_postcodes'),'place','postcode',postcode,country_code,";
354                 $sSQL .= "ST_SetSRID(ST_Point(x,y),4326) as geometry from (select country_code,postcode,";
355                 $sSQL .= "avg(st_x(st_centroid(geometry))) as x,avg(st_y(st_centroid(geometry))) as y ";
356                 $sSQL .= "from placex where postcode is not null group by country_code,postcode) as x";
357                 if (!pg_query($oDB->connection, $sSQL)) fail(pg_last_error($oDB->connection));
358
359                 $sSQL = "insert into placex (osm_type,osm_id,class,type,postcode,country_code,geometry) ";
360                 $sSQL .= "select 'P',nextval('seq_postcodes'),'place','postcode',postcode,'us',";
361                 $sSQL .= "ST_SetSRID(ST_Point(x,y),4326) as geometry from us_postcode";
362                 if (!pg_query($oDB->connection, $sSQL)) fail(pg_last_error($oDB->connection));
363         }
364
365         if (($aCMDResult['osmosis-init'] || $aCMDResult['all']) && isset($aCMDResult['osmosis-init-date']))
366         {
367                 $bDidSomething = true;
368                 $oDB =& getDB();
369
370                 if (!file_exists(CONST_Osmosis_Binary)) fail("please download osmosis");
371                 if (file_exists(CONST_BasePath.'/settings/configuration.txt')) echo "settings/configuration.txt already exists\n";
372                 else passthru(CONST_Osmosis_Binary.' --read-replication-interval-init '.CONST_BasePath.'/settings');
373
374                 $sDate = $aCMDResult['osmosis-init-date'];
375                 $aDate = date_parse_from_format("Y-m-d\TH-i", $sDate);
376                 $sURL = 'http://toolserver.org/~mazder/replicate-sequences/?';
377                 $sURL .= 'Y='.$aDate['year'].'&m='.$aDate['month'].'&d='.$aDate['day'];
378                 $sURL .= '&H='.$aDate['hour'].'&i='.$aDate['minute'].'&s=0';
379                 $sURL .= '&stream=minute';
380                 echo "Getting state file: $sURL\n";
381                 $sStateFile = file_get_contents($sURL);
382                 if (!$sStateFile || strlen($sStateFile) > 1000) fail("unable to obtain state file");
383                 file_put_contents(CONST_BasePath.'/settings/state.txt', $sStateFile);
384                 echo "Updating DB status\n";
385                 pg_query($oDB->connection, 'TRUNCATE import_status');
386                 $sSQL = "INSERT INTO import_status VALUES('".$sDate."')";
387                 pg_query($oDB->connection, $sSQL);
388
389         }
390
391         if ($aCMDResult['index'] || $aCMDResult['all'])
392         {
393                 $bDidSomething = true;
394                 $sOutputFile = '';
395                 if (isset($aCMDResult['index-output'])) $sOutputFile = ' -F '.$aCMDResult['index-output'];
396                 $sBaseCmd = CONST_BasePath.'/nominatim/nominatim -i -d '.$aDSNInfo['database'].' -t '.$iInstances.$sOutputFile;
397                 passthru($sBaseCmd.' -R 4');
398                 pgsqlRunScript('ANALYSE');
399                 passthru($sBaseCmd.' -r 5 -R 25');
400                 pgsqlRunScript('ANALYSE');
401                 passthru($sBaseCmd.' -r 26');
402         }
403
404         if ($aCMDResult['create-search-indices'] || $aCMDResult['all'])
405         {
406                 echo "Search indices\n";
407                 $bDidSomething = true;
408                 $oDB =& getDB();
409                 $sSQL = 'select partition from country_name order by country_code';
410                 $aPartitions = $oDB->getCol($sSQL);
411                 if (PEAR::isError($aPartitions))
412                 {
413                         fail($aPartitions->getMessage());
414                 }
415                 $aPartitions[] = 0;
416
417                 $sTemplate = file_get_contents(CONST_BasePath.'/sql/indices.src.sql');
418                 preg_match_all('#^-- start(.*?)^-- end#ms', $sTemplate, $aMatches, PREG_SET_ORDER);
419                 foreach($aMatches as $aMatch)
420                 {
421                         $sResult = '';
422                         foreach($aPartitions as $sPartitionName)
423                         {
424                                 $sResult .= str_replace('-partition-', $sPartitionName, $aMatch[1]);
425                         }
426                         $sTemplate = str_replace($aMatch[0], $sResult, $sTemplate);
427                 }
428
429                 pgsqlRunScript($sTemplate);
430         }
431
432         if (isset($aCMDResult['create-website']))
433         {
434                 $bDidSomething = true;
435                 $sTargetDir = $aCMDResult['create-website'];
436                 if (!is_dir($sTargetDir)) fail('please specify a directory to setup');
437                 @symlink(CONST_BasePath.'/website/details.php', $sTargetDir.'/details.php');
438                 @symlink(CONST_BasePath.'/website/reverse.php', $sTargetDir.'/reverse.php');
439                 @symlink(CONST_BasePath.'/website/search.php', $sTargetDir.'/search.php');
440                 @symlink(CONST_BasePath.'/website/search.php', $sTargetDir.'/index.php');
441                 @symlink(CONST_BasePath.'/website/images', $sTargetDir.'/images');
442                 @symlink(CONST_BasePath.'/website/js', $sTargetDir.'/js');
443                 echo "Symlinks created\n";
444         }
445
446         if (!$bDidSomething)
447         {
448                 showUsage($aCMDOptions, true);
449         }
450
451         function pgsqlRunScriptFile($sFilename)
452         {
453                 if (!file_exists($sFilename)) fail('unable to find '.$sFilename);
454
455                 // Convert database DSN to psql paramaters
456                 $aDSNInfo = DB::parseDSN(CONST_Database_DSN);
457                 $sCMD = 'psql -f '.$sFilename.' '.$aDSNInfo['database'];
458
459                 $aDescriptors = array(
460                         0 => array('pipe', 'r'),
461                         1 => array('pipe', 'w'),
462                         2 => array('file', '/dev/null', 'a')
463                 );
464                 $ahPipes = null;
465                 $hProcess = proc_open($sCMD, $aDescriptors, $ahPipes);
466                 if (!is_resource($hProcess)) fail('unable to start pgsql');
467
468                 fclose($ahPipes[0]);
469
470                 // TODO: error checking
471                 while(!feof($ahPipes[1]))
472                 {
473                         echo fread($ahPipes[1], 4096);
474                 }
475                 fclose($ahPipes[1]);
476
477                 proc_close($hProcess);
478         }
479
480         function pgsqlRunScript($sScript)
481         {
482                 // Convert database DSN to psql paramaters
483                 $aDSNInfo = DB::parseDSN(CONST_Database_DSN);
484                 if (!isset($aDSNInfo['port']) || !$aDSNInfo['port']) $aDSNInfo['port'] = 5432;
485                 $sCMD = 'psql -p '.$aDSNInfo['port'].' '.$aDSNInfo['database'];
486                 $aDescriptors = array(
487                         0 => array('pipe', 'r'),
488                         1 => STDOUT, 
489                         2 => STDERR
490                 );
491                 $ahPipes = null;
492                 $hProcess = @proc_open($sCMD, $aDescriptors, $ahPipes);
493                 if (!is_resource($hProcess)) fail('unable to start pgsql');
494
495                 while(strlen($sScript))
496                 {
497                         $written = fwrite($ahPipes[0], $sScript);
498                         $sScript = substr($sScript, $written);
499                 }
500                 fclose($ahPipes[0]);
501                 proc_close($hProcess);
502         }