Module: ODBCExt

Defined in:
lib/active_record/vendor/odbcext_db2.rb,
lib/active_record/vendor/odbcext_mysql.rb,
lib/active_record/vendor/odbcext_ingres.rb,
lib/active_record/vendor/odbcext_oracle.rb,
lib/active_record/vendor/odbcext_sybase.rb,
lib/active_record/vendor/odbcext_informix.rb,
lib/active_record/vendor/odbcext_progress.rb,
lib/active_record/vendor/odbcext_virtuoso.rb,
lib/active_record/vendor/odbcext_postgresql.rb,
lib/active_record/vendor/odbcext_progress89.rb,
lib/active_record/vendor/odbcext_sqlanywhere.rb,
lib/active_record/vendor/odbcext_microsoftsqlserver.rb

Overview

$Id: odbcext_microsoftsqlserver.rb,v 1.2 2007/02/27 11:00:49 source Exp $

OpenLink ODBC Adapter for Ruby on Rails
Copyright (C) 2006 OpenLink Software

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject
to the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Instance Method Summary collapse

Instance Method Details

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



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/active_record/vendor/odbcext_ingres.rb', line 95

def add_column(table_name, column_name, type, options = {})
  @logger.unknown("ODBCAdapter#add_column>") if @trace
  @logger.unknown("args=[#{table_name}|#{column_name}]") if @trace
  
  sql = "ALTER TABLE #{table_name} ADD #{quote_column_name(column_name)} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
  sql << " DEFAULT #{quote(options[:default], options[:column])}" unless options[:default].nil?

  # Ingres requires that if 'ALTER TABLE table ADD column' specifies a NOT NULL constraint,
  # then 'WITH DEFAULT' must also be specified *without* a default value.
  # Ingres will report an error if both options[:null] == false && options[:default]
  if options[:null] == false
    sql << " NOT NULL"
    sql << " WITH DEFAULT" if options[:default].nil?
  end
  execute(sql)
  rescue Exception => e
    @logger.unknown("exception=#{e}") if @trace
    raise ActiveRecord::ActiveRecordError, e.message
end

#add_column_options!(sql, options) ⇒ Object

Progress SQL89 requires that the DEFAULT specification follows any NOT NULL constraint.



144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/active_record/vendor/odbcext_sybase.rb', line 144

def add_column_options!(sql, options) # :nodoc:
  @logger.unknown("ODBCAdapter#add_column_options!>") if @trace
  @logger.unknown("args=[#{sql}]") if @trace
  sql << " DEFAULT #{quote(options[:default], options[:column])}" if options_include_default?(options)
  
  if column_type_allows_null?(sql, options)
    sql << (options[:null] == false ? " NOT NULL" : " NULL")
  end
  sql   																											
rescue Exception => e
  @logger.unknown("exception=#{e}") if @trace
  raise ActiveRecord::StatementInvalid, e.message
end

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



104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/active_record/vendor/odbcext_mysql.rb', line 104

def change_column(table_name, column_name, type, options = {})
  @logger.unknown("ODBCAdapter#change_column>") if @trace
  # column_name.to_s used in case column_name is a symbol
  unless options_include_default?(options)
    options[:default] = columns(table_name).find { |c| c.name == column_name.to_s }.default    
  end
  change_column_sql = "ALTER TABLE #{table_name} CHANGE #{column_name} #{column_name} #{type_to_sql(type, options[:limit], options[:precision], options[:scale])}"
  add_column_options!(change_column_sql, options)
  execute(change_column_sql)
rescue Exception => e
  @logger.unknown("exception=#{e}") if @trace
  raise  
end

#change_column_default(table_name, column_name, default) ⇒ Object



57
58
59
60
61
62
63
64
# File 'lib/active_record/vendor/odbcext_db2.rb', line 57

def change_column_default(table_name, column_name, default)
  @logger.unknown("ODBCAdapter#change_column_default>") if @trace
  @logger.unknown("args=[#{table_name}|#{column_name}]") if @trace    
  execute "ALTER TABLE #{table_name} ALTER #{column_name} SET DEFAULT #{quote(default)}"
rescue Exception => e
  @logger.unknown("exception=#{e}") if @trace
  raise ActiveRecord::ActiveRecordError, e.message
end

#create_database(name) ⇒ Object


Method redefinitions

DBMS specific methods which override the default implementation provided by the ODBCAdapter core.



81
82
83
84
85
86
87
88
# File 'lib/active_record/vendor/odbcext_microsoftsqlserver.rb', line 81

def create_database(name)
  @logger.unknown("ODBCAdapter#create_database>") if @trace
  @logger.unknown("args=[#{name}]") if @trace    
  execute "CREATE DATABASE `#{name}`"
rescue Exception => e
  @logger.unknown("exception=#{e}") if @trace
  raise    
end

#create_table(name, options = {}) ⇒ Object


Method redefinitions

DBMS specific methods which override the default implementation provided by the ODBCAdapter core.



74
75
76
77
78
79
80
# File 'lib/active_record/vendor/odbcext_ingres.rb', line 74

def create_table(name, options = {})
  @logger.unknown("ODBCAdapter#create_table>") if @trace
  super(name, {:options => "ENGINE=InnoDB"}.merge(options))
rescue Exception => e
  @logger.unknown("exception=#{e}") if @trace
  raise
end

#default_sequence_name(table, column) ⇒ Object



88
89
90
91
92
# File 'lib/active_record/vendor/odbcext_postgresql.rb', line 88

def default_sequence_name(table, column)
  @logger.unknown("ODBCAdapter#default_sequence_name>") if @trace
  @logger.unknown("args=[#{table}|#{column}]") if @trace
  "#{table}_#{column}_seq"      
end

#drop_database(name) ⇒ Object



79
80
81
82
83
84
85
86
# File 'lib/active_record/vendor/odbcext_mysql.rb', line 79

def drop_database(name)
  @logger.unknown("ODBCAdapter#drop_database>") if @trace
  @logger.unknown("args=[#{name}]") if @trace    
  execute "DROP DATABASE IF EXISTS `#{name}`"
rescue Exception => e
  @logger.unknown("exception=#{e}") if @trace
  raise    
end

#drop_table(name, options = {}) ⇒ Object



85
86
87
88
89
90
91
92
93
# File 'lib/active_record/vendor/odbcext_ingres.rb', line 85

def drop_table(name, options = {})
  @logger.unknown("ODBCAdapter#drop_table>") if @trace
  @logger.unknown("args=[#{name}]") if @trace
  super(name, options)
  execute "DROP SEQUENCE #{name}_seq"          
rescue Exception => e
  @logger.unknown("exception=#{e}") if @trace
  raise ActiveRecord::ActiveRecordError, e.message
end

#indexes(table_name, name = nil) ⇒ Object



82
83
84
85
# File 'lib/active_record/vendor/odbcext_db2.rb', line 82

def indexes(table_name, name = nil)
  # Hide primary key indexes
  super(table_name, name).delete_if { |i| i.unique && i.name =~ /^sql\d+$/ }
end

#last_insert_id(table, sequence_name, stmt = nil) ⇒ Object

#last_insert_id must be implemented for any database which returns false from #prefetch_primary_key?



36
37
38
39
40
# File 'lib/active_record/vendor/odbcext_db2.rb', line 36

def last_insert_id(table, sequence_name, stmt = nil)
  @logger.unknown("ODBCAdapter#last_insert_id>") if @trace
  @logger.unknown("args=[#{table}]") if @trace
  select_value("VALUES IDENTITY_VAL_LOCAL()", 'last_insert_id')    
end

#next_sequence_value(sequence_name) ⇒ Object

#next_sequence_value must be implemented for any database which returns true from #prefetch_primary_key?

Returns the next sequence value from a sequence generator. Not generally called directly; used by ActiveRecord to get the next primary key value when inserting a new database record (see #prefetch_primary_key?).



48
49
50
51
52
# File 'lib/active_record/vendor/odbcext_ingres.rb', line 48

def next_sequence_value(sequence_name)
  @logger.unknown("ODBCAdapter#next_sequence_value>") if @trace
  @logger.unknown("args=[#{sequence_name}]") if @trace
  select_one("select #{sequence_name}.nextval id")['id']
end

#options_include_default?(options) ⇒ Boolean

Returns:

  • (Boolean)


144
145
146
147
148
149
150
151
152
# File 'lib/active_record/vendor/odbcext_mysql.rb', line 144

def options_include_default?(options)
  # MySQL 5.x doesn't allow DEFAULT NULL for first timestamp column in a table
  if options.include?(:default) && options[:default].nil?
    if options.include?(:column) && options[:column].sql_type =~ /timestamp/i
      options.delete(:default)
    end
  end
  super(options)
end

#post_insert(sql, name, pk, id_value, sequence_name) ⇒ Object

Post action for ODBCAdapter#insert



67
68
69
70
71
72
73
74
75
# File 'lib/active_record/vendor/odbcext_sybase.rb', line 67

def post_insert(sql, name, pk, id_value, sequence_name)
  if @iiEnabled
    begin
      @connection.do(enable_identity_insert(@iiTable, false))
    rescue Exception => e
      raise ActiveRecordError, "IDENTITY_INSERT could not be turned off"
    end
  end
end

#pre_insert(sql, name, pk, id_value, sequence_name) ⇒ Object

Pre action for ODBCAdapter#insert



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/active_record/vendor/odbcext_sybase.rb', line 49

def pre_insert(sql, name, pk, id_value, sequence_name)
  @iiTable = get_table_name(sql)
  @iiCol = get_autounique_column(@iiTable)
  @iiEnabled = false
  
  if @iiCol != nil
    if query_contains_autounique_col(sql, @iiCol)
      begin
        @connection.do(enable_identity_insert(@iiTable, true))
        @iiEnabled = true
      rescue Exception => e
        raise ActiveRecordError, "IDENTITY_INSERT could not be turned on"
      end
    end
  end
end

#quote_column_name(name) ⇒ Object


Method redefinitions

DBMS specific methods which override the default implementation provided by the ODBCAdapter core.



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/active_record/vendor/odbcext_progress.rb', line 58

def quote_column_name(name)
  @logger.unknown("ODBCAdapter#quote_column_name>") if @trace
  @logger.unknown("args=[#{name}]") if @trace        
  name = name.to_s if name.class == Symbol                
  idQuoteChar = @dsInfo.info[ODBC::SQL_IDENTIFIER_QUOTE_CHAR]
      
  return name if !idQuoteChar || ((idQuoteChar = idQuoteChar.strip).length == 0)
  idQuoteChar = idQuoteChar[0]
  
  # Avoid quoting any already quoted name
  return name if name[0] == idQuoteChar && name[-1] == idQuoteChar
  
  # If a DBMS's SQL_IDENTIFIER_CASE is SQL_IC_UPPER, this adapter's base 
  # implementation of #quote_column_name only quotes mixed case names.
  # But for Progress v9 or later, for which we force SQL_IDENTIFIER_CASE to
  # SQL_IC_UPPER (see DSInfo#new), we want to quote *ALL* column names. 
  # This is done because many of the Rails tests and fixtures use a column
  # named 'type', but type is a reserved word in Progress SQL. Progress 9
  # accepts the quoting of all column names because its 
  # SQL_QUOTED_IDENTIFIER_CASE behaviour is SQL_IC_MIXED.
  idQuoteChar.chr + name + idQuoteChar.chr
end

#quote_string(string) ⇒ Object


Method redefinitions

DBMS specific methods which override the default implementation provided by the ODBCAdapter core.



63
64
65
66
67
68
# File 'lib/active_record/vendor/odbcext_mysql.rb', line 63

def quote_string(string)
  @logger.unknown("ODBCAdapter#quote_string>") if @trace
  
  # MySQL requires backslashes to be escaped				
  string.gsub(/\\/, '\&\&').gsub(/'/, "''")
end

#quoted_date(value) ⇒ Object


Method redefinitions

DBMS specific methods which override the default implementation provided by the ODBCAdapter core.



72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/active_record/vendor/odbcext_oracle.rb', line 72

def quoted_date(value)
  @logger.unknown("ODBCAdapter#quoted_date>") if @trace
  # Ideally, we'd return an ODBC date or timestamp literal escape 
  # sequence, but not all ODBC drivers support them.
  case value
  when Time, DateTime
    #%Q!{ts '#{value.strftime("%Y-%m-%d %H:%M:%S")}'}!
    "to_timestamp(\'#{value.strftime("%Y-%m-%d %H:%M:%S")}\', \'YYYY-MM-DD HH24:MI:SS\')"
  when Date
    #%Q!{d '#{value.strftime("%Y-%m-%d")}'}!
    "to_timestamp(\'#{value.strftime("%Y-%m-%d")}\', \'YYYY-MM-DD\')"
  end
end

#quoted_falseObject



79
80
81
# File 'lib/active_record/vendor/odbcext_postgresql.rb', line 79

def quoted_false
  "'f'"
end

#quoted_trueObject


Method redefinitions

DBMS specific methods which override the default implementation provided by the ODBCAdapter core.



75
76
77
# File 'lib/active_record/vendor/odbcext_postgresql.rb', line 75

def quoted_true
  "'t'"
end

#remove_column(table_name, column_name) ⇒ Object

Raises:

  • (ActiveRecord::ActiveRecordError)


66
67
68
69
70
71
# File 'lib/active_record/vendor/odbcext_db2.rb', line 66

def remove_column(table_name, column_name)
  @logger.unknown("ODBCAdapter#remove_column>\n" +
                  "args=[#{table_name}|#{column_name}]\n" + 
                  "exception=remove_column is not supported") if @trace
  raise ActiveRecord::ActiveRecordError, "remove_column is not supported"
end

#remove_index(table_name, options = {}) ⇒ Object



73
74
75
76
77
78
79
80
# File 'lib/active_record/vendor/odbcext_db2.rb', line 73

def remove_index(table_name, options = {})
  @logger.unknown("ODBCAdapter#remove_index>") if @trace
  @logger.unknown("args=[#{table_name}]") if @trace    
  execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
rescue Exception => e
  @logger.unknown("exception=#{e}") if @trace
  raise ActiveRecord::ActiveRecordError, e.message
end

#rename_column(table_name, column_name, new_column_name) ⇒ Object



118
119
120
121
122
123
124
125
126
127
# File 'lib/active_record/vendor/odbcext_mysql.rb', line 118

def rename_column(table_name, column_name, new_column_name)
  @logger.unknown("ODBCAdapter#rename_column>") if @trace
  col = columns(table_name).find{ |c| c.name == column_name.to_s }
  current_type = col.sql_type
  current_type << "(#{col.limit})" if col.limit
  execute "ALTER TABLE #{table_name} CHANGE #{column_name} #{new_column_name} #{current_type}"
rescue Exception => e
  @logger.unknown("exception=#{e}") if @trace
  raise
end

#rename_table(name, new_name) ⇒ Object


Method redefinitions

DBMS specific methods which override the default implementation provided by the ODBCAdapter core.



48
49
50
51
52
53
54
55
# File 'lib/active_record/vendor/odbcext_db2.rb', line 48

def rename_table(name, new_name)
  @logger.unknown("ODBCAdapter#rename_table>") if @trace
  @logger.unknown("args=[#{name}|#{new_name}]") if @trace    
  execute "RENAME TABLE #{name} TO #{new_name}"
rescue Exception => e
  @logger.unknown("exception=#{e}") if @trace
  raise ActiveRecord::ActiveRecordError, e.message
end

#select_all(sql, name = nil) ⇒ Object

Progress SQL-89 doesn’t support column aliases Strip ‘AS <alias>’ from all selects



100
101
102
# File 'lib/active_record/vendor/odbcext_progress89.rb', line 100

def select_all(sql, name = nil)   
  super(remove_select_column_aliases(sql), name)
end

#select_one(sql, name = nil) ⇒ Object



104
105
106
# File 'lib/active_record/vendor/odbcext_progress89.rb', line 104

def select_one(sql, name = nil)
  super(remove_select_column_aliases(sql), name)
end

#select_value(sql, name = nil) ⇒ Object



108
109
110
# File 'lib/active_record/vendor/odbcext_progress89.rb', line 108

def select_value(sql, name = nil)
  super(remove_select_column_aliases(sql), name)
end

#select_values(sql, name = nil) ⇒ Object



112
113
114
# File 'lib/active_record/vendor/odbcext_progress89.rb', line 112

def select_values(sql, name = nil)
  super(remove_select_column_aliases(sql), name)
end

#set_sequence(table_name, pk) ⇒ Object

Post action for ODBCAdapter#insert def post_insert(sql, name, pk, id_value, sequence_name) end



57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/active_record/vendor/odbcext_virtuoso.rb', line 57

def set_sequence(table_name, pk)
  begin
    stmt = @connection.run("select max(#{pk}) + 1 from #{table_name}")
    next_pk_val = stmt.fetch
   stmt.drop
   flds = table_name.split('.')
   @connection.do("sequence_set('#{flds[0]}.#{flds[1]}.#{table_name}.#{pk}', #{next_pk_val}, 0)")
   return true
  rescue Exception => e
    @logger.unknown("exception=#{e}") if @trace
  end
  return false
end

#string_to_binary(value) ⇒ Object

Post action for ODBCAdapter#insert def post_insert(sql, name, pk, id_value, sequence_name) end



60
61
62
63
64
65
66
67
# File 'lib/active_record/vendor/odbcext_postgresql.rb', line 60

def string_to_binary(value)
  # Escape data prior to insert into a bytea column
  if value
    res = ''
    value.each_byte { |b| res << sprintf('\\\\%03o', b) }
    res
  end
end

#structure_dumpObject



154
155
156
157
158
159
160
161
162
# File 'lib/active_record/vendor/odbcext_mysql.rb', line 154

def structure_dump
  @logger.unknown("ODBCAdapter#structure_dump>") if @trace
  select_all("SHOW TABLES").inject("") do |structure, table|
    structure += select_one("SHOW CREATE TABLE #{table.to_a.first.last}")["Create Table"] + ";\n\n"
  end
rescue Exception => e
  @logger.unknown("exception=#{e}") if @trace
  raise
end

#table_filter(schemaName, tblName, tblType) ⇒ Object

Filter for ODBCAdapter#tables Omits table from #tables if table_filter returns true



48
49
50
# File 'lib/active_record/vendor/odbcext_postgresql.rb', line 48

def table_filter(schemaName, tblName, tblType)
  ["information_schema", "pg_catalog"].include?(schemaName) || tblType !~ /TABLE/i
end

#tables(name = nil) ⇒ Object



146
147
148
149
# File 'lib/active_record/vendor/odbcext_ingres.rb', line 146

def tables(name = nil)
  # Hide system tables
  super(name).delete_if {|t| t =~ /^ii/i }
end

#type_to_sql(type, limit = nil, precision = nil, scale = nil) ⇒ Object


Method redefinitions

DBMS specific methods which override the default implementation provided by the ODBCAdapter core.



49
50
51
52
53
54
55
56
57
58
# File 'lib/active_record/vendor/odbcext_informix.rb', line 49

def type_to_sql(type, limit = nil, precision = nil, scale = nil)
  if type == :decimal
    # Force an explicit scale if none supplied to specify the fixed
    # point form of Informix's DECIMAL type. If no scale is specified,
    # the Informix DECIMAL type stores floating point values.
    precision ||= 32
    scale ||= 0
  end
  super(type, limit, precision, scale)
end