Class: ActiveRecord::ConnectionAdapters::PostgreSQLAdapter

Inherits:
Object
  • Object
show all
Defined in:
lib/spatial_adapter/postgresql.rb

Instance Method Summary collapse

Instance Method Details

#add_column(table_name, column_name, type, options = {}) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/spatial_adapter/postgresql.rb', line 111

def add_column(table_name, column_name, type, options = {})
  unless SpatialAdapter.geometry_data_types[type].nil?
    geom_column = ActiveRecord::ConnectionAdapters::PostgreSQLColumnDefinition.new(self, column_name, type, nil, nil, options[:null], options[:srid] || -1 , options[:with_z] || false , options[:with_m] || false, options[:geographic] || false)
    if geom_column.geographic
      default = options[:default]
      notnull = options[:null] == false

      execute("ALTER TABLE #{quote_table_name(table_name)} ADD COLUMN #{geom_column.to_sql}")

      change_column_default(table_name, column_name, default) if options_include_default?(options)
      change_column_null(table_name, column_name, false, default) if notnull
    else
      geom_column.table_name = table_name
      execute geom_column.to_sql
    end
  else
    original_add_column(table_name, column_name, type, options)
  end
end

#add_index(table_name, column_name, options = {}) ⇒ Object

Adds an index to a column.



132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/spatial_adapter/postgresql.rb', line 132

def add_index(table_name, column_name, options = {})
  column_names = Array(column_name)
  index_name   = index_name(table_name, :column => column_names)

  if Hash === options # legacy support, since this param was a string
    index_type = options[:unique] ? "UNIQUE" : ""
    index_name = options[:name] || index_name
    index_method = options[:spatial] ? 'USING GIST' : ""
  else
    index_type = options
  end
  quoted_column_names = column_names.map { |e| quote_column_name(e) }.join(", ")
  execute "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{index_method} (#{quoted_column_names})"
end

#columns(table_name, name = nil) ⇒ Object

:nodoc:



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/spatial_adapter/postgresql.rb', line 47

def columns(table_name, name = nil) #:nodoc:
  raw_geom_infos = column_spatial_info(table_name)

  column_definitions(table_name).collect do |name, type, default, notnull|
    case type
    when /geography/i
      ActiveRecord::ConnectionAdapters::SpatialPostgreSQLColumn.create_from_geography(name, default, type, notnull == 'f')
    when /geometry/i
      raw_geom_info = raw_geom_infos[name]
      if raw_geom_info.nil?
        # This column isn't in the geometry_columns table, so we don't know anything else about it
        ActiveRecord::ConnectionAdapters::SpatialPostgreSQLColumn.create_simplified(name, default, notnull == "f")
      else
        ActiveRecord::ConnectionAdapters::SpatialPostgreSQLColumn.new(name, default, raw_geom_info.type, notnull == "f", raw_geom_info.srid, raw_geom_info.with_z, raw_geom_info.with_m)
      end
    else
      ActiveRecord::ConnectionAdapters::PostgreSQLColumn.new(name, default, type, notnull == "f")
    end
  end
end

#create_table(table_name, options = {}) {|table_definition| ... } ⇒ Object

Yields:

  • (table_definition)


68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/spatial_adapter/postgresql.rb', line 68

def create_table(table_name, options = {})
  # Using the subclassed table definition
  table_definition = ActiveRecord::ConnectionAdapters::PostgreSQLTableDefinition.new(self)
  table_definition.primary_key(options[:primary_key] || ActiveRecord::Base.get_primary_key(table_name.to_s.singularize)) unless options[:id] == false

  yield table_definition if block_given?

  if options[:force] && table_exists?(table_name)
    drop_table(table_name, options)
  end

  create_sql = "CREATE#{' TEMPORARY' if options[:temporary]} TABLE "
  create_sql << "#{quote_table_name(table_name)} ("
  create_sql << table_definition.to_sql
  create_sql << ") #{options[:options]}"

  # This is the additional portion for PostGIS
  unless table_definition.geom_columns.nil?
    table_definition.geom_columns.each do |geom_column|
      geom_column.table_name = table_name
      create_sql << "; " + geom_column.to_sql
    end
  end

  execute create_sql
end

#disable_referential_integrity(&block) ⇒ Object

:nodoc:



198
199
200
201
202
203
204
205
206
207
# File 'lib/spatial_adapter/postgresql.rb', line 198

def disable_referential_integrity(&block) #:nodoc:
  if supports_disable_referential_integrity?() then
    execute(tables_without_postgis.collect { |name| "ALTER TABLE #{quote_table_name(name)} DISABLE TRIGGER ALL" }.join(";"))
  end
  yield
ensure
  if supports_disable_referential_integrity?() then
    execute(tables_without_postgis.collect { |name| "ALTER TABLE #{quote_table_name(name)} ENABLE TRIGGER ALL" }.join(";"))
  end
end

#indexes(table_name, name = nil) ⇒ Object

Returns the list of all indexes for a table.

This is a full replacement for the ActiveRecord method and as a result has a higher probability of breaking in future releases.



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/spatial_adapter/postgresql.rb', line 151

def indexes(table_name, name = nil)
   schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')

   # Changed from upstread: link to pg_am to grab the index type (e.g. "gist")
   result = query(<<-SQL, name)
     SELECT distinct i.relname, d.indisunique, d.indkey, t.oid, am.amname
       FROM pg_class t, pg_class i, pg_index d, pg_attribute a, pg_am am
     WHERE i.relkind = 'i'
       AND d.indexrelid = i.oid
       AND d.indisprimary = 'f'
       AND t.oid = d.indrelid
       AND t.relname = '#{table_name}'
       AND i.relnamespace IN (SELECT oid FROM pg_namespace WHERE nspname IN (#{schemas}) )
       AND i.relam = am.oid
       AND a.attrelid = t.oid
    ORDER BY i.relname
  SQL


  indexes = []

  indexes = result.map do |row|
    index_name = row[0]
    unique = row[1] == 't'
    indkey = row[2].split(" ")
    oid = row[3]
    indtype = row[4]

    # Changed from upstream: need to get the column types to test for spatial indexes
    columns = query(<<-SQL, "Columns for index #{row[0]} on #{table_name}").inject({}) {|attlist, r| attlist[r[1]] = [r[0], r[2]]; attlist}
    SELECT a.attname, a.attnum, t.typname
    FROM pg_attribute a, pg_type t
    WHERE a.attrelid = #{oid}
    AND a.attnum IN (#{indkey.join(",")})
    AND a.atttypid = t.oid
    SQL

    # Only GiST indexes on spatial columns denote a spatial index
    spatial = indtype == 'gist' && columns.size == 1 && (columns.values.first[1] == 'geometry' || columns.values.first[1] == 'geography')

    column_names = indkey.map {|attnum| columns[attnum] ? columns[attnum][0] : nil }
    ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, index_name, unique, column_names, spatial)
  end

  indexes
end

#native_database_typesObject



33
34
35
# File 'lib/spatial_adapter/postgresql.rb', line 33

def native_database_types
  original_native_database_types.merge!(SpatialAdapter.geometry_data_types)
end

#original_add_columnObject



110
# File 'lib/spatial_adapter/postgresql.rb', line 110

alias :original_add_column :add_column

#original_native_database_typesObject



32
# File 'lib/spatial_adapter/postgresql.rb', line 32

alias :original_native_database_types :native_database_types

#original_quoteObject



37
# File 'lib/spatial_adapter/postgresql.rb', line 37

alias :original_quote :quote

#original_remove_columnObject



95
# File 'lib/spatial_adapter/postgresql.rb', line 95

alias :original_remove_column :remove_column

#postgis_major_versionObject



14
15
16
17
# File 'lib/spatial_adapter/postgresql.rb', line 14

def postgis_major_version
  version = postgis_version
  version ? version.scan(/^(\d)\.\d\.\d$/)[0][0].to_i : nil
end

#postgis_minor_versionObject



19
20
21
22
# File 'lib/spatial_adapter/postgresql.rb', line 19

def postgis_minor_version
  version = postgis_version
  version ? version.scan(/^\d\.(\d)\.\d$/)[0][0].to_i : nil
end

#postgis_versionObject



6
7
8
9
10
11
12
# File 'lib/spatial_adapter/postgresql.rb', line 6

def postgis_version
  begin
    select_value("SELECT postgis_full_version()").scan(/POSTGIS="([\d\.]*)"/)[0][0]
  rescue ActiveRecord::StatementInvalid
    nil
  end
end

#quote(value, column = nil) ⇒ Object

Redefines the quote method to add behaviour for when a Geometry is encountered



39
40
41
42
43
44
45
# File 'lib/spatial_adapter/postgresql.rb', line 39

def quote(value, column = nil)
  if value.kind_of?(GeoRuby::SimpleFeatures::Geometry)
    "'#{value.as_hex_ewkb}'"
  else
    original_quote(value,column)
  end
end

#remove_column(table_name, *column_names) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/spatial_adapter/postgresql.rb', line 96

def remove_column(table_name, *column_names)
  column_names = column_names.flatten
  columns(table_name).each do |col|
    if column_names.include?(col.name.to_sym)
      # Geometry columns have to be removed using DropGeometryColumn
      if col.is_a?(::SpatialAdapter::SpatialColumn) && col.spatial? && !col.geographic?
        execute "SELECT DropGeometryColumn('#{table_name}','#{col.name}')"
      else
        original_remove_column(table_name, col.name)
      end
    end
  end
end

#spatial?Boolean

Returns:

  • (Boolean)


24
25
26
# File 'lib/spatial_adapter/postgresql.rb', line 24

def spatial?
  !postgis_version.nil?
end

#supports_geographic?Boolean

Returns:

  • (Boolean)


28
29
30
# File 'lib/spatial_adapter/postgresql.rb', line 28

def supports_geographic?
  postgis_major_version > 1 || (postgis_major_version == 1 && postgis_minor_version >= 5)
end