/[thuban]/branches/WIP-pyshapelib-bramz/test/postgissupport.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/test/postgissupport.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2106 - (show annotations)
Fri Mar 12 12:59:33 2004 UTC (20 years, 11 months ago) by bh
Original Path: trunk/thuban/test/postgissupport.py
File MIME type: text/x-python
File size: 26741 byte(s)
Support views in addition to normal tables in the postgis shapestore

* Thuban/Model/postgisdb.py
(PostGISShapeStore._fetch_table_information): Add a fallback for
the case where the table name is not in the geometry_columns
table.  This is usually the case for views.  Also, set
self.shapestore here.
(PostGISShapeStore.ShapeType): No need to query the database all
the time.  The shape type is now determined in
_fetch_table_information

* test/postgissupport.py (PostgreSQLServer.new_postgis_db)
(PostgreSQLServer.get_static_data_db, PostGISDatabase.__init__):
New parameter to specify views.
(PostGISDatabase.has_data): Also compare the views.  New views
parameter
(PostGISDatabase.initdb): Create the views.
(PostgreSQLServer.get_default_static_data_db): Add the v_landmarks
view

* test/test_postgis_db.py
(TestPostGISShapestorePointFromViews): New.  Test a
PostGISShapeStore with a view
(TestPostGISShapestorePointOIDAsGIDColumn.setUp): Pass the name of
the geometry_column explicitly to test whether that works

1 # Copyright (C) 2003, 2004 by Intevation GmbH
2 # Authors:
3 # Bernhard Herzog <[email protected]>
4 #
5 # This program is free software under the GPL (>=v2)
6 # Read the file COPYING coming with the software for details.
7
8 """Support module for tests that use a live PostGIS database"""
9
10 __version__ = "$Revision$"
11 # $Source$
12 # $Id$
13
14 import sys
15 import os
16 import time
17 import popen2
18 import shutil
19 import traceback
20
21 import support
22
23 try:
24 import psycopg
25 except ImportError:
26 psycopg = None
27
28 #
29 # Helper code
30 #
31
32 def run_config_script(cmdline):
33 """Run command cmdline and return its stdout or none in case of errors"""
34 pipe = os.popen(cmdline)
35 result = pipe.read()
36 if pipe.close() is not None:
37 raise RuntimeError('Command %r failed' % cmdline)
38 return result
39
40 def run_command(command, outfilename = None):
41 """Run command as a subprocess and send its stdout and stderr to outfile
42
43 The subprocess is run synchroneously so the function returns once
44 the subprocess has termninated. If the process' exit code is not
45 zero raise a RuntimeError.
46
47 If outfilename is None stdout and stderr are still captured but they
48 are ignored and not written to any file.
49 """
50 proc = popen2.Popen4(command)
51 proc.tochild.close()
52 output = proc.fromchild.read()
53 status = proc.wait()
54 if outfilename is not None:
55 outfile = open(outfilename, "w")
56 outfile.write(output)
57 outfile.close()
58 if not os.WIFEXITED(status) or os.WEXITSTATUS(status) != 0:
59 if outfilename:
60 message = "see %s" % outfilename
61 else:
62 message = output
63 raise RuntimeError("command %r exited with code %d.\n%s"
64 % (command, status, message))
65
66
67 def run_boolean_command(command):
68 """
69 Run command as a subprocess silently and return whether it ran successfully
70
71 Silently means that all output is captured and ignored. The exit
72 status is true if the command ran successfull, i.e. it terminated by
73 exiting and returned as zero exit code and false other wise
74 """
75 try:
76 run_command(command, None)
77 return 1
78 except RuntimeError:
79 pass
80 return 0
81
82
83 #
84 # PostgreSQL and database
85 #
86
87 class PostgreSQLServer:
88
89 """A PostgreSQL server
90
91 Instances of this class represent a PostgreSQL server with postgis
92 extensions run explicitly for the test cases. Such a server has its
93 own database directory and its own directory for the unix sockets so
94 that it doesn't interfere with any other PostgreSQL server already
95 running on the system.
96 """
97
98 def __init__(self, dbdir, port, postgis_sql, socket_dir):
99 """Initialize the PostgreSQLServer object
100
101 Parameters:
102
103 dbdir -- The directory for the databases
104 port -- The port to use
105 postgis_sql -- The name of the file with the SQL statements to
106 initialize a database for postgis.
107 socket_dir -- The directory for the socket files.
108
109 When connecting to the database server use the port and host
110 instance variables.
111 """
112 self.dbdir = dbdir
113 self.port = port
114 self.postgis_sql = postgis_sql
115 self.socket_dir = socket_dir
116
117 # For the client side the socket directory can be used as the
118 # host if the name starts with a slash.
119 self.host = os.path.abspath(socket_dir)
120
121 # name and password for the admin and an unprivileged user
122 self.admin_name = "postgres"
123 self.admin_password = "postgres"
124 self.user_name = "observer"
125 self.user_password = "telescope"
126
127 # Map db names to db objects
128 self.known_dbs = {}
129
130 def createdb(self):
131 """Create the database in dbdir and start the server.
132
133 First check whether the dbdir already exists and if necessary
134 stop an already running postmaster and remove the dbdir
135 directory completely. Then create a new database cluster in the
136 dbdir and start a postmaster.
137 """
138 if os.path.isdir(self.dbdir):
139 if self.is_running():
140 self.shutdown()
141 shutil.rmtree(self.dbdir)
142 os.mkdir(self.dbdir)
143
144 run_command(["initdb", "-D", self.dbdir, "-U", self.admin_name],
145 os.path.join(self.dbdir, "initdb.log"))
146
147 extra_opts = "-p %d" % self.port
148 if self.socket_dir is not None:
149 extra_opts += " -k %s" % self.socket_dir
150 run_command(["pg_ctl", "-D", self.dbdir,
151 "-l", os.path.join(self.dbdir, "logfile"),
152 "-o", extra_opts, "start"],
153 os.path.join(self.dbdir, "pg_ctl-start.log"))
154 # the -w option of pg_ctl doesn't work properly when the port is
155 # not the default port, so we have to implement waiting for the
156 # server ourselves
157 self.wait_for_postmaster()
158
159 self.alter_user(self.admin_name, self.admin_password)
160 self.create_user(self.user_name, self.user_password)
161
162 def wait_for_postmaster(self):
163 """Return when the database server is running
164
165 Internal method to wait until the postmaster process has been
166 started and is ready for client connections.
167 """
168 max_count = 60
169 count = 0
170 while count < max_count:
171 try:
172 run_command(["psql", "-l", "-p", str(self.port),
173 "-h", self.host, "-U", self.admin_name],
174 os.path.join(self.dbdir, "psql-%d.log" % count))
175 except RuntimeError:
176 pass
177 except:
178 traceback.print_exc()
179 else:
180 break
181 time.sleep(0.5)
182 count += 1
183 else:
184 raise RuntimeError("postmaster didn't start")
185
186 def is_running(self):
187 """Return true a postmaster process is running on self.dbdir
188
189 This method runs pg_ctl status on the dbdir so even if the
190 object has just been created it is possible that this method
191 returns true if there's still a postmaster process running for
192 self.dbdir.
193 """
194 return run_boolean_command(["pg_ctl", "-D", self.dbdir, "status"])
195
196 def shutdown(self):
197 """Stop the postmaster running for self.dbdir"""
198 run_command(["pg_ctl", "-m", "fast", "-D", self.dbdir, "stop"],
199 os.path.join(self.dbdir, "pg_ctl-stop.log"))
200
201 def new_postgis_db(self, dbname, tables = None, reference_systems = None,
202 views = None):
203 """Create and return a new PostGISDatabase object using self as server
204 """
205 db = PostGISDatabase(self, self.postgis_sql, dbname, tables = tables,
206 reference_systems = reference_systems,
207 views = views)
208 db.initdb()
209 self.known_dbs[dbname] = db
210 return db
211
212 def get_static_data_db(self, dbname, tables, reference_systems, views):
213 """Return a PostGISDatabase for a database with the given static data
214
215 If no databasse of the name dbname exists, create a new one via
216 new_postgis_db and upload the data.
217
218 If a database of the name dbname already exists and uses the
219 indicated data, return that. If the already existing db uses
220 different data raise a value error.
221
222 If the database doesn't exist, create a new one via
223 self.new_postgis_db.
224
225 The parameters tables and reference_systems have the same
226 meaning as for new_postgis_db.
227 """
228 db = self.known_dbs.get(dbname)
229 if db is not None:
230 if db.has_data(tables, reference_systems, views):
231 return db
232 raise ValueError("PostGISDatabase named %r doesn't have tables %r"
233 % (dbname, tables))
234 return self.new_postgis_db(dbname, tables, reference_systems, views)
235
236 def get_default_static_data_db(self):
237 dbname = "PostGISStaticTests"
238 srids = [(1, "proj=longlat datum=WGS84")]
239 tables = [
240 # Direct copies of the shapefiles. The shapeids are exactly
241 # the same, except where changed with "gid_offset", of
242 # course. Note that the test implementation requires that
243 # all the landmard tables use an gid_offset of 1000.
244 ("landmarks", os.path.join("..", "Data", "iceland",
245 "cultural_landmark-point.shp"),
246 [("gid_offset", 1000)]),
247 ("political", os.path.join("..", "Data", "iceland",
248 "political.shp")),
249 ("roads", os.path.join("..", "Data", "iceland",
250 "roads-line.shp")),
251
252 # The polygon data as a MULTIPOLYGON geometry type
253 ("political_multi", os.path.join("..", "Data", "iceland",
254 "political.shp"),
255 [("force_wkt_type", "MULTIPOLYGON")]),
256
257 # Copy of landmarks but using an srid != -1
258 ("landmarks_srid", os.path.join("..", "Data", "iceland",
259 "cultural_landmark-point.shp"),
260 [("gid_offset", 1000),
261 ("srid", 1)]),
262
263 # Copy of landmarks with a gid column called "point_id" instead
264 # of "gid" and using an srid != -1.
265 ("landmarks_point_id", os.path.join("..", "Data", "iceland",
266 "cultural_landmark-point.shp"),
267 [("gid_offset", 1000),
268 ("srid", 1),
269 ("gid_column", "point_id")]),
270 ]
271 views = [("v_landmarks", "SELECT * FROM landmarks_point_id")]
272 return self.get_static_data_db(dbname, tables, srids, views)
273
274 def connection_params(self, user):
275 """Return the connection parameters for the given user
276
277 The return value is a dictionary suitable as keyword argument
278 list to PostGISConnection. The user parameter may be either
279 'admin' to connect as admin or 'user' to connect as an
280 unprivileged user.
281 """
282 return {"host": self.host, "port": self.port,
283 "user": getattr(self, user + "_name"),
284 "password": getattr(self, user + "_password")}
285
286 def connection_string(self, user):
287 """Return (part of) the connection string to pass to psycopg.connect
288
289 The string contains host, port, user and password. The user
290 parameter must be either 'admin' or 'user', as for
291 connection_params.
292 """
293 params = []
294 for key, value in self.connection_params(user).items():
295 # FIXME: this doesn't do quiting correctly but that
296 # shouldn't be much of a problem (people shouldn't be using
297 # single quotes in filenames anyway :) )
298 params.append("%s='%s'" % (key, value))
299 return " ".join(params)
300
301 def execute_sql(self, dbname, user, sql):
302 """Execute the sql statament
303
304 The user parameter us used as in connection_params. The dbname
305 parameter must be the name of a database in the cluster.
306 """
307 conn = psycopg.connect("dbname=%s " % dbname
308 + self.connection_string(user))
309 cursor = conn.cursor()
310 cursor.execute(sql)
311 conn.commit()
312 conn.close()
313
314 def require_authentication(self, required):
315 """Switch authentication requirements on or off
316
317 When started for the first time no passwords are required. Some
318 tests want to explicitly test whether Thuban's password
319 infrastructure works and switch password authentication on
320 explicitly. When switching it on, there should be a
321 corresponding call to switch it off again in the test case'
322 tearDown method or in a finally: block.
323 """
324 if required:
325 contents = "local all password\n"
326 else:
327 contents = "local all trust\n"
328 f = open(os.path.join(self.dbdir, "pg_hba.conf"), "w")
329 f.write(contents)
330 f.close()
331 run_command(["pg_ctl", "-D", self.dbdir, "reload"],
332 os.path.join(self.dbdir, "pg_ctl-reload.log"))
333
334
335 def create_user(self, username, password):
336 """Create user username with password in the database"""
337 self.execute_sql("template1", "admin",
338 "CREATE USER %s PASSWORD '%s';" % (username,password))
339
340 def alter_user(self, username, password):
341 """Change the user username's password in the database"""
342 self.execute_sql("template1", "admin",
343 "ALTER USER %s PASSWORD '%s';" % (username,password))
344
345
346 class PostGISDatabase:
347
348 """A PostGIS database in a PostgreSQLServer"""
349
350 def __init__(self, server, postgis_sql, dbname, tables = None,
351 reference_systems = (), views = None):
352 """Initialize the PostGISDatabase
353
354 Parameters:
355
356 server -- The PostgreSQLServer instance containing the
357 database
358
359 postgis_sql -- Filename of the postgis.sql file with the
360 postgis initialization code
361
362 dbname -- The name of the database
363
364 tables -- Optional description of tables to create in the
365 new database. If given it should be a list of
366 (tablename, shapefilename) pairs meaning that a table
367 tablename will be created with the contents of the given
368 shapefile or (tablename, shapefilename, extraargs)
369 triples. The extraargs should be a list of key, value
370 pairs to use as keyword arguments to upload_shapefile.
371
372 reference_systems -- Optional description of spatial
373 reference systems. If given, it should be a sequence of
374 (srid, params) pairs where srid is the srid defined by
375 the proj4 paramter string params. The srid can be given
376 as an extra parameter in the tables list.
377
378 views -- Optional description of views. If given it should
379 be a list of (viewname, select_stmt) pairs where
380 viewname is the name of the view to be created and
381 select_stmt is the select statement to use as the basis.
382 The views will be created after the tables and may refer
383 to them in the select_stmt.
384 """
385 self.server = server
386 self.postgis_sql = postgis_sql
387 self.dbname = dbname
388 self.tables = tables
389 self.views = views
390 if reference_systems:
391 self.reference_systems = reference_systems
392 else:
393 # Make sure that it's a sequence we can iterate over even if
394 # the parameter's None
395 self.reference_systems = ()
396
397 def initdb(self):
398 """Remove the old db directory and create and initialize a new database
399 """
400 run_command(["createdb", "-p", str(self.server.port),
401 "-h", self.server.host, "-U", self.server.admin_name,
402 self.dbname],
403 os.path.join(self.server.dbdir, "createdb.log"))
404 run_command(["createlang", "-p", str(self.server.port),
405 "-h", self.server.host, "-U", self.server.admin_name,
406 "plpgsql", self.dbname],
407 os.path.join(self.server.dbdir, "createlang.log"))
408 # for some reason psql doesn't exit with an error code if the
409 # file given as -f doesn't exist, so we check manually by trying
410 # to open it before we run psql
411 f = open(self.postgis_sql)
412 f.close()
413 del f
414 run_command(["psql", "-f", self.postgis_sql, "-d", self.dbname,
415 "-p", str(self.server.port), "-h", self.server.host,
416 "-U", self.server.admin_name],
417 os.path.join(self.server.dbdir, "psql.log"))
418
419 self.server.execute_sql(self.dbname, "admin",
420 "GRANT SELECT ON geometry_columns TO PUBLIC;")
421 self.server.execute_sql(self.dbname, "admin",
422 "GRANT SELECT ON spatial_ref_sys TO PUBLIC;")
423
424 for srid, params in self.reference_systems:
425 self.server.execute_sql(self.dbname, "admin",
426 "INSERT INTO spatial_ref_sys VALUES"
427 " (%d, '', %d, '', '%s');"
428 % (srid, srid, params))
429 if self.tables is not None:
430 def unpack(item):
431 extra = {"force_wkt_type": None, "gid_offset": 0,
432 "srid": -1}
433 if len(info) == 2:
434 tablename, shapefile = info
435 else:
436 tablename, shapefile, kw = info
437 for key, val in kw:
438 extra[key] = val
439 return tablename, shapefile, extra
440
441 for info in self.tables:
442 tablename, shapefile, kw = unpack(info)
443 upload_shapefile(shapefile, self, tablename, **kw)
444
445 if self.views is not None:
446 for viewname, select_stmt in self.views:
447 self.server.execute_sql(self.dbname, "admin",
448 "CREATE VIEW %s AS %s" % (viewname,
449 select_stmt))
450 self.server.execute_sql(self.dbname, "admin",
451 "GRANT SELECT ON %s TO PUBLIC;"
452 % viewname)
453
454 def has_data(self, tables, reference_systems, views):
455 return (self.tables == tables
456 and self.reference_systems == reference_systems
457 and self.views == views)
458
459
460 def find_postgis_sql():
461 """Return the name of the postgis_sql file
462
463 A postgis installation usually has the postgis_sql file in
464 PostgreSQL's datadir (i.e. the directory where PostgreSQL keeps
465 static files, not the directory containing the databases).
466 Unfortunately there's no way to determine the name of this directory
467 with pg_config so we assume here that it's
468 $bindir/../share/postgresql/.
469 """
470 bindir = run_config_script("pg_config --bindir").strip()
471 return os.path.join(bindir, "..", "share", "postgresql",
472 "contrib", "postgis.sql")
473
474 _postgres_server = None
475 def get_test_server():
476 """Return the test database server object.
477
478 If it doesn't exist yet, create it first.
479
480 The server will use the directory postgis under the temp dir (as
481 defined by support.create_temp_dir()) for the database cluster.
482 Sockets will be created in tempdir.
483 """
484 global _postgres_server
485 if _postgres_server is None:
486 tempdir = support.create_temp_dir()
487 dbdir = os.path.join(tempdir, "postgis")
488 socket_dir = tempdir
489
490 _postgres_server = PostgreSQLServer(dbdir, 6543, find_postgis_sql(),
491 socket_dir = socket_dir)
492 _postgres_server.createdb()
493
494 return _postgres_server
495
496 def shutdown_test_server():
497 """Shutdown the test server if it is running"""
498 global _postgres_server
499 if _postgres_server is not None:
500 _postgres_server.shutdown()
501 _postgres_server = None
502
503
504 def reason_for_not_running_tests():
505 """
506 Determine whether postgis tests can be run and return a reason they can't
507
508 There's no fool-proof way to reliably determine this short of
509 actually running the tests but we try the following here:
510
511 - test whether pg_ctl --help can be run successfully
512 - test whether the postgis_sql can be opened
513 The name of the postgis_sql file is determined by find_postgis_sql()
514 - psycopg can be imported successfully.
515 """
516 # run_command currently uses Popen4 which is not available under
517 # Windows, for example.
518 if not hasattr(popen2, "Popen4"):
519 return "Can't run PostGIS test because popen2.Popen4 does not exist"
520
521 try:
522 run_command(["pg_ctl", "--help"], None)
523 except RuntimeError:
524 return "Can't run PostGIS tests because pg_ctl fails"
525
526 try:
527 postgis_sql = find_postgis_sql()
528 except:
529 return "Can't run PostGIS tests because postgis.sql can't be found"
530
531 try:
532 f = open(postgis_sql)
533 f.close()
534 except:
535 return "Can't run PostGIS tests because postgis.sql can't be opened"
536
537 # The test for psycopg was already done when this module was
538 # imported so we only have to check whether it was successful
539 if psycopg is None:
540 return "Can't run PostGIS tests because psycopg can't be imported"
541
542 return ""
543
544
545 _cannot_run_postgis_tests = None
546 def skip_if_no_postgis():
547 global _cannot_run_postgis_tests
548 if _cannot_run_postgis_tests is None:
549 _cannot_run_postgis_tests = reason_for_not_running_tests()
550 if _cannot_run_postgis_tests:
551 raise support.SkipTest(_cannot_run_postgis_tests)
552
553 def skip_if_addgeometrycolumn_does_not_use_quote_ident():
554 """Skip a test if the AddGeometryColumn function doesn't use quote_ident
555
556 If the AddGeometryColumn function doesn't use quote_ident it doesn't
557 support unusual table or column names properly, that is, it will
558 fail with errors for names that contain spaces or double quotes.
559
560 The test performed by this function is a bit simplistic because it
561 only tests whether the string 'quote_ident' occurs anywhere in the
562 postgis.sql file. This will hopefully work because when this was
563 fixed in postgis CVS AddGeometryColumn was the first function to use
564 quote_ident.
565 """
566 f = file(find_postgis_sql())
567 content = f.read()
568 f.close()
569 if content.find("quote_ident") < 0:
570 raise support.SkipTest("AddGeometryColumn doesn't use quote_ident")
571
572 def coords_to_point(coords):
573 """Return string with a WKT representation of the point in coords"""
574 x, y = coords[0]
575 return "POINT(%r %r)" % (x, y)
576
577 def coords_to_polygon(coords):
578 """Return string with a WKT representation of the polygon in coords"""
579 poly = []
580 for ring in coords:
581 poly.append(", ".join(["%r %r" % p for p in ring]))
582 return "POLYGON((%s))" % "), (".join(poly)
583
584 def coords_to_multilinestring(coords):
585 """Return string with a WKT representation of the arc in coords"""
586 poly = []
587 for ring in coords:
588 poly.append(", ".join(["%r %r" % p for p in ring]))
589 return "MULTILINESTRING((%s))" % "), (".join(poly)
590
591 def coords_to_multipolygon(coords):
592 """Return string with a WKT representation of the polygon in coords"""
593 poly = []
594 for ring in coords:
595 poly.append(", ".join(["%r %r" % p for p in ring]))
596 return "MULTIPOLYGON(((%s)))" % ")), ((".join(poly)
597
598 wkt_converter = {
599 "POINT": coords_to_point,
600 "MULTILINESTRING": coords_to_multilinestring,
601 "POLYGON": coords_to_polygon,
602 "MULTIPOLYGON": coords_to_multipolygon,
603 }
604
605 def upload_shapefile(filename, db, tablename, force_wkt_type = None,
606 gid_offset = 0, gid_column = "gid", srid = -1):
607 """Upload a shapefile into a new database table
608
609 Parameters:
610
611 filename -- The name of the shapefile
612
613 db -- The PostGISDatabase instance representing the database
614
615 tablename -- The name of the table to create and into which the data
616 is to be inserted
617
618 force_wkt_type -- If given the real WKT geometry type to use instead
619 of the default that would be chosen based on the type of
620 the shapefile
621
622 gid_offset -- A number to add to the shapeid to get the value for
623 the gid column (default 0)
624
625 gid_column -- The name of the column with the shape ids. Default
626 'gid'. If None, no gid column will be created. The
627 name is directly used in SQL statements, so if it
628 contains unusualy characters the caller should provide
629 a suitable quoted string.
630
631 srid -- The srid of the spatial references system used by the table
632 and the data
633 """
634 import dbflib, shapelib
635
636 # We build this map here because we need shapelib which can only be
637 # imported after support.initthuban has been called which we can't
638 # easily do in this module because it's imported by support.
639 shp_to_wkt = {
640 shapelib.SHPT_POINT: "POINT",
641 shapelib.SHPT_ARC: "MULTILINESTRING",
642 shapelib.SHPT_POLYGON: "POLYGON",
643 }
644
645 server = db.server
646 dbname = db.dbname
647 conn = psycopg.connect("dbname=%s " % dbname
648 + db.server.connection_string("admin"))
649 cursor = conn.cursor()
650
651 shp = shapelib.ShapeFile(filename)
652 dbf = dbflib.DBFFile(filename)
653 typemap = {dbflib.FTString: "VARCHAR",
654 dbflib.FTInteger: "INTEGER",
655 dbflib.FTDouble: "DOUBLE PRECISION"}
656
657 insert_formats = []
658 if gid_column:
659 insert_formats.append("%(gid)s")
660
661 fields = []
662 fields_decl = []
663 if gid_column:
664 fields.append(gid_column)
665 fields_decl.append("%s INT" % gid_column)
666 for i in range(dbf.field_count()):
667 ftype, name, width, prec = dbf.field_info(i)
668 fields.append(name)
669 fields_decl.append("%s %s" % (name, typemap[ftype]))
670 insert_formats.append("%%(%s)s" % name)
671 stmt = "CREATE TABLE %s (\n %s\n);" % (tablename,
672 ",\n ".join(fields_decl))
673 cursor.execute(stmt)
674 #print stmt
675
676 numshapes, shapetype, mins, maxs = shp.info()
677 wkttype = shp_to_wkt[shapetype]
678 if force_wkt_type:
679 wkttype = force_wkt_type
680 convert = wkt_converter[wkttype]
681
682 cursor.execute("select AddGeometryColumn('%(dbname)s',"
683 "'%(tablename)s', 'the_geom', %(srid)d, '%(wkttype)s', 2);"
684 % locals())
685 fields.append("the_geom")
686 insert_formats.append("GeometryFromText(%(the_geom)s, %(srid)d)")
687
688 insert = ("INSERT INTO %s (%s) VALUES (%s)"
689 % (tablename, ", ".join(fields), ", ".join(insert_formats)))
690
691 for i in range(numshapes):
692 data = dbf.read_record(i)
693 data["tablename"] = tablename
694 if gid_column:
695 data["gid"] = i + gid_offset
696 data["srid"] = srid
697 data["the_geom"] = convert(shp.read_object(i).vertices())
698 #print insert % data
699 cursor.execute(insert, data)
700
701 cursor.execute("GRANT SELECT ON %s TO PUBLIC;" % tablename)
702
703 conn.commit()

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26