source: subversion/applications/utils/export/osm2pgsql/osm2pgsql.c @ 22371

Revision 22371, 29.2 KB checked in by mazdermind, 4 years ago (diff)

add hstore-column option, which allows to create specific hstore columns for sub tags. '--hstore-column name:' will for example create a column "name:" with all the values of name:xx tags ind the form of xx=>Value for any name:xx tagged to an element. This changeset also includes changes to the regular hstore code by moving it to a separate function and also extending keyvals.c/h with an inline wrapper-function.

  • Property svn:keywords set to Rev
Line 
1/*
2#-----------------------------------------------------------------------------
3# osm2pgsql - converts planet.osm file into PostgreSQL
4# compatible output suitable to be rendered by mapnik
5# Use: osm2pgsql planet.osm.bz2
6#-----------------------------------------------------------------------------
7# Original Python implementation by Artem Pavlenko
8# Re-implementation by Jon Burgess, Copyright 2006
9#
10# This program is free software; you can redistribute it and/or
11# modify it under the terms of the GNU General Public License
12# as published by the Free Software Foundation; either version 2
13# of the License, or (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program; if not, write to the Free Software
22# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
23#-----------------------------------------------------------------------------
24*/
25
26#define _GNU_SOURCE
27#include <stdio.h>
28#include <unistd.h>
29#include <stdlib.h>
30#include <string.h>
31#include <assert.h>
32#include <getopt.h>
33#include <libgen.h>
34
35#include <libpq-fe.h>
36
37#include <libxml/xmlstring.h>
38#include <libxml/xmlreader.h>
39
40#include "osmtypes.h"
41#include "build_geometry.h"
42#include "keyvals.h"
43#include "middle-pgsql.h"
44#include "middle-ram.h"
45#include "output-pgsql.h"
46#include "output-gazetteer.h"
47#include "output-null.h"
48#include "sanitizer.h"
49#include "reprojection.h"
50#include "text-tree.h"
51#include "input.h"
52#include "sprompt.h"
53
54typedef enum { FILETYPE_NONE, FILETYPE_OSM, FILETYPE_OSMCHANGE, FILETYPE_PLANETDIFF } filetypes_t;
55typedef enum { ACTION_NONE, ACTION_CREATE, ACTION_MODIFY, ACTION_DELETE } actions_t;
56
57static int count_node,    max_node;
58static int count_way,     max_way;
59static int count_rel,     max_rel;
60
61struct output_t *out;
62
63/* Since {node,way} elements are not nested we can guarantee the
64   values in an end tag must match those of the corresponding
65   start tag and can therefore be cached.
66*/
67static double node_lon, node_lat;
68static struct keyval tags;
69static int *nds;
70static int nd_count, nd_max;
71static struct member *members;
72static int member_count, member_max;
73static int osm_id;
74
75#define INIT_MAX_MEMBERS 64
76#define INIT_MAX_NODES  4096
77
78int verbose;
79static void realloc_nodes();
80static void realloc_members();
81
82// Bounding box to filter imported data
83const char *bbox = NULL;
84static double minlon, minlat, maxlon, maxlat;
85static int extra_attributes;
86
87static void printStatus(void)
88{
89    fprintf(stderr, "\rProcessing: Node(%dk) Way(%dk) Relation(%dk)",
90            count_node/1000, count_way/1000, count_rel/1000);
91}
92
93static int parse_bbox(void)
94{
95    int n;
96
97    if (!bbox)
98        return 0;
99
100    n = sscanf(bbox, "%lf,%lf,%lf,%lf", &minlon, &minlat, &maxlon, &maxlat);
101    if (n != 4) {
102        fprintf(stderr, "Bounding box must be specified like: minlon,minlat,maxlon,maxlat\n");
103        return 1;
104    }
105    if (maxlon <= minlon) {
106        fprintf(stderr, "Bounding box failed due to maxlon <= minlon\n");
107        return 1;
108    }
109    if (maxlat <= minlat) {
110        fprintf(stderr, "Bounding box failed due to maxlat <= minlat\n");
111        return 1;
112    }
113    printf("Applying Bounding box: %f,%f to %f,%f\n", minlon,minlat,maxlon,maxlat);
114    return 0;
115}
116
117static int node_wanted(double lat, double lon)
118{
119    if (!bbox)
120        return 1;
121
122    if (lat < minlat || lat > maxlat)
123        return 0;
124    if (lon < minlon || lon > maxlon)
125        return 0;
126    return 1;
127}
128
129static filetypes_t filetype = FILETYPE_NONE;
130static actions_t action = ACTION_NONE;
131
132/* Parses the action="foo" tags in JOSM change files. Obvisouly not useful from osmChange files */
133static actions_t ParseAction( xmlTextReaderPtr reader )
134{
135    if( filetype == FILETYPE_OSMCHANGE || filetype == FILETYPE_PLANETDIFF )
136        return action;
137    actions_t new_action = ACTION_NONE;
138    xmlChar *action = xmlTextReaderGetAttribute( reader, BAD_CAST "action" );
139    if( action == NULL )
140        new_action = ACTION_CREATE;
141    else if( strcmp((char *)action, "modify") == 0 )
142        new_action = ACTION_MODIFY;
143    else if( strcmp((char *)action, "delete") == 0 )
144        new_action = ACTION_DELETE;
145    else
146    {
147        fprintf( stderr, "Unknown value for action: %s\n", (char*)action );
148        exit_nicely();
149    }
150    return new_action;
151}
152
153void StartElement(xmlTextReaderPtr reader, const xmlChar *name)
154{
155    xmlChar *xid, *xlat, *xlon, *xk, *xv, *xrole, *xtype;
156    char *k;
157
158    if (filetype == FILETYPE_NONE)
159    {
160        if (xmlStrEqual(name, BAD_CAST "osm"))
161        {
162            filetype = FILETYPE_OSM;
163            action = ACTION_CREATE;
164        }
165        else if (xmlStrEqual(name, BAD_CAST "osmChange"))
166        {
167            filetype = FILETYPE_OSMCHANGE;
168            action = ACTION_NONE;
169        }
170        else if (xmlStrEqual(name, BAD_CAST "planetdiff"))
171        {
172            filetype = FILETYPE_PLANETDIFF;
173            action = ACTION_NONE;
174        }
175        else
176        {
177            fprintf( stderr, "Unknown XML document type: %s\n", name );
178            exit_nicely();
179        }
180        return;
181    }
182   
183    if (xmlStrEqual(name, BAD_CAST "node")) {
184        xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
185        xlon = xmlTextReaderGetAttribute(reader, BAD_CAST "lon");
186        xlat = xmlTextReaderGetAttribute(reader, BAD_CAST "lat");
187        assert(xid); assert(xlon); assert(xlat);
188
189        osm_id  = strtol((char *)xid, NULL, 10);
190        node_lon = strtod((char *)xlon, NULL);
191        node_lat = strtod((char *)xlat, NULL);
192        action = ParseAction( reader );
193
194        if (osm_id > max_node)
195            max_node = osm_id;
196
197        count_node++;
198        if (count_node%10000 == 0)
199            printStatus();
200
201        xmlFree(xid);
202        xmlFree(xlon);
203        xmlFree(xlat);
204    } else if (xmlStrEqual(name, BAD_CAST "tag")) {
205        xk = xmlTextReaderGetAttribute(reader, BAD_CAST "k");
206        assert(xk);
207
208        /* 'created_by' and 'source' are common and not interesting to mapnik renderer */
209        if (strcmp((char *)xk, "created_by") && strcmp((char *)xk, "source")) {
210            char *p;
211            xv = xmlTextReaderGetAttribute(reader, BAD_CAST "v");
212            assert(xv);
213            k  = (char *)xmlStrdup(xk);
214            while ((p = strchr(k, ' ')))
215                *p = '_';
216
217            addItem(&tags, k, (char *)xv, 0);
218            xmlFree(k);
219            xmlFree(xv);
220        }
221        xmlFree(xk);
222    } else if (xmlStrEqual(name, BAD_CAST "way")) {
223
224        xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
225        assert(xid);
226        osm_id   = strtol((char *)xid, NULL, 10);
227        action = ParseAction( reader );
228       
229        if (osm_id > max_way)
230          max_way = osm_id;
231       
232        count_way++;
233        if (count_way%1000 == 0)
234          printStatus();
235       
236        nd_count = 0;
237        xmlFree(xid);
238
239    } else if (xmlStrEqual(name, BAD_CAST "nd")) {
240        xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "ref");
241        assert(xid);
242
243        nds[nd_count++] = strtol( (char *)xid, NULL, 10 );
244
245        if( nd_count >= nd_max )
246          realloc_nodes();
247        xmlFree(xid);
248    } else if (xmlStrEqual(name, BAD_CAST "relation")) {
249        xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
250        assert(xid);
251        osm_id   = strtol((char *)xid, NULL, 10);
252        action = ParseAction( reader );
253
254        if (osm_id > max_rel)
255            max_rel = osm_id;
256
257        count_rel++;
258        if (count_rel%1000 == 0)
259            printStatus();
260
261        member_count = 0;
262        xmlFree(xid);
263    } else if (xmlStrEqual(name, BAD_CAST "member")) {
264        xrole = xmlTextReaderGetAttribute(reader, BAD_CAST "role");
265        assert(xrole);
266
267        xtype = xmlTextReaderGetAttribute(reader, BAD_CAST "type");
268        assert(xtype);
269
270        xid  = xmlTextReaderGetAttribute(reader, BAD_CAST "ref");
271        assert(xid);
272
273        members[member_count].id   = strtol( (char *)xid, NULL, 0 );
274        members[member_count].role = strdup( (char *)xrole );
275       
276        /* Currently we are only interested in 'way' members since these form polygons with holes */
277        if (xmlStrEqual(xtype, BAD_CAST "way"))
278            members[member_count].type = OSMTYPE_WAY;
279        if (xmlStrEqual(xtype, BAD_CAST "node"))
280            members[member_count].type = OSMTYPE_NODE;
281        if (xmlStrEqual(xtype, BAD_CAST "relation"))
282            members[member_count].type = OSMTYPE_RELATION;
283        member_count++;
284
285        if( member_count >= member_max )
286          realloc_members();
287        xmlFree(xid);
288        xmlFree(xrole);
289        xmlFree(xtype);
290    } else if (xmlStrEqual(name, BAD_CAST "add") ||
291               xmlStrEqual(name, BAD_CAST "create")) {
292        action = ACTION_CREATE;
293        action = ACTION_MODIFY; // Turns all creates into modifies, makes it resiliant against inconsistant snapshots.
294    } else if (xmlStrEqual(name, BAD_CAST "modify")) {
295        action = ACTION_MODIFY;
296    } else if (xmlStrEqual(name, BAD_CAST "delete")) {
297        action = ACTION_DELETE;
298    } else if (xmlStrEqual(name, BAD_CAST "bound")) {
299        /* ignore */
300    } else if (xmlStrEqual(name, BAD_CAST "bounds")) {
301        /* ignore */
302    } else if (xmlStrEqual(name, BAD_CAST "changeset")) {
303        /* ignore */
304    } else {
305        fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
306    }
307
308    // Collect extra attribute information and add as tags
309    if (extra_attributes && (xmlStrEqual(name, BAD_CAST "node") ||
310                             xmlStrEqual(name, BAD_CAST "way") ||
311                             xmlStrEqual(name, BAD_CAST "relation")))
312    {
313        xmlChar *xtmp;
314
315        xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "user");
316        if (xtmp) {
317            addItem(&tags, "osm_user", (char *)xtmp, 0);
318            xmlFree(xtmp);
319        }
320
321        xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "uid");
322        if (xtmp) {
323            addItem(&tags, "osm_uid", (char *)xtmp, 0);
324            xmlFree(xtmp);
325        }
326
327        xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "version");
328        if (xtmp) {
329            addItem(&tags, "osm_version", (char *)xtmp, 0);
330            xmlFree(xtmp);
331        }
332
333        xtmp = xmlTextReaderGetAttribute(reader, BAD_CAST "timestamp");
334        if (xtmp) {
335            addItem(&tags, "osm_timestamp", (char *)xtmp, 0);
336            xmlFree(xtmp);
337        }
338    }
339}
340
341static void resetMembers()
342{
343  int i;
344  for(i=0; i<member_count; i++ )
345    free( members[i].role );
346}
347
348void EndElement(const xmlChar *name)
349{
350    if (xmlStrEqual(name, BAD_CAST "node")) {
351        if (node_wanted(node_lat, node_lon)) {
352            reproject(&node_lat, &node_lon);
353            if( action == ACTION_CREATE )
354                out->node_add(osm_id, node_lat, node_lon, &tags);
355            else if( action == ACTION_MODIFY )
356                out->node_modify(osm_id, node_lat, node_lon, &tags);
357            else if( action == ACTION_DELETE )
358                out->node_delete(osm_id);
359            else
360            {
361                fprintf( stderr, "Don't know action for node %d\n", osm_id );
362                exit_nicely();
363            }
364        }
365        resetList(&tags);
366    } else if (xmlStrEqual(name, BAD_CAST "way")) {
367        if( action == ACTION_CREATE )
368            out->way_add(osm_id, nds, nd_count, &tags );
369        else if( action == ACTION_MODIFY )
370            out->way_modify(osm_id, nds, nd_count, &tags );
371        else if( action == ACTION_DELETE )
372            out->way_delete(osm_id);
373        else
374        {
375            fprintf( stderr, "Don't know action for way %d\n", osm_id );
376            exit_nicely();
377        }
378        resetList(&tags);
379    } else if (xmlStrEqual(name, BAD_CAST "relation")) {
380        if( action == ACTION_CREATE )
381            out->relation_add(osm_id, members, member_count, &tags);
382        else if( action == ACTION_MODIFY )
383            out->relation_modify(osm_id, members, member_count, &tags);
384        else if( action == ACTION_DELETE )
385            out->relation_delete(osm_id);
386        else
387        {
388            fprintf( stderr, "Don't know action for relation %d\n", osm_id );
389            exit_nicely();
390        }
391        resetList(&tags);
392        resetMembers();
393    } else if (xmlStrEqual(name, BAD_CAST "tag")) {
394        /* ignore */
395    } else if (xmlStrEqual(name, BAD_CAST "nd")) {
396        /* ignore */
397    } else if (xmlStrEqual(name, BAD_CAST "member")) {
398        /* ignore */
399    } else if (xmlStrEqual(name, BAD_CAST "osm")) {
400        printStatus();
401        filetype = FILETYPE_NONE;
402    } else if (xmlStrEqual(name, BAD_CAST "osmChange")) {
403        printStatus();
404        filetype = FILETYPE_NONE;
405    } else if (xmlStrEqual(name, BAD_CAST "planetdiff")) {
406        printStatus();
407        filetype = FILETYPE_NONE;
408    } else if (xmlStrEqual(name, BAD_CAST "bound")) {
409        /* ignore */
410    } else if (xmlStrEqual(name, BAD_CAST "bounds")) {
411        /* ignore */
412    } else if (xmlStrEqual(name, BAD_CAST "changeset")) {
413        /* ignore */
414        resetList(&tags); /* We may have accumulated some tags even if we ignored the changeset */
415    } else if (xmlStrEqual(name, BAD_CAST "add")) {
416        action = ACTION_NONE;
417    } else if (xmlStrEqual(name, BAD_CAST "create")) {
418        action = ACTION_NONE;
419    } else if (xmlStrEqual(name, BAD_CAST "modify")) {
420        action = ACTION_NONE;
421    } else if (xmlStrEqual(name, BAD_CAST "delete")) {
422        action = ACTION_NONE;
423    } else {
424        fprintf(stderr, "%s: Unknown element name: %s\n", __FUNCTION__, name);
425    }
426}
427
428static void processNode(xmlTextReaderPtr reader) {
429    xmlChar *name;
430    name = xmlTextReaderName(reader);
431    if (name == NULL)
432        name = xmlStrdup(BAD_CAST "--");
433       
434    switch(xmlTextReaderNodeType(reader)) {
435        case XML_READER_TYPE_ELEMENT:
436            StartElement(reader, name);
437            if (xmlTextReaderIsEmptyElement(reader))
438                EndElement(name); /* No end_element for self closing tags! */
439            break;
440        case XML_READER_TYPE_END_ELEMENT:
441            EndElement(name);
442            break;
443        case XML_READER_TYPE_SIGNIFICANT_WHITESPACE:
444            /* Ignore */
445            break;
446        default:
447            fprintf(stderr, "Unknown node type %d\n", xmlTextReaderNodeType(reader));
448            break;
449    }
450
451    xmlFree(name);
452}
453
454static int streamFile(char *filename, int sanitize) {
455    xmlTextReaderPtr reader;
456    int ret = 0;
457
458    if (sanitize)
459        reader = sanitizerOpen(filename);
460    else
461        reader = inputUTF8(filename);
462
463    if (reader != NULL) {
464        ret = xmlTextReaderRead(reader);
465        while (ret == 1) {
466            processNode(reader);
467            ret = xmlTextReaderRead(reader);
468        }
469
470        if (ret != 0) {
471            fprintf(stderr, "%s : failed to parse\n", filename);
472            return ret;
473        }
474
475        xmlFreeTextReader(reader);
476    } else {
477        fprintf(stderr, "Unable to open %s\n", filename);
478        return 1;
479    }
480    return 0;
481}
482
483void exit_nicely(void)
484{
485    fprintf(stderr, "Error occurred, cleaning up\n");
486    out->cleanup();
487    exit(1);
488}
489 
490static void short_usage(char *arg0)
491{
492    const char *name = basename(arg0);
493
494    fprintf(stderr, "Usage error. For further information see:\n");
495    fprintf(stderr, "\t%s -h|--help\n", name);
496}
497
498static void long_usage(char *arg0)
499{
500    int i;
501    const char *name = basename(arg0);
502
503    fprintf(stderr, "Usage:\n");
504    fprintf(stderr, "\t%s [options] planet.osm\n", name);
505    fprintf(stderr, "\t%s [options] planet.osm.{gz,bz2}\n", name);
506    fprintf(stderr, "\t%s [options] file1.osm file2.osm file3.osm\n", name);
507    fprintf(stderr, "\nThis will import the data from the OSM file(s) into a PostgreSQL database\n");
508    fprintf(stderr, "suitable for use by the Mapnik renderer\n");
509    fprintf(stderr, "\nOptions:\n");
510    fprintf(stderr, "   -a|--append\t\tAdd the OSM file into the database without removing\n");
511    fprintf(stderr, "              \t\texisting data.\n");
512    fprintf(stderr, "   -b|--bbox\t\tApply a bounding box filter on the imported data\n");
513    fprintf(stderr, "              \t\tMust be specified as: minlon,minlat,maxlon,maxlat\n");
514    fprintf(stderr, "              \t\te.g. --bbox -0.5,51.25,0.5,51.75\n");
515    fprintf(stderr, "   -c|--create\t\tRemove existing data from the database. This is the \n");
516    fprintf(stderr, "              \t\tdefault if --append is not specified.\n");
517    fprintf(stderr, "   -d|--database\tThe name of the PostgreSQL database to connect\n");
518    fprintf(stderr, "                \tto (default: gis).\n");
519    fprintf(stderr, "   -i|--tablespace-index\tThe name of the PostgreSQL tablespace where indexes will be create\n");
520    fprintf(stderr, "                \tto (default: pg_default).\n");
521    fprintf(stderr, "   -l|--latlong\t\tStore data in degrees of latitude & longitude.\n");
522    fprintf(stderr, "   -m|--merc\t\tStore data in proper spherical mercator (default)\n");
523    fprintf(stderr, "   -M|--oldmerc\t\tStore data in the legacy OSM mercator format\n");
524    fprintf(stderr, "   -E|--proj num\tUse projection EPSG:num\n");
525    fprintf(stderr, "   -u|--utf8-sanitize\tRepair bad UTF8 input data (present in planet\n");
526    fprintf(stderr, "                \tdumps prior to August 2007). Adds about 10%% overhead.\n");
527    fprintf(stderr, "   -p|--prefix\t\tPrefix for table names (default planet_osm)\n");
528    fprintf(stderr, "   -s|--slim\t\tStore temporary data in the database. This greatly\n");
529    fprintf(stderr, "            \t\treduces the RAM usage but is much slower.\n");
530
531    if (sizeof(int*) == 4) {
532        fprintf(stderr, "            \t\tYou are running this on 32bit system, so at most\n");
533        fprintf(stderr, "            \t\t3GB of RAM will be used. If you encounter unexpected\n");
534        fprintf(stderr, "            \t\texceptions during import, you should try this switch.\n");
535    }
536   
537    fprintf(stderr, "   -S|--style\t\tLocation of the style file. Defaults to " OSM2PGSQL_DATADIR "/default.style\n");
538    fprintf(stderr, "   -C|--cache\t\tOnly for slim mode: Use upto this many MB for caching nodes\n");
539    fprintf(stderr, "             \t\tDefault is 800\n");
540    fprintf(stderr, "   -U|--username\tPostgresql user name.\n");
541    fprintf(stderr, "   -W|--password\tForce password prompt.\n");
542    fprintf(stderr, "   -H|--host\t\tDatabase server hostname or socket location.\n");
543    fprintf(stderr, "   -P|--port\t\tDatabase server port.\n");
544    fprintf(stderr, "   -e|--expire-tiles [min_zoom-]max_zoom\tCreate a tile expiry list.\n");
545    fprintf(stderr, "   -o|--expire-output filename\tOutput filename for expired tiles list.\n");
546    fprintf(stderr, "   -O|--output\t\tOutput backend.\n");
547    fprintf(stderr, "              \t\tpgsql - Output to a PostGIS database. (default)\n");
548    fprintf(stderr, "              \t\tgazetteer - Output to a PostGIS database suitable for gazetteer\n");
549    fprintf(stderr, "              \t\tnull  - No output. Useful for testing.\n");
550    fprintf(stderr, "   -x|--extra-attributes\n");
551    fprintf(stderr, "              \t\tInclude attributes for each object in the database.\n");
552    fprintf(stderr, "              \t\tThis includes the username, userid, timestamp and version.\n"); 
553    fprintf(stderr, "              \t\tNote: this option also requires additional entries in your style file.\n"); 
554    fprintf(stderr, "   -k|--hstore\t\tGenerate an additional hstore (key/value) column to  postgresql tables\n");
555    fprintf(stderr, "   -z|--hstore-column\tGenerate an additional hstore (key/value) column to containing all tags\n");
556    fprintf(stderr, "                     \tthat start with the specified string, eg --hstore-column \"name:\" will\n");
557    fprintf(stderr, "                     \tproduce an extra hstore column that contains all name:xx tags\n");
558    fprintf(stderr, "   -G|--multi-geometry\t\tGenerate multi-geometry features in postgresql tables.\n");
559    fprintf(stderr, "   -h|--help\t\tHelp information.\n");
560    fprintf(stderr, "   -v|--verbose\t\tVerbose output.\n");
561    fprintf(stderr, "\n");
562    if(!verbose)
563    {
564        fprintf(stderr, "Add -v to display supported projections.\n");
565        fprintf(stderr, "Use -E to access any espg projections (usually in /usr/share/proj/epsg)\n" );
566    }
567    else
568    {
569        fprintf(stderr, "Supported projections:\n" );
570        for(i=0; i<PROJ_COUNT; i++ )
571        {
572            fprintf( stderr, "%-20s(%2s) SRS:%6d %s\n", 
573                    Projection_Info[i].descr, Projection_Info[i].option, Projection_Info[i].srs, Projection_Info[i].proj4text);
574        }
575    }
576}
577
578const char *build_conninfo(const char *db, const char *username, const char *password, const char *host, const char *port)
579{
580    static char conninfo[1024];
581
582    conninfo[0]='\0';
583    strcat(conninfo, "dbname='");
584    strcat(conninfo, db);
585    strcat(conninfo, "'");
586
587    if (username) {
588        strcat(conninfo, " user='");
589        strcat(conninfo, username);
590        strcat(conninfo, "'");
591    }
592    if (password) {
593        strcat(conninfo, " password='");
594        strcat(conninfo, password);
595        strcat(conninfo, "'");
596    }
597    if (host) {
598        strcat(conninfo, " host='");
599        strcat(conninfo, host);
600        strcat(conninfo, "'");
601    }
602    if (port) {
603        strcat(conninfo, " port='");
604        strcat(conninfo, port);
605        strcat(conninfo, "'");
606    }
607
608    return conninfo;
609}
610
611static void realloc_nodes()
612{
613  if( nd_max == 0 )
614    nd_max = INIT_MAX_NODES;
615  else
616    nd_max <<= 1;
617   
618  nds = realloc( nds, nd_max * sizeof( nds[0] ) );
619  if( !nds )
620  {
621    fprintf( stderr, "Failed to expand node list to %d\n", nd_max );
622    exit_nicely();
623  }
624}
625
626static void realloc_members()
627{
628  if( member_max == 0 )
629    member_max = INIT_MAX_NODES;
630  else
631    member_max <<= 1;
632   
633  members = realloc( members, member_max * sizeof( members[0] ) );
634  if( !members )
635  {
636    fprintf( stderr, "Failed to expand member list to %d\n", member_max );
637    exit_nicely();
638  }
639}
640
641int main(int argc, char *argv[])
642{
643    int append=0;
644    int create=0;
645    int slim=0;
646    int sanitize=0;
647    int long_usage_bool=0;
648    int pass_prompt=0;
649    int projection = PROJ_SPHERE_MERC;
650    int expire_tiles_zoom = -1;
651    int expire_tiles_zoom_min = -1;
652    int enable_hstore = 0;
653    int enable_multi = 0;
654    const char *expire_tiles_filename = "dirty_tiles";
655    const char *db = "gis";
656    const char *username=NULL;
657    const char *host=NULL;
658    const char *password=NULL;
659    const char *port = "5432";
660    const char *tblsindex = "pg_default"; // default TABLESPACE for index
661    const char *conninfo = NULL;
662    const char *prefix = "planet_osm";
663    const char *style = OSM2PGSQL_DATADIR "/default.style";
664    const char *temparg;
665    const char *output_backend = "pgsql";
666    const char **hstore_columns = NULL;
667    int n_hstore_columns = 0;
668    int cache = 800;
669    struct output_options options;
670    PGconn *sql_conn;
671
672    fprintf(stderr, "osm2pgsql SVN version %s\n\n", VERSION);
673
674    while (1) {
675        int c, option_index = 0;
676        static struct option long_options[] = {
677            {"append",   0, 0, 'a'},
678            {"bbox",     1, 0, 'b'},
679            {"create",   0, 0, 'c'},
680            {"database", 1, 0, 'd'},
681            {"latlong",  0, 0, 'l'},
682            {"verbose",  0, 0, 'v'},
683            {"slim",     0, 0, 's'},
684            {"prefix",   1, 0, 'p'},
685            {"proj",     1, 0, 'E'},
686            {"merc",     0, 0, 'm'},
687            {"oldmerc",  0, 0, 'M'},
688            {"utf8-sanitize", 0, 0, 'u'},
689            {"cache",    1, 0, 'C'},
690            {"username", 1, 0, 'U'},
691            {"password", 0, 0, 'W'},
692            {"host",     1, 0, 'H'},
693            {"port",     1, 0, 'P'},
694            {"tablespace-index", 1, 0, 'i'},
695            {"help",     0, 0, 'h'},
696            {"style",    1, 0, 'S'},
697            {"expire-tiles", 1, 0, 'e'},
698            {"expire-output", 1, 0, 'o'},
699            {"output",   1, 0, 'O'},
700            {"extra-attributes", 0, 0, 'x'},
701            {"hstore", 0, 0, 'k'},
702            {"hstore-column", 1, 0, 'z'},
703            {"multi-geometry", 0, 0, 'G'},
704            {0, 0, 0, 0}
705        };
706
707        c = getopt_long (argc, argv, "ab:cd:hlmMp:suvU:WH:P:i:E:C:S:e:o:O:xkGz:", long_options, &option_index);
708        if (c == -1)
709            break;
710
711        switch (c) {
712            case 'a': append=1;   break;
713            case 'b': bbox=optarg; break;
714            case 'c': create=1;   break;
715            case 'v': verbose=1;  break;
716            case 's': slim=1;     break;
717            case 'u': sanitize=1; break;
718            case 'l': projection=PROJ_LATLONG;  break;
719            case 'm': projection=PROJ_SPHERE_MERC; break;
720            case 'M': projection=PROJ_MERC; break;
721            case 'E': projection=-atoi(optarg); break;
722            case 'p': prefix=optarg; break;
723            case 'd': db=optarg;  break;
724            case 'C': cache = atoi(optarg); break;
725            case 'U': username=optarg; break;
726            case 'W': pass_prompt=1; break;
727            case 'H': host=optarg; break;
728            case 'P': port=optarg; break;
729            case 'S': style=optarg; break;
730            case 'i': tblsindex=optarg; break;
731            case 'e':
732                expire_tiles_zoom_min = atoi(optarg);
733                temparg = strchr(optarg, '-');
734                if (temparg) expire_tiles_zoom = atoi(temparg + 1);
735                if (expire_tiles_zoom < expire_tiles_zoom_min) expire_tiles_zoom = expire_tiles_zoom_min;
736                break;
737            case 'o': expire_tiles_filename=optarg; break;
738            case 'O': output_backend = optarg; break;
739            case 'x': extra_attributes=1; break;
740            case 'k': enable_hstore=1; break;
741            case 'z':
742                n_hstore_columns++;
743                hstore_columns = (const char**)realloc(hstore_columns, sizeof(&n_hstore_columns) * n_hstore_columns);
744                hstore_columns[n_hstore_columns-1] = optarg;
745                break;
746            case 'G': enable_multi=1; break;
747            case 'h': long_usage_bool=1; break;
748            case '?':
749            default:
750                short_usage(argv[0]);
751                exit(EXIT_FAILURE);
752        }
753    }
754
755    if (long_usage_bool) {
756        long_usage(argv[0]);
757        exit(EXIT_FAILURE);
758    }
759
760    if (argc == optind) {  // No non-switch arguments
761        short_usage(argv[0]);
762        exit(EXIT_FAILURE);
763    }
764
765    if (append && create) {
766        fprintf(stderr, "Error: --append and --create options can not be used at the same time!\n");
767        exit(EXIT_FAILURE);
768    }
769
770    if( cache < 0 ) cache = 0;
771
772    if (pass_prompt)
773        password = simple_prompt("Password:", 100, 0);
774    else {
775        password = getenv("PGPASS");
776    }   
777       
778
779    conninfo = build_conninfo(db, username, password, host, port);
780    sql_conn = PQconnectdb(conninfo);
781    if (PQstatus(sql_conn) != CONNECTION_OK) {
782        fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(sql_conn));
783        exit(EXIT_FAILURE);
784    }
785    PQfinish(sql_conn);
786
787    text_init();
788    initList(&tags);
789
790    count_node = max_node = 0;
791    count_way = max_way = 0;
792    count_rel = max_rel = 0;
793
794    LIBXML_TEST_VERSION
795
796    project_init(projection);
797    fprintf(stderr, "Using projection SRS %d (%s)\n", 
798        project_getprojinfo()->srs, project_getprojinfo()->descr );
799
800    if (parse_bbox())
801        return 1;
802
803    options.conninfo = conninfo;
804    options.prefix = prefix;
805    options.append = append;
806    options.slim = slim;
807    options.projection = project_getprojinfo()->srs;
808    options.scale = (projection==PROJ_LATLONG)?10000000:100;
809    options.mid = slim ? &mid_pgsql : &mid_ram;
810    options.cache = cache;
811    options.style = style;
812    options.tblsindex = tblsindex;
813    options.expire_tiles_zoom = expire_tiles_zoom;
814    options.expire_tiles_zoom_min = expire_tiles_zoom_min;
815    options.expire_tiles_filename = expire_tiles_filename;
816    options.enable_multi = enable_multi;
817    options.enable_hstore = enable_hstore;
818    options.hstore_columns = hstore_columns;
819    options.n_hstore_columns = n_hstore_columns;
820
821    if (strcmp("pgsql", output_backend) == 0) {
822      out = &out_pgsql;
823    } else if (strcmp("gazetteer", output_backend) == 0) {
824      out = &out_gazetteer;
825    } else if (strcmp("null", output_backend) == 0) {
826      out = &out_null;
827    } else {
828      fprintf(stderr, "Output backend `%s' not recognised. Should be one of [pgsql, gazetteer, null].\n", output_backend);
829      exit(EXIT_FAILURE);
830    }
831
832    out->start(&options);
833
834    realloc_nodes();
835    realloc_members();
836
837    if (sizeof(int*) == 4 && options.slim != 1) {
838        fprintf(stderr, "\n!! You are running this on 32bit system, so at most\n");
839        fprintf(stderr, "!! 3GB of RAM can be used. If you encounter unexpected\n");
840        fprintf(stderr, "!! exceptions during import, you should try running in slim\n");
841        fprintf(stderr, "!! mode using parameter -s.\n");
842    }
843
844    while (optind < argc) {
845        fprintf(stderr, "\nReading in file: %s\n", argv[optind]);
846        if (streamFile(argv[optind], sanitize) != 0)
847            exit_nicely();
848        optind++;
849    }
850
851    xmlCleanupParser();
852    xmlMemoryDump();
853   
854    if (count_node || count_way || count_rel) {
855        fprintf(stderr, "\n");
856        fprintf(stderr, "Node stats: total(%d), max(%d)\n", count_node, max_node);
857        fprintf(stderr, "Way stats: total(%d), max(%d)\n", count_way, max_way);
858        fprintf(stderr, "Relation stats: total(%d), max(%d)\n", count_rel, max_rel);
859    }
860    out->stop();
861   
862    free(nds);
863    free(members);
864   
865    // free the column pointer buffer
866    free(hstore_columns);
867
868    project_exit();
869    text_exit();
870    fprintf(stderr, "\n");
871
872    return 0;
873}
Note: See TracBrowser for help on using the repository browser.