presto-client 0.5.14 → 0.6.4

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.
@@ -29,7 +29,9 @@ module Presto::Client
29
29
  require 'presto/client/model_versions/0.173.rb'
30
30
  require 'presto/client/model_versions/0.178.rb'
31
31
  require 'presto/client/model_versions/0.205.rb'
32
+ require 'presto/client/model_versions/303.rb'
33
+ require 'presto/client/model_versions/316.rb'
32
34
 
33
- Models = ModelVersions::V0_205
35
+ Models = ModelVersions::V316
34
36
 
35
37
  end
@@ -16,6 +16,7 @@
16
16
  module Presto::Client
17
17
 
18
18
  require 'faraday'
19
+ require 'faraday_middleware'
19
20
  require 'presto/client/models'
20
21
  require 'presto/client/errors'
21
22
  require 'presto/client/faraday_client'
@@ -125,16 +126,13 @@ module Presto::Client
125
126
  end
126
127
 
127
128
  def close
128
- @api.cancel_leaf_stage
129
+ @api.close
129
130
  nil
130
131
  end
131
132
 
132
133
  def raise_if_failed
133
- if @api.closed?
134
+ if @api.client_aborted?
134
135
  raise PrestoClientError, "Query aborted by user"
135
- elsif @api.exception?
136
- # query is gone
137
- raise @api.exception
138
136
  elsif @api.query_failed?
139
137
  results = @api.current_results
140
138
  error = results.error
@@ -31,8 +31,7 @@ module Presto::Client
31
31
 
32
32
  @options = options
33
33
  @query = query
34
- @closed = false
35
- @exception = nil
34
+ @state = :running
36
35
  @retry_timeout = options[:retry_timeout] || 120
37
36
  if model_version = @options[:model_version]
38
37
  @models = ModelVersions.const_get("V#{model_version.gsub(".", "_")}")
@@ -76,7 +75,7 @@ module Presto::Client
76
75
 
77
76
  # TODO error handling
78
77
  if response.status != 200
79
- raise PrestoHttpError.new(response.status, "Failed to start query: #{response.body} (#{response.status})")
78
+ exception! PrestoHttpError.new(response.status, "Failed to start query: #{response.body} (#{response.status})")
80
79
  end
81
80
 
82
81
  @results_headers = response.headers
@@ -91,14 +90,20 @@ module Presto::Client
91
90
  !!@options[:debug]
92
91
  end
93
92
 
94
- def closed?
95
- @closed
93
+ def running?
94
+ @state == :running
96
95
  end
97
96
 
98
- attr_reader :exception
97
+ def client_aborted?
98
+ @state == :client_aborted
99
+ end
100
+
101
+ def client_error?
102
+ @state == :client_error
103
+ end
99
104
 
100
- def exception?
101
- @exception
105
+ def finished?
106
+ @state == :finished
102
107
  end
103
108
 
104
109
  def query_failed?
@@ -106,7 +111,7 @@ module Presto::Client
106
111
  end
107
112
 
108
113
  def query_succeeded?
109
- @results.error == nil && !@exception && !@closed
114
+ @results.error == nil && finished?
110
115
  end
111
116
 
112
117
  def current_results
@@ -117,16 +122,29 @@ module Presto::Client
117
122
  @results_headers
118
123
  end
119
124
 
125
+ def query_id
126
+ @results.id
127
+ end
128
+
120
129
  def has_next?
121
130
  !!@results.next_uri
122
131
  end
123
132
 
133
+ def exception!(e)
134
+ @state = :client_error
135
+ raise e
136
+ end
137
+
124
138
  def advance
125
- if closed? || !has_next?
139
+ return false unless running?
140
+
141
+ unless has_next?
142
+ @state = :finished
126
143
  return false
127
144
  end
128
145
 
129
146
  uri = @results.next_uri
147
+
130
148
  response = faraday_get_with_retry(uri)
131
149
  @results_headers = response.headers
132
150
  @results = decode_model(uri, parse_body(response), @models::QueryResults)
@@ -150,8 +168,7 @@ module Presto::Client
150
168
  if body.size > 1024 + 3
151
169
  body = "#{body[0, 1024]}..."
152
170
  end
153
- @exception = PrestoHttpError.new(500, "Presto API returned unexpected structure at #{uri}. Expected #{body_class} but got #{body}: #{e}")
154
- raise @exception
171
+ exception! PrestoHttpError.new(500, "Presto API returned unexpected structure at #{uri}. Expected #{body_class} but got #{body}: #{e}")
155
172
  end
156
173
  end
157
174
 
@@ -166,8 +183,7 @@ module Presto::Client
166
183
  JSON.parse(response.body, opts = JSON_OPTIONS)
167
184
  end
168
185
  rescue => e
169
- @exception = PrestoHttpError.new(500, "Presto API returned unexpected data format. #{e}")
170
- raise @exception
186
+ exception! PrestoHttpError.new(500, "Presto API returned unexpected data format. #{e}")
171
187
  end
172
188
  end
173
189
 
@@ -184,8 +200,7 @@ module Presto::Client
184
200
  # temporally error to retry
185
201
  response = nil
186
202
  rescue => e
187
- @exception = e
188
- raise @exception
203
+ exception! e
189
204
  end
190
205
 
191
206
  if response
@@ -195,8 +210,7 @@ module Presto::Client
195
210
 
196
211
  if response.status != 503 # retry only if 503 Service Unavailable
197
212
  # deterministic error
198
- @exception = PrestoHttpError.new(response.status, "Presto API error at #{uri} returned #{response.status}: #{response.body}")
199
- raise @exception
213
+ exception! PrestoHttpError.new(response.status, "Presto API error at #{uri} returned #{response.status}: #{response.body}")
200
214
  end
201
215
  end
202
216
 
@@ -204,18 +218,14 @@ module Presto::Client
204
218
 
205
219
  attempts += 1
206
220
  sleep attempts * 0.1
207
- end while (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) < @retry_timeout && !@closed
221
+ end while (Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) < @retry_timeout && !client_aborted?
208
222
 
209
- @exception = PrestoHttpError.new(408, "Presto API error due to timeout")
210
- raise @exception
223
+ exception! PrestoHttpError.new(408, "Presto API error due to timeout")
211
224
  end
212
225
 
213
226
  def raise_if_timeout!
214
227
  if @started_at
215
- if @results && @results.next_uri == nil
216
- # query is already done
217
- return
218
- end
228
+ return if finished?
219
229
 
220
230
  elapsed = Process.clock_gettime(Process::CLOCK_MONOTONIC) - @started_at
221
231
 
@@ -234,30 +244,34 @@ module Presto::Client
234
244
 
235
245
  def raise_timeout_error!
236
246
  if query_id = @results && @results.id
237
- raise PrestoQueryTimeoutError, "Query #{query_id} timed out"
247
+ exception! PrestoQueryTimeoutError.new("Query #{query_id} timed out")
238
248
  else
239
- raise PrestoQueryTimeoutError, "Query timed out"
249
+ exception! PrestoQueryTimeoutError.new("Query timed out")
240
250
  end
241
251
  end
242
252
 
243
253
  def cancel_leaf_stage
244
- if uri = @results.next_uri
245
- response = @faraday.delete do |req|
254
+ if uri = @results.partial_cancel_uri
255
+ @faraday.delete do |req|
246
256
  req.url uri
247
257
  end
248
- return response.status / 100 == 2
249
258
  end
250
- return false
251
259
  end
252
260
 
253
261
  def close
254
- return if @closed
262
+ return unless running?
255
263
 
256
- # cancel running statement
257
- # TODO make async reqeust and ignore response?
258
- cancel_leaf_stage
264
+ @state = :client_aborted
265
+
266
+ begin
267
+ if uri = @results.next_uri
268
+ @faraday.delete do |req|
269
+ req.url uri
270
+ end
271
+ end
272
+ rescue => e
273
+ end
259
274
 
260
- @closed = true
261
275
  nil
262
276
  end
263
277
  end
@@ -15,6 +15,6 @@
15
15
  #
16
16
  module Presto
17
17
  module Client
18
- VERSION = "0.5.14"
18
+ VERSION = "0.6.4"
19
19
  end
20
20
  end
@@ -131,6 +131,7 @@ module Presto::Client::ModelVersions
131
131
  when "apply" then ApplyNode
132
132
  when "assignUniqueId" then AssignUniqueId
133
133
  when "lateralJoin" then LateralJoinNode
134
+ when "statisticsWriterNode" then StatisticsWriterNode
134
135
  end
135
136
  if model_class
136
137
  node = model_class.decode(hash)
@@ -197,9 +198,25 @@ module Presto::Client::ModelVersions
197
198
  end
198
199
  obj = allocate
199
200
  model_class = case hash["@type"]
200
- when "CreateHandle" then CreateHandle
201
- when "InsertHandle" then InsertHandle
202
- when "DeleteHandle" then DeleteHandle
201
+ when "CreateTarget" then CreateTarget
202
+ when "InsertTarget" then InsertTarget
203
+ when "DeleteTarget" then DeleteTarget
204
+ end
205
+ if model_class
206
+ model_class.decode(hash)
207
+ end
208
+ end
209
+ end
210
+
211
+ class << WriteStatisticsTarget =
212
+ Base.new(:type, :handle)
213
+ def decode(hash)
214
+ unless hash.is_a?(Hash)
215
+ raise TypeError, "Can't convert #{hash.class} to Hash"
216
+ end
217
+ obj = allocate
218
+ model_class = case hash["@type"]
219
+ when "WriteStatisticsHandle" then WriteStatisticsHandle
203
220
  end
204
221
  if model_class
205
222
  model_class.decode(hash)
@@ -246,6 +263,13 @@ module Presto::Client::ModelVersions
246
263
  end
247
264
  end
248
265
 
266
+ class ResourceGroupId < Array
267
+ def initialize(array)
268
+ super()
269
+ concat(array)
270
+ end
271
+ end
272
+
249
273
  ##
250
274
  # Those model classes are automatically generated
251
275
  #
data/modelgen/modelgen.rb CHANGED
@@ -13,13 +13,13 @@ erb = ERB.new(File.read(template_path))
13
13
 
14
14
  source_path = source_dir
15
15
 
16
- predefined_simple_classes = %w[StageId TaskId Lifespan ConnectorSession]
17
- predefined_models = %w[DistributionSnapshot PlanNode EquiJoinClause WriterTarget OperatorInfo HashCollisionsInfo]
16
+ predefined_simple_classes = %w[StageId TaskId Lifespan ConnectorSession ResourceGroupId]
17
+ predefined_models = %w[DistributionSnapshot PlanNode EquiJoinClause WriterTarget WriteStatisticsTarget OperatorInfo HashCollisionsInfo]
18
18
 
19
- assume_primitive = %w[Object Type Long Symbol QueryId PlanNodeId PlanFragmentId MemoryPoolId TransactionId URI Duration DataSize DateTime ColumnHandle ConnectorTableHandle ConnectorOutputTableHandle ConnectorIndexHandle ConnectorColumnHandle ConnectorInsertTableHandle ConnectorTableLayoutHandle Expression FunctionCall TimeZoneKey Locale TypeSignature Frame TupleDomain<ColumnHandle> SerializableNativeValue ConnectorTransactionHandle OutputBufferId ConnectorPartitioningHandle NullableValue ConnectorId HostAddress JsonNode Node]
20
- enum_types = %w[QueryState StageState TaskState QueueState PlanDistribution OutputPartitioning Step SortOrder BufferState NullPartitioning BlockedReason ParameterKind FunctionKind PartitionFunctionHandle Scope ErrorType DistributionType PipelineExecutionStrategy JoinType]
19
+ assume_primitive = %w[Object Type Long Symbol QueryId PlanNodeId PlanFragmentId MemoryPoolId TransactionId URI Duration DataSize DateTime ColumnHandle ConnectorTableHandle ConnectorOutputTableHandle ConnectorIndexHandle ConnectorColumnHandle ConnectorInsertTableHandle ConnectorTableLayoutHandle Expression FunctionCall TimeZoneKey Locale TypeSignature Frame TupleDomain<ColumnHandle> SerializableNativeValue ConnectorTransactionHandle OutputBufferId ConnectorPartitioningHandle NullableValue ConnectorId HostAddress JsonNode Node CatalogName QualifiedObjectName]
20
+ enum_types = %w[QueryState StageState TaskState QueueState PlanDistribution OutputPartitioning Step SortOrder BufferState NullPartitioning BlockedReason ParameterKind FunctionKind PartitionFunctionHandle Scope ErrorType DistributionType PipelineExecutionStrategy JoinType ExchangeNode.Type ColumnStatisticType TableStatisticType StageExecutionStrategy SemanticErrorCode]
21
21
 
22
- root_models = %w[QueryResults QueryInfo] + %w[
22
+ root_models = %w[QueryResults QueryInfo BasicQueryInfo] + %w[
23
23
  OutputNode
24
24
  ProjectNode
25
25
  TableScanNode
@@ -42,7 +42,6 @@ IndexJoinNode
42
42
  IndexSourceNode
43
43
  TableWriterNode
44
44
  DeleteNode
45
- MetadataDeleteNode
46
45
  TableFinishNode
47
46
  UnnestNode
48
47
  ExchangeNode
@@ -54,6 +53,7 @@ ExplainAnalyzeNode
54
53
  ApplyNode
55
54
  AssignUniqueId
56
55
  LateralJoinNode
56
+ StatisticsWriterNode
57
57
  ] + %w[
58
58
  ExchangeClientStatus
59
59
  LocalExchangeBufferInfo
@@ -62,7 +62,8 @@ SplitOperatorInfo
62
62
  PartitionedOutputInfo
63
63
  JoinOperatorInfo
64
64
  WindowInfo
65
- TableWriterInfo]
65
+ TableWriterInfo
66
+ ]
66
67
 
67
68
  name_mapping = Hash[*%w[
68
69
  StatementStats StageStats ClientStageStats
@@ -71,13 +72,14 @@ QueryResults Column ClientColumn
71
72
  ].each_slice(3).map { |x, y, z| [[x,y], z] }.flatten(1)]
72
73
 
73
74
  path_mapping = Hash[*%w[
74
- ClientColumn presto-client/src/main/java/com/facebook/presto/client/Column.java
75
- ClientStageStats presto-client/src/main/java/com/facebook/presto/client/StageStats.java
76
- Column presto-main/src/main/java/com/facebook/presto/execution/Column.java
77
- QueryStats presto-main/src/main/java/com/facebook/presto/execution/QueryStats.java
78
- StageStats presto-main/src/main/java/com/facebook/presto/execution/StageStats.java
79
- PartitionedOutputInfo presto-main/src/main/java/com/facebook/presto/operator/PartitionedOutputOperator.java
80
- TableWriterInfo presto-main/src/main/java/com/facebook/presto/operator/TableWriterOperator.java
75
+ ClientColumn presto-client/src/main/java/io/prestosql/client/Column.java
76
+ ClientStageStats presto-client/src/main/java/io/prestosql/client/StageStats.java
77
+ Column presto-main/src/main/java/io/prestosql/execution/Column.java
78
+ QueryStats presto-main/src/main/java/io/prestosql/execution/QueryStats.java
79
+ StageStats presto-main/src/main/java/io/prestosql/execution/StageStats.java
80
+ PartitionedOutputInfo presto-main/src/main/java/io/prestosql/operator/PartitionedOutputOperator.java
81
+ TableWriterInfo presto-main/src/main/java/io/prestosql/operator/TableWriterOperator.java
82
+ TableInfo presto-main/src/main/java/io/prestosql/execution/TableInfo.java
81
83
  ].map.with_index { |v,i| i % 2 == 0 ? v : (source_path + "/" + v) }]
82
84
 
83
85
  # model => [ [key,nullable,type], ... ]
@@ -3,13 +3,13 @@ module PrestoModels
3
3
  require 'find'
4
4
  require 'stringio'
5
5
 
6
- PRIMITIVE_TYPES = %w[String boolean long int short byte double float Integer]
6
+ PRIMITIVE_TYPES = %w[String boolean long int short byte double float Integer Double Boolean]
7
7
  ARRAY_PRIMITIVE_TYPES = PRIMITIVE_TYPES.map { |t| "#{t}[]" }
8
8
 
9
9
  class Model < Struct.new(:name, :fields)
10
10
  end
11
11
 
12
- class Field < Struct.new(:key, :nullable, :array, :map, :type, :base_type, :map_value_base_type)
12
+ class Field < Struct.new(:key, :nullable, :array, :map, :type, :base_type, :map_value_base_type, :base_type_alias)
13
13
  alias_method :nullable?, :nullable
14
14
  alias_method :array?, :array
15
15
  alias_method :map?, :map
@@ -47,10 +47,12 @@ module PrestoModels
47
47
 
48
48
  private
49
49
 
50
- PROPERTY_PATTERN = /@JsonProperty\(\"(\w+)\"\)\s+(@Nullable\s+)?([\w\<\>\[\]\,\s]+)\s+\w+/
50
+ PROPERTY_PATTERN = /@JsonProperty\(\"(\w+)\"\)\s+(@Nullable\s+)?([\w\<\>\[\]\,\s\.]+)\s+\w+/
51
51
  CREATOR_PATTERN = /@JsonCreator[\s]+public[\s]+(static\s+)?(\w+)[\w\s]*\((?:\s*#{PROPERTY_PATTERN}\s*,?)+\)/
52
+ GENERIC_PATTERN = /(\w+)\<(\w+)\>/
52
53
 
53
- def analyze_fields(model_name, creator_block)
54
+ def analyze_fields(model_name, creator_block, generic: nil)
55
+ model_name = "#{model_name}_#{generic}" if generic
54
56
  extra = @extra_fields[model_name] || []
55
57
  fields = creator_block.scan(PROPERTY_PATTERN).concat(extra).map do |key,nullable,type|
56
58
  map = false
@@ -63,7 +65,7 @@ module PrestoModels
63
65
  base_type = m[1]
64
66
  map_value_base_type = m[2]
65
67
  map = true
66
- elsif m = /Optional<([\w\[\]]+)>/.match(type)
68
+ elsif m = /Optional<([\w\[\]\<\>]+)>/.match(type)
67
69
  base_type = m[1]
68
70
  nullable = true
69
71
  elsif m = /OptionalInt/.match(type)
@@ -72,6 +74,9 @@ module PrestoModels
72
74
  elsif m = /OptionalLong/.match(type)
73
75
  base_type = 'Long'
74
76
  nullable = true
77
+ elsif m = /OptionalDouble/.match(type)
78
+ base_type = 'Double'
79
+ nullable = true
75
80
  elsif type =~ /\w+/
76
81
  base_type = type
77
82
  else
@@ -79,7 +84,16 @@ module PrestoModels
79
84
  end
80
85
  base_type = @name_mapping[[model_name, base_type]] || base_type
81
86
  map_value_base_type = @name_mapping[[model_name, map_value_base_type]] || map_value_base_type
82
- Field.new(key, !!nullable, array, map, type, base_type, map_value_base_type)
87
+
88
+ if generic
89
+ base_type = generic if base_type == 'T'
90
+ map_value_base_type = generic if map_value_base_type == 'T'
91
+ end
92
+ if m = GENERIC_PATTERN.match(base_type)
93
+ base_type_alias = "#{m[1]}_#{m[2]}"
94
+ end
95
+
96
+ Field.new(key, !!nullable, array, map, type, base_type, map_value_base_type, base_type_alias)
83
97
  end
84
98
 
85
99
  @models[model_name] = Model.new(model_name, fields)
@@ -92,9 +106,15 @@ module PrestoModels
92
106
  return fields
93
107
  end
94
108
 
95
- def analyze_model(model_name, parent_model = nil)
109
+ def analyze_model(model_name, parent_model= nil, generic: nil)
96
110
  return if @models[model_name] || @ignore_types.include?(model_name)
97
111
 
112
+ if m = GENERIC_PATTERN.match(model_name)
113
+ analyze_model(m[1], generic: m[2])
114
+ analyze_model(m[2])
115
+ return
116
+ end
117
+
98
118
  path = find_class_file(model_name, parent_model)
99
119
  java = File.read(path)
100
120
 
@@ -114,7 +134,7 @@ module PrestoModels
114
134
  fields = analyze_fields(inner_model_name, m[0])
115
135
  end
116
136
 
117
- fields = analyze_fields(model_name, body)
137
+ fields = analyze_fields(model_name, body, generic: generic)
118
138
 
119
139
  rescue => e
120
140
  puts "Skipping model #{parent_model}/#{model_name}: #{e}"
@@ -214,7 +234,7 @@ module PrestoModels
214
234
  elem_expr = convert_expression(field.base_type, field.base_type, "h")
215
235
  expr << "hash[\"#{field.key}\"].map {|h| #{elem_expr} }"
216
236
  else
217
- expr << convert_expression(field.type, field.base_type, "hash[\"#{field.key}\"]")
237
+ expr << convert_expression(field.type, field.base_type_alias || field.base_type, "hash[\"#{field.key}\"]")
218
238
  end
219
239
  end
220
240