clickhouse-activerecord 1.3.1 → 1.5.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 +4 -4
- data/.docker/clickhouse/cluster/server1_config.xml +10 -2
- data/.docker/clickhouse/cluster/server2_config.xml +10 -2
- data/.docker/clickhouse/single/config.xml +9 -2
- data/.docker/clickhouse/users.xml +10 -1
- data/.docker/docker-compose.cluster.yml +2 -2
- data/.docker/docker-compose.yml +1 -1
- data/.github/workflows/testing.yml +12 -8
- data/CHANGELOG.md +51 -1
- data/README.md +5 -2
- data/lib/active_record/connection_adapters/clickhouse/column.rb +1 -1
- data/lib/active_record/connection_adapters/clickhouse/schema_creation.rb +6 -1
- data/lib/active_record/connection_adapters/clickhouse/schema_statements.rb +105 -118
- data/lib/active_record/connection_adapters/clickhouse/statement/format_manager.rb +46 -0
- data/lib/active_record/connection_adapters/clickhouse/statement/response_processor.rb +99 -0
- data/lib/active_record/connection_adapters/clickhouse/statement.rb +30 -0
- data/lib/active_record/connection_adapters/clickhouse_adapter.rb +33 -25
- data/lib/arel/visitors/clickhouse.rb +7 -1
- data/lib/clickhouse-activerecord/schema_dumper.rb +3 -1
- data/lib/clickhouse-activerecord/tasks.rb +2 -3
- data/lib/clickhouse-activerecord/version.rb +1 -1
- data/lib/core_extensions/active_record/relation.rb +56 -11
- data/lib/core_extensions/arel/nodes/select_core.rb +7 -0
- data/lib/core_extensions/arel/nodes/select_statement.rb +4 -0
- metadata +6 -7
- data/lib/tasks/clickhouse.rake +0 -90
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b8c5d0d360ba85375ca8f11600f5a6c3e37cd24504ede6255dbced8e3652319b
|
|
4
|
+
data.tar.gz: d2491e138a661eeb1c9952064e55125eed84f61fdebab88279e3ba73d881d19f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3904eff8d2ff017cdb2572483baa5e201e8280799a4ab8753e5545ac27795365bec5174b183b2128cdbe7c8cf075c935f9d9f0b83045c5569db397a22ece8ad7
|
|
7
|
+
data.tar.gz: 80aed33044ca6ebf12280f352e41584a7c9582f7e934f44370a49148ad292a3af499f2d5132621142756fd384cea51111c59bed8f4a188539ed80b552befba7e
|
|
@@ -15,15 +15,16 @@
|
|
|
15
15
|
<tmp_path>/var/lib/clickhouse/tmp/</tmp_path>
|
|
16
16
|
<user_files_path>/var/lib/clickhouse/user_files/</user_files_path>
|
|
17
17
|
<access_control_path>/var/lib/clickhouse/access/</access_control_path>
|
|
18
|
+
<format_schema_path>/var/lib/clickhouse/format_schemas/</format_schema_path>
|
|
18
19
|
<keep_alive_timeout>3</keep_alive_timeout>
|
|
19
20
|
|
|
20
21
|
<logger>
|
|
21
|
-
<level>
|
|
22
|
+
<level>error</level>
|
|
22
23
|
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
|
|
23
24
|
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
|
|
24
25
|
<size>1000M</size>
|
|
25
26
|
<count>10</count>
|
|
26
|
-
<console>
|
|
27
|
+
<console>0</console>
|
|
27
28
|
</logger>
|
|
28
29
|
|
|
29
30
|
<remote_servers>
|
|
@@ -114,4 +115,11 @@
|
|
|
114
115
|
<value>86400</value>
|
|
115
116
|
</header>
|
|
116
117
|
</http_options_response>
|
|
118
|
+
|
|
119
|
+
<user_directories>
|
|
120
|
+
<users_xml>
|
|
121
|
+
<path>users.xml</path>
|
|
122
|
+
</users_xml>
|
|
123
|
+
</user_directories>
|
|
124
|
+
|
|
117
125
|
</clickhouse>
|
|
@@ -15,15 +15,16 @@
|
|
|
15
15
|
<tmp_path>/var/lib/clickhouse/tmp/</tmp_path>
|
|
16
16
|
<user_files_path>/var/lib/clickhouse/user_files/</user_files_path>
|
|
17
17
|
<access_control_path>/var/lib/clickhouse/access/</access_control_path>
|
|
18
|
+
<format_schema_path>/var/lib/clickhouse/format_schemas/</format_schema_path>
|
|
18
19
|
<keep_alive_timeout>3</keep_alive_timeout>
|
|
19
20
|
|
|
20
21
|
<logger>
|
|
21
|
-
<level>
|
|
22
|
+
<level>error</level>
|
|
22
23
|
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
|
|
23
24
|
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
|
|
24
25
|
<size>1000M</size>
|
|
25
26
|
<count>10</count>
|
|
26
|
-
<console>
|
|
27
|
+
<console>0</console>
|
|
27
28
|
</logger>
|
|
28
29
|
|
|
29
30
|
<remote_servers>
|
|
@@ -114,4 +115,11 @@
|
|
|
114
115
|
<value>86400</value>
|
|
115
116
|
</header>
|
|
116
117
|
</http_options_response>
|
|
118
|
+
|
|
119
|
+
<user_directories>
|
|
120
|
+
<users_xml>
|
|
121
|
+
<path>users.xml</path>
|
|
122
|
+
</users_xml>
|
|
123
|
+
</user_directories>
|
|
124
|
+
|
|
117
125
|
</clickhouse>
|
|
@@ -14,15 +14,16 @@
|
|
|
14
14
|
<tmp_path>/var/lib/clickhouse/tmp/</tmp_path>
|
|
15
15
|
<user_files_path>/var/lib/clickhouse/user_files/</user_files_path>
|
|
16
16
|
<access_control_path>/var/lib/clickhouse/access/</access_control_path>
|
|
17
|
+
<format_schema_path>/var/lib/clickhouse/format_schemas/</format_schema_path>
|
|
17
18
|
<keep_alive_timeout>3</keep_alive_timeout>
|
|
18
19
|
|
|
19
20
|
<logger>
|
|
20
|
-
<level>
|
|
21
|
+
<level>error</level>
|
|
21
22
|
<log>/var/log/clickhouse-server/clickhouse-server.log</log>
|
|
22
23
|
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
|
|
23
24
|
<size>1000M</size>
|
|
24
25
|
<count>10</count>
|
|
25
|
-
<console>
|
|
26
|
+
<console>0</console>
|
|
26
27
|
</logger>
|
|
27
28
|
|
|
28
29
|
<query_log>
|
|
@@ -51,4 +52,10 @@
|
|
|
51
52
|
</header>
|
|
52
53
|
</http_options_response>
|
|
53
54
|
|
|
55
|
+
<user_directories>
|
|
56
|
+
<users_xml>
|
|
57
|
+
<path>users.xml</path>
|
|
58
|
+
</users_xml>
|
|
59
|
+
</user_directories>
|
|
60
|
+
|
|
54
61
|
</clickhouse>
|
|
@@ -8,8 +8,17 @@
|
|
|
8
8
|
</profiles>
|
|
9
9
|
|
|
10
10
|
<users>
|
|
11
|
+
<test>
|
|
12
|
+
<password>test</password>
|
|
13
|
+
<networks>
|
|
14
|
+
<ip>::/0</ip>
|
|
15
|
+
</networks>
|
|
16
|
+
<profile>default</profile>
|
|
17
|
+
<quota>default</quota>
|
|
18
|
+
<access_management>1</access_management>
|
|
19
|
+
</test>
|
|
11
20
|
<default>
|
|
12
|
-
<password
|
|
21
|
+
<password />
|
|
13
22
|
<networks>
|
|
14
23
|
<ip>::/0</ip>
|
|
15
24
|
</networks>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
services:
|
|
2
2
|
clickhouse1:
|
|
3
|
-
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION
|
|
3
|
+
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION}'
|
|
4
4
|
ulimits:
|
|
5
5
|
nofile:
|
|
6
6
|
soft: 262144
|
|
@@ -18,7 +18,7 @@ services:
|
|
|
18
18
|
interval: 5s
|
|
19
19
|
|
|
20
20
|
clickhouse2:
|
|
21
|
-
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION
|
|
21
|
+
image: 'clickhouse/clickhouse-server:${CLICKHOUSE_VERSION}'
|
|
22
22
|
ulimits:
|
|
23
23
|
nofile:
|
|
24
24
|
soft: 262144
|
data/.docker/docker-compose.yml
CHANGED
|
@@ -14,6 +14,8 @@ jobs:
|
|
|
14
14
|
env:
|
|
15
15
|
CLICKHOUSE_PORT: 18123
|
|
16
16
|
CLICKHOUSE_DATABASE: default
|
|
17
|
+
CLICKHOUSE_USER: test
|
|
18
|
+
CLICKHOUSE_PASSWORD: test
|
|
17
19
|
|
|
18
20
|
strategy:
|
|
19
21
|
fail-fast: true
|
|
@@ -22,21 +24,21 @@ jobs:
|
|
|
22
24
|
version:
|
|
23
25
|
- ruby: 2.7
|
|
24
26
|
rails: 7.1.3
|
|
25
|
-
- ruby: 3.0
|
|
26
|
-
rails: 7.1.3
|
|
27
27
|
- ruby: 3.2
|
|
28
28
|
rails: 7.1.3
|
|
29
29
|
- ruby: 3.2
|
|
30
30
|
rails: 7.2.1
|
|
31
31
|
- ruby: 3.2
|
|
32
32
|
rails: 8.0.1
|
|
33
|
-
|
|
33
|
+
- ruby: 3.2
|
|
34
|
+
rails: 8.1
|
|
35
|
+
clickhouse: [ '24.9', '25.10' ]
|
|
34
36
|
|
|
35
37
|
steps:
|
|
36
38
|
- uses: actions/checkout@v4
|
|
37
39
|
|
|
38
40
|
- name: Start ClickHouse ${{ matrix.clickhouse }}
|
|
39
|
-
uses: hoverkraft-tech/compose-action@v2.1
|
|
41
|
+
uses: hoverkraft-tech/compose-action@v2.4.1
|
|
40
42
|
env:
|
|
41
43
|
CLICKHOUSE_VERSION: ${{ matrix.clickhouse }}
|
|
42
44
|
with:
|
|
@@ -61,6 +63,8 @@ jobs:
|
|
|
61
63
|
CLICKHOUSE_PORT: 28123
|
|
62
64
|
CLICKHOUSE_DATABASE: default
|
|
63
65
|
CLICKHOUSE_CLUSTER: test_cluster
|
|
66
|
+
CLICKHOUSE_USER: test
|
|
67
|
+
CLICKHOUSE_PASSWORD: test
|
|
64
68
|
|
|
65
69
|
strategy:
|
|
66
70
|
fail-fast: true
|
|
@@ -69,21 +73,21 @@ jobs:
|
|
|
69
73
|
version:
|
|
70
74
|
- ruby: 2.7
|
|
71
75
|
rails: 7.1.3
|
|
72
|
-
- ruby: 3.0
|
|
73
|
-
rails: 7.1.3
|
|
74
76
|
- ruby: 3.2
|
|
75
77
|
rails: 7.1.3
|
|
76
78
|
- ruby: 3.2
|
|
77
79
|
rails: 7.2.1
|
|
78
80
|
- ruby: 3.2
|
|
79
81
|
rails: 8.0.1
|
|
80
|
-
|
|
82
|
+
- ruby: 3.2
|
|
83
|
+
rails: 8.1
|
|
84
|
+
clickhouse: [ '24.9', '25.10' ]
|
|
81
85
|
|
|
82
86
|
steps:
|
|
83
87
|
- uses: actions/checkout@v4
|
|
84
88
|
|
|
85
89
|
- name: Start ClickHouse Cluster ${{ matrix.clickhouse }}
|
|
86
|
-
uses: hoverkraft-tech/compose-action@v2.1
|
|
90
|
+
uses: hoverkraft-tech/compose-action@v2.4.1
|
|
87
91
|
env:
|
|
88
92
|
CLICKHOUSE_VERSION: ${{ matrix.clickhouse }}
|
|
89
93
|
with:
|
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,54 @@
|
|
|
1
|
-
### Version 1.
|
|
1
|
+
### Version 1.5.0 (Nov 5, 2025)
|
|
2
|
+
|
|
3
|
+
* 🎉 Support for Rails 8.1
|
|
4
|
+
* Fix sql structure dump with `schema_migrations` #138
|
|
5
|
+
* Remove old tasks
|
|
6
|
+
|
|
7
|
+
### Version 1.4.0 (Sep 18, 2025)
|
|
8
|
+
|
|
9
|
+
* `CREATE OR REPLACE FUNCTION` in SQL schema dumps in #198
|
|
10
|
+
* Added shard config to handle replica path with shard in #201
|
|
11
|
+
* Add support for simple schema dumping in #203
|
|
12
|
+
* Unscope :final and :settings in #208
|
|
13
|
+
* Encapsulate format logic within Statement and helper classes in #162
|
|
14
|
+
|
|
15
|
+
### Version 1.3.1 (Feb 12, 2025)
|
|
16
|
+
|
|
17
|
+
* Restore replace database from dump schema table creation
|
|
18
|
+
|
|
19
|
+
### Version 1.3.0 (Jan 24, 2025)
|
|
20
|
+
|
|
21
|
+
* 🎉 Support for Rails 8.0 #189
|
|
22
|
+
* Restore multi-line table definitions in structure dumps #187
|
|
23
|
+
* Use a flag to track updates/deletes in SQL visitor #188
|
|
24
|
+
|
|
25
|
+
### Version 1.2.1 (Nov 18, 2024)
|
|
26
|
+
|
|
27
|
+
* Maintain primary key type specificity in #183
|
|
28
|
+
* Reliably sort functions, views, and materialized views in schema in #181
|
|
29
|
+
* Improve function dumps in #179
|
|
30
|
+
* Add support for integer limits in map type in #178
|
|
31
|
+
* Add support for `request_settings` in create_table
|
|
32
|
+
|
|
33
|
+
### Version 1.2.0 (Oct 23, 2024)
|
|
34
|
+
|
|
35
|
+
* Fix for function creation in `structure.sql` #166
|
|
36
|
+
* Add `group_by_grouping_sets` query method #161
|
|
37
|
+
* Add support for `CREATE FUNCTION` and `CREATE OR REPLACE FUNCTION`; the later in schema loading #146
|
|
38
|
+
* Add support for `LIMIT BY` clause #169
|
|
39
|
+
* Include column definitions in schema dump if the column name is not `id` #173
|
|
40
|
+
* Add blank line after create_function in schema #170
|
|
41
|
+
* Improve DB::Exception error handling #164
|
|
42
|
+
* SchemaDumper adds materialized view destination #159
|
|
43
|
+
* Add Array support to Map #158
|
|
44
|
+
* Add support codec compression parameter #135
|
|
45
|
+
|
|
46
|
+
### Version 1.1.3 (Sep 27, 2024)
|
|
47
|
+
|
|
48
|
+
* Fix schema dumper #163
|
|
49
|
+
|
|
50
|
+
### Version 1.1.2 (Aug 27, 2024)
|
|
51
|
+
|
|
2
52
|
* 🎉 Support for rails 7.2 #156
|
|
3
53
|
* Add method `views` for getting table `View` list in #152
|
|
4
54
|
* Add support for Map datatype in #144
|
data/README.md
CHANGED
|
@@ -33,6 +33,9 @@ default: &default
|
|
|
33
33
|
migrations_paths: db/clickhouse # optional, default: db/migrate_clickhouse
|
|
34
34
|
cluster_name: 'cluster_name' # optional for creating tables in cluster
|
|
35
35
|
replica_name: '{replica}' # replica macros name, optional for creating replicated tables
|
|
36
|
+
read_timeout: 300 # change network timeouts, by default 60 seconds
|
|
37
|
+
write_timeout: 300
|
|
38
|
+
keep_alive_timeout: 300
|
|
36
39
|
```
|
|
37
40
|
|
|
38
41
|
Alternatively if you wish to pass a custom `Net::HTTP` transport (or any other
|
|
@@ -282,10 +285,10 @@ Engines `MergeTree` and all support replication engines will be replaced to `Rep
|
|
|
282
285
|
|
|
283
286
|
Donations to this project are going directly to [PNixx](https://github.com/PNixx), the original author of this project:
|
|
284
287
|
|
|
285
|
-
* BTC address: `
|
|
288
|
+
* BTC address: `bc1qr73vls0kv2ujk4ugqmpqj6j0qtqvdr3nx25xdl`
|
|
286
289
|
* ETH address: `0x6F094365A70fe7836A633d2eE80A1FA9758234d5`
|
|
287
290
|
* XMR address: `42gP71qLB5M43RuDnrQ3vSJFFxis9Kw9VMURhpx9NLQRRwNvaZRjm2TFojAMC8Fk1BQhZNKyWhoyJSn5Ak9kppgZPjE17Zh`
|
|
288
|
-
* TON address: `
|
|
291
|
+
* TON address: `UQBCnxOfBsHPZ3PesGgMedVMEf5UHnm0jrSq-042pMWw08Ux`
|
|
289
292
|
|
|
290
293
|
## Development
|
|
291
294
|
|
|
@@ -43,7 +43,12 @@ module ActiveRecord
|
|
|
43
43
|
sql.gsub!(/\s+(.*)/, " \\1 CODEC(#{options[:codec]})")
|
|
44
44
|
end
|
|
45
45
|
sql.gsub!(/(\sString)\(\d+\)/, '\1')
|
|
46
|
-
|
|
46
|
+
|
|
47
|
+
if ::ActiveRecord::version >= Gem::Version.new('8.1')
|
|
48
|
+
sql << " DEFAULT #{quote_default_expression_for_column_definition(options[:default], options[:column])}" if options_include_default?(options)
|
|
49
|
+
else
|
|
50
|
+
sql << " DEFAULT #{quote_default_expression(options[:default], options[:column])}" if options_include_default?(options)
|
|
51
|
+
end
|
|
47
52
|
sql
|
|
48
53
|
end
|
|
49
54
|
|
|
@@ -6,22 +6,55 @@ module ActiveRecord
|
|
|
6
6
|
module ConnectionAdapters
|
|
7
7
|
module Clickhouse
|
|
8
8
|
module SchemaStatements
|
|
9
|
-
DEFAULT_RESPONSE_FORMAT = 'JSONCompactEachRowWithNamesAndTypes'.freeze
|
|
10
9
|
|
|
11
|
-
|
|
10
|
+
def with_settings(**settings)
|
|
11
|
+
@block_settings ||= {}
|
|
12
|
+
prev_settings = @block_settings
|
|
13
|
+
@block_settings = @block_settings.merge(settings)
|
|
14
|
+
yield
|
|
15
|
+
ensure
|
|
16
|
+
@block_settings = prev_settings
|
|
17
|
+
end
|
|
12
18
|
|
|
13
|
-
|
|
14
|
-
|
|
19
|
+
# Request a specific format for the duration of the provided block.
|
|
20
|
+
# Pass `nil` to explicitly send the SQL statement without a `FORMAT` clause.
|
|
21
|
+
# @param [String, nil] format
|
|
22
|
+
#
|
|
23
|
+
# @example Specify CSVWithNamesAndTypes format
|
|
24
|
+
# with_response_format('CSVWithNamesAndTypes') do
|
|
25
|
+
# Table.connection.execute('SELECT * FROM table')
|
|
26
|
+
# end
|
|
27
|
+
# # sends and executes "SELECT * FROM table FORMAT CSVWithNamesAndTypes"
|
|
28
|
+
#
|
|
29
|
+
# @example Specify no format
|
|
30
|
+
# with_response_format(nil) do
|
|
31
|
+
# Table.connection.execute('SELECT * FROM table')
|
|
32
|
+
# end
|
|
33
|
+
# # sends and executes "SELECT * FROM table"
|
|
34
|
+
def with_response_format(format)
|
|
35
|
+
prev_format = @response_format
|
|
36
|
+
@response_format = format
|
|
37
|
+
yield
|
|
38
|
+
ensure
|
|
39
|
+
@response_format = prev_format
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def execute(sql, name = nil, format: @response_format, settings: {})
|
|
43
|
+
with_response_format(format) do
|
|
44
|
+
log(sql, [adapter_name, name].compact.join(' ')) do
|
|
45
|
+
raw_execute(sql, settings: settings)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
15
48
|
end
|
|
16
49
|
|
|
17
|
-
def exec_insert(sql, name, _binds, _pk = nil, _sequence_name = nil, returning: nil)
|
|
18
|
-
new_sql = sql.
|
|
19
|
-
|
|
50
|
+
def exec_insert(sql, name = nil, _binds = [], _pk = nil, _sequence_name = nil, returning: nil)
|
|
51
|
+
new_sql = sql.sub(/ (DEFAULT )?VALUES/, " VALUES")
|
|
52
|
+
with_response_format(nil) { execute(new_sql, name) }
|
|
20
53
|
true
|
|
21
54
|
end
|
|
22
55
|
|
|
23
56
|
def internal_exec_query(sql, name = nil, binds = [], prepare: false, async: false, allow_retry: false)
|
|
24
|
-
result =
|
|
57
|
+
result = execute(sql, name)
|
|
25
58
|
columns = result['meta'].map { |m| m['name'] }
|
|
26
59
|
types = {}
|
|
27
60
|
result['meta'].each_with_index do |m, i|
|
|
@@ -37,24 +70,25 @@ module ActiveRecord
|
|
|
37
70
|
end
|
|
38
71
|
|
|
39
72
|
def exec_insert_all(sql, name)
|
|
40
|
-
|
|
73
|
+
with_response_format(nil) { execute(sql, name) }
|
|
41
74
|
true
|
|
42
75
|
end
|
|
43
76
|
|
|
44
77
|
# @link https://clickhouse.com/docs/en/sql-reference/statements/alter/update
|
|
45
|
-
def exec_update(
|
|
46
|
-
|
|
78
|
+
def exec_update(sql, name = nil, _binds = [])
|
|
79
|
+
execute(sql, name)
|
|
47
80
|
0
|
|
48
81
|
end
|
|
49
82
|
|
|
50
83
|
# @link https://clickhouse.com/docs/en/sql-reference/statements/delete
|
|
51
|
-
def exec_delete(
|
|
52
|
-
log(
|
|
53
|
-
|
|
84
|
+
def exec_delete(sql, name = nil, _binds = [])
|
|
85
|
+
log(sql, "#{adapter_name} #{name}") do
|
|
86
|
+
statement = Statement.new(sql, format: @response_format)
|
|
87
|
+
res = request(statement)
|
|
54
88
|
begin
|
|
55
89
|
data = JSON.parse(res.header['x-clickhouse-summary'])
|
|
56
90
|
data['result_rows'].to_i
|
|
57
|
-
rescue
|
|
91
|
+
rescue JSON::ParserError
|
|
58
92
|
0
|
|
59
93
|
end
|
|
60
94
|
end
|
|
@@ -85,7 +119,10 @@ module ActiveRecord
|
|
|
85
119
|
end
|
|
86
120
|
|
|
87
121
|
def show_create_function(function)
|
|
88
|
-
|
|
122
|
+
result = do_system_execute("SELECT create_query FROM system.functions WHERE origin = 'SQLUserDefined' AND name = '#{function}'")
|
|
123
|
+
return if result.nil?
|
|
124
|
+
|
|
125
|
+
result['data'].flatten.first.sub(/\ACREATE FUNCTION/, 'CREATE OR REPLACE FUNCTION')
|
|
89
126
|
end
|
|
90
127
|
|
|
91
128
|
def table_options(table)
|
|
@@ -110,18 +147,18 @@ module ActiveRecord
|
|
|
110
147
|
tables
|
|
111
148
|
end
|
|
112
149
|
|
|
113
|
-
def do_system_execute(sql, name = nil)
|
|
114
|
-
log_with_debug(sql,
|
|
115
|
-
|
|
116
|
-
process_response(res, DEFAULT_RESPONSE_FORMAT, sql)
|
|
150
|
+
def do_system_execute(sql, name = nil, except_params: [])
|
|
151
|
+
log_with_debug(sql, [adapter_name, name].compact.join(' ')) do
|
|
152
|
+
raw_execute(sql, except_params: except_params)
|
|
117
153
|
end
|
|
118
154
|
end
|
|
119
155
|
|
|
120
156
|
def do_execute(sql, name = nil, format: DEFAULT_RESPONSE_FORMAT, settings: {})
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
157
|
+
ActiveRecord.deprecator.warn(<<~MSG.squish)
|
|
158
|
+
`do_execute` is deprecated and will be removed in an upcoming release.
|
|
159
|
+
Please use `execute` instead.
|
|
160
|
+
MSG
|
|
161
|
+
execute(sql, name, format: format, settings: settings)
|
|
125
162
|
end
|
|
126
163
|
|
|
127
164
|
if ::ActiveRecord::version >= Gem::Version.new('7.2')
|
|
@@ -154,7 +191,7 @@ module ActiveRecord
|
|
|
154
191
|
if (duplicate = inserting.detect { |v| inserting.count(v) > 1 })
|
|
155
192
|
raise "Duplicate migration #{duplicate}. Please renumber your migrations to resolve the conflict."
|
|
156
193
|
end
|
|
157
|
-
|
|
194
|
+
execute(insert_versions_sql(inserting), nil, settings: {max_partitions_per_insert_block: [100, inserting.size].max})
|
|
158
195
|
end
|
|
159
196
|
end
|
|
160
197
|
|
|
@@ -168,56 +205,19 @@ module ActiveRecord
|
|
|
168
205
|
end
|
|
169
206
|
end
|
|
170
207
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
# Make HTTP request to ClickHouse server
|
|
174
|
-
# @param [String] sql
|
|
175
|
-
# @param [String, nil] format
|
|
176
|
-
# @param [Hash] settings
|
|
177
|
-
# @return [Net::HTTPResponse]
|
|
178
|
-
def request(sql, format = nil, settings = {})
|
|
179
|
-
formatted_sql = apply_format(sql, format)
|
|
180
|
-
request_params = @connection_config || {}
|
|
181
|
-
@lock.synchronize do
|
|
182
|
-
@connection.post("/?#{request_params.merge(settings).to_param}", formatted_sql, {
|
|
183
|
-
'User-Agent' => "Clickhouse ActiveRecord #{ClickhouseActiverecord::VERSION}",
|
|
184
|
-
'Content-Type' => 'application/x-www-form-urlencoded',
|
|
185
|
-
})
|
|
186
|
-
end
|
|
187
|
-
end
|
|
208
|
+
protected
|
|
188
209
|
|
|
189
|
-
def
|
|
190
|
-
|
|
191
|
-
|
|
210
|
+
def table_structure(table_name)
|
|
211
|
+
result = do_system_execute("DESCRIBE TABLE `#{table_name}`", table_name)
|
|
212
|
+
data = result['data']
|
|
192
213
|
|
|
193
|
-
|
|
194
|
-
case res.code.to_i
|
|
195
|
-
when 200
|
|
196
|
-
body = res.body
|
|
214
|
+
return data unless data.empty?
|
|
197
215
|
|
|
198
|
-
|
|
199
|
-
raise ActiveRecord::ActiveRecordError, "Response code: #{res.code}:\n#{res.body}#{sql ? "\nQuery: #{sql}" : ''}"
|
|
200
|
-
else
|
|
201
|
-
format_body_response(res.body, format)
|
|
202
|
-
end
|
|
203
|
-
else
|
|
204
|
-
case res.body
|
|
205
|
-
when /DB::Exception:.*\(UNKNOWN_DATABASE\)/
|
|
206
|
-
raise ActiveRecord::NoDatabaseError
|
|
207
|
-
when /DB::Exception:.*\(DATABASE_ALREADY_EXISTS\)/
|
|
208
|
-
raise ActiveRecord::DatabaseAlreadyExists
|
|
209
|
-
else
|
|
210
|
-
raise ActiveRecord::ActiveRecordError, "Response code: #{res.code}:\n#{res.body}"
|
|
211
|
-
end
|
|
212
|
-
end
|
|
213
|
-
rescue JSON::ParserError
|
|
214
|
-
res.body
|
|
216
|
+
raise ActiveRecord::StatementInvalid, "Could not find table '#{table_name}'"
|
|
215
217
|
end
|
|
218
|
+
alias column_definitions table_structure
|
|
216
219
|
|
|
217
|
-
|
|
218
|
-
return yield unless @debug
|
|
219
|
-
log(sql, "#{name} (system)") { yield }
|
|
220
|
-
end
|
|
220
|
+
private
|
|
221
221
|
|
|
222
222
|
def schema_creation
|
|
223
223
|
Clickhouse::SchemaCreation.new(self)
|
|
@@ -228,29 +228,20 @@ module ActiveRecord
|
|
|
228
228
|
end
|
|
229
229
|
|
|
230
230
|
def new_column_from_field(table_name, field, _definitions)
|
|
231
|
-
sql_type = field
|
|
231
|
+
column_name, sql_type, default_type, default_expression = field
|
|
232
232
|
type_metadata = fetch_type_metadata(sql_type)
|
|
233
|
-
default_value = extract_value_from_default(
|
|
234
|
-
default_function = extract_default_function(
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
protected
|
|
240
|
-
|
|
241
|
-
def table_structure(table_name)
|
|
242
|
-
result = do_system_execute("DESCRIBE TABLE `#{table_name}`", table_name)
|
|
243
|
-
data = result['data']
|
|
233
|
+
default_value = extract_value_from_default(default_expression, default_type)
|
|
234
|
+
default_function = extract_default_function(default_expression)
|
|
235
|
+
cast_type = lookup_cast_type(sql_type)
|
|
236
|
+
default_value = cast_type.cast(default_value)
|
|
244
237
|
|
|
245
|
-
|
|
238
|
+
args = [column_name]
|
|
239
|
+
args << cast_type if ::ActiveRecord::version >= Gem::Version.new('8.1')
|
|
240
|
+
args += [default_value, type_metadata, field[1].include?('Nullable'), default_function]
|
|
246
241
|
|
|
247
|
-
|
|
242
|
+
Clickhouse::Column.new(*args, codec: field[5].presence)
|
|
248
243
|
end
|
|
249
|
-
alias column_definitions table_structure
|
|
250
|
-
|
|
251
|
-
private
|
|
252
244
|
|
|
253
|
-
# Extracts the value from a PostgreSQL column default definition.
|
|
254
245
|
def extract_value_from_default(default_expression, default_type)
|
|
255
246
|
return nil if default_type != 'DEFAULT' || default_expression.blank?
|
|
256
247
|
return nil if has_default_function?(default_expression)
|
|
@@ -269,42 +260,38 @@ module ActiveRecord
|
|
|
269
260
|
(%r{\w+\(.*\)} === default)
|
|
270
261
|
end
|
|
271
262
|
|
|
272
|
-
def
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
when 'JSONCompact'
|
|
277
|
-
format_from_json_compact(body)
|
|
278
|
-
when 'JSONCompactEachRowWithNamesAndTypes'
|
|
279
|
-
format_from_json_compact_each_row_with_names_and_types(body)
|
|
280
|
-
else
|
|
281
|
-
body
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
def format_from_json_compact(body)
|
|
286
|
-
parse_json_payload(body)
|
|
263
|
+
def raw_execute(sql, settings: {}, except_params: [])
|
|
264
|
+
statement = Statement.new(sql, format: @response_format)
|
|
265
|
+
statement.response = request(statement, settings: settings, except_params: except_params)
|
|
266
|
+
statement.processed_response
|
|
287
267
|
end
|
|
288
268
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
269
|
+
# Make HTTP request to ClickHouse server
|
|
270
|
+
# @param [ActiveRecord::ConnectionAdapters::Clickhouse::Statement] statement
|
|
271
|
+
# @param [Hash] settings
|
|
272
|
+
# @param [Array] except_params
|
|
273
|
+
# @return [Net::HTTPResponse]
|
|
274
|
+
def request(statement, settings: {}, except_params: [])
|
|
275
|
+
@lock.synchronize do
|
|
276
|
+
@connection.post("/?#{settings_params(settings, except: except_params)}",
|
|
277
|
+
statement.formatted_sql,
|
|
278
|
+
'Content-Type' => 'application/x-www-form-urlencoded',
|
|
279
|
+
'User-Agent' => ClickhouseAdapter::USER_AGENT)
|
|
298
280
|
end
|
|
281
|
+
end
|
|
299
282
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
283
|
+
def log_with_debug(sql, name = nil)
|
|
284
|
+
return yield unless @debug
|
|
285
|
+
log(sql, "#{name} (system)") { yield }
|
|
304
286
|
end
|
|
305
287
|
|
|
306
|
-
def
|
|
307
|
-
|
|
288
|
+
def settings_params(settings = {}, except: [])
|
|
289
|
+
request_params = @connection_config || {}
|
|
290
|
+
block_settings = @block_settings || {}
|
|
291
|
+
request_params.merge(block_settings)
|
|
292
|
+
.merge(settings)
|
|
293
|
+
.except(*except)
|
|
294
|
+
.to_param
|
|
308
295
|
end
|
|
309
296
|
end
|
|
310
297
|
end
|