google-cloud-spanner 1.6.4 → 1.7.1

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.
@@ -34,7 +34,7 @@ module Google
34
34
  #
35
35
  # db = spanner.client "my-instance", "my-database"
36
36
  #
37
- # results = db.execute "SELECT * FROM users"
37
+ # results = db.execute_query "SELECT * FROM users"
38
38
  #
39
39
  # results.rows.each do |row|
40
40
  # puts "User #{row[:id]} is #{row[:name]}"
@@ -33,7 +33,7 @@ module Google
33
33
  #
34
34
  # db = spanner.client "my-instance", "my-database"
35
35
  #
36
- # results = db.execute "SELECT * FROM users"
36
+ # results = db.execute_query "SELECT * FROM users"
37
37
  #
38
38
  # results.fields.pairs.each do |name, type|
39
39
  # puts "Column #{name} is type #{type}"
@@ -52,11 +52,15 @@ module Google
52
52
  def initialize; end
53
53
 
54
54
  ##
55
- # Whether the partition was created for an execute/query operation.
55
+ # Whether the partition was created for an execute_query/query
56
+ # operation.
56
57
  # @return [Boolean]
57
- def execute?
58
+ def execute_query?
58
59
  !@execute.nil?
59
60
  end
61
+ alias execute? execute_query?
62
+ alias execute_sql? execute_query?
63
+ alias query? execute_query?
60
64
 
61
65
  ##
62
66
  # Whether the partition was created for a read operation.
@@ -67,7 +71,8 @@ module Google
67
71
 
68
72
  ##
69
73
  # @private
70
- # Whether the partition does not have an execute or read operation.
74
+ # Whether the partition does not have an execute_query or read
75
+ # operation.
71
76
  # @return [Boolean]
72
77
  def empty?
73
78
  @execute.nil? && @read.nil?
@@ -84,7 +89,7 @@ module Google
84
89
  def to_h
85
90
  {}.tap do |h|
86
91
  h[:execute] = Base64.strict_encode64(@execute.to_proto) if @execute
87
- h[:read] = Base64.strict_encode64(@read.to_proto) if @read
92
+ h[:read] = Base64.strict_encode64(@read.to_proto) if @read
88
93
  end
89
94
  end
90
95
 
@@ -163,12 +168,14 @@ module Google
163
168
  def self.load data
164
169
  data = JSON.parse data, symbolize_names: true unless data.is_a? Hash
165
170
 
166
- # TODO: raise if hash[:execute].nil? && hash[:read].nil?
171
+ # TODO: raise if hash[:execute_query].nil? && hash[:read].nil?
167
172
  new.tap do |p|
168
173
  if data[:execute]
169
- execute_grpc = Google::Spanner::V1::ExecuteSqlRequest.decode \
170
- Base64.decode64(data[:execute])
171
- p.instance_variable_set :@execute, execute_grpc
174
+ execute_sql_grpc = \
175
+ Google::Spanner::V1::ExecuteSqlRequest.decode(
176
+ Base64.decode64(data[:execute])
177
+ )
178
+ p.instance_variable_set :@execute, execute_sql_grpc
172
179
  end
173
180
  if data[:read]
174
181
  read_grpc = Google::Spanner::V1::ReadRequest.decode \
@@ -189,7 +196,7 @@ module Google
189
196
  ##
190
197
  # @private New Partition from a Google::Spanner::V1::ExecuteSqlRequest
191
198
  # object.
192
- def self.from_execute_grpc grpc
199
+ def self.from_execute_sql_grpc grpc
193
200
  new.tap do |p|
194
201
  p.instance_variable_set :@execute, grpc
195
202
  end
@@ -58,7 +58,7 @@ module Google
58
58
  # db = spanner.client "my-instance", "my-database"
59
59
  #
60
60
  # db.transaction do |tx|
61
- # results = tx.execute "SELECT * FROM users"
61
+ # results = tx.execute_query "SELECT * FROM users"
62
62
  #
63
63
  # results.rows.each do |row|
64
64
  # puts "User #{row[:id]} is #{row[:name]}"
@@ -463,7 +463,7 @@ module Google
463
463
  # db = spanner.client "my-instance", "my-database"
464
464
  #
465
465
  # db.transaction do |tx|
466
- # results = tx.execute "SELECT * FROM users"
466
+ # results = tx.execute_query "SELECT * FROM users"
467
467
  #
468
468
  # results.rows.each do |row|
469
469
  # puts "User #{row[:id]} is #{row[:name]}"
@@ -24,7 +24,7 @@ module Google
24
24
  #
25
25
  # Represents the result set from an operation returning data.
26
26
  #
27
- # See {Google::Cloud::Spanner::Client#execute} and
27
+ # See {Google::Cloud::Spanner::Client#execute_query} and
28
28
  # {Google::Cloud::Spanner::Client#read}.
29
29
  #
30
30
  # @example
@@ -34,7 +34,7 @@ module Google
34
34
  #
35
35
  # db = spanner.client "my-instance", "my-database"
36
36
  #
37
- # results = db.execute "SELECT * FROM users"
37
+ # results = db.execute_query "SELECT * FROM users"
38
38
  #
39
39
  # results.fields.pairs.each do |name, type|
40
40
  # puts "Column #{name} is type #{type}"
@@ -63,7 +63,7 @@ module Google
63
63
  #
64
64
  # db = spanner.client "my-instance", "my-database"
65
65
  #
66
- # results = db.execute "SELECT * FROM users"
66
+ # results = db.execute_query "SELECT * FROM users"
67
67
  #
68
68
  # results.fields.pairs.each do |name, type|
69
69
  # puts "Column #{name} is type #{type}"
@@ -88,7 +88,7 @@ module Google
88
88
  #
89
89
  # db = spanner.client "my-instance", "my-database"
90
90
  #
91
- # results = db.execute "SELECT * FROM users"
91
+ # results = db.execute_query "SELECT * FROM users"
92
92
  #
93
93
  # results.rows.each do |row|
94
94
  # puts "User #{row[:id]} is #{row[:name]}"
@@ -102,11 +102,6 @@ module Google
102
102
  end
103
103
 
104
104
  fields = @metadata.row_type.fields
105
- if fields.count.zero?
106
- @closed = true
107
- return []
108
- end
109
-
110
105
  values = []
111
106
  buffered_responses = []
112
107
  buffer_upper_bound = 10
@@ -130,16 +125,18 @@ module Google
130
125
  # This can set the resume_token to nil
131
126
  resume_token = grpc.resume_token
132
127
 
133
- buffered_responses.each do |resp|
134
- if chunked_value
135
- resp.values.unshift merge(chunked_value, resp.values.shift)
136
- chunked_value = nil
137
- end
138
- to_iterate = values + Array(resp.values)
139
- chunked_value = to_iterate.pop if resp.chunked_value
140
- values = to_iterate.pop(to_iterate.count % fields.count)
141
- to_iterate.each_slice(fields.count) do |slice|
142
- yield Data.from_grpc(slice, fields)
128
+ if fields.count > 0
129
+ buffered_responses.each do |resp|
130
+ if chunked_value
131
+ resp.values.unshift merge(chunked_value, resp.values.shift)
132
+ chunked_value = nil
133
+ end
134
+ to_iterate = values + Array(resp.values)
135
+ chunked_value = to_iterate.pop if resp.chunked_value
136
+ values = to_iterate.pop(to_iterate.count % fields.count)
137
+ to_iterate.each_slice(fields.count) do |slice|
138
+ yield Data.from_grpc(slice, fields)
139
+ end
143
140
  end
144
141
  end
145
142
 
@@ -154,10 +151,10 @@ module Google
154
151
  end
155
152
 
156
153
  # Resume the stream from the last known resume_token
157
- if @execute_options
158
- @enum = @service.streaming_execute_sql \
154
+ if @execute_query_options
155
+ @enum = @service.execute_streaming_sql \
159
156
  @session_path, @sql,
160
- @execute_options.merge(resume_token: resume_token)
157
+ @execute_query_options.merge(resume_token: resume_token)
161
158
  else
162
159
  @enum = @service.streaming_read_table \
163
160
  @session_path, @table, @columns,
@@ -174,21 +171,23 @@ module Google
174
171
  end
175
172
 
176
173
  # clear out any remaining values left over
177
- buffered_responses.each do |resp|
178
- if chunked_value
179
- resp.values.unshift merge(chunked_value, resp.values.shift)
180
- chunked_value = nil
174
+ if fields.count > 0
175
+ buffered_responses.each do |resp|
176
+ if chunked_value
177
+ resp.values.unshift merge(chunked_value, resp.values.shift)
178
+ chunked_value = nil
179
+ end
180
+ to_iterate = values + Array(resp.values)
181
+ chunked_value = to_iterate.pop if resp.chunked_value
182
+ values = to_iterate.pop(to_iterate.count % fields.count)
183
+ to_iterate.each_slice(fields.count) do |slice|
184
+ yield Data.from_grpc(slice, fields)
185
+ end
181
186
  end
182
- to_iterate = values + Array(resp.values)
183
- chunked_value = to_iterate.pop if resp.chunked_value
184
- values = to_iterate.pop(to_iterate.count % fields.count)
185
- to_iterate.each_slice(fields.count) do |slice|
187
+ values.each_slice(fields.count) do |slice|
186
188
  yield Data.from_grpc(slice, fields)
187
189
  end
188
190
  end
189
- values.each_slice(fields.count) do |slice|
190
- yield Data.from_grpc(slice, fields)
191
- end
192
191
 
193
192
  # If we get this far then we can release the session
194
193
  @closed = true
@@ -197,6 +196,33 @@ module Google
197
196
 
198
197
  # rubocop:enable all
199
198
 
199
+ ##
200
+ # @private
201
+ # Get row count from stats. This will be the exact row count for DML
202
+ # statements, and the lower bound row count for PDML statements.
203
+ def row_count
204
+ return @stats.row_count_lower_bound if row_count_lower_bound?
205
+ return @stats.row_count_exact if row_count_exact?
206
+ nil
207
+ end
208
+
209
+ ##
210
+ # @private
211
+ # Whether the row count is the lower bound row count for PDML
212
+ # statements.
213
+ def row_count_lower_bound?
214
+ return nil if @stats.nil?
215
+ @stats.row_count == :row_count_lower_bound
216
+ end
217
+
218
+ ##
219
+ # @private
220
+ # Whether the row count is the exact row count for DML statements.
221
+ def row_count_exact?
222
+ return nil if @stats.nil?
223
+ @stats.row_count == :row_count_exact
224
+ end
225
+
200
226
  # @private
201
227
  def self.from_enum enum, service
202
228
  grpc = enum.peek
@@ -211,16 +237,21 @@ module Google
211
237
  end
212
238
 
213
239
  # @private
214
- def self.execute service, session_path, sql, params: nil, types: nil,
215
- transaction: nil, partition_token: nil
216
- execute_options = { transaction: transaction, params: params,
217
- types: types, partition_token: partition_token }
218
- enum = service.streaming_execute_sql session_path, sql,
219
- execute_options
240
+
241
+ def self.execute_query service, session_path, sql, params: nil,
242
+ types: nil, transaction: nil,
243
+ partition_token: nil, seqno: nil
244
+ execute_query_options = {
245
+ transaction: transaction, params: params, types: types,
246
+ partition_token: partition_token, seqno: seqno
247
+ }
248
+ enum = service.execute_streaming_sql session_path, sql,
249
+ execute_query_options
220
250
  from_enum(enum, service).tap do |results|
221
- results.instance_variable_set :@session_path, session_path
222
- results.instance_variable_set :@sql, sql
223
- results.instance_variable_set :@execute_options, execute_options
251
+ results.instance_variable_set :@session_path, session_path
252
+ results.instance_variable_set :@sql, sql
253
+ results.instance_variable_set :@execute_query_options,
254
+ execute_query_options
224
255
  end
225
256
  end
226
257
 
@@ -257,16 +257,19 @@ module Google
257
257
  end
258
258
  end
259
259
 
260
- def streaming_execute_sql session_name, sql, transaction: nil,
260
+ def execute_streaming_sql session_name, sql, transaction: nil,
261
261
  params: nil, types: nil, resume_token: nil,
262
- partition_token: nil
262
+ partition_token: nil, seqno: nil
263
263
  opts = default_options_from_session session_name
264
264
  execute do
265
265
  service.execute_streaming_sql \
266
- session_name, sql, transaction: transaction, params: params,
266
+ session_name, sql, transaction: transaction,
267
+ params: params,
267
268
  param_types: types,
268
269
  resume_token: resume_token,
269
- partition_token: partition_token, options: opts
270
+ partition_token: partition_token,
271
+ seqno: seqno,
272
+ options: opts
270
273
  end
271
274
  end
272
275
 
@@ -367,6 +370,17 @@ module Google
367
370
  end
368
371
  end
369
372
 
373
+ def create_pdml session_name
374
+ tx_opts = Google::Spanner::V1::TransactionOptions.new(
375
+ partitioned_dml: \
376
+ Google::Spanner::V1::TransactionOptions::PartitionedDml.new
377
+ )
378
+ opts = default_options_from_session session_name
379
+ execute do
380
+ service.begin_transaction session_name, tx_opts, options: opts
381
+ end
382
+ end
383
+
370
384
  def inspect
371
385
  "#{self.class}(#{@project})"
372
386
  end
@@ -151,6 +151,8 @@ module Google
151
151
  # @param [Google::Spanner::V1::TransactionSelector] transaction The
152
152
  # transaction selector value to send. Only used for single-use
153
153
  # transactions.
154
+ # @param [Integer] seqno A per-transaction sequence number used to
155
+ # identify this request.
154
156
  #
155
157
  # @return [Google::Cloud::Spanner::Results] The results of the query
156
158
  # execution.
@@ -162,7 +164,7 @@ module Google
162
164
  #
163
165
  # db = spanner.client "my-instance", "my-database"
164
166
  #
165
- # results = db.execute "SELECT * FROM users"
167
+ # results = db.execute_query "SELECT * FROM users"
166
168
  #
167
169
  # results.rows.each do |row|
168
170
  # puts "User #{row[:id]} is #{row[:name]}"
@@ -175,8 +177,10 @@ module Google
175
177
  #
176
178
  # db = spanner.client "my-instance", "my-database"
177
179
  #
178
- # results = db.execute "SELECT * FROM users WHERE active = @active",
179
- # params: { active: true }
180
+ # results = db.execute_query(
181
+ # "SELECT * FROM users WHERE active = @active",
182
+ # params: { active: true }
183
+ # )
180
184
  #
181
185
  # results.rows.each do |row|
182
186
  # puts "User #{row[:id]} is #{row[:name]}"
@@ -191,11 +195,13 @@ module Google
191
195
  #
192
196
  # user_hash = { id: 1, name: "Charlie", active: false }
193
197
  #
194
- # results = db.execute "SELECT * FROM users WHERE " \
195
- # "ID = @user_struct.id " \
196
- # "AND name = @user_struct.name " \
197
- # "AND active = @user_struct.active",
198
- # params: { user_struct: user_hash }
198
+ # results = db.execute_query(
199
+ # "SELECT * FROM users WHERE " \
200
+ # "ID = @user_struct.id " \
201
+ # "AND name = @user_struct.name " \
202
+ # "AND active = @user_struct.active",
203
+ # params: { user_struct: user_hash }
204
+ # )
199
205
  #
200
206
  # results.rows.each do |row|
201
207
  # puts "User #{row[:id]} is #{row[:name]}"
@@ -211,12 +217,14 @@ module Google
211
217
  # user_type = db.fields id: :INT64, name: :STRING, active: :BOOL
212
218
  # user_hash = { id: 1, name: nil, active: false }
213
219
  #
214
- # results = db.execute "SELECT * FROM users WHERE " \
215
- # "ID = @user_struct.id " \
216
- # "AND name = @user_struct.name " \
217
- # "AND active = @user_struct.active",
218
- # params: { user_struct: user_hash },
219
- # types: { user_struct: user_type }
220
+ # results = db.execute_query(
221
+ # "SELECT * FROM users WHERE " \
222
+ # "ID = @user_struct.id " \
223
+ # "AND name = @user_struct.name " \
224
+ # "AND active = @user_struct.active",
225
+ # params: { user_struct: user_hash },
226
+ # types: { user_struct: user_type }
227
+ # )
220
228
  #
221
229
  # results.rows.each do |row|
222
230
  # puts "User #{row[:id]} is #{row[:name]}"
@@ -232,31 +240,35 @@ module Google
232
240
  # user_type = db.fields id: :INT64, name: :STRING, active: :BOOL
233
241
  # user_data = user_type.struct id: 1, name: nil, active: false
234
242
  #
235
- # results = db.execute "SELECT * FROM users WHERE " \
236
- # "ID = @user_struct.id " \
237
- # "AND name = @user_struct.name " \
238
- # "AND active = @user_struct.active",
239
- # params: { user_struct: user_struct }
243
+ # results = db.execute_query(
244
+ # "SELECT * FROM users WHERE " \
245
+ # "ID = @user_struct.id " \
246
+ # "AND name = @user_struct.name " \
247
+ # "AND active = @user_struct.active",
248
+ # params: { user_struct: user_struct }
249
+ # )
240
250
  #
241
251
  # results.rows.each do |row|
242
252
  # puts "User #{row[:id]} is #{row[:name]}"
243
253
  # end
244
254
  #
245
- def execute sql, params: nil, types: nil, transaction: nil,
246
- partition_token: nil
255
+ def execute_query sql, params: nil, types: nil, transaction: nil,
256
+ partition_token: nil, seqno: nil
247
257
  ensure_service!
248
258
 
249
- results = Results.execute service, path, sql,
250
- params: params, types: types,
251
- transaction: transaction,
252
- partition_token: partition_token
259
+ results = Results.execute_query service, path, sql,
260
+ params: params,
261
+ types: types,
262
+ transaction: transaction,
263
+ partition_token: partition_token,
264
+ seqno: seqno
253
265
  @last_updated_at = Time.now
254
266
  results
255
267
  end
256
268
 
257
269
  ##
258
270
  # Read rows from a database table, as a simple alternative to
259
- # {#execute}.
271
+ # {#execute_query}.
260
272
  #
261
273
  # @param [String] table The name of the table in the database to be
262
274
  # read.
@@ -612,7 +624,7 @@ module Google
612
624
  # Keeps the session alive by executing `"SELECT 1"`.
613
625
  def keepalive!
614
626
  ensure_service!
615
- execute "SELECT 1"
627
+ execute_query "SELECT 1"
616
628
  return true
617
629
  rescue Google::Cloud::NotFoundError
618
630
  labels = @grpc.labels.to_h unless @grpc.labels.to_h.empty?