postgres-pr-opt 0.6.9

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,225 @@
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
+ require 'postgres-pr/typeconv/conv'
7
+ require 'postgres-pr/typeconv/bytea'
8
+
9
+ class PGconn
10
+ extend Postgres::Conversion
11
+ include Postgres::Conversion
12
+ PQTRANS_IDLE = 0 #(connection idle)
13
+ PQTRANS_INTRANS = 2 #(idle, within transaction block)
14
+ PQTRANS_INERROR = 3 #(idle, within failed transaction)
15
+ PQTRANS_UNKNOWN = 4 #(cannot determine status)
16
+
17
+ class << self
18
+ alias connect new
19
+ end
20
+
21
+ def initialize(host, port, options, tty, database, user, auth)
22
+ uri =
23
+ if host.nil?
24
+ nil
25
+ elsif host[0] != ?/
26
+ "tcp://#{ host }:#{ port }"
27
+ else
28
+ "unix:#{ host }/.s.PGSQL.#{ port }"
29
+ end
30
+ @host = host
31
+ @db = database
32
+ @user = user
33
+ @conn = PostgresPR::Connection.new(database, user, auth, uri)
34
+ end
35
+
36
+ def close
37
+ @conn.close
38
+ end
39
+
40
+ alias finish close
41
+
42
+ attr_reader :host, :db, :user
43
+
44
+ def query(sql)
45
+ PGresult.new(@conn.query(sql))
46
+ end
47
+
48
+ alias exec query
49
+ alias async_exec exec
50
+
51
+ def transaction_status
52
+ @conn.transaction_status
53
+ end
54
+
55
+ def self.escape(str)
56
+ str.gsub("'","''").gsub("\\", "\\\\\\\\")
57
+ end
58
+
59
+ def escape(str)
60
+ self.class.escape(str)
61
+ end
62
+
63
+ if RUBY_VERSION < '1.9'
64
+ def escape_string(str)
65
+ case @conn.params['client_encoding']
66
+ when /ASCII/, /ISO/, /KOI8/, /WIN/, /LATIN/
67
+ def self.escape_string(str)
68
+ str.gsub("'", "''").gsub("\\", "\\\\\\\\")
69
+ end
70
+ else
71
+ def self.escape_string(str)
72
+ str.gsub(/'/u, "''").gsub(/\\/u, "\\\\\\\\")
73
+ end
74
+ end
75
+ escape_string(str)
76
+ end
77
+ else
78
+ def escape_string(str)
79
+ str.gsub("'", "''").gsub("\\", "\\\\\\\\")
80
+ end
81
+ end
82
+
83
+ def notice_processor
84
+ @conn.notice_processor
85
+ end
86
+
87
+ def notice_processor=(np)
88
+ @conn.notice_processor = np
89
+ end
90
+
91
+ def self.quote_ident(name)
92
+ %("#{name}")
93
+ end
94
+
95
+ end
96
+
97
+ class PGresult
98
+ include Enumerable
99
+
100
+ EMPTY_QUERY = 0
101
+ COMMAND_OK = 1
102
+ TUPLES_OK = 2
103
+ COPY_OUT = 3
104
+ COPY_IN = 4
105
+ BAD_RESPONSE = 5
106
+ NONFATAL_ERROR = 6
107
+ FATAL_ERROR = 7
108
+
109
+ def each(&block)
110
+ @result.each(&block)
111
+ end
112
+
113
+ def [](index)
114
+ @result[index]
115
+ end
116
+
117
+ def initialize(res)
118
+ @res = res
119
+ @fields = @res.fields.map {|f| f.name}
120
+ @result = []
121
+ @res.rows.each do |row|
122
+ h = {}
123
+ @fields.zip(row){|field, value| h[field] = value}
124
+ @result << h
125
+ end
126
+ end
127
+
128
+ # TODO: status, cmdstatus
129
+
130
+ def values
131
+ @res.rows
132
+ end
133
+
134
+ def column_values(i)
135
+ raise IndexError, "no column #{i} in result" unless i < @fields.size
136
+ @res.rows.map{|row| row[i]}
137
+ end
138
+
139
+ def field_values(field)
140
+ raise IndexError, "no such field '#{field}' in result" unless @fields.include?(field)
141
+ @result.map{|row| row[field]}
142
+ end
143
+
144
+ attr_reader :result, :fields
145
+
146
+ def num_tuples
147
+ @result.size
148
+ end
149
+
150
+ alias :ntuples :num_tuples
151
+
152
+ def num_fields
153
+ @fields.size
154
+ end
155
+
156
+ alias :nfields :num_fields
157
+
158
+ def fname(index)
159
+ @fields[index]
160
+ end
161
+
162
+ alias fieldname fname
163
+
164
+ def fnum(name)
165
+ @fields.index(name)
166
+ end
167
+
168
+ alias fieldnum fnum
169
+
170
+ def type(index)
171
+ # TODO: correct?
172
+ @res.fields[index].type_oid
173
+ end
174
+
175
+ alias :ftype :type
176
+
177
+ def size(index)
178
+ raise
179
+ # TODO: correct?
180
+ @res.fields[index].typlen
181
+ end
182
+
183
+ def getvalue(tup_num, field_num)
184
+ @res.rows[tup_num][field_num]
185
+ end
186
+
187
+ def getlength(tup_num, field_num)
188
+ @res.rows[typ_num][field_num].length
189
+ end
190
+
191
+ def status
192
+ if num_tuples > 0
193
+ TUPLES_OK
194
+ else
195
+ COMMAND_OK
196
+ end
197
+ end
198
+
199
+ def cmdstatus
200
+ @res.cmd_tag || ''
201
+ end
202
+
203
+ # free the result set
204
+ def clear
205
+ @res = @fields = @result = nil
206
+ end
207
+
208
+ # Returns the number of rows affected by the SQL command
209
+ def cmdtuples
210
+ case @res.cmd_tag
211
+ when nil
212
+ return nil
213
+ when /^INSERT\s+(\d+)\s+(\d+)$/, /^(DELETE|UPDATE|MOVE|FETCH)\s+(\d+)$/
214
+ $2.to_i
215
+ else
216
+ nil
217
+ end
218
+ end
219
+
220
+ alias :cmd_tuples :cmdtuples
221
+
222
+ end
223
+
224
+ class PGError < Exception
225
+ end
@@ -0,0 +1,169 @@
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 PGError, 'size not implemented'
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
+ PGError = PostgresPR::PGError
@@ -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