postgres-pr-opt 0.6.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -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