og 0.19.0 → 0.20.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.
@@ -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