--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/app/django/contrib/gis/db/backend/postgis/creation.py Tue Oct 14 16:00:59 2008 +0000
@@ -0,0 +1,224 @@
+import os, re, sys
+
+from django.conf import settings
+from django.core.management import call_command
+from django.db import connection
+from django.db.backends.creation import TEST_DATABASE_PREFIX
+
+def getstatusoutput(cmd):
+ "A simpler version of getstatusoutput that works on win32 platforms."
+ stdin, stdout, stderr = os.popen3(cmd)
+ output = stdout.read()
+ if output.endswith('\n'): output = output[:-1]
+ status = stdin.close()
+ return status, output
+
+def create_lang(db_name, verbosity=1):
+ "Sets up the pl/pgsql language on the given database."
+
+ # Getting the command-line options for the shell command
+ options = get_cmd_options(db_name)
+
+ # Constructing the 'createlang' command.
+ createlang_cmd = 'createlang %splpgsql' % options
+ if verbosity >= 1: print createlang_cmd
+
+ # Must have database super-user privileges to execute createlang -- it must
+ # also be in your path.
+ status, output = getstatusoutput(createlang_cmd)
+
+ # Checking the status of the command, 0 => execution successful
+ if status:
+ raise Exception("Error executing 'plpgsql' command: %s\n" % output)
+
+def _create_with_cursor(db_name, verbosity=1, autoclobber=False):
+ "Creates database with psycopg2 cursor."
+
+ # Constructing the necessary SQL to create the database (the DATABASE_USER
+ # must possess the privileges to create a database)
+ create_sql = 'CREATE DATABASE %s' % connection.ops.quote_name(db_name)
+ if settings.DATABASE_USER:
+ create_sql += ' OWNER %s' % settings.DATABASE_USER
+
+ cursor = connection.cursor()
+ connection.creation.set_autocommit()
+
+ try:
+ # Trying to create the database first.
+ cursor.execute(create_sql)
+ #print create_sql
+ except Exception, e:
+ # Drop and recreate, if necessary.
+ if not autoclobber:
+ confirm = raw_input("\nIt appears the database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % db_name)
+ if autoclobber or confirm == 'yes':
+ if verbosity >= 1: print 'Destroying old spatial database...'
+ drop_db(db_name)
+ if verbosity >= 1: print 'Creating new spatial database...'
+ cursor.execute(create_sql)
+ else:
+ raise Exception('Spatial Database Creation canceled.')
+
+created_regex = re.compile(r'^createdb: database creation failed: ERROR: database ".+" already exists')
+def _create_with_shell(db_name, verbosity=1, autoclobber=False):
+ """
+ If no spatial database already exists, then using a cursor will not work.
+ Thus, a `createdb` command will be issued through the shell to bootstrap
+ creation of the spatial database.
+ """
+
+ # Getting the command-line options for the shell command
+ options = get_cmd_options(False)
+ create_cmd = 'createdb -O %s %s%s' % (settings.DATABASE_USER, options, db_name)
+ if verbosity >= 1: print create_cmd
+
+ # Attempting to create the database.
+ status, output = getstatusoutput(create_cmd)
+
+ if status:
+ if created_regex.match(output):
+ if not autoclobber:
+ confirm = raw_input("\nIt appears the database, %s, already exists. Type 'yes' to delete it, or 'no' to cancel: " % db_name)
+ if autoclobber or confirm == 'yes':
+ if verbosity >= 1: print 'Destroying old spatial database...'
+ drop_cmd = 'dropdb %s%s' % (options, db_name)
+ status, output = getstatusoutput(drop_cmd)
+ if status != 0:
+ raise Exception('Could not drop database %s: %s' % (db_name, output))
+ if verbosity >= 1: print 'Creating new spatial database...'
+ status, output = getstatusoutput(create_cmd)
+ if status != 0:
+ raise Exception('Could not create database after dropping: %s' % output)
+ else:
+ raise Exception('Spatial Database Creation canceled.')
+ else:
+ raise Exception('Unknown error occurred in creating database: %s' % output)
+
+def create_spatial_db(test=False, verbosity=1, autoclobber=False, interactive=False):
+ "Creates a spatial database based on the settings."
+
+ # Making sure we're using PostgreSQL and psycopg2
+ if settings.DATABASE_ENGINE != 'postgresql_psycopg2':
+ raise Exception('Spatial database creation only supported postgresql_psycopg2 platform.')
+
+ # Getting the spatial database name
+ if test:
+ db_name = get_spatial_db(test=True)
+ _create_with_cursor(db_name, verbosity=verbosity, autoclobber=autoclobber)
+ else:
+ db_name = get_spatial_db()
+ _create_with_shell(db_name, verbosity=verbosity, autoclobber=autoclobber)
+
+ # Creating the db language, does not need to be done on NT platforms
+ # since the PostGIS installer enables this capability.
+ if os.name != 'nt':
+ create_lang(db_name, verbosity=verbosity)
+
+ # Now adding in the PostGIS routines.
+ load_postgis_sql(db_name, verbosity=verbosity)
+
+ if verbosity >= 1: print 'Creation of spatial database %s successful.' % db_name
+
+ # Closing the connection
+ connection.close()
+ settings.DATABASE_NAME = db_name
+
+ # Syncing the database
+ call_command('syncdb', verbosity=verbosity, interactive=interactive)
+
+def drop_db(db_name=False, test=False):
+ """
+ Drops the given database (defaults to what is returned from
+ get_spatial_db()). All exceptions are propagated up to the caller.
+ """
+ if not db_name: db_name = get_spatial_db(test=test)
+ cursor = connection.cursor()
+ cursor.execute('DROP DATABASE %s' % connection.ops.quote_name(db_name))
+
+def get_cmd_options(db_name):
+ "Obtains the command-line PostgreSQL connection options for shell commands."
+ # The db_name parameter is optional
+ options = ''
+ if db_name:
+ options += '-d %s ' % db_name
+ if settings.DATABASE_USER:
+ options += '-U %s ' % settings.DATABASE_USER
+ if settings.DATABASE_HOST:
+ options += '-h %s ' % settings.DATABASE_HOST
+ if settings.DATABASE_PORT:
+ options += '-p %s ' % settings.DATABASE_PORT
+ return options
+
+def get_spatial_db(test=False):
+ """
+ Returns the name of the spatial database. The 'test' keyword may be set
+ to return the test spatial database name.
+ """
+ if test:
+ if settings.TEST_DATABASE_NAME:
+ test_db_name = settings.TEST_DATABASE_NAME
+ else:
+ test_db_name = TEST_DATABASE_PREFIX + settings.DATABASE_NAME
+ return test_db_name
+ else:
+ if not settings.DATABASE_NAME:
+ raise Exception('must configure DATABASE_NAME in settings.py')
+ return settings.DATABASE_NAME
+
+def load_postgis_sql(db_name, verbosity=1):
+ """
+ This routine loads up the PostGIS SQL files lwpostgis.sql and
+ spatial_ref_sys.sql.
+ """
+
+ # Getting the path to the PostGIS SQL
+ try:
+ # POSTGIS_SQL_PATH may be placed in settings to tell GeoDjango where the
+ # PostGIS SQL files are located. This is especially useful on Win32
+ # platforms since the output of pg_config looks like "C:/PROGRA~1/..".
+ sql_path = settings.POSTGIS_SQL_PATH
+ except AttributeError:
+ status, sql_path = getstatusoutput('pg_config --sharedir')
+ if status:
+ sql_path = '/usr/local/share'
+
+ # The PostGIS SQL post-creation files.
+ lwpostgis_file = os.path.join(sql_path, 'lwpostgis.sql')
+ srefsys_file = os.path.join(sql_path, 'spatial_ref_sys.sql')
+ if not os.path.isfile(lwpostgis_file):
+ raise Exception('Could not find PostGIS function definitions in %s' % lwpostgis_file)
+ if not os.path.isfile(srefsys_file):
+ raise Exception('Could not find PostGIS spatial reference system definitions in %s' % srefsys_file)
+
+ # Getting the psql command-line options, and command format.
+ options = get_cmd_options(db_name)
+ cmd_fmt = 'psql %s-f "%%s"' % options
+
+ # Now trying to load up the PostGIS functions
+ cmd = cmd_fmt % lwpostgis_file
+ if verbosity >= 1: print cmd
+ status, output = getstatusoutput(cmd)
+ if status:
+ raise Exception('Error in loading PostGIS lwgeometry routines.')
+
+ # Now trying to load up the Spatial Reference System table
+ cmd = cmd_fmt % srefsys_file
+ if verbosity >= 1: print cmd
+ status, output = getstatusoutput(cmd)
+ if status:
+ raise Exception('Error in loading PostGIS spatial_ref_sys table.')
+
+ # Setting the permissions because on Windows platforms the owner
+ # of the spatial_ref_sys and geometry_columns tables is always
+ # the postgres user, regardless of how the db is created.
+ if os.name == 'nt': set_permissions(db_name)
+
+def set_permissions(db_name):
+ """
+ Sets the permissions on the given database to that of the user specified
+ in the settings. Needed specifically for PostGIS on Win32 platforms.
+ """
+ cursor = connection.cursor()
+ user = settings.DATABASE_USER
+ cursor.execute('ALTER TABLE geometry_columns OWNER TO %s' % user)
+ cursor.execute('ALTER TABLE spatial_ref_sys OWNER TO %s' % user)