Class: Sequel::Firebird::Database

Inherits:
Database show all
Defined in:
lib/sequel_core/adapters/firebird.rb

Constant Summary collapse

AUTO_INCREMENT =
''.freeze

Constants inherited from Database

Database::ADAPTERS, Database::SQL_BEGIN, Database::SQL_COMMIT, Database::SQL_ROLLBACK

Constants included from Schema::SQL

Schema::SQL::AUTOINCREMENT, Schema::SQL::CASCADE, Schema::SQL::COMMA_SEPARATOR, Schema::SQL::NOT_NULL, Schema::SQL::NO_ACTION, Schema::SQL::NULL, Schema::SQL::PRIMARY_KEY, Schema::SQL::RESTRICT, Schema::SQL::SET_DEFAULT, Schema::SQL::SET_NULL, Schema::SQL::TYPES, Schema::SQL::UNDERSCORE, Schema::SQL::UNIQUE, Schema::SQL::UNSIGNED

Instance Attribute Summary

Attributes inherited from Database

#default_schema, #loggers, #opts, #pool, #prepared_statements

Instance Method Summary collapse

Methods inherited from Database

#<<, #[], adapter_class, adapter_scheme, #add_column, #add_index, #alter_table, #call, connect, #create_or_replace_view, #create_table!, #create_view, #disconnect, #drop_column, #drop_index, #drop_table, #drop_view, #execute_ddl, #execute_dui, #execute_insert, #fetch, #from, #get, #identifier_input_method, identifier_input_method, #identifier_input_method=, identifier_input_method=, #identifier_output_method, identifier_output_method, #identifier_output_method=, identifier_output_method=, #inspect, #log_info, #logger, #logger=, #multi_threaded?, #query, quote_identifiers=, #quote_identifiers=, #quote_identifiers?, #rename_column, #rename_table, #select, #serial_primary_key_options, #set_column_default, #set_column_type, single_threaded=, #single_threaded?, #synchronize, #table_exists?, #test_connection, #typecast_value, #upcase_identifiers=, upcase_identifiers=, #upcase_identifiers?, #uri, #url

Methods included from Schema::SQL

#alter_table_sql_list, #column_definition_sql, #column_list_sql, #column_references_sql, #constraint_definition_sql, #default_index_name, #drop_index_sql, #drop_table_sql, #filter_expr, #index_definition_sql, #index_list_sql_list, #literal, #on_delete_clause, #quote_identifier, #quote_schema_table, #rename_table_sql, #schema, #schema_utility_dataset

Constructor Details

#initialize(*args) ⇒ Database

Add the primary_keys and primary_key_sequences instance variables, so we can get the correct return values for inserted rows.



15
16
17
18
19
# File 'lib/sequel_core/adapters/firebird.rb', line 15

def initialize(*args)
  super
  @primary_keys = {}
  @primary_key_sequences = {}
end

Instance Method Details

#alter_table_sql(table, op) ⇒ Object

Use Firebird specific syntax for add column



22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/sequel_core/adapters/firebird.rb', line 22

def alter_table_sql(table, op)
  case op[:op]
  when :add_column
    "ALTER TABLE #{quote_schema_table(table)} ADD #{column_definition_sql(op)}"
  when :drop_column
    "ALTER TABLE #{quote_schema_table(table)} DROP #{column_definition_sql(op)}"
  when :rename_column
    "ALTER TABLE #{quote_schema_table(table)} ALTER #{quote_identifier(op[:name])} TO #{quote_identifier(op[:new_name])}"
  when :set_column_type
    "ALTER TABLE #{quote_schema_table(table)} ALTER #{quote_identifier(op[:name])} TYPE #{type_literal(op)}"
  else
    super(table, op)
  end
end

#auto_increment_sqlObject



37
38
39
# File 'lib/sequel_core/adapters/firebird.rb', line 37

def auto_increment_sql()
  AUTO_INCREMENT
end

#connect(server) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
# File 'lib/sequel_core/adapters/firebird.rb', line 41

def connect(server)
  opts = server_opts(server)

  db = Fb::Database.new(
    :database => "#{opts[:host]}:#{opts[:database]}",
    :username => opts[:user],
    :password => opts[:password])
  conn = db.connect
  conn.downcase_names = true
  conn
end

#create_sequence_sql(name, opts = {}) ⇒ Object



53
54
55
# File 'lib/sequel_core/adapters/firebird.rb', line 53

def create_sequence_sql(name, opts={})
  "CREATE SEQUENCE #{quote_identifier(name)}"
end

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

Creates a table with the columns given in the provided block:

DB.create_table :posts do
  primary_key :id, :serial
  column :title, :text
  column :content, :text
  index :title
end

See Schema::Generator. Firebird gets an override because of the mess of creating a generator for auto-incrementing primary keys.



69
70
71
72
73
74
75
76
77
78
# File 'lib/sequel_core/adapters/firebird.rb', line 69

def create_table(name, options={}, &block)
  options = {:generator=>options} if options.is_a?(Schema::Generator)
  statements = create_table_sql_list(name, *((options[:generator] ||= Schema::Generator.new(self, &block)).create_info << options))
  begin
    execute_ddl(statements[1])
  rescue
    nil
  end if statements[1]
  statements[0].flatten.each {|sql| execute_ddl(sql)}
end

#create_table_sql_list(name, columns, indexes = nil, options = {}) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/sequel_core/adapters/firebird.rb', line 80

def create_table_sql_list(name, columns, indexes = nil, options={})
  statements = super
  drop_seq_statement = nil
  columns.each do |c|
    if c[:auto_increment]
      c[:sequence_name] ||= "seq_#{name}_#{c[:name]}"
      unless c[:create_sequence] == false
        drop_seq_statement = drop_sequence_sql(c[:sequence_name])
        statements << create_sequence_sql(c[:sequence_name])
        statements << restart_sequence_sql(c[:sequence_name], {:restart_position => c[:sequence_start_position]}) if c[:sequence_start_position]
      end
      unless c[:create_trigger] == false
        c[:trigger_name] ||= "BI_#{name}_#{c[:name]}"
        c[:quoted_name] = quote_identifier(c[:name])
        trigger_definition = <<-END
        begin
          if ((new.#{c[:quoted_name]} is null) or (new.#{c[:quoted_name]} = 0)) then
          begin
            new.#{c[:quoted_name]} = next value for #{c[:sequence_name]};
          end
        end
        END
        statements << create_trigger_sql(name, c[:trigger_name], trigger_definition, {:events => [:insert]})
      end
    end
  end
  [statements, drop_seq_statement]
end

#create_trigger(*args) ⇒ Object



109
110
111
# File 'lib/sequel_core/adapters/firebird.rb', line 109

def create_trigger(*args)
  self << create_trigger_sql(*args)
end

#create_trigger_sql(table, name, definition, opts = {}) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/sequel_core/adapters/firebird.rb', line 113

def create_trigger_sql(table, name, definition, opts={})
  events = opts[:events] ? Array(opts[:events]) : [:insert, :update, :delete]
  whence = opts[:after] ? 'AFTER' : 'BEFORE'
  inactive = opts[:inactive] ? 'INACTIVE' : 'ACTIVE'
  position = opts[:position] ? opts[:position] : 0
  sql = <<-end_sql
    CREATE TRIGGER #{quote_identifier(name)} for #{quote_identifier(table)}
    #{inactive} #{whence} #{events.map{|e| e.to_s.upcase}.join(' OR ')} position #{position}
    as #{definition}
  end_sql
  sql
end

#dataset(opts = nil) ⇒ Object



126
127
128
# File 'lib/sequel_core/adapters/firebird.rb', line 126

def dataset(opts = nil)
  Firebird::Dataset.new(self, opts)
end

#drop_sequence(name) ⇒ Object



130
131
132
# File 'lib/sequel_core/adapters/firebird.rb', line 130

def drop_sequence(name)
  self << drop_sequence_sql(name)
end

#drop_sequence_sql(name) ⇒ Object



134
135
136
# File 'lib/sequel_core/adapters/firebird.rb', line 134

def drop_sequence_sql(name)
  "DROP SEQUENCE #{quote_identifier(name)}"
end

#execute(sql, opts = {}) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/sequel_core/adapters/firebird.rb', line 138

def execute(sql, opts={})
  log_info(sql)
  begin
    synchronize(opts[:server]) do |conn|
      r = conn.execute(sql)
      yield(r) if block_given?
      r
    end
  rescue => e
    log_info(e.message)
    raise_error(e, :classes=>[Fb::Error])
  end
end

#primary_key(table, server = nil) ⇒ Object

Return primary key for the given table.



153
154
155
# File 'lib/sequel_core/adapters/firebird.rb', line 153

def primary_key(table, server=nil)
  synchronize(server){|conn| primary_key_for_table(conn, table)}
end

#primary_key_for_table(conn, table) ⇒ Object

Returns primary key for the given table. This information is cached, and if the primary key for a table is changed, the



160
161
162
# File 'lib/sequel_core/adapters/firebird.rb', line 160

def primary_key_for_table(conn, table)
  @primary_keys[quote_identifier(table)] ||= conn.table_primary_key(quote_identifier(table))
end

#restart_sequence(*args) ⇒ Object



164
165
166
# File 'lib/sequel_core/adapters/firebird.rb', line 164

def restart_sequence(*args)
  self << restart_sequence_sql(*args)
end

#restart_sequence_sql(name, opts = {}) ⇒ Object



168
169
170
171
# File 'lib/sequel_core/adapters/firebird.rb', line 168

def restart_sequence_sql(name, opts={})
  seq_name = quote_identifier(name)
  "ALTER SEQUENCE #{seq_name} RESTART WITH #{opts[:restart_position]}"
end

#sequences(opts = {}) ⇒ Object



173
174
175
176
# File 'lib/sequel_core/adapters/firebird.rb', line 173

def sequences(opts={})
  ds = self[:"rdb$generators"].server(opts[:server]).filter(:"rdb$system_flag" => 0).select(:"rdb$generator_name")
  block_given? ? yield(ds) : ds.map{|r| ds.send(:output_identifier, r[:"rdb$generator_name"])}
end

#tables(opts = {}) ⇒ Object



178
179
180
181
# File 'lib/sequel_core/adapters/firebird.rb', line 178

def tables(opts={})
  ds = self[:"rdb$relations"].server(opts[:server]).filter(:"rdb$view_blr" => nil, Sequel::SQL::Function.new(:COALESCE, :"rdb$system_flag", 0) => 0).select(:"rdb$relation_name")
  block_given? ? yield(ds) : ds.map{|r| ds.send(:output_identifier, r[:"rdb$relation_name"])}
end

#transaction(server = nil) ⇒ Object



183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
# File 'lib/sequel_core/adapters/firebird.rb', line 183

def transaction(server=nil)
  synchronize(server) do |conn|
    return yield(conn) if @transactions.include?(Thread.current)
    log_info("Transaction.begin")
    conn.transaction
    begin
      @transactions << Thread.current
      yield(conn)
    rescue ::Exception => e
      log_info("Transaction.rollback")
      conn.rollback
      transaction_error(e, Fb::Error)
    ensure
      unless e
        log_info("Transaction.commit")
        conn.commit
      end
      @transactions.delete(Thread.current)
    end
  end
end