postgres-pr-encoding 0.7.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.
- checksums.yaml +7 -0
- data/examples/client.rb +34 -0
- data/examples/og/test.rb +50 -0
- data/examples/server.rb +12 -0
- data/examples/test_connection.rb +18 -0
- data/lib/binary_reader.rb +120 -0
- data/lib/binary_writer.rb +100 -0
- data/lib/buffer.rb +97 -0
- data/lib/byteorder.rb +32 -0
- data/lib/pg.rb +4 -0
- data/lib/postgres-pr/connection.rb +177 -0
- data/lib/postgres-pr/message.rb +542 -0
- data/lib/postgres-pr/pg-compat.rb +174 -0
- data/lib/postgres-pr/postgres-compat.rb +170 -0
- data/lib/postgres-pr/typeconv/TC_conv.rb +18 -0
- data/lib/postgres-pr/typeconv/array.rb +46 -0
- data/lib/postgres-pr/typeconv/bytea.rb +28 -0
- data/lib/postgres-pr/typeconv/conv.rb +5 -0
- data/lib/postgres-pr/version.rb +3 -0
- data/lib/postgres.rb +8 -0
- data/test/TC_message.rb +103 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d0abce872430818917834a4090ee43ad100f65dd
|
4
|
+
data.tar.gz: 7121f1313924c2ac97160a3a6a0983812de2df77
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 982e80829402a1b479e8d2f668abfacc990d0a484cfa3b1abfb735c2bd90cb9eb004c6baccafa5853342dacac2e332cf3813346f87cc6a73138bdac9203e9b22
|
7
|
+
data.tar.gz: 3000ebc135b2c720111116b45492acd0d8052c578ae981b57620c52421ba1785b387dfaf717dc4729cb3a32f0a5e1a418e43c8e96d1d236f7ded8de5d7a04312
|
data/examples/client.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
$LOAD_PATH.unshift "../lib"
|
2
|
+
require 'postgres-pr/message'
|
3
|
+
require 'socket'
|
4
|
+
include PostgresPR
|
5
|
+
|
6
|
+
s = UNIXSocket.new(ARGV.shift || "/tmp/.s.PGSQL.5432")
|
7
|
+
|
8
|
+
msg = StartupMessage.new(196608, "user" => "mneumann", "database" => "mneumann")
|
9
|
+
s << msg.dump
|
10
|
+
|
11
|
+
Thread.start(s) { |s|
|
12
|
+
sleep 2
|
13
|
+
s << Query.new("drop table test").dump
|
14
|
+
s << Query.new("create table test (i int, v varchar(100))").dump
|
15
|
+
s << Parse.new("insert into test (i, v) values ($1, $2)", "blah").dump
|
16
|
+
s << Query.new("EXECUTE blah(1, 'hallo')").dump
|
17
|
+
|
18
|
+
while not (line = gets.chomp).empty?
|
19
|
+
s << Query.new(line).dump
|
20
|
+
end
|
21
|
+
exit
|
22
|
+
}
|
23
|
+
|
24
|
+
loop do
|
25
|
+
msg = Message.read(s)
|
26
|
+
p msg
|
27
|
+
|
28
|
+
case msg
|
29
|
+
when AuthentificationOk
|
30
|
+
p "OK"
|
31
|
+
when ErrorResponse
|
32
|
+
p "FAILED"
|
33
|
+
end
|
34
|
+
end
|
data/examples/og/test.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
$LOAD_PATH.unshift '../../lib'
|
2
|
+
require 'rubygems'
|
3
|
+
require 'og'
|
4
|
+
require 'glue/logger'
|
5
|
+
|
6
|
+
$DBG = true
|
7
|
+
|
8
|
+
class User
|
9
|
+
end
|
10
|
+
|
11
|
+
class Comment
|
12
|
+
prop_accessor :body, String
|
13
|
+
belongs_to :user, User
|
14
|
+
end
|
15
|
+
|
16
|
+
class User
|
17
|
+
prop_accessor :name, String
|
18
|
+
has_many :comments, Comment
|
19
|
+
end
|
20
|
+
|
21
|
+
if __FILE__ == $0
|
22
|
+
config = {
|
23
|
+
:address => "localhost",
|
24
|
+
:database => "mneumann",
|
25
|
+
:backend => "psql",
|
26
|
+
:user => "mneumann",
|
27
|
+
:password => "",
|
28
|
+
:connection_count => 1
|
29
|
+
}
|
30
|
+
$log = Logger.new(STDERR)
|
31
|
+
$og = Og::Database.new(config)
|
32
|
+
|
33
|
+
$og.get_connection
|
34
|
+
|
35
|
+
u1 = User.new
|
36
|
+
u1.name = "Michael Neumann"
|
37
|
+
u1.save!
|
38
|
+
|
39
|
+
u2 = User.new
|
40
|
+
u2.name = "John User"
|
41
|
+
u2.save!
|
42
|
+
|
43
|
+
c1 = Comment.new
|
44
|
+
c1.body = "og test"
|
45
|
+
c1.user = u1
|
46
|
+
c1.save!
|
47
|
+
|
48
|
+
p User.all
|
49
|
+
p Comment.all
|
50
|
+
end
|
data/examples/server.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
$LOAD_PATH.unshift '../lib'
|
2
|
+
require 'postgres-pr/connection'
|
3
|
+
|
4
|
+
conn = PostgresPR::Connection.new('mneumann', 'mneumann', nil, 'unix:/var/run/postgresql/.s.PGSQL.5432')
|
5
|
+
p conn.query("DROP TABLE test") rescue nil
|
6
|
+
p conn.query("CREATE TABLE test (a VARCHAR(100))")
|
7
|
+
p conn.query("INSERT INTO test VALUES ('hallo')")
|
8
|
+
p conn.query("INSERT INTO test VALUES ('leute')")
|
9
|
+
conn.query("COMMIT")
|
10
|
+
|
11
|
+
conn.query("BEGIN")
|
12
|
+
10000.times do |i|
|
13
|
+
p i
|
14
|
+
conn.query("INSERT INTO test VALUES ('#{i}')")
|
15
|
+
end
|
16
|
+
conn.query("COMMIT")
|
17
|
+
|
18
|
+
p conn.query("SELECT * FROM test")
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'byteorder'
|
2
|
+
|
3
|
+
# This mixin solely depends on method read(n), which must be defined
|
4
|
+
# in the class/module where you mixin this module.
|
5
|
+
module BinaryReaderMixin
|
6
|
+
|
7
|
+
# == 8 bit
|
8
|
+
|
9
|
+
# no byteorder for 8 bit!
|
10
|
+
|
11
|
+
def read_word8
|
12
|
+
ru(1, 'C')
|
13
|
+
end
|
14
|
+
|
15
|
+
def read_int8
|
16
|
+
ru(1, 'c')
|
17
|
+
end
|
18
|
+
|
19
|
+
alias read_byte read_word8
|
20
|
+
|
21
|
+
# == 16 bit
|
22
|
+
|
23
|
+
# === Unsigned
|
24
|
+
|
25
|
+
def read_word16_native
|
26
|
+
ru(2, 'S')
|
27
|
+
end
|
28
|
+
|
29
|
+
def read_word16_little
|
30
|
+
ru(2, 'v')
|
31
|
+
end
|
32
|
+
|
33
|
+
def read_word16_big
|
34
|
+
ru(2, 'n')
|
35
|
+
end
|
36
|
+
|
37
|
+
# === Signed
|
38
|
+
|
39
|
+
def read_int16_native
|
40
|
+
ru(2, 's')
|
41
|
+
end
|
42
|
+
|
43
|
+
def read_int16_little
|
44
|
+
# swap bytes if native=big (but we want little)
|
45
|
+
ru_swap(2, 's', ByteOrder::Big)
|
46
|
+
end
|
47
|
+
|
48
|
+
def read_int16_big
|
49
|
+
# swap bytes if native=little (but we want big)
|
50
|
+
ru_swap(2, 's', ByteOrder::Little)
|
51
|
+
end
|
52
|
+
|
53
|
+
# == 32 bit
|
54
|
+
|
55
|
+
# === Unsigned
|
56
|
+
|
57
|
+
def read_word32_native
|
58
|
+
ru(4, 'L')
|
59
|
+
end
|
60
|
+
|
61
|
+
def read_word32_little
|
62
|
+
ru(4, 'V')
|
63
|
+
end
|
64
|
+
|
65
|
+
def read_word32_big
|
66
|
+
ru(4, 'N')
|
67
|
+
end
|
68
|
+
|
69
|
+
# === Signed
|
70
|
+
|
71
|
+
def read_int32_native
|
72
|
+
ru(4, 'l')
|
73
|
+
end
|
74
|
+
|
75
|
+
def read_int32_little
|
76
|
+
# swap bytes if native=big (but we want little)
|
77
|
+
ru_swap(4, 'l', ByteOrder::Big)
|
78
|
+
end
|
79
|
+
|
80
|
+
def read_int32_big
|
81
|
+
# swap bytes if native=little (but we want big)
|
82
|
+
ru_swap(4, 'l', ByteOrder::Little)
|
83
|
+
end
|
84
|
+
|
85
|
+
# == Aliases
|
86
|
+
|
87
|
+
alias read_uint8 read_word8
|
88
|
+
|
89
|
+
# add some short-cut functions
|
90
|
+
%w(word16 int16 word32 int32).each do |typ|
|
91
|
+
alias_method "read_#{typ}_network", "read_#{typ}_big"
|
92
|
+
end
|
93
|
+
|
94
|
+
{:word16 => :uint16, :word32 => :uint32}.each do |old, new|
|
95
|
+
['_native', '_little', '_big', '_network'].each do |bo|
|
96
|
+
alias_method "read_#{new}#{bo}", "read_#{old}#{bo}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# read exactly n characters, otherwise raise an exception.
|
101
|
+
def readn(n)
|
102
|
+
str = read(n)
|
103
|
+
raise "couldn't read #{n} characters" if str.nil? or str.size != n
|
104
|
+
str
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
# shortcut method for readn+unpack
|
110
|
+
def ru(size, template)
|
111
|
+
readn(size).unpack(template).first
|
112
|
+
end
|
113
|
+
|
114
|
+
# same as method +ru+, but swap bytes if native byteorder == _byteorder_
|
115
|
+
def ru_swap(size, template, byteorder)
|
116
|
+
str = readn(size)
|
117
|
+
str.reverse! if ByteOrder.byteorder == byteorder
|
118
|
+
str.unpack(template).first
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'byteorder'
|
2
|
+
|
3
|
+
module BinaryWriterMixin
|
4
|
+
|
5
|
+
# == 8 bit
|
6
|
+
|
7
|
+
# no byteorder for 8 bit!
|
8
|
+
|
9
|
+
def write_word8(val)
|
10
|
+
pw(val, 'C')
|
11
|
+
end
|
12
|
+
|
13
|
+
def write_int8(val)
|
14
|
+
pw(val, 'c')
|
15
|
+
end
|
16
|
+
|
17
|
+
alias write_byte write_word8
|
18
|
+
|
19
|
+
# == 16 bit
|
20
|
+
|
21
|
+
# === Unsigned
|
22
|
+
|
23
|
+
def write_word16_native(val)
|
24
|
+
pw(val, 'S')
|
25
|
+
end
|
26
|
+
|
27
|
+
def write_word16_little(val)
|
28
|
+
str = [val].pack('S')
|
29
|
+
str.reverse! if ByteOrder.network? # swap bytes as native=network (and we want little)
|
30
|
+
write(str)
|
31
|
+
end
|
32
|
+
|
33
|
+
def write_word16_network(val)
|
34
|
+
str = [val].pack('S')
|
35
|
+
str.reverse! if ByteOrder.little? # swap bytes as native=little (and we want network)
|
36
|
+
write(str)
|
37
|
+
end
|
38
|
+
|
39
|
+
# === Signed
|
40
|
+
|
41
|
+
def write_int16_native(val)
|
42
|
+
pw(val, 's')
|
43
|
+
end
|
44
|
+
|
45
|
+
def write_int16_little(val)
|
46
|
+
pw(val, 'v')
|
47
|
+
end
|
48
|
+
|
49
|
+
def write_int16_network(val)
|
50
|
+
pw(val, 'n')
|
51
|
+
end
|
52
|
+
|
53
|
+
# == 32 bit
|
54
|
+
|
55
|
+
# === Unsigned
|
56
|
+
|
57
|
+
def write_word32_native(val)
|
58
|
+
pw(val, 'L')
|
59
|
+
end
|
60
|
+
|
61
|
+
def write_word32_little(val)
|
62
|
+
str = [val].pack('L')
|
63
|
+
str.reverse! if ByteOrder.network? # swap bytes as native=network (and we want little)
|
64
|
+
write(str)
|
65
|
+
end
|
66
|
+
|
67
|
+
def write_word32_network(val)
|
68
|
+
str = [val].pack('L')
|
69
|
+
str.reverse! if ByteOrder.little? # swap bytes as native=little (and we want network)
|
70
|
+
write(str)
|
71
|
+
end
|
72
|
+
|
73
|
+
# === Signed
|
74
|
+
|
75
|
+
def write_int32_native(val)
|
76
|
+
pw(val, 'l')
|
77
|
+
end
|
78
|
+
|
79
|
+
def write_int32_little(val)
|
80
|
+
pw(val, 'V')
|
81
|
+
end
|
82
|
+
|
83
|
+
def write_int32_network(val)
|
84
|
+
pw(val, 'N')
|
85
|
+
end
|
86
|
+
|
87
|
+
# add some short-cut functions
|
88
|
+
%w(word16 int16 word32 int32).each do |typ|
|
89
|
+
alias_method "write_#{typ}_big", "write_#{typ}_network"
|
90
|
+
end
|
91
|
+
|
92
|
+
# == Other methods
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# shortcut for pack and write
|
97
|
+
def pw(val, template)
|
98
|
+
write([val].pack(template))
|
99
|
+
end
|
100
|
+
end
|
data/lib/buffer.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'binary_writer'
|
2
|
+
require 'binary_reader'
|
3
|
+
|
4
|
+
# Fixed size buffer.
|
5
|
+
class Buffer
|
6
|
+
|
7
|
+
class Error < RuntimeError; end
|
8
|
+
class EOF < Error; end
|
9
|
+
|
10
|
+
def self.from_string(str)
|
11
|
+
new(str)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.of_size(size)
|
15
|
+
raise ArgumentError if size < 0
|
16
|
+
new('#' * size)
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(content)
|
20
|
+
@size = content.size
|
21
|
+
@content = content
|
22
|
+
@position = 0
|
23
|
+
end
|
24
|
+
|
25
|
+
def size
|
26
|
+
@size
|
27
|
+
end
|
28
|
+
|
29
|
+
def position
|
30
|
+
@position
|
31
|
+
end
|
32
|
+
|
33
|
+
def position=(new_pos)
|
34
|
+
raise ArgumentError if new_pos < 0 or new_pos > @size
|
35
|
+
@position = new_pos
|
36
|
+
end
|
37
|
+
|
38
|
+
def at_end?
|
39
|
+
@position == @size
|
40
|
+
end
|
41
|
+
|
42
|
+
def content
|
43
|
+
@content
|
44
|
+
end
|
45
|
+
|
46
|
+
def read(n)
|
47
|
+
raise EOF, 'cannot read beyond the end of buffer' if @position + n > @size
|
48
|
+
str = @content[@position, n]
|
49
|
+
@position += n
|
50
|
+
str
|
51
|
+
end
|
52
|
+
|
53
|
+
def write(str)
|
54
|
+
sz = str.size
|
55
|
+
raise EOF, 'cannot write beyond the end of buffer' if @position + sz > @size
|
56
|
+
@content[@position, sz] = str
|
57
|
+
@position += sz
|
58
|
+
self
|
59
|
+
end
|
60
|
+
|
61
|
+
def copy_from_stream(stream, n)
|
62
|
+
raise ArgumentError if n < 0
|
63
|
+
while n > 0
|
64
|
+
str = stream.read(n)
|
65
|
+
write(str)
|
66
|
+
n -= str.size
|
67
|
+
end
|
68
|
+
raise if n < 0
|
69
|
+
end
|
70
|
+
|
71
|
+
NUL = "\000"
|
72
|
+
|
73
|
+
def write_cstring(cstr)
|
74
|
+
raise ArgumentError, "Invalid Ruby/cstring" if cstr.include?(NUL)
|
75
|
+
write(cstr)
|
76
|
+
write(NUL)
|
77
|
+
end
|
78
|
+
|
79
|
+
# returns a Ruby string without the trailing NUL character
|
80
|
+
def read_cstring
|
81
|
+
nul_pos = @content.index(NUL, @position)
|
82
|
+
raise Error, "no cstring found!" unless nul_pos
|
83
|
+
|
84
|
+
sz = nul_pos - @position
|
85
|
+
str = @content[@position, sz]
|
86
|
+
@position += sz + 1
|
87
|
+
return str
|
88
|
+
end
|
89
|
+
|
90
|
+
# read till the end of the buffer
|
91
|
+
def read_rest
|
92
|
+
read(self.size-@position)
|
93
|
+
end
|
94
|
+
|
95
|
+
include BinaryWriterMixin
|
96
|
+
include BinaryReaderMixin
|
97
|
+
end
|