og 0.16.0 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +485 -0
- data/README +35 -12
- data/Rakefile +4 -7
- data/benchmark/bench.rb +1 -1
- data/doc/AUTHORS +3 -3
- data/doc/RELEASES +153 -2
- data/doc/config.txt +0 -7
- data/doc/tutorial.txt +7 -0
- data/examples/README +5 -0
- data/examples/mysql_to_psql.rb +25 -50
- data/examples/run.rb +62 -77
- data/install.rb +1 -1
- data/lib/og.rb +45 -106
- data/lib/og/collection.rb +156 -0
- data/lib/og/entity.rb +131 -0
- data/lib/og/errors.rb +10 -15
- data/lib/og/manager.rb +115 -0
- data/lib/og/{mixins → mixin}/hierarchical.rb +43 -37
- data/lib/og/{mixins → mixin}/orderable.rb +35 -35
- data/lib/og/{mixins → mixin}/timestamped.rb +0 -6
- data/lib/og/{mixins → mixin}/tree.rb +0 -4
- data/lib/og/relation.rb +178 -0
- data/lib/og/relation/belongs_to.rb +14 -0
- data/lib/og/relation/has_many.rb +62 -0
- data/lib/og/relation/has_one.rb +17 -0
- data/lib/og/relation/joins_many.rb +69 -0
- data/lib/og/relation/many_to_many.rb +17 -0
- data/lib/og/relation/refers_to.rb +31 -0
- data/lib/og/store.rb +223 -0
- data/lib/og/store/filesys.rb +113 -0
- data/lib/og/store/madeleine.rb +4 -0
- data/lib/og/store/memory.rb +291 -0
- data/lib/og/store/mysql.rb +283 -0
- data/lib/og/store/psql.rb +238 -0
- data/lib/og/store/sql.rb +599 -0
- data/lib/og/store/sqlite.rb +190 -0
- data/lib/og/store/sqlserver.rb +262 -0
- data/lib/og/types.rb +19 -0
- data/lib/og/validation.rb +0 -4
- data/test/og/{mixins → mixin}/tc_hierarchical.rb +21 -23
- data/test/og/{mixins → mixin}/tc_orderable.rb +15 -14
- data/test/og/mixin/tc_timestamped.rb +38 -0
- data/test/og/store/tc_filesys.rb +71 -0
- data/test/og/tc_relation.rb +36 -0
- data/test/og/tc_store.rb +290 -0
- data/test/og/tc_types.rb +21 -0
- metadata +54 -40
- data/examples/mock_example.rb +0 -50
- data/lib/og/adapters/base.rb +0 -706
- data/lib/og/adapters/filesys.rb +0 -117
- data/lib/og/adapters/mysql.rb +0 -350
- data/lib/og/adapters/oracle.rb +0 -368
- data/lib/og/adapters/psql.rb +0 -272
- data/lib/og/adapters/sqlite.rb +0 -265
- data/lib/og/adapters/sqlserver.rb +0 -356
- data/lib/og/database.rb +0 -290
- data/lib/og/enchant.rb +0 -149
- data/lib/og/meta.rb +0 -407
- data/lib/og/testing/mock.rb +0 -165
- data/lib/og/typemacros.rb +0 -24
- data/test/og/adapters/tc_filesys.rb +0 -83
- data/test/og/adapters/tc_sqlite.rb +0 -86
- data/test/og/adapters/tc_sqlserver.rb +0 -96
- data/test/og/tc_automanage.rb +0 -46
- data/test/og/tc_lifecycle.rb +0 -105
- data/test/og/tc_many_to_many.rb +0 -61
- data/test/og/tc_meta.rb +0 -55
- data/test/og/tc_validation.rb +0 -89
- data/test/tc_og.rb +0 -364
data/lib/og/adapters/sqlite.rb
DELETED
@@ -1,265 +0,0 @@
|
|
1
|
-
# * George Moschovitis <gm@navel.gr>
|
2
|
-
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
-
# $Id: sqlite.rb 17 2005-04-14 16:03:40Z gmosx $
|
4
|
-
|
5
|
-
begin
|
6
|
-
require 'sqlite3'
|
7
|
-
rescue Object => ex
|
8
|
-
Logger.error 'Ruby-Sqlite3 bindings are not installed!'
|
9
|
-
Logger.error ex
|
10
|
-
end
|
11
|
-
|
12
|
-
require 'fileutils'
|
13
|
-
|
14
|
-
require 'og/adapters/base'
|
15
|
-
|
16
|
-
module Og
|
17
|
-
|
18
|
-
# The SQLite adapter. This adapter communicates with
|
19
|
-
# an SQLite3 rdbms. For extra documentation see
|
20
|
-
# lib/og/adapter.rb
|
21
|
-
|
22
|
-
class SqliteAdapter < Adapter
|
23
|
-
|
24
|
-
def drop_db(database, user = nil, password = nil)
|
25
|
-
begin
|
26
|
-
FileUtils.rm("#{database}.db")
|
27
|
-
super
|
28
|
-
rescue
|
29
|
-
Logger.error "Cannot drop '#{database}'!"
|
30
|
-
end
|
31
|
-
end
|
32
|
-
=begin
|
33
|
-
def write_prop(p)
|
34
|
-
if p.klass.ancestors.include?(Integer)
|
35
|
-
return "@#{p.symbol}"
|
36
|
-
elsif p.klass.ancestors.include?(Float)
|
37
|
-
return "@#{p.symbol}"
|
38
|
-
elsif p.klass.ancestors.include?(String)
|
39
|
-
return "#{self.class}.escape(@#{p.symbol})"
|
40
|
-
elsif p.klass.ancestors.include?(Time)
|
41
|
-
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.timestamp(@#{p.symbol})\}'" : 'NULL'\}|
|
42
|
-
elsif p.klass.ancestors.include?(Date)
|
43
|
-
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.date(@#{p.symbol})\}'" : 'NULL'\}|
|
44
|
-
elsif p.klass.ancestors.include?(TrueClass)
|
45
|
-
return "#\{@#{p.symbol} ? \"'t'\" : 'NULL' \}"
|
46
|
-
else
|
47
|
-
return %|#\{@#{p.symbol} ? "'#\{#{self.class}.escape(@#{p.symbol}.to_yaml)\}'" : "''"\}|
|
48
|
-
end
|
49
|
-
end
|
50
|
-
=end
|
51
|
-
def insert_code(klass, db)
|
52
|
-
props = props_for_insert(klass)
|
53
|
-
values = props.collect { |p| write_prop(p) }.join(',')
|
54
|
-
|
55
|
-
sql = "INSERT INTO #{klass::DBTABLE} (#{props.collect {|p| p.name}.join(',')}) VALUES (#{values})"
|
56
|
-
|
57
|
-
%{
|
58
|
-
conn.store.query("#{sql}").close
|
59
|
-
@oid = conn.store.last_insert_row_id
|
60
|
-
}
|
61
|
-
=begin
|
62
|
-
props = props_for_insert(klass)
|
63
|
-
|
64
|
-
placeholders = Array.new(props.size, '?').join(',')
|
65
|
-
values = props.collect { |p| write_prop(p) }.join(',')
|
66
|
-
|
67
|
-
sql = "INSERT INTO #{klass::DBTABLE} (#{props.collect {|p| p.name}.join(',')}) VALUES (#{placeholders})"
|
68
|
-
klass.class_eval %{
|
69
|
-
cattr_accessor :og_insert_statement
|
70
|
-
}
|
71
|
-
|
72
|
-
klass.og_insert_statement = db.prepare(sql)
|
73
|
-
|
74
|
-
%{
|
75
|
-
#{pre_cb}
|
76
|
-
@@og_insert_statement.execute(#{values})
|
77
|
-
@oid = conn.store.last_insert_row_id
|
78
|
-
#{post_cb}
|
79
|
-
}
|
80
|
-
=end
|
81
|
-
end
|
82
|
-
|
83
|
-
def new_connection(db)
|
84
|
-
return SqliteConnection.new(db)
|
85
|
-
end
|
86
|
-
|
87
|
-
def calc_field_index(klass, db)
|
88
|
-
res = db.query "SELECT * FROM #{klass::DBTABLE} LIMIT 1"
|
89
|
-
meta = db.managed_classes[klass]
|
90
|
-
|
91
|
-
columns = res.columns
|
92
|
-
|
93
|
-
for idx in (0...columns.size)
|
94
|
-
meta.field_index[columns[idx]] = idx
|
95
|
-
end
|
96
|
-
|
97
|
-
ensure
|
98
|
-
res.close
|
99
|
-
end
|
100
|
-
|
101
|
-
def create_table(klass, db)
|
102
|
-
conn = db.get_connection
|
103
|
-
|
104
|
-
fields = create_fields(klass)
|
105
|
-
|
106
|
-
sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
|
107
|
-
|
108
|
-
# Create table constrains
|
109
|
-
|
110
|
-
if klass.__meta and constrains = klass.__meta[:sql_constrain]
|
111
|
-
sql << ", #{constrains.join(', ')}"
|
112
|
-
end
|
113
|
-
|
114
|
-
sql << ");"
|
115
|
-
|
116
|
-
# Create indices
|
117
|
-
|
118
|
-
if klass.__meta and indices = klass.__meta[:sql_index]
|
119
|
-
for data in indices
|
120
|
-
idx, options = *data
|
121
|
-
idx = idx.to_s
|
122
|
-
pre_sql, post_sql = options[:pre], options[:post]
|
123
|
-
idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
|
124
|
-
sql << " CREATE #{pre_sql} INDEX #{klass::DBTABLE}_#{idxname}_idx #{post_sql} ON #{klass::DBTABLE} (#{idx});"
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
begin
|
129
|
-
conn.store.query(sql).close
|
130
|
-
Logger.info "Created table '#{klass::DBTABLE}'."
|
131
|
-
rescue Exception => ex
|
132
|
-
# gmosx: any idea how to better test this?
|
133
|
-
if ex.to_s =~ /table .* already exists/i
|
134
|
-
Logger.debug "Table already exists" if $DBG
|
135
|
-
return
|
136
|
-
else
|
137
|
-
raise
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
# Create join tables if needed. Join tables are used in
|
142
|
-
# 'many_to_many' relations.
|
143
|
-
|
144
|
-
if klass.__meta and joins = klass.__meta[:sql_join]
|
145
|
-
for data in joins
|
146
|
-
# the class to join to and some options.
|
147
|
-
join_name, join_class, options = *data
|
148
|
-
|
149
|
-
# gmosx: dont use DBTABLE here, perhaps the join class
|
150
|
-
# is not managed yet.
|
151
|
-
join_table = "#{self.class.join_table(klass, join_class, join_name)}"
|
152
|
-
join_src = "#{self.class.encode(klass)}_oid"
|
153
|
-
join_dst = "#{self.class.encode(join_class)}_oid"
|
154
|
-
begin
|
155
|
-
conn.store.query("CREATE TABLE #{join_table} ( key1 integer NOT NULL, key2 integer NOT NULL )").close
|
156
|
-
conn.store.query("CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)").close
|
157
|
-
conn.store.query("CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)").close
|
158
|
-
rescue Exception => ex
|
159
|
-
# gmosx: any idea how to better test this?
|
160
|
-
if ex.to_s =~ /table .* already exists/i
|
161
|
-
Logger.debug "Join table already exists" if $DBG
|
162
|
-
else
|
163
|
-
raise
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
ensure
|
170
|
-
db.put_connection
|
171
|
-
end
|
172
|
-
|
173
|
-
end
|
174
|
-
|
175
|
-
# The SQLite connection.
|
176
|
-
|
177
|
-
class SqliteConnection < Connection
|
178
|
-
|
179
|
-
def initialize(db)
|
180
|
-
@store = SQLite3::Database.new("#{db.config[:database]}.db")
|
181
|
-
super
|
182
|
-
end
|
183
|
-
|
184
|
-
def close
|
185
|
-
@store.close
|
186
|
-
super
|
187
|
-
end
|
188
|
-
|
189
|
-
def prepare(sql)
|
190
|
-
@store.prepare(sql)
|
191
|
-
end
|
192
|
-
|
193
|
-
def query(sql)
|
194
|
-
Logger.debug sql if $DBG
|
195
|
-
begin
|
196
|
-
return @store.query(sql)
|
197
|
-
rescue => ex
|
198
|
-
handle_db_exception(ex, sql)
|
199
|
-
end
|
200
|
-
end
|
201
|
-
|
202
|
-
def exec(sql)
|
203
|
-
Logger.debug sql if $DBG
|
204
|
-
begin
|
205
|
-
@store.query(sql).close
|
206
|
-
rescue => ex
|
207
|
-
handle_db_exception(ex, sql)
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
def start
|
212
|
-
@store.transaction
|
213
|
-
end
|
214
|
-
|
215
|
-
def commit
|
216
|
-
@store.commit
|
217
|
-
end
|
218
|
-
|
219
|
-
def rollback
|
220
|
-
@store.rollback
|
221
|
-
end
|
222
|
-
|
223
|
-
def valid_res?(res)
|
224
|
-
return !(res.nil?)
|
225
|
-
end
|
226
|
-
|
227
|
-
def read_one(res, klass)
|
228
|
-
return nil unless valid_res?(res)
|
229
|
-
row = res.next
|
230
|
-
return nil unless row
|
231
|
-
|
232
|
-
obj = klass.allocate
|
233
|
-
obj.og_read(row)
|
234
|
-
|
235
|
-
res.close
|
236
|
-
return obj
|
237
|
-
end
|
238
|
-
|
239
|
-
def read_all(res, klass)
|
240
|
-
return [] unless valid_res?(res)
|
241
|
-
objects = []
|
242
|
-
|
243
|
-
res.each do |row|
|
244
|
-
obj = klass.allocate
|
245
|
-
obj.og_read(row)
|
246
|
-
objects << obj
|
247
|
-
end
|
248
|
-
|
249
|
-
res.close
|
250
|
-
return objects
|
251
|
-
end
|
252
|
-
|
253
|
-
def read_int(res, idx = 0)
|
254
|
-
val = res.next[idx].to_i
|
255
|
-
res.close
|
256
|
-
return val
|
257
|
-
end
|
258
|
-
|
259
|
-
def get_row(res)
|
260
|
-
res.next
|
261
|
-
end
|
262
|
-
|
263
|
-
end
|
264
|
-
|
265
|
-
end
|
@@ -1,356 +0,0 @@
|
|
1
|
-
# * Anastasios Koutoumanos <ak@navel.gr>
|
2
|
-
# (c) 2004-2005 Navel, all rights reserved.
|
3
|
-
# $Id: sqlserver.rb 17 2005-04-14 16:03:40Z gmosx $
|
4
|
-
|
5
|
-
begin
|
6
|
-
require 'dbi'
|
7
|
-
rescue Object => ex
|
8
|
-
Logger.error 'Ruby-DBI bindings not present or ADO support not available.'
|
9
|
-
Logger.error ex
|
10
|
-
end
|
11
|
-
|
12
|
-
require 'og/adapters/base'
|
13
|
-
|
14
|
-
module Og
|
15
|
-
|
16
|
-
# The Microsoft SQL Server Sql Server adapter. This adapter
|
17
|
-
# communicates with a Microsoft SQL Server sql server rdbms.
|
18
|
-
# This adapter will ONLY work on Windows systems, since it
|
19
|
-
# relies on Win32OLE is apparently only available on Windows.
|
20
|
-
# It relies on the ADO support in the DBI module. If you are using the
|
21
|
-
# one-click installer of Ruby, then you already have DBI installed, but
|
22
|
-
# the ADO module is *NOT* installed. You will need to get the latest
|
23
|
-
# source distribution of Ruby-DBI from http://ruby-dbi.sourceforge.net/
|
24
|
-
# unzip it, and copy the file <tt>src/lib/dbd_ado/ADO.rb</tt> to
|
25
|
-
# <tt>X:/Ruby/lib/ruby/site_ruby/1.8/DBD/ADO/ADO.rb</tt>
|
26
|
-
# (you will need to create the ADO directory). Once you've installed
|
27
|
-
# that file, you are ready to go.
|
28
|
-
# Originally based on the sqlserver_adapter.rb -- the ActiveRecord
|
29
|
-
# adapter for Microsoft SQL Server by Joey Gibson and DeLynn Berry.
|
30
|
-
# Information related to the SQL Server datatypes:
|
31
|
-
# http://msdn.microsoft.com/library/default.asp?url=/library/en-us/architec/8_ar_da_4ucz.asp
|
32
|
-
# For extra documentation see lib/og/adapter.rb
|
33
|
-
|
34
|
-
class SqlserverAdapter < Adapter
|
35
|
-
|
36
|
-
def initialize
|
37
|
-
super
|
38
|
-
@typemap.update(
|
39
|
-
Integer => 'int', # drak: maybe smallint?
|
40
|
-
Fixnum => 'int',
|
41
|
-
Float => 'float',
|
42
|
-
String => 'varchar(1024)', # drak: maybe nvarchar for unicode
|
43
|
-
Time => 'datetime', # drak: maybe smalldatime?
|
44
|
-
Date => 'smalldatetime',
|
45
|
-
TrueClass => 'bit'
|
46
|
-
)
|
47
|
-
|
48
|
-
@typecast.update(TrueClass => "#\{:s: ? \'1\' : '0' \}")
|
49
|
-
end
|
50
|
-
|
51
|
-
|
52
|
-
def self.timestamp(time = Time.now)
|
53
|
-
return nil unless time
|
54
|
-
return time.strftime("%Y-%m-%d %H:%M:%S")
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.date(date)
|
58
|
-
return nil unless date
|
59
|
-
return "#{date.year}-#{date.month}-#{date.mday}"
|
60
|
-
end
|
61
|
-
|
62
|
-
def read_prop(p, idx)
|
63
|
-
if p.klass.ancestors.include?(Integer)
|
64
|
-
return "res[tuple][#{idx}].to_i"
|
65
|
-
elsif p.klass.ancestors.include?(Float)
|
66
|
-
return "res[tuple][#{idx}].to_f"
|
67
|
-
elsif p.klass.ancestors.include?(String)
|
68
|
-
return "res[tuple][#{idx}]"
|
69
|
-
elsif p.klass.ancestors.include?(Time)
|
70
|
-
return "#{self.class}.parse_timestamp(res[tuple][#{idx}])"
|
71
|
-
elsif p.klass.ancestors.include?(Date)
|
72
|
-
return "#{self.class}.parse_date(res[tuple][#{idx}])"
|
73
|
-
elsif p.klass.ancestors.include?(TrueClass)
|
74
|
-
return "('0' != res[tuple][#{idx}])"
|
75
|
-
else
|
76
|
-
return "YAML::load(res[tuple][#{idx}])"
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def create_db(database, user = nil, password = nil)
|
81
|
-
raise 'Not implemented!'
|
82
|
-
|
83
|
-
### how can we get a valid connection when the database does not already exist?
|
84
|
-
begin
|
85
|
-
conn = DBI.connect("DBI:ADO:Provider=SQLOLEDB;Data Source=localhost;Initial Catalog=master;User Id=sa;Password=sa;")
|
86
|
-
conn["AutoCommit"] = true
|
87
|
-
conn.execute("CREATE DATABASE #{database}")
|
88
|
-
conn.commit
|
89
|
-
Logger.warn "Ignoring credentials for database creation (not implemented)" if user
|
90
|
-
Logger.info "Created database '#{database}'."
|
91
|
-
super
|
92
|
-
rescue Exception => ex
|
93
|
-
# gmosx: any idea how to better test this?
|
94
|
-
if ex.to_s =~ /0x80020009/i
|
95
|
-
Logger.warn "Cannot drop database '#{database}', it does not exist!"
|
96
|
-
super
|
97
|
-
else
|
98
|
-
raise
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
def drop_db(database, user = nil, password = nil)
|
104
|
-
raise 'Not implemented!'
|
105
|
-
|
106
|
-
begin
|
107
|
-
conn = DBI.connect("DBI:ADO:Provider=SQLOLEDB;Data Source=localhost;Initial Catalog=master;User Id=sa;Password=sa;")
|
108
|
-
conn["AutoCommit"] = true
|
109
|
-
# FIXME: why no drop?
|
110
|
-
# conn.execute("DROP DATABASE #{database}")
|
111
|
-
Logger.warn "Ignoring credentials for database drop (not implemented)" if user
|
112
|
-
Logger.info "Dropped database '#{database}'."
|
113
|
-
super
|
114
|
-
rescue Exception => ex
|
115
|
-
# gmosx: any idea how to better test this?
|
116
|
-
if ex.to_s =~ /0x80020009/i
|
117
|
-
Logger.warn "Cannot drop database '#{database}', it does not exist!"
|
118
|
-
super
|
119
|
-
else
|
120
|
-
raise
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def props_for_insert(klass)
|
126
|
-
klass.__props.reject { |p| :oid == p.symbol }
|
127
|
-
end
|
128
|
-
|
129
|
-
def insert_code(klass, db)
|
130
|
-
props = props_for_insert(klass)
|
131
|
-
values = props.collect { |p| write_prop(p) }.join(',')
|
132
|
-
|
133
|
-
sql = "INSERT INTO #{klass::DBTABLE} (#{props.collect {|p| p.name}.join(',')}) VALUES (#{values});"
|
134
|
-
|
135
|
-
%{
|
136
|
-
conn.exec "#{sql}"
|
137
|
-
conn.commit
|
138
|
-
res = conn.query("SELECT IDENT_CURRENT('#{klass::DBTABLE}')")
|
139
|
-
@oid = res[0][0].to_i
|
140
|
-
#res.finish
|
141
|
-
}
|
142
|
-
end
|
143
|
-
|
144
|
-
def new_connection(db)
|
145
|
-
return SqlserverConnection.new(db)
|
146
|
-
end
|
147
|
-
|
148
|
-
def calc_field_index(klass, db)
|
149
|
-
res = db.get_connection.store.execute("SELECT TOP 1 * FROM #{klass::DBTABLE}")
|
150
|
-
meta = db.managed_classes[klass]
|
151
|
-
columns = res.column_names
|
152
|
-
|
153
|
-
for idx in (0...columns.size)
|
154
|
-
meta.field_index[columns[idx]] = idx
|
155
|
-
end
|
156
|
-
|
157
|
-
ensure
|
158
|
-
res.finish
|
159
|
-
end
|
160
|
-
|
161
|
-
def create_table(klass, db)
|
162
|
-
conn = db.get_connection
|
163
|
-
|
164
|
-
fields = create_fields(klass)
|
165
|
-
|
166
|
-
sql = "CREATE TABLE #{klass::DBTABLE} (#{fields.join(', ')}"
|
167
|
-
|
168
|
-
# Create table constrains.
|
169
|
-
if klass.__meta and constrains = klass.__meta[:sql_constrain]
|
170
|
-
sql << ", #{constrains.join(', ')}"
|
171
|
-
end
|
172
|
-
sql << ");"
|
173
|
-
|
174
|
-
begin
|
175
|
-
conn.store.execute(sql)
|
176
|
-
conn.commit
|
177
|
-
Logger.info "Created table '#{klass::DBTABLE}'."
|
178
|
-
rescue => ex
|
179
|
-
if ex.to_s =~ /80040E14/i
|
180
|
-
Logger.debug 'Table already exists' if $DBG
|
181
|
-
else
|
182
|
-
raise
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
# Create indices.
|
187
|
-
|
188
|
-
if klass.__meta and indices = klass.__meta[:sql_index]
|
189
|
-
for data in indices
|
190
|
-
idx, options = *data
|
191
|
-
idx = idx.to_s
|
192
|
-
pre_sql, post_sql = options[:pre], options[:post]
|
193
|
-
idxname = idx.gsub(/ /, "").gsub(/,/, "_").gsub(/\(.*\)/, "")
|
194
|
-
sql << " CREATE #{pre_sql} INDEX #{klass::DBTABLE}_#{idxname}_idx #{post_sql} ON #{klass::DBTABLE} (#{idx});"
|
195
|
-
begin
|
196
|
-
conn.store.execute(sql)
|
197
|
-
conn.commit
|
198
|
-
rescue => ex
|
199
|
-
if ex.to_s =~ /80040E14/i
|
200
|
-
Logger.debug 'Table already exists' if $DBG
|
201
|
-
else
|
202
|
-
raise
|
203
|
-
end
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
207
|
-
|
208
|
-
# Create join tables if needed. Join tables are used in
|
209
|
-
# 'many_to_many' relations.
|
210
|
-
|
211
|
-
if klass.__meta and joins = klass.__meta[:sql_join]
|
212
|
-
for data in joins
|
213
|
-
# the class to join to and some options.
|
214
|
-
join_name, join_class, options = *data
|
215
|
-
|
216
|
-
# gmosx: dont use DBTABLE here, perhaps the join class
|
217
|
-
# is not managed yet.
|
218
|
-
join_table = "#{self.class.join_table(klass, join_class, join_name)}"
|
219
|
-
join_src = "#{self.class.encode(klass)}_oid"
|
220
|
-
join_dst = "#{self.class.encode(join_class)}_oid"
|
221
|
-
begin
|
222
|
-
conn.store.execute("CREATE TABLE #{join_table} ( key1 integer NOT NULL, key2 integer NOT NULL )").finish
|
223
|
-
conn.store.execute("CREATE INDEX #{join_table}_key1_idx ON #{join_table} (key1)").finish
|
224
|
-
conn.store.execute("CREATE INDEX #{join_table}_key2_idx ON #{join_table} (key2)").finish
|
225
|
-
conn.commit
|
226
|
-
rescue => ex
|
227
|
-
# gmosx: any idea how to better test this?
|
228
|
-
if ex.to_s =~ /80040E14/i
|
229
|
-
Logger.debug "Join table already exists" if $DBG
|
230
|
-
else
|
231
|
-
raise
|
232
|
-
end
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
ensure
|
238
|
-
db.put_connection
|
239
|
-
end
|
240
|
-
|
241
|
-
def drop_table(klass)
|
242
|
-
super
|
243
|
-
exec "DROP TABLE #{klass::DBTABLE}"
|
244
|
-
end
|
245
|
-
|
246
|
-
# Generate the property for oid.
|
247
|
-
|
248
|
-
def eval_og_oid(klass)
|
249
|
-
klass.class_eval %{
|
250
|
-
prop_accessor :oid, Fixnum, :sql => 'int NOT NULL IDENTITY(1, 1) PRIMARY KEY'
|
251
|
-
}
|
252
|
-
end
|
253
|
-
|
254
|
-
end
|
255
|
-
|
256
|
-
# The SqlserverConnection connection.
|
257
|
-
|
258
|
-
class SqlserverConnection < Connection
|
259
|
-
|
260
|
-
def initialize(db)
|
261
|
-
super
|
262
|
-
config = db.config
|
263
|
-
|
264
|
-
begin
|
265
|
-
@store = DBI.connect("DBI:ADO:Provider=SQLOLEDB;Data Source=#{config[:address]};Initial Catalog=#{config[:database]};User Id=#{config[:user].to_s};Password=#{config[:password].to_s};")
|
266
|
-
rescue => ex
|
267
|
-
# gmosx, FIXME: drak, fix this!
|
268
|
-
if ex.to_s =~ /database .* does not exist/i
|
269
|
-
Logger.info "Database '#{config[:database]}' not found!"
|
270
|
-
@db.adapter.create_db(config[:database], config[:user])
|
271
|
-
retry
|
272
|
-
end
|
273
|
-
raise
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
def close
|
278
|
-
@store.disconnect
|
279
|
-
super
|
280
|
-
end
|
281
|
-
|
282
|
-
def prepare(sql)
|
283
|
-
@store.prepare(sql)
|
284
|
-
end
|
285
|
-
|
286
|
-
def query(sql)
|
287
|
-
Logger.debug sql if $DBG
|
288
|
-
begin
|
289
|
-
res = @store.select_all(sql)
|
290
|
-
return res
|
291
|
-
rescue => ex
|
292
|
-
handle_db_exception(ex, sql)
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
def exec(sql)
|
297
|
-
Logger.debug sql if $DBG
|
298
|
-
begin
|
299
|
-
@store.execute(sql).finish
|
300
|
-
rescue => ex
|
301
|
-
handle_db_exception(ex, sql)
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
|
-
def start
|
306
|
-
# no need to do something.
|
307
|
-
end
|
308
|
-
|
309
|
-
def commit
|
310
|
-
@store.commit
|
311
|
-
end
|
312
|
-
|
313
|
-
def rollback
|
314
|
-
@store.rollback
|
315
|
-
end
|
316
|
-
|
317
|
-
def valid_res?(res)
|
318
|
-
return !(res.nil?)
|
319
|
-
end
|
320
|
-
|
321
|
-
def read_one(res, klass)
|
322
|
-
return nil unless valid_res?(res)
|
323
|
-
return nil unless res
|
324
|
-
|
325
|
-
obj = klass.allocate
|
326
|
-
obj.og_read(res)
|
327
|
-
|
328
|
-
return obj
|
329
|
-
end
|
330
|
-
|
331
|
-
def read_all(res, klass)
|
332
|
-
return [] unless valid_res?(res)
|
333
|
-
objects = []
|
334
|
-
|
335
|
-
for tuple in (0...res.size)
|
336
|
-
obj = klass.allocate
|
337
|
-
obj.og_read(res, tuple)
|
338
|
-
objects << obj
|
339
|
-
end
|
340
|
-
|
341
|
-
return objects
|
342
|
-
end
|
343
|
-
|
344
|
-
def read_int(res, idx = 0)
|
345
|
-
val = res.next[idx].to_i
|
346
|
-
res.finish
|
347
|
-
return val
|
348
|
-
end
|
349
|
-
|
350
|
-
def get_row(res)
|
351
|
-
res.next
|
352
|
-
end
|
353
|
-
|
354
|
-
end
|
355
|
-
|
356
|
-
end
|