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.
@@ -0,0 +1,174 @@
1
+ # This is a compatibility layer for using the pure Ruby postgres-pr instead of
2
+ # the C interface of postgres.
3
+
4
+ require 'rexml/syncenumerator'
5
+ require 'postgres-pr/connection'
6
+
7
+ class PGconn
8
+ PQTRANS_IDLE = 0 #(connection idle)
9
+ PQTRANS_INTRANS = 2 #(idle, within transaction block)
10
+ PQTRANS_INERROR = 3 #(idle, within failed transaction)
11
+ PQTRANS_UNKNOWN = 4 #(cannot determine status)
12
+
13
+ class << self
14
+ alias connect new
15
+ end
16
+
17
+ def initialize(host, port, options, tty, database, user, auth)
18
+ uri =
19
+ if host.nil?
20
+ nil
21
+ elsif host[0] != ?/
22
+ "tcp://#{ host }:#{ port }"
23
+ else
24
+ "unix:#{ host }/.s.PGSQL.#{ port }"
25
+ end
26
+ @host = host
27
+ @db = database
28
+ @user = user
29
+ @conn = PostgresPR::Connection.new(database, user, auth, uri)
30
+ end
31
+
32
+ def close
33
+ @conn.close
34
+ end
35
+
36
+ attr_reader :host, :db, :user
37
+
38
+ def query(sql)
39
+ PGresult.new(@conn.query(sql))
40
+ end
41
+
42
+ alias exec query
43
+
44
+ def transaction_status
45
+ @conn.transaction_status
46
+ end
47
+
48
+ def self.escape(str)
49
+ str.gsub("'","''").gsub("\\", "\\\\\\\\")
50
+ end
51
+
52
+ def escape(str)
53
+ self.class.escape(str)
54
+ end
55
+
56
+ def notice_processor
57
+ @conn.notice_processor
58
+ end
59
+
60
+ def notice_processor=(np)
61
+ @conn.notice_processor = np
62
+ end
63
+
64
+ def self.quote_ident(name)
65
+ %("#{name}")
66
+ end
67
+
68
+ end
69
+
70
+ class PGresult
71
+ include Enumerable
72
+
73
+ EMPTY_QUERY = 0
74
+ COMMAND_OK = 1
75
+ TUPLES_OK = 2
76
+ COPY_OUT = 3
77
+ COPY_IN = 4
78
+ BAD_RESPONSE = 5
79
+ NONFATAL_ERROR = 6
80
+ FATAL_ERROR = 7
81
+
82
+ def each(&block)
83
+ @result.each(&block)
84
+ end
85
+
86
+ def [](index)
87
+ @result[index]
88
+ end
89
+
90
+ def initialize(res)
91
+ @res = res
92
+ @fields = @res.fields.map {|f| f.name}
93
+ @result = []
94
+ @res.rows.each do |row|
95
+ @result << REXML::SyncEnumerator.new(fields, row).map {|name, value| [name, value]}
96
+ end
97
+ end
98
+
99
+ # TODO: status, getlength, cmdstatus
100
+
101
+ attr_reader :result, :fields
102
+
103
+ def num_tuples
104
+ @result.size
105
+ end
106
+
107
+ alias :ntuples :num_tuples
108
+
109
+ def num_fields
110
+ @fields.size
111
+ end
112
+
113
+ alias :nfields :num_fields
114
+
115
+ def fieldname(index)
116
+ @fields[index]
117
+ end
118
+
119
+ def fieldnum(name)
120
+ @fields.index(name)
121
+ end
122
+
123
+ def type(index)
124
+ # TODO: correct?
125
+ @res.fields[index].type_oid
126
+ end
127
+
128
+ alias :ftype :type
129
+
130
+ def size(index)
131
+ raise
132
+ # TODO: correct?
133
+ @res.fields[index].typlen
134
+ end
135
+
136
+ def getvalue(tup_num, field_num)
137
+ @result[tup_num][field_num]
138
+ end
139
+
140
+ def status
141
+ if num_tuples > 0
142
+ TUPLES_OK
143
+ else
144
+ COMMAND_OK
145
+ end
146
+ end
147
+
148
+ def cmdstatus
149
+ @res.cmd_tag || ''
150
+ end
151
+
152
+ # free the result set
153
+ def clear
154
+ @res = @fields = @result = nil
155
+ end
156
+
157
+ # Returns the number of rows affected by the SQL command
158
+ def cmdtuples
159
+ case @res.cmd_tag
160
+ when nil
161
+ return nil
162
+ when /^INSERT\s+(\d+)\s+(\d+)$/, /^(DELETE|UPDATE|MOVE|FETCH)\s+(\d+)$/
163
+ $2.to_i
164
+ else
165
+ nil
166
+ end
167
+ end
168
+
169
+ alias :cmd_tuples :cmdtuples
170
+
171
+ end
172
+
173
+ class PGError < Exception
174
+ end
@@ -0,0 +1,170 @@
1
+ # This is a compatibility layer for using the pure Ruby postgres-pr instead of
2
+ # the C interface of postgres.
3
+
4
+ require 'postgres-pr/connection'
5
+
6
+ class PGconn
7
+ PQTRANS_IDLE = 0 #(connection idle)
8
+ PQTRANS_INTRANS = 2 #(idle, within transaction block)
9
+ PQTRANS_INERROR = 3 #(idle, within failed transaction)
10
+ PQTRANS_UNKNOWN = 4 #(cannot determine status)
11
+
12
+ class << self
13
+ alias connect new
14
+ end
15
+
16
+ def initialize(host, port, options, tty, database, user, auth)
17
+ uri =
18
+ if host.nil?
19
+ nil
20
+ elsif host[0] != ?/
21
+ "tcp://#{ host }:#{ port }"
22
+ else
23
+ "unix:#{ host }/.s.PGSQL.#{ port }"
24
+ end
25
+ @host = host
26
+ @db = database
27
+ @user = user
28
+ @conn = PostgresPR::Connection.new(database, user, auth, uri)
29
+ end
30
+
31
+ def close
32
+ @conn.close
33
+ end
34
+
35
+ attr_reader :host, :db, :user
36
+
37
+ def query(sql)
38
+ PGresult.new(@conn.query(sql))
39
+ end
40
+
41
+ alias exec query
42
+
43
+ def transaction_status
44
+ @conn.transaction_status
45
+ end
46
+
47
+ def self.escape(str)
48
+ str.gsub("'","''").gsub("\\", "\\\\\\\\")
49
+ end
50
+
51
+ def escape(str)
52
+ self.class.escape(str)
53
+ end
54
+
55
+ def notice_processor
56
+ @conn.notice_processor
57
+ end
58
+
59
+ def notice_processor=(np)
60
+ @conn.notice_processor = np
61
+ end
62
+
63
+ def self.quote_ident(name)
64
+ %("#{name}")
65
+ end
66
+
67
+ end
68
+
69
+ class PGresult
70
+ include Enumerable
71
+
72
+ EMPTY_QUERY = 0
73
+ COMMAND_OK = 1
74
+ TUPLES_OK = 2
75
+ COPY_OUT = 3
76
+ COPY_IN = 4
77
+ BAD_RESPONSE = 5
78
+ NONFATAL_ERROR = 6
79
+ FATAL_ERROR = 7
80
+
81
+ def each(&block)
82
+ @result.each(&block)
83
+ end
84
+
85
+ def [](index)
86
+ @result[index]
87
+ end
88
+
89
+ def initialize(res)
90
+ @res = res
91
+ @fields = @res.fields.map {|f| f.name}
92
+ @result = @res.rows
93
+ end
94
+
95
+ # TODO: status, getlength, cmdstatus
96
+
97
+ attr_reader :result, :fields
98
+
99
+ def num_tuples
100
+ @result.size
101
+ end
102
+
103
+ alias :ntuples :num_tuples
104
+
105
+ def num_fields
106
+ @fields.size
107
+ end
108
+
109
+ alias :nfields :num_fields
110
+
111
+ def fieldname(index)
112
+ @fields[index]
113
+ end
114
+
115
+ def fieldnum(name)
116
+ @fields.index(name)
117
+ end
118
+
119
+ def type(index)
120
+ # TODO: correct?
121
+ @res.fields[index].type_oid
122
+ end
123
+
124
+ alias :ftype :type
125
+
126
+ def size(index)
127
+ raise
128
+ # TODO: correct?
129
+ @res.fields[index].typlen
130
+ end
131
+
132
+ def getvalue(tup_num, field_num)
133
+ @result[tup_num][field_num]
134
+ end
135
+
136
+ def status
137
+ if num_tuples > 0
138
+ TUPLES_OK
139
+ else
140
+ COMMAND_OK
141
+ end
142
+ end
143
+
144
+ def cmdstatus
145
+ @res.cmd_tag || ''
146
+ end
147
+
148
+ # free the result set
149
+ def clear
150
+ @res = @fields = @result = nil
151
+ end
152
+
153
+ # Returns the number of rows affected by the SQL command
154
+ def cmdtuples
155
+ case @res.cmd_tag
156
+ when nil
157
+ return nil
158
+ when /^INSERT\s+(\d+)\s+(\d+)$/, /^(DELETE|UPDATE|MOVE|FETCH)\s+(\d+)$/
159
+ $2.to_i
160
+ else
161
+ nil
162
+ end
163
+ end
164
+
165
+ alias :cmd_tuples :cmdtuples
166
+
167
+ end
168
+
169
+ class PGError < Exception
170
+ end
@@ -0,0 +1,18 @@
1
+ require 'test/unit'
2
+ require 'conv'
3
+ require 'array'
4
+ require 'bytea'
5
+
6
+ class TC_Conversion < Test::Unit::TestCase
7
+ def test_decode_array
8
+ assert_equal ["abcdef ", "hallo", ["1", "2"]], decode_array("{ abcdef , hallo, { 1, 2} }")
9
+ assert_equal [""], decode_array("{ }") # TODO: Correct?
10
+ assert_equal [], decode_array("{}")
11
+ assert_equal ["hallo", ""], decode_array("{hallo,}")
12
+ end
13
+
14
+ def test_bytea
15
+ end
16
+
17
+ include Postgres::Conversion
18
+ end
@@ -0,0 +1,46 @@
1
+ require 'strscan'
2
+
3
+ module Postgres::Conversion
4
+
5
+ def decode_array(str, delim=',', &conv_proc)
6
+ delim = Regexp.escape(delim)
7
+ buf = StringScanner.new(str)
8
+ return parse_arr(buf, delim, &conv_proc)
9
+ ensure
10
+ raise ConversionError, "end of string expected (#{buf.rest})" unless buf.empty?
11
+ end
12
+
13
+ private
14
+
15
+ def parse_arr(buf, delim, &conv_proc)
16
+ # skip whitespace
17
+ buf.skip(/\s*/)
18
+
19
+ raise ConversionError, "'{' expected" unless buf.get_byte == '{'
20
+
21
+ elems = []
22
+ unless buf.scan(/\}/) # array is not empty
23
+ loop do
24
+ # skip whitespace
25
+ buf.skip(/\s+/)
26
+
27
+ elems <<
28
+ if buf.check(/\{/)
29
+ parse_arr(buf, delim, &conv_proc)
30
+ else
31
+ e = buf.scan(/("((\\.)|[^"])*"|\\.|[^\}#{ delim }])*/) || raise(ConversionError)
32
+ if conv_proc then conv_proc.call(e) else e end
33
+ end
34
+
35
+ break if buf.scan(/\}/)
36
+ break unless buf.scan(/#{ delim }/)
37
+ end
38
+ end
39
+
40
+ # skip whitespace
41
+ buf.skip(/\s*/)
42
+
43
+ elems
44
+ end
45
+
46
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: US-ASCII
2
+
3
+ module Postgres::Conversion
4
+
5
+ #
6
+ # Encodes a string as bytea value.
7
+ #
8
+ # for encoding rules see:
9
+ # http://www.postgresql.org/docs/7.4/static/datatype-binary.html
10
+ #
11
+
12
+ def encode_bytea(str)
13
+ str.gsub(/[\000-\037\047\134\177-\377]/) {|b| "\\#{ b[0].to_s(8).rjust(3, '0') }" }
14
+ end
15
+
16
+ #
17
+ # Decodes a bytea encoded string.
18
+ #
19
+ # for decoding rules see:
20
+ # http://www.postgresql.org/docs/7.4/static/datatype-binary.html
21
+ #
22
+ def decode_bytea(str)
23
+ str.gsub(/\\(\\|'|[0-3][0-7][0-7])/) {|s|
24
+ if s.size == 2 then s[1,1] else s[1,3].oct.chr end
25
+ }
26
+ end
27
+
28
+ end
@@ -0,0 +1,5 @@
1
+ module Postgres
2
+ module Conversion
3
+ class ConversionError < Exception; end
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module PostgresPR
2
+ Version = "0.7.0"
3
+ end