og 0.19.0 → 0.20.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,306 @@
1
+ #
2
+ # mysq411.rb - 0.1 - Matt Mower <self@mattmower.com>
3
+ #
4
+ # The native Ruby MySQL client (mysql.rb) by Tomita Masahiro does not (yet) handle the new MySQL
5
+ # protocol introduced in MySQL 4.1.1. This protocol introduces a new authentication scheme as
6
+ # well as modifications to the client/server exchanges themselves.
7
+ #
8
+ # mysql411.rb modifies the Mysql class to add MySQL 4.1.x support. It modifies the connection
9
+ # algorithm to detect a 4.1.1 server and respond with the new authentication scheme, otherwise using
10
+ # the original one. Similarly for the changes to packet structures and field definitions, etc...
11
+ #
12
+ # It redefines serveral methods which behave differently depending upon the server context. The
13
+ # way I have implemented this is to alias the old method, create a new alternative method, and redefine
14
+ # the original method as a selector which calls the appropriate method based upon the server version.
15
+ # There may have been a neater way to do this.
16
+ #
17
+ # In general I've tried not to change the original code any more than necessary, i.e. even where I
18
+ # redefine a method I have made the smallest number of changes possible, rather than rewriting from
19
+ # scratch.
20
+ #
21
+ # *Caveat Lector* This code passes all current ActiveRecord unit tests however this is no guarantee that
22
+ # full & correct MySQL 4.1 support has been achieved.
23
+ #
24
+
25
+ require 'digest/sha1'
26
+
27
+ #
28
+ # Extend the Mysql class to work with MySQL 4.1.1+ servers. After version
29
+ # 4.1.1 the password hashing function (and some other connection details) have
30
+ # changed rendering the previous Mysql class unable to connect:
31
+ #
32
+ #
33
+
34
+ class Mysql
35
+ CLIENT_PROTOCOL_41 = 512
36
+ CLIENT_SECURE_CONNECTION = 32768
37
+
38
+ def real_connect( host=nil, user=nil, passwd=nil, db=nil, port=nil, socket=nil, flag=nil )
39
+ @server_status = SERVER_STATUS_AUTOCOMMIT
40
+
41
+ if( host == nil || host == "localhost" ) && defined? UNIXSocket
42
+ unix_socket = socket || ENV["MYSQL_UNIX_PORT"] || MYSQL_UNIX_ADDR
43
+ sock = UNIXSocket::new( unix_socket )
44
+ @host_info = Error::err( Error::CR_LOCALHOST_CONNECTION )
45
+ @unix_socket = unix_socket
46
+ else
47
+ sock = TCPSocket::new(host, port||ENV["MYSQL_TCP_PORT"]||(Socket::getservbyname("mysql","tcp") rescue MYSQL_PORT))
48
+ @host_info = sprintf Error::err(Error::CR_TCP_CONNECTION), host
49
+ end
50
+
51
+ @host = host ? host.dup : nil
52
+ sock.setsockopt Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true
53
+ @net = Net::new sock
54
+
55
+ a = read
56
+
57
+ @protocol_version = a.slice!(0)
58
+ @server_version, a = a.split(/\0/,2)
59
+
60
+ # Store the version number components for speedy comparison
61
+ version, ostag = @server_version.split( /-/, 2 )
62
+ @major_ver, @minor_ver, @revision_num = version.split( /\./ ).map { |v| v.to_i }
63
+
64
+ @thread_id, @scramble_buff = a.slice!(0,13).unpack("La8")
65
+ if a.size >= 2 then
66
+ @server_capabilities, = a.slice!(0,2).unpack("v")
67
+ end
68
+ if a.size >= 16 then
69
+ @server_language, @server_status = a.unpack("cv")
70
+ end
71
+
72
+ # Set the flags we'll send back to the server
73
+ flag = 0 if flag == nil
74
+ flag |= @client_flag | CLIENT_CAPABILITIES
75
+ flag |= CLIENT_CONNECT_WITH_DB if db
76
+
77
+ if version_meets_minimum?( 4, 1, 1 )
78
+ # In 4.1.1+ the seed comes in two parts which must be combined
79
+ a.slice!( 0, 16 )
80
+ seed_part_2 = a.slice!( 0, 12 );
81
+ @scramble_buff << seed_part_2
82
+
83
+ flag |= CLIENT_FOUND_ROWS
84
+ flag |= CLIENT_PROTOCOL_41
85
+ flag |= CLIENT_SECURE_CONNECTION if @server_capabilities & CLIENT_SECURE_CONNECTION;
86
+
87
+ if db && @server_capabilities & CLIENT_CONNECT_WITH_DB != 0
88
+ @db = db.dup
89
+ end
90
+
91
+ scrambled_password = scramble411( passwd, @scramble_buff, @protocol_version==9 )
92
+ data = make_client_auth_packet_41( flag, user, scrambled_password, db )
93
+ else
94
+ scrambled_password = scramble( passwd, @scramble_buff, @protocol_version == 9 )
95
+ data = Net::int2str(flag)+Net::int3str(@max_allowed_packet)+(user||"")+"\0"+scrambled_password
96
+ if db and @server_capabilities & CLIENT_CONNECT_WITH_DB != 0 then
97
+ data << "\0"+db
98
+ @db = db.dup
99
+ end
100
+ end
101
+
102
+ write data
103
+ read
104
+ self
105
+ end
106
+ alias :connect :real_connect
107
+
108
+ # Pack the authentication information into depending upon whether an initial database has
109
+ # been specified
110
+ def make_client_auth_packet_41( flag, user, password, db )
111
+ if db && @server_capabilities & CLIENT_CONNECT_WITH_DB != 0
112
+ template = "VVcx23a#{user.size+1}cA#{password.size}a#{db.size+1}"
113
+ else
114
+ template = "VVcx23a#{user.size+1}cA#{password.size}x"
115
+ end
116
+
117
+ [ flag, @max_allowed_packet, @server_language, user, password.size, password, db ].pack( template )
118
+ end
119
+
120
+ def version_meets_minimum?( major, minor, revision )
121
+ @major_ver >= major && @minor_ver >= minor && @revision_num >= revision
122
+ end
123
+
124
+ # SERVER: public_seed=create_random_string()
125
+ # send(public_seed)
126
+ #
127
+ # CLIENT: recv(public_seed)
128
+ # hash_stage1=sha1("password")
129
+ # hash_stage2=sha1(hash_stage1)
130
+ # reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
131
+ #
132
+ # #this three steps are done in scramble()
133
+ #
134
+ # send(reply)
135
+ #
136
+ #
137
+ # SERVER: recv(reply)
138
+ # hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
139
+ # candidate_hash2=sha1(hash_stage1)
140
+ # check(candidate_hash2==hash_stage2)
141
+ def scramble411( password, seed, old_ver )
142
+ return "" if password == nil or password == ""
143
+ raise "old version password is not implemented" if old_ver
144
+
145
+ # print "Seed Bytes = "
146
+ # seed.each_byte { |b| print "0x#{b.to_s( 16 )}, " }
147
+ # puts
148
+
149
+ stage1 = Digest::SHA1.digest( password )
150
+ stage2 = Digest::SHA1.digest( stage1 )
151
+
152
+ dgst = Digest::SHA1.new
153
+ dgst << seed
154
+ dgst << stage2
155
+ stage3 = dgst.digest
156
+
157
+ # stage1.zip( stage3 ).map { |a, b| (a ^ b).chr }.join
158
+ scrambled = ( 0 ... stage3.size ).map { |i| stage3[i] ^ stage1[i] }
159
+ scrambled = scrambled.map { |x| x.chr }
160
+ scrambled.join
161
+ end
162
+
163
+ def change_user(user="", passwd="", db="")
164
+ scrambled_password = version_meets_minimum?( 4, 1, 1 ) ? scramble411( passwd, @scramble_buff, @protocol_version==9 ) : scramble( passwd, @scramble_buff, @protocol_version==9 )
165
+ data = user+"\0"+scrambled_password+"\0"+db
166
+ command COM_CHANGE_USER, data
167
+ @user = user
168
+ @passwd = passwd
169
+ @db = db
170
+ end
171
+
172
+ #
173
+ # The 4.1 protocol changed the length of the END packet
174
+ #
175
+ alias_method :old_read_one_row, :read_one_row
176
+
177
+ def read_one_row( field_count )
178
+ if version_meets_minimum?( 4, 1, 1 )
179
+ read_one_row_41( field_count )
180
+ else
181
+ old_read_one_row( field_count )
182
+ end
183
+ end
184
+
185
+ def read_one_row_41( field_count )
186
+ data = read
187
+ return if data[0] == 254 and data.length < 9
188
+ rec = []
189
+ field_count.times do
190
+ len = get_length data
191
+ if len == nil then
192
+ rec << len
193
+ else
194
+ rec << data.slice!(0,len)
195
+ end
196
+ end
197
+ rec
198
+ end
199
+
200
+ #
201
+ # The 4.1 protocol changed the length of the END packet
202
+ #
203
+ alias_method :old_skip_result, :skip_result
204
+
205
+ def skip_result
206
+ if version_meets_minimum?( 4, 1, 1 )
207
+ skip_result_41
208
+ else
209
+ old_skip_result
210
+ end
211
+ end
212
+
213
+ def skip_result_41()
214
+ if @status == :STATUS_USE_RESULT then
215
+ loop do
216
+ data = read
217
+ break if data[0] == 254 and data.length == 1
218
+ end
219
+ @status = :STATUS_READY
220
+ end
221
+ end
222
+
223
+ # The field description structure is changed for the 4.1 protocol passing
224
+ # more data and a different packing form. NOTE: The 4.1 protocol now passes
225
+ # back a "catalog" name for each field which is a new feature. Since AR has
226
+ # nowhere to put it I'm throwing it away. Possibly this is not the best
227
+ # idea?
228
+ #
229
+ alias_method :old_unpack_fields, :unpack_fields
230
+
231
+ def unpack_fields( data, long_flag_protocol )
232
+ if version_meets_minimum?( 4, 1, 1 )
233
+ unpack_fields_41( data, long_flag_protocol )
234
+ else
235
+ old_unpack_fields( data, long_flag_protocol )
236
+ end
237
+ end
238
+
239
+ def unpack_fields_41( data, long_flag_protocol )
240
+ ret = []
241
+
242
+ data.each do |f|
243
+ catalog_name = f[0]
244
+ database_name = f[1]
245
+ table_name_alias = f[2]
246
+ table_name = f[3]
247
+ column_name_alias = f[4]
248
+ column_name = f[5]
249
+
250
+ charset = f[6][0] + f[6][1]*256
251
+ length = f[6][2] + f[6][3]*256 + f[6][4]*256*256 + f[6][5]*256*256*256
252
+ type = f[6][6]
253
+ flags = f[6][7] + f[6][8]*256
254
+ decimals = f[6][9]
255
+ def_value = f[7]
256
+ max_length = 0
257
+
258
+ ret << Field::new(table_name, table_name, column_name_alias, length, type, flags, decimals, def_value, max_length)
259
+ end
260
+ ret
261
+ end
262
+
263
+ # In this instance the read_query_result method in mysql is bound to read 5 field parameters which
264
+ # is expanded to 7 in the 4.1 protocol. So in this case we redefine this entire method in order
265
+ # to write "read_rows 7" instead of "read_rows 5"!
266
+ #
267
+ alias_method :old_read_query_result, :read_query_result
268
+
269
+ def read_query_result
270
+ if version_meets_minimum?( 4, 1, 1 )
271
+ read_query_result_41
272
+ else
273
+ old_read_query_result
274
+ end
275
+ end
276
+
277
+ def read_query_result_41
278
+ data = read
279
+ @field_count = get_length(data)
280
+ if @field_count == nil then # LOAD DATA LOCAL INFILE
281
+ File::open(data) do |f|
282
+ write f.read
283
+ end
284
+ write "" # mark EOF
285
+ data = read
286
+ @field_count = get_length(data)
287
+ end
288
+ if @field_count == 0 then
289
+ @affected_rows = get_length(data, true)
290
+ @insert_id = get_length(data, true)
291
+ if @server_capabilities & CLIENT_TRANSACTIONS != 0 then
292
+ a = data.slice!(0,2)
293
+ @server_status = a[0]+a[1]*256
294
+ end
295
+ if data.size > 0 and get_length(data) then
296
+ @info = data
297
+ end
298
+ else
299
+ @extra_info = get_length(data, true)
300
+ fields = read_rows 7
301
+ @fields = unpack_fields(fields, @server_capabilities & CLIENT_LONG_FLAG != 0)
302
+ @status = :STATUS_GET_RESULT
303
+ end
304
+ self
305
+ end
306
+ end
@@ -7,9 +7,9 @@ require 'og'
7
7
  require 'og/mixin/hierarchical'
8
8
 
9
9
  $og = Og.setup(
10
- :store => 'psql',
10
+ :store => 'mysql',
11
11
  :name => 'test',
12
- :user => 'postgres',
12
+ :user => 'root',
13
13
  :password => 'navelrulez',
14
14
  :destroy => true
15
15
  )
@@ -71,6 +71,10 @@ class TC_OgHierarchical < Test::Unit::TestCase # :nodoc: all
71
71
  assert_equal 6, c1.full_comments.size
72
72
  assert_equal 5, c1.comments.size
73
73
  assert_equal 2, c1.direct_comments.size
74
+
75
+ c8.reload
76
+
77
+ assert_equal 'root', c8.parent.body
74
78
  end
75
79
 
76
80
  end
@@ -28,6 +28,12 @@ class TestCaseOgRelation < Test::Unit::TestCase # :nodoc: all
28
28
  rel = User.relation(:articles)
29
29
  rel.resolve_target
30
30
  assert_equal TestCaseOgRelation::Article, rel.target_class
31
+
32
+ # bug: test the no belongs_to case in Article
33
+
34
+ og = Og.setup(:store => :memory, :name => 'test')
35
+ og.manage_classes
36
+
31
37
  end
32
38
  end
33
39
 
@@ -48,12 +48,19 @@ class TCOgStore < Test::Unit::TestCase # :nodoc: all
48
48
  belongs_to :article, Article
49
49
  belongs_to User
50
50
 
51
+ order 'hits ASC'
52
+
51
53
  def initialize(body = nil, user = nil)
52
54
  @body = body
53
55
  @user = user
54
56
  @hits = 0
55
57
  end
56
58
  end
59
+
60
+ class Bugger
61
+ property :name, String
62
+ many_to_many Bugger
63
+ end
57
64
 
58
65
  def setup
59
66
  @og = nil
@@ -262,6 +269,11 @@ class TCOgStore < Test::Unit::TestCase # :nodoc: all
262
269
 
263
270
  assert_equal 4, a4.comments(:reload => true).size
264
271
 
272
+ assert_equal 2, a4.comments(:limit => 2, :reload => true).size
273
+
274
+ # bug:
275
+ assert_equal 4, a4.comments(:reload => true).size
276
+
265
277
  a4.comments.delete(c1)
266
278
  assert_equal 3, a4.comments.size
267
279
 
@@ -311,6 +323,15 @@ class TCOgStore < Test::Unit::TestCase # :nodoc: all
311
323
 
312
324
  c = Category.find_by_title('News')
313
325
  assert_equal 1, c.articles.size
326
+
327
+ # bug: self join bug.
328
+
329
+ b1 = Bugger.create
330
+ b2 = Bugger.create
331
+
332
+ b1.buggers << b2
333
+
334
+ assert b1.buggers.first
314
335
  end
315
336
 
316
337
  def conversions_test
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.10
3
3
  specification_version: 1
4
4
  name: og
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.19.0
7
- date: 2005-06-17
6
+ version: 0.20.0
7
+ date: 2005-07-12
8
8
  summary: Og (ObjectGraph)
9
9
  require_paths:
10
10
  - lib
@@ -47,6 +47,7 @@ files:
47
47
  - doc/AUTHORS
48
48
  - lib/og
49
49
  - lib/og.rb
50
+ - lib/vendor
50
51
  - lib/og/collection.rb
51
52
  - lib/og/entity.rb
52
53
  - lib/og/relation.rb
@@ -78,10 +79,10 @@ files:
78
79
  - lib/og/store/sqlite.rb
79
80
  - lib/og/store/kirby.rb
80
81
  - lib/og/store/memory.rb
81
- - lib/og/store/kirby
82
- - lib/og/store/kirby/kirbybase.rb
83
- - lib/og/store/kirby/readme.txt
84
- - lib/og/store/kirby/README
82
+ - lib/vendor/mysql411.rb
83
+ - lib/vendor/mysql.rb
84
+ - lib/vendor/kirbybase.rb
85
+ - lib/vendor/README
85
86
  - test/og
86
87
  - test/og/store
87
88
  - test/og/mixin
@@ -120,7 +121,7 @@ dependencies:
120
121
  -
121
122
  - "="
122
123
  - !ruby/object:Gem::Version
123
- version: 0.19.0
124
+ version: 0.20.0
124
125
  version:
125
126
  - !ruby/object:Gem::Dependency
126
127
  name: facets
@@ -1,6 +0,0 @@
1
- = KirbyBase
2
-
3
- The contents of this folder where copied from the KirbyBase
4
- 2.2 distribution.
5
-
6
- Copyright (c) 2005 Jamey Cribbs
@@ -1,63 +0,0 @@
1
- KirbyBase 2.2
2
-
3
- A small, plain-text, dbms written in Ruby. It can be used either embedded
4
- or client/server. Version 2 is a complete re-write with a completely new
5
- interface. It is NOT backwards compatible. If you need backwards
6
- compatibility, please use version 1.6.
7
-
8
-
9
- *Installation:
10
-
11
- Unpack the file you downloaded. Execute "ruby install.rb" or simply make
12
- sure kirbybase.rb is somewhere in your Ruby library path.
13
-
14
-
15
- *Documentation:
16
-
17
- Documentation is in manual.html. Also, RDoc generated documentation is in
18
- the doc directory.
19
-
20
- See kbtest.rb for examples of how to use KirbyBase.
21
-
22
-
23
- *Manifest:
24
-
25
- readme.txt - this file
26
- install.rb - install script
27
- changes.txt - history of changes.
28
- manual.html - documentation
29
- kirbybase.rb - dbms library
30
- kbserver.rb - multi-threaded database server script.
31
- kbtest.rb - test script with examples.
32
- record_class_test.rb - script showing how to have KB return class instances.
33
- csv_import_test.rb - script showing how to have KB import a csv file.
34
- plane.csv - sample csv file used in csv_import_test.rb
35
- doc directory - RDoc generated documentation in html format.
36
-
37
-
38
- *License:
39
-
40
- KirbyBase is distributed under the same license as Ruby.
41
-
42
-
43
- *Warranty:
44
-
45
- I should probably put something more legalese here but let me just say:
46
-
47
- KirbyBase carries no warranty! Use at your own risk. If it eats your
48
- data, please don't come after me. :)
49
-
50
-
51
- That being said, please send any bug reports, suggestions, ideas,
52
- improvements, to:
53
-
54
- jcribbs@twmi.rr.com
55
-
56
- You can find more info about KirbyBase at:
57
-
58
- http://www.netpromi.com/kirbybase.html
59
-
60
-
61
- Thanks for trying KirbyBase.
62
-
63
- Jamey Cribbs