trino-client 1.0.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.
- checksums.yaml +7 -0
- data/.github/CODEOWNERS +1 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +18 -0
- data/.github/workflows/ruby.yml +30 -0
- data/.gitignore +4 -0
- data/ChangeLog.md +168 -0
- data/Gemfile +7 -0
- data/LICENSE +202 -0
- data/README.md +131 -0
- data/Rakefile +45 -0
- data/lib/trino-client.rb +1 -0
- data/lib/trino/client.rb +23 -0
- data/lib/trino/client/client.rb +78 -0
- data/lib/trino/client/errors.rb +46 -0
- data/lib/trino/client/faraday_client.rb +242 -0
- data/lib/trino/client/model_versions/0.149.rb +1683 -0
- data/lib/trino/client/model_versions/0.153.rb +1719 -0
- data/lib/trino/client/model_versions/0.173.rb +1685 -0
- data/lib/trino/client/model_versions/0.178.rb +1964 -0
- data/lib/trino/client/model_versions/0.205.rb +2169 -0
- data/lib/trino/client/model_versions/303.rb +2574 -0
- data/lib/trino/client/model_versions/316.rb +2595 -0
- data/lib/trino/client/model_versions/351.rb +2726 -0
- data/lib/trino/client/models.rb +38 -0
- data/lib/trino/client/query.rb +144 -0
- data/lib/trino/client/statement_client.rb +279 -0
- data/lib/trino/client/version.rb +20 -0
- data/modelgen/model_versions.rb +280 -0
- data/modelgen/modelgen.rb +119 -0
- data/modelgen/models.rb +31 -0
- data/modelgen/trino_models.rb +270 -0
- data/release.rb +56 -0
- data/spec/basic_query_spec.rb +82 -0
- data/spec/client_spec.rb +75 -0
- data/spec/gzip_spec.rb +40 -0
- data/spec/model_spec.rb +35 -0
- data/spec/spec_helper.rb +42 -0
- data/spec/statement_client_spec.rb +637 -0
- data/spec/tpch/q01.sql +21 -0
- data/spec/tpch/q02.sql +43 -0
- data/spec/tpch_query_spec.rb +41 -0
- data/trino-client.gemspec +31 -0
- metadata +211 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
#
|
2
|
+
# Trino client for Ruby
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
module Trino
|
17
|
+
module Client
|
18
|
+
VERSION = "1.0.0"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,280 @@
|
|
1
|
+
#
|
2
|
+
# Trino client for Ruby
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
module Trino::Client::ModelVersions
|
17
|
+
|
18
|
+
####
|
19
|
+
## lib/trino/client/model_versions/*.rb is automatically generated using "rake modelgen:all" command.
|
20
|
+
## You should not edit this file directly. To modify the class definitions, edit
|
21
|
+
## modelgen/model_versions.rb file and run "rake modelgen:all".
|
22
|
+
##
|
23
|
+
|
24
|
+
module V<%= @model_version.gsub(".", "_") %>
|
25
|
+
class Base < Struct
|
26
|
+
class << self
|
27
|
+
alias_method :new_struct, :new
|
28
|
+
|
29
|
+
def new(*args)
|
30
|
+
new_struct(*args) do
|
31
|
+
# make it immutable
|
32
|
+
undef_method :"[]="
|
33
|
+
members.each do |m|
|
34
|
+
undef_method :"#{m}="
|
35
|
+
end
|
36
|
+
|
37
|
+
# replace constructor to receive hash instead of array
|
38
|
+
alias_method :initialize_struct, :initialize
|
39
|
+
|
40
|
+
def initialize(params={})
|
41
|
+
initialize_struct(*members.map {|m| params[m] })
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class StageId < String
|
49
|
+
def initialize(str)
|
50
|
+
super
|
51
|
+
splitted = split('.', 2)
|
52
|
+
@query_id = splitted[0]
|
53
|
+
@id = splitted[1]
|
54
|
+
end
|
55
|
+
|
56
|
+
attr_reader :query_id, :id
|
57
|
+
end
|
58
|
+
|
59
|
+
class TaskId < String
|
60
|
+
def initialize(str)
|
61
|
+
super
|
62
|
+
splitted = split('.', 3)
|
63
|
+
@stage_id = StageId.new("#{splitted[0]}.#{splitted[1]}")
|
64
|
+
@query_id = @stage_id.query_id
|
65
|
+
@id = splitted[2]
|
66
|
+
end
|
67
|
+
|
68
|
+
attr_reader :query_id, :stage_id, :id
|
69
|
+
end
|
70
|
+
|
71
|
+
class Lifespan < String
|
72
|
+
def initialize(str)
|
73
|
+
super
|
74
|
+
if str == "TaskWide"
|
75
|
+
@grouped = false
|
76
|
+
@group_id = 0
|
77
|
+
else
|
78
|
+
# Group1
|
79
|
+
@grouped = true
|
80
|
+
@group_id = str[5..-1].to_i
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
attr_reader :grouped, :group_id
|
85
|
+
end
|
86
|
+
|
87
|
+
class ConnectorSession < Hash
|
88
|
+
def initialize(hash)
|
89
|
+
super()
|
90
|
+
merge!(hash)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
module PlanNode
|
95
|
+
def self.decode(hash)
|
96
|
+
unless hash.is_a?(Hash)
|
97
|
+
raise TypeError, "Can't convert #{hash.class} to Hash"
|
98
|
+
end
|
99
|
+
model_class = case hash["@type"]
|
100
|
+
when "output" then OutputNode
|
101
|
+
when "project" then ProjectNode
|
102
|
+
when "tablescan" then TableScanNode
|
103
|
+
when "values" then ValuesNode
|
104
|
+
when "aggregation" then AggregationNode
|
105
|
+
when "markDistinct" then MarkDistinctNode
|
106
|
+
when "filter" then FilterNode
|
107
|
+
when "window" then WindowNode
|
108
|
+
when "rowNumber" then RowNumberNode
|
109
|
+
when "topnRowNumber" then TopNRowNumberNode
|
110
|
+
when "limit" then LimitNode
|
111
|
+
when "distinctlimit" then DistinctLimitNode
|
112
|
+
when "topn" then TopNNode
|
113
|
+
when "sample" then SampleNode
|
114
|
+
when "sort" then SortNode
|
115
|
+
when "remoteSource" then RemoteSourceNode
|
116
|
+
when "join" then JoinNode
|
117
|
+
when "semijoin" then SemiJoinNode
|
118
|
+
when "spatialjoin" then SpatialJoinNode
|
119
|
+
when "indexjoin" then IndexJoinNode
|
120
|
+
when "indexsource" then IndexSourceNode
|
121
|
+
when "tablewriter" then TableWriterNode
|
122
|
+
when "delete" then DeleteNode
|
123
|
+
when "metadatadelete" then MetadataDeleteNode
|
124
|
+
when "tablecommit" then TableFinishNode
|
125
|
+
when "unnest" then UnnestNode
|
126
|
+
when "exchange" then ExchangeNode
|
127
|
+
when "union" then UnionNode
|
128
|
+
when "intersect" then IntersectNode
|
129
|
+
when "scalar" then EnforceSingleRowNode
|
130
|
+
when "groupid" then GroupIdNode
|
131
|
+
when "explainAnalyze" then ExplainAnalyzeNode
|
132
|
+
when "apply" then ApplyNode
|
133
|
+
when "assignUniqueId" then AssignUniqueId
|
134
|
+
when "correlatedJoin" then CorrelatedJoinNode
|
135
|
+
when "statisticsWriterNode" then StatisticsWriterNode
|
136
|
+
end
|
137
|
+
if model_class
|
138
|
+
node = model_class.decode(hash)
|
139
|
+
class << node
|
140
|
+
attr_accessor :plan_node_type
|
141
|
+
end
|
142
|
+
node.plan_node_type = hash['@type']
|
143
|
+
node
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# io.airlift.stats.Distribution.DistributionSnapshot
|
149
|
+
class << DistributionSnapshot =
|
150
|
+
Base.new(:max_error, :count, :total, :p01, :p05, :p10, :p25, :p50, :p75, :p90, :p95, :p99, :min, :max)
|
151
|
+
def decode(hash)
|
152
|
+
unless hash.is_a?(Hash)
|
153
|
+
raise TypeError, "Can't convert #{hash.class} to Hash"
|
154
|
+
end
|
155
|
+
obj = allocate
|
156
|
+
obj.send(:initialize_struct,
|
157
|
+
hash["maxError"],
|
158
|
+
hash["count"],
|
159
|
+
hash["total"],
|
160
|
+
hash["p01"],
|
161
|
+
hash["p05"],
|
162
|
+
hash["p10"],
|
163
|
+
hash["p25"],
|
164
|
+
hash["p50"],
|
165
|
+
hash["p75"],
|
166
|
+
hash["p90"],
|
167
|
+
hash["p95"],
|
168
|
+
hash["p99"],
|
169
|
+
hash["min"],
|
170
|
+
hash["max"],
|
171
|
+
)
|
172
|
+
obj
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
# This is a hybrid of JoinNode.EquiJoinClause and IndexJoinNode.EquiJoinClause
|
177
|
+
class << EquiJoinClause =
|
178
|
+
Base.new(:left, :right, :probe, :index)
|
179
|
+
def decode(hash)
|
180
|
+
unless hash.is_a?(Hash)
|
181
|
+
raise TypeError, "Can't convert #{hash.class} to Hash"
|
182
|
+
end
|
183
|
+
obj = allocate
|
184
|
+
obj.send(:initialize_struct,
|
185
|
+
hash["left"],
|
186
|
+
hash["right"],
|
187
|
+
hash["probe"],
|
188
|
+
hash["index"],
|
189
|
+
)
|
190
|
+
obj
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
class << WriterTarget =
|
195
|
+
Base.new(:type, :handle)
|
196
|
+
def decode(hash)
|
197
|
+
unless hash.is_a?(Hash)
|
198
|
+
raise TypeError, "Can't convert #{hash.class} to Hash"
|
199
|
+
end
|
200
|
+
obj = allocate
|
201
|
+
model_class = case hash["@type"]
|
202
|
+
when "CreateTarget" then CreateTarget
|
203
|
+
when "InsertTarget" then InsertTarget
|
204
|
+
when "DeleteTarget" then DeleteTarget
|
205
|
+
end
|
206
|
+
if model_class
|
207
|
+
model_class.decode(hash)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
class << WriteStatisticsTarget =
|
213
|
+
Base.new(:type, :handle)
|
214
|
+
def decode(hash)
|
215
|
+
unless hash.is_a?(Hash)
|
216
|
+
raise TypeError, "Can't convert #{hash.class} to Hash"
|
217
|
+
end
|
218
|
+
obj = allocate
|
219
|
+
model_class = case hash["@type"]
|
220
|
+
when "WriteStatisticsHandle" then WriteStatisticsHandle
|
221
|
+
end
|
222
|
+
if model_class
|
223
|
+
model_class.decode(hash)
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Inner classes
|
229
|
+
module OperatorInfo
|
230
|
+
def self.decode(hash)
|
231
|
+
unless hash.is_a?(Hash)
|
232
|
+
raise TypeError, "Can't convert #{hash.class} to Hash"
|
233
|
+
end
|
234
|
+
model_class = case hash["@type"]
|
235
|
+
when "exchangeClientStatus" then ExchangeClientStatus
|
236
|
+
when "localExchangeBuffer" then LocalExchangeBufferInfo
|
237
|
+
when "tableFinish" then TableFinishInfo
|
238
|
+
when "splitOperator" then SplitOperatorInfo
|
239
|
+
when "hashCollisionsInfo" then HashCollisionsInfo
|
240
|
+
when "partitionedOutput" then PartitionedOutputInfo
|
241
|
+
when "joinOperatorInfo" then JoinOperatorInfo
|
242
|
+
when "windowInfo" then WindowInfo
|
243
|
+
when "tableWriter" then TableWriterInfo
|
244
|
+
end
|
245
|
+
if model_class
|
246
|
+
model_class.decode(hash)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
class << HashCollisionsInfo =
|
252
|
+
Base.new(:weighted_hash_collisions, :weighted_sum_squared_hash_collisions, :weighted_expectedHash_collisions)
|
253
|
+
def decode(hash)
|
254
|
+
unless hash.is_a?(Hash)
|
255
|
+
raise TypeError, "Can't convert #{hash.class} to Hash"
|
256
|
+
end
|
257
|
+
obj = allocate
|
258
|
+
obj.send(:initialize_struct,
|
259
|
+
hash["weighted_hash_collisions"],
|
260
|
+
hash["weighted_sum_squared_hash_collisions"],
|
261
|
+
hash["weighted_expectedHash_collisions"]
|
262
|
+
)
|
263
|
+
obj
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
class ResourceGroupId < Array
|
268
|
+
def initialize(array)
|
269
|
+
super()
|
270
|
+
concat(array)
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
##
|
275
|
+
# Those model classes are automatically generated
|
276
|
+
#
|
277
|
+
|
278
|
+
<%= @contents %>
|
279
|
+
end
|
280
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
|
2
|
+
if ARGV.length != 4
|
3
|
+
puts "usage: <model-version> <trino-source-dir> <template.erb> <output.rb>"
|
4
|
+
exit 1
|
5
|
+
end
|
6
|
+
|
7
|
+
model_version, source_dir, template_path, output_path = *ARGV
|
8
|
+
|
9
|
+
require_relative 'trino_models'
|
10
|
+
|
11
|
+
require 'erb'
|
12
|
+
erb = ERB.new(File.read(template_path))
|
13
|
+
|
14
|
+
source_path = source_dir
|
15
|
+
|
16
|
+
predefined_simple_classes = %w[StageId TaskId Lifespan ConnectorSession ResourceGroupId]
|
17
|
+
predefined_models = %w[DistributionSnapshot PlanNode EquiJoinClause WriterTarget WriteStatisticsTarget OperatorInfo HashCollisionsInfo]
|
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 CatalogName QualifiedObjectName FunctionId DynamicFilterId Instant]
|
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 QueryType]
|
21
|
+
|
22
|
+
root_models = %w[QueryResults QueryInfo BasicQueryInfo] + %w[
|
23
|
+
OutputNode
|
24
|
+
ProjectNode
|
25
|
+
TableScanNode
|
26
|
+
ValuesNode
|
27
|
+
AggregationNode
|
28
|
+
MarkDistinctNode
|
29
|
+
FilterNode
|
30
|
+
WindowNode
|
31
|
+
RowNumberNode
|
32
|
+
TopNRowNumberNode
|
33
|
+
LimitNode
|
34
|
+
DistinctLimitNode
|
35
|
+
TopNNode
|
36
|
+
SampleNode
|
37
|
+
SortNode
|
38
|
+
RemoteSourceNode
|
39
|
+
JoinNode
|
40
|
+
SemiJoinNode
|
41
|
+
SpatialJoinNode
|
42
|
+
IndexJoinNode
|
43
|
+
IndexSourceNode
|
44
|
+
TableWriterNode
|
45
|
+
DeleteNode
|
46
|
+
TableFinishNode
|
47
|
+
UnnestNode
|
48
|
+
ExchangeNode
|
49
|
+
UnionNode
|
50
|
+
IntersectNode
|
51
|
+
EnforceSingleRowNode
|
52
|
+
GroupIdNode
|
53
|
+
ExplainAnalyzeNode
|
54
|
+
ApplyNode
|
55
|
+
AssignUniqueId
|
56
|
+
CorrelatedJoinNode
|
57
|
+
StatisticsWriterNode
|
58
|
+
] + %w[
|
59
|
+
ExchangeClientStatus
|
60
|
+
LocalExchangeBufferInfo
|
61
|
+
TableFinishInfo
|
62
|
+
SplitOperatorInfo
|
63
|
+
PartitionedOutputInfo
|
64
|
+
JoinOperatorInfo
|
65
|
+
WindowInfo
|
66
|
+
TableWriterInfo
|
67
|
+
]
|
68
|
+
|
69
|
+
name_mapping = Hash[*%w[
|
70
|
+
StatementStats StageStats ClientStageStats
|
71
|
+
ClientStageStats StageStats ClientStageStats
|
72
|
+
QueryResults Column ClientColumn
|
73
|
+
].each_slice(3).map { |x, y, z| [[x,y], z] }.flatten(1)]
|
74
|
+
|
75
|
+
path_mapping = Hash[*%w[
|
76
|
+
ClientColumn client/trino-client/src/main/java/io/trino/client/Column.java
|
77
|
+
ClientStageStats client/trino-client/src/main/java/io/trino/client/StageStats.java
|
78
|
+
Column core/trino-main/src/main/java/io/trino/execution/Column.java
|
79
|
+
QueryStats core/trino-main/src/main/java/io/trino/execution/QueryStats.java
|
80
|
+
StageStats core/trino-main/src/main/java/io/trino/execution/StageStats.java
|
81
|
+
PartitionedOutputInfo core/trino-main/src/main/java/io/trino/operator/PartitionedOutputOperator.java
|
82
|
+
TableWriterInfo core/trino-main/src/main/java/io/trino/operator/TableWriterOperator.java
|
83
|
+
TableInfo core/trino-main/src/main/java/io/trino/execution/TableInfo.java
|
84
|
+
DynamicFiltersStats core/trino-main/src/main/java/io/trino/server/DynamicFilterService.java
|
85
|
+
].map.with_index { |v,i| i % 2 == 0 ? v : (source_path + "/" + v) }]
|
86
|
+
|
87
|
+
# model => [ [key,nullable,type], ... ]
|
88
|
+
extra_fields = {
|
89
|
+
'QueryInfo' => [['finalQueryInfo', nil, 'boolean']]
|
90
|
+
}
|
91
|
+
|
92
|
+
analyzer = TrinoModels::ModelAnalyzer.new(
|
93
|
+
source_path,
|
94
|
+
skip_models: predefined_models + predefined_simple_classes + assume_primitive + enum_types,
|
95
|
+
path_mapping: path_mapping,
|
96
|
+
name_mapping: name_mapping,
|
97
|
+
extra_fields: extra_fields
|
98
|
+
)
|
99
|
+
analyzer.analyze(root_models)
|
100
|
+
models = analyzer.models
|
101
|
+
skipped_models = analyzer.skipped_models
|
102
|
+
|
103
|
+
formatter = TrinoModels::ModelFormatter.new(
|
104
|
+
base_indent_count: 2,
|
105
|
+
struct_class: "Base",
|
106
|
+
special_struct_initialize_method: "initialize_struct",
|
107
|
+
primitive_types: assume_primitive,
|
108
|
+
skip_types: skipped_models,
|
109
|
+
simple_classes: predefined_simple_classes,
|
110
|
+
enum_types: enum_types,
|
111
|
+
)
|
112
|
+
formatter.format(models)
|
113
|
+
|
114
|
+
@contents = formatter.contents
|
115
|
+
@model_version = model_version
|
116
|
+
|
117
|
+
data = erb.result
|
118
|
+
File.write(output_path, data)
|
119
|
+
|
data/modelgen/models.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#
|
2
|
+
# Trino client for Ruby
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
#
|
16
|
+
module Trino::Client
|
17
|
+
|
18
|
+
####
|
19
|
+
## lib/trino/client/models.rb is automatically generated using "rake modelgen:latest" command.
|
20
|
+
## You should not edit this file directly. To modify the class definitions, edit
|
21
|
+
## modelgen/models.rb file and run "rake modelgen:latest".
|
22
|
+
##
|
23
|
+
|
24
|
+
module ModelVersions
|
25
|
+
end
|
26
|
+
<% @versions.each do |ver| %>
|
27
|
+
require 'trino/client/model_versions/<%= ver %>.rb'<% end %>
|
28
|
+
|
29
|
+
Models = ModelVersions::V<%= @latest_version.gsub(".", "_") %>
|
30
|
+
|
31
|
+
end
|