activerecord-tidb-adapter 0.3.0 → 5.2.2
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/.buildkite/hooks/pre-command +10 -0
- data/.buildkite/pipeline.yml +7 -0
- data/.github/entrypoint.sh +16 -0
- data/.github/workflows/ci.yml +35 -0
- data/Gemfile +5 -1
- data/Gemfile.lock +66 -79
- data/README.md +66 -4
- data/Rakefile +1 -1
- data/activerecord-tidb-adapter.gemspec +1 -1
- data/lib/active_record/connection_adapters/tidb/database_statements.rb +19 -0
- data/lib/active_record/connection_adapters/tidb/schema_statements.rb +28 -0
- data/lib/active_record/connection_adapters/tidb/type.rb +2 -0
- data/lib/active_record/connection_adapters/tidb_adapter.rb +28 -4
- data/lib/active_record/sequence/adapter.rb +50 -0
- data/lib/active_record/sequence/command_recorder.rb +20 -0
- data/lib/active_record/sequence/model_methods.rb +22 -0
- data/lib/active_record/sequence/schema_dumper.rb +54 -0
- data/lib/active_record/sequence.rb +21 -0
- data/lib/version.rb +1 -1
- data/testing.sh +14 -0
- metadata +16 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ec81c5f43cb98b0fe8fb61484ea7b0050a84cb8c7caac6d25e314d58f5f1be0
|
4
|
+
data.tar.gz: 4a99eafd9d2f53885e063cc89af6ecf2afce3506e0f9b118a999e52c5fe93e71
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66909adaf233af63fb1f7f251cb8f11ba4a484c80e7646c9202c5636a7477575880f85927e01403ce26f8ebaa4a88c5eea6ffa1052a5a34d4e8b12d18f5cbb86
|
7
|
+
data.tar.gz: 8ad7289243de4d4f4e1b34d759be041f33c5b02d6b99428e9fc09ad918baa021751d708adc335c126495dce29eae9fca61a63cf7533711c7cd88cb6caf3511a3
|
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
set -eu
|
3
|
+
service supervisor start
|
4
|
+
|
5
|
+
while sleep 60; do
|
6
|
+
ps aux |grep tidb |grep -q -v grep
|
7
|
+
TIDB_STATUS=$?
|
8
|
+
ps aux |grep tikv |grep -q -v grep
|
9
|
+
TIKV_STATUS=$?
|
10
|
+
# If the greps above find anything, they exit with 0 status
|
11
|
+
# If they are not both 0, then something is wrong
|
12
|
+
if [ $TIDB_STATUS -ne 0 -o $TIKV_STATUS -ne 0 ]; then
|
13
|
+
echo "One of the processes has already exited."
|
14
|
+
exit 1
|
15
|
+
fi
|
16
|
+
done
|
@@ -0,0 +1,35 @@
|
|
1
|
+
name: activerecord-tidb-adapter ci
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches:
|
6
|
+
- 5-2-stable
|
7
|
+
paths-ignore:
|
8
|
+
- 'README*.md'
|
9
|
+
- 'docs/**'
|
10
|
+
pull_request:
|
11
|
+
branches:
|
12
|
+
- 5-2-stable
|
13
|
+
paths-ignore:
|
14
|
+
- 'README*.md'
|
15
|
+
- 'docs/**'
|
16
|
+
|
17
|
+
jobs:
|
18
|
+
build:
|
19
|
+
if: ${{ !contains(github.event.commits[0].message, '[skip ci]') }}
|
20
|
+
runs-on: ubuntu-latest
|
21
|
+
services:
|
22
|
+
tidb:
|
23
|
+
image: hawkingrei/tind:v5.1.0
|
24
|
+
options: --entrypoint /entrypoint.sh
|
25
|
+
env:
|
26
|
+
TIDB_VERSION: v5.1.0
|
27
|
+
ports: ["4000:4000"]
|
28
|
+
steps:
|
29
|
+
- uses: actions/checkout@v2
|
30
|
+
- uses: ruby/setup-ruby@v1
|
31
|
+
with:
|
32
|
+
ruby-version: 2.7
|
33
|
+
bundler-cache: true
|
34
|
+
- run: sleep 30 && MYSQL_USER=root MYSQL_HOST=127.0.0.1 MYSQL_PORT=4000 tidb=1 ARCONN=tidb bundle exec rake db:tidb:build
|
35
|
+
- run: sleep 10 && MYSQL_USER=root MYSQL_HOST=127.0.0.1 MYSQL_PORT=4000 tidb=1 ARCONN=tidb bundle exec rake test:tidb
|
data/Gemfile
CHANGED
@@ -14,10 +14,14 @@ gem 'pry'
|
|
14
14
|
|
15
15
|
gem 'rubocop', '~> 1.18'
|
16
16
|
|
17
|
-
gem 'rails', git: 'https://github.com/
|
17
|
+
gem 'rails', git: 'https://github.com/pingcap/rails.git', branch: '5-2-stable'
|
18
18
|
|
19
19
|
gem 'byebug', '~> 11.1'
|
20
20
|
|
21
21
|
gem 'sqlite3', '~> 1.4'
|
22
22
|
|
23
23
|
gem 'pg', '~> 1.2'
|
24
|
+
|
25
|
+
gem "mocha", "~> 1.13"
|
26
|
+
|
27
|
+
gem "bcrypt", "~> 3.1"
|
data/Gemfile.lock
CHANGED
@@ -1,100 +1,82 @@
|
|
1
1
|
GIT
|
2
|
-
remote: https://github.com/
|
3
|
-
revision:
|
4
|
-
branch:
|
2
|
+
remote: https://github.com/pingcap/rails.git
|
3
|
+
revision: a1adbde17b229e9131d40787ee4342c1180afb36
|
4
|
+
branch: 5-2-stable
|
5
5
|
specs:
|
6
|
-
actioncable (
|
7
|
-
actionpack (=
|
8
|
-
activesupport (= 6.1.4)
|
6
|
+
actioncable (5.2.6)
|
7
|
+
actionpack (= 5.2.6)
|
9
8
|
nio4r (~> 2.0)
|
10
9
|
websocket-driver (>= 0.6.1)
|
11
|
-
|
12
|
-
actionpack (=
|
13
|
-
|
14
|
-
|
15
|
-
activestorage (= 6.1.4)
|
16
|
-
activesupport (= 6.1.4)
|
17
|
-
mail (>= 2.7.1)
|
18
|
-
actionmailer (6.1.4)
|
19
|
-
actionpack (= 6.1.4)
|
20
|
-
actionview (= 6.1.4)
|
21
|
-
activejob (= 6.1.4)
|
22
|
-
activesupport (= 6.1.4)
|
10
|
+
actionmailer (5.2.6)
|
11
|
+
actionpack (= 5.2.6)
|
12
|
+
actionview (= 5.2.6)
|
13
|
+
activejob (= 5.2.6)
|
23
14
|
mail (~> 2.5, >= 2.5.4)
|
24
15
|
rails-dom-testing (~> 2.0)
|
25
|
-
actionpack (
|
26
|
-
actionview (=
|
27
|
-
activesupport (=
|
28
|
-
rack (~> 2.0, >= 2.0.
|
16
|
+
actionpack (5.2.6)
|
17
|
+
actionview (= 5.2.6)
|
18
|
+
activesupport (= 5.2.6)
|
19
|
+
rack (~> 2.0, >= 2.0.8)
|
29
20
|
rack-test (>= 0.6.3)
|
30
21
|
rails-dom-testing (~> 2.0)
|
31
|
-
rails-html-sanitizer (~> 1.0, >= 1.2
|
32
|
-
|
33
|
-
|
34
|
-
activerecord (= 6.1.4)
|
35
|
-
activestorage (= 6.1.4)
|
36
|
-
activesupport (= 6.1.4)
|
37
|
-
nokogiri (>= 1.8.5)
|
38
|
-
actionview (6.1.4)
|
39
|
-
activesupport (= 6.1.4)
|
22
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
23
|
+
actionview (5.2.6)
|
24
|
+
activesupport (= 5.2.6)
|
40
25
|
builder (~> 3.1)
|
41
26
|
erubi (~> 1.4)
|
42
27
|
rails-dom-testing (~> 2.0)
|
43
|
-
rails-html-sanitizer (~> 1.
|
44
|
-
activejob (
|
45
|
-
activesupport (=
|
28
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
29
|
+
activejob (5.2.6)
|
30
|
+
activesupport (= 5.2.6)
|
46
31
|
globalid (>= 0.3.6)
|
47
|
-
activemodel (
|
48
|
-
activesupport (=
|
49
|
-
activerecord (
|
50
|
-
activemodel (=
|
51
|
-
activesupport (=
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
activerecord (=
|
56
|
-
activesupport (= 6.1.4)
|
32
|
+
activemodel (5.2.6)
|
33
|
+
activesupport (= 5.2.6)
|
34
|
+
activerecord (5.2.6)
|
35
|
+
activemodel (= 5.2.6)
|
36
|
+
activesupport (= 5.2.6)
|
37
|
+
arel (>= 9.0)
|
38
|
+
activestorage (5.2.6)
|
39
|
+
actionpack (= 5.2.6)
|
40
|
+
activerecord (= 5.2.6)
|
57
41
|
marcel (~> 1.0.0)
|
58
|
-
|
59
|
-
activesupport (6.1.4)
|
42
|
+
activesupport (5.2.6)
|
60
43
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
61
|
-
i18n (>=
|
62
|
-
minitest (
|
63
|
-
tzinfo (~>
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
activesupport (= 6.1.4)
|
77
|
-
bundler (>= 1.15.0)
|
78
|
-
railties (= 6.1.4)
|
44
|
+
i18n (>= 0.7, < 2)
|
45
|
+
minitest (~> 5.1)
|
46
|
+
tzinfo (~> 1.1)
|
47
|
+
rails (5.2.6)
|
48
|
+
actioncable (= 5.2.6)
|
49
|
+
actionmailer (= 5.2.6)
|
50
|
+
actionpack (= 5.2.6)
|
51
|
+
actionview (= 5.2.6)
|
52
|
+
activejob (= 5.2.6)
|
53
|
+
activemodel (= 5.2.6)
|
54
|
+
activerecord (= 5.2.6)
|
55
|
+
activestorage (= 5.2.6)
|
56
|
+
activesupport (= 5.2.6)
|
57
|
+
bundler (>= 1.3.0)
|
58
|
+
railties (= 5.2.6)
|
79
59
|
sprockets-rails (>= 2.0.0)
|
80
|
-
railties (
|
81
|
-
actionpack (=
|
82
|
-
activesupport (=
|
60
|
+
railties (5.2.6)
|
61
|
+
actionpack (= 5.2.6)
|
62
|
+
activesupport (= 5.2.6)
|
83
63
|
method_source
|
84
|
-
rake (>= 0.
|
85
|
-
thor (
|
64
|
+
rake (>= 0.8.7)
|
65
|
+
thor (>= 0.19.0, < 2.0)
|
86
66
|
|
87
67
|
PATH
|
88
68
|
remote: .
|
89
69
|
specs:
|
90
|
-
activerecord-tidb-adapter (
|
91
|
-
activerecord (~>
|
70
|
+
activerecord-tidb-adapter (5.2.2)
|
71
|
+
activerecord (~> 5.2)
|
92
72
|
mysql2
|
93
73
|
|
94
74
|
GEM
|
95
75
|
remote: https://rubygems.org/
|
96
76
|
specs:
|
77
|
+
arel (9.0.0)
|
97
78
|
ast (2.4.2)
|
79
|
+
bcrypt (3.1.16)
|
98
80
|
builder (3.2.4)
|
99
81
|
byebug (11.1.3)
|
100
82
|
coderay (1.1.3)
|
@@ -105,7 +87,7 @@ GEM
|
|
105
87
|
activesupport (>= 5.0)
|
106
88
|
i18n (1.8.10)
|
107
89
|
concurrent-ruby (~> 1.0)
|
108
|
-
loofah (2.
|
90
|
+
loofah (2.12.0)
|
109
91
|
crass (~> 1.0.2)
|
110
92
|
nokogiri (>= 1.5.9)
|
111
93
|
mail (2.7.1)
|
@@ -116,8 +98,11 @@ GEM
|
|
116
98
|
minitest (5.14.4)
|
117
99
|
minitest-excludes (2.0.1)
|
118
100
|
minitest (~> 5.0)
|
101
|
+
mocha (1.13.0)
|
119
102
|
mysql2 (0.5.3)
|
120
103
|
nio4r (2.5.8)
|
104
|
+
nokogiri (1.12.3-x86_64-darwin)
|
105
|
+
racc (~> 1.4)
|
121
106
|
nokogiri (1.12.3-x86_64-linux)
|
122
107
|
racc (~> 1.4)
|
123
108
|
parallel (1.20.1)
|
@@ -134,22 +119,22 @@ GEM
|
|
134
119
|
rails-dom-testing (2.0.3)
|
135
120
|
activesupport (>= 4.2.0)
|
136
121
|
nokogiri (>= 1.6)
|
137
|
-
rails-html-sanitizer (1.
|
122
|
+
rails-html-sanitizer (1.4.1)
|
138
123
|
loofah (~> 2.3)
|
139
124
|
rainbow (3.0.0)
|
140
125
|
rake (13.0.6)
|
141
126
|
regexp_parser (2.1.1)
|
142
127
|
rexml (3.2.5)
|
143
|
-
rubocop (1.
|
128
|
+
rubocop (1.19.0)
|
144
129
|
parallel (~> 1.10)
|
145
130
|
parser (>= 3.0.0.0)
|
146
131
|
rainbow (>= 2.2.2, < 4.0)
|
147
132
|
regexp_parser (>= 1.8, < 3.0)
|
148
133
|
rexml
|
149
|
-
rubocop-ast (>= 1.
|
134
|
+
rubocop-ast (>= 1.9.1, < 2.0)
|
150
135
|
ruby-progressbar (~> 1.7)
|
151
136
|
unicode-display_width (>= 1.4.0, < 3.0)
|
152
|
-
rubocop-ast (1.
|
137
|
+
rubocop-ast (1.10.0)
|
153
138
|
parser (>= 3.0.1.1)
|
154
139
|
ruby-progressbar (1.11.0)
|
155
140
|
sprockets (4.0.2)
|
@@ -161,13 +146,13 @@ GEM
|
|
161
146
|
sprockets (>= 3.0.0)
|
162
147
|
sqlite3 (1.4.2)
|
163
148
|
thor (1.1.0)
|
164
|
-
|
165
|
-
|
149
|
+
thread_safe (0.3.6)
|
150
|
+
tzinfo (1.2.9)
|
151
|
+
thread_safe (~> 0.1)
|
166
152
|
unicode-display_width (2.0.0)
|
167
153
|
websocket-driver (0.7.5)
|
168
154
|
websocket-extensions (>= 0.1.0)
|
169
155
|
websocket-extensions (0.1.5)
|
170
|
-
zeitwerk (2.4.2)
|
171
156
|
|
172
157
|
PLATFORMS
|
173
158
|
x86_64-darwin-18
|
@@ -175,9 +160,11 @@ PLATFORMS
|
|
175
160
|
|
176
161
|
DEPENDENCIES
|
177
162
|
activerecord-tidb-adapter!
|
163
|
+
bcrypt (~> 3.1)
|
178
164
|
byebug (~> 11.1)
|
179
165
|
minitest (~> 5.0)
|
180
166
|
minitest-excludes (~> 2.0)
|
167
|
+
mocha (~> 1.13)
|
181
168
|
pg (~> 1.2)
|
182
169
|
pry
|
183
170
|
rails!
|
data/README.md
CHANGED
@@ -8,7 +8,7 @@ TiDB adapter for ActiveRecord 5 and 6. This is a lightweight extension of the my
|
|
8
8
|
Add this line to your application's Gemfile:
|
9
9
|
|
10
10
|
```ruby
|
11
|
-
gem 'activerecord-tidb-adapter'
|
11
|
+
gem 'activerecord-tidb-adapter', "~> 5.2.2"
|
12
12
|
```
|
13
13
|
|
14
14
|
And then execute:
|
@@ -44,6 +44,62 @@ development:
|
|
44
44
|
|
45
45
|
* demo repo with rails 6.1.4: https://github.com/hooopo/activerecord-tidb-adapter-demo
|
46
46
|
|
47
|
+
## TiDB features
|
48
|
+
|
49
|
+
**[Sequence](https://docs.pingcap.com/tidb/stable/sql-statement-create-sequence)**
|
50
|
+
|
51
|
+
Sequence as primary key
|
52
|
+
|
53
|
+
```ruby
|
54
|
+
class TestSeq < ActiveRecord::Migration[6.1]
|
55
|
+
def up
|
56
|
+
# more options: increment, min_value, cycle, cache
|
57
|
+
create_sequence :orders_seq, start: 1024
|
58
|
+
create_table :orders, id: false do |t|
|
59
|
+
t.primary_key :id, default: -> { "nextval(orders_seq)" }
|
60
|
+
t.string :name
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def down
|
65
|
+
drop_table :orders
|
66
|
+
drop_sequence :orders_seq
|
67
|
+
end
|
68
|
+
end
|
69
|
+
```
|
70
|
+
|
71
|
+
Generated DDL
|
72
|
+
```sql
|
73
|
+
mysql> show create table orders_seq\G;
|
74
|
+
*************************** 1. row ***************************
|
75
|
+
Sequence: orders_seq
|
76
|
+
Create Sequence: CREATE SEQUENCE `orders_seq` start with 1024 minvalue 1 maxvalue 9223372036854775806 increment by 1 nocache nocycle ENGINE=InnoDB
|
77
|
+
|
78
|
+
mysql> show create table orders\G;
|
79
|
+
*************************** 1. row ***************************
|
80
|
+
Table: orders
|
81
|
+
Create Table: CREATE TABLE `orders` (
|
82
|
+
`id` bigint(20) NOT NULL DEFAULT nextval(`activerecord_tidb_adapter_demo_development`.`orders_seq`),
|
83
|
+
`name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL,
|
84
|
+
PRIMARY KEY (`id`) /*T![clustered_index] CLUSTERED */
|
85
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci
|
86
|
+
|
87
|
+
```
|
88
|
+
|
89
|
+
This gem also adds a few helpers to interact with `SEQUENCE`
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
# Advance sequence and return new value
|
93
|
+
ActiveRecord::Base.nextval("numbers")
|
94
|
+
|
95
|
+
# Return value most recently obtained with nextval for specified sequence.
|
96
|
+
ActiveRecord::Base.lastval("numbers")
|
97
|
+
|
98
|
+
# Set sequence's current value
|
99
|
+
ActiveRecord::Base.setval("numbers", 1234)
|
100
|
+
```
|
101
|
+
|
102
|
+
|
47
103
|
## Setting up local TiDB server
|
48
104
|
|
49
105
|
Install [tiup](https://github.com/pingcap/tiup)
|
@@ -84,16 +140,22 @@ MYSQL_USER=root MYSQL_HOST=127.0.0.1 MYSQL_PORT=4000 tidb=1 ARCONN=tidb bundle e
|
|
84
140
|
|
85
141
|
```
|
86
142
|
|
87
|
-
run tidb adapter tests
|
143
|
+
run tidb adapter tests and activerecord buildin tests
|
144
|
+
|
145
|
+
```
|
146
|
+
MYSQL_USER=root MYSQL_HOST=127.0.0.1 MYSQL_PORT=4000 tidb=1 ARCONN=tidb bundle exec rake test:tidb
|
88
147
|
|
89
148
|
```
|
90
|
-
MYSQL_USER=root MYSQL_HOST=127.0.0.1 MYSQL_PORT=4000 tidb=1 ARCONN=tidb bundle exec rake test:idb
|
91
149
|
|
150
|
+
run **ONLY** tidb adapter tests using `ONLY_TEST_TIDB` env:
|
151
|
+
|
152
|
+
```
|
153
|
+
ONLY_TEST_TIDB=1 MYSQL_USER=root MYSQL_HOST=127.0.0.1 MYSQL_PORT=4000 tidb=1 ARCONN=tidb bundle exec rake test:tidb
|
92
154
|
```
|
93
155
|
|
94
156
|
## Contributing
|
95
157
|
|
96
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
158
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/pingcap/activerecord-tidb-adapter.
|
97
159
|
|
98
160
|
## License
|
99
161
|
|
data/Rakefile
CHANGED
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
|
|
29
29
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
30
30
|
spec.require_paths = ['lib']
|
31
31
|
|
32
|
-
spec.add_dependency 'activerecord', '~>
|
32
|
+
spec.add_dependency 'activerecord', '~> 5.2'
|
33
33
|
spec.add_dependency 'mysql2'
|
34
34
|
|
35
35
|
# Uncomment to register a new dependency of your gem
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'active_record/connection_adapters/abstract/database_statements'
|
2
|
+
|
3
|
+
ActiveRecord::ConnectionAdapters::DatabaseStatements.class_eval do
|
4
|
+
def insert(arel, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = [])
|
5
|
+
sql, binds = to_sql_and_binds(arel, binds)
|
6
|
+
value = exec_insert(sql, name, binds, pk, sequence_name)
|
7
|
+
|
8
|
+
return id_value if id_value.present?
|
9
|
+
return last_inserted_id(value) if arel.is_a?(String)
|
10
|
+
table_name = arel.ast.relation.table_name
|
11
|
+
pk_def = schema_cache.columns_hash(table_name)[pk]
|
12
|
+
if pk_def&.default_function && pk_def.default_function =~ /nextval/
|
13
|
+
query_value("SELECT #{pk_def.default_function.sub('nextval', 'lastval')}")
|
14
|
+
else
|
15
|
+
last_inserted_id(value)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
alias create insert
|
19
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'pry'
|
2
|
+
require 'active_record/connection_adapters/mysql/schema_statements'
|
3
|
+
|
4
|
+
|
5
|
+
ActiveRecord::ConnectionAdapters::MySQL::SchemaStatements.class_eval do
|
6
|
+
def new_column_from_field(table_name, field)
|
7
|
+
type_metadata = fetch_type_metadata(field[:Type], field[:Extra])
|
8
|
+
if type_metadata.type == :datetime && /\ACURRENT_TIMESTAMP(?:\([0-6]?\))?\z/i.match?(field[:Default])
|
9
|
+
default, default_function = nil, field[:Default]
|
10
|
+
elsif field[:Default].to_s =~ /nextval/i
|
11
|
+
default_function = field[:Default]
|
12
|
+
default = nil
|
13
|
+
else
|
14
|
+
default, default_function = field[:Default], nil
|
15
|
+
end
|
16
|
+
|
17
|
+
ActiveRecord::ConnectionAdapters::MySQL::Column.new(
|
18
|
+
field[:Field],
|
19
|
+
default,
|
20
|
+
type_metadata,
|
21
|
+
field[:Null] == "YES",
|
22
|
+
table_name,
|
23
|
+
default_function,
|
24
|
+
field[:Collation],
|
25
|
+
comment: field[:Comment].presence
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
@@ -1,16 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'active_record/connection_adapters'
|
4
3
|
require 'active_record/connection_adapters/mysql2_adapter'
|
5
4
|
require 'active_record/connection_adapters/tidb/setup'
|
6
5
|
require_relative '../../version'
|
6
|
+
require_relative '../sequence'
|
7
|
+
require_relative 'tidb/database_statements'
|
8
|
+
require_relative 'tidb/schema_statements'
|
7
9
|
|
8
10
|
ActiveRecord::ConnectionAdapters::Tidb.initial_setup
|
9
11
|
|
10
12
|
module ActiveRecord
|
11
|
-
module ConnectionHandling
|
13
|
+
module ConnectionHandling # :nodoc:
|
12
14
|
# Establishes a connection to the database that's used by all Active Record objects.
|
13
|
-
def tidb_connection(config)
|
15
|
+
def tidb_connection(config) # :nodoc:
|
14
16
|
config = config.symbolize_keys
|
15
17
|
config[:flags] ||= 0
|
16
18
|
|
@@ -29,8 +31,30 @@ module ActiveRecord
|
|
29
31
|
end
|
30
32
|
end
|
31
33
|
|
34
|
+
|
35
|
+
|
32
36
|
module ConnectionAdapters
|
37
|
+
class Mysql2Adapter < AbstractMysqlAdapter
|
38
|
+
ER_BAD_DB_ERROR = 1049
|
39
|
+
ADAPTER_NAME = "Mysql2"
|
40
|
+
|
41
|
+
include MySQL::DatabaseStatements
|
42
|
+
|
43
|
+
class << self
|
44
|
+
def new_client(config)
|
45
|
+
Mysql2::Client.new(config)
|
46
|
+
rescue Mysql2::Error => error
|
47
|
+
if error.error_number == ConnectionAdapters::Mysql2Adapter::ER_BAD_DB_ERROR
|
48
|
+
raise ActiveRecord::NoDatabaseError
|
49
|
+
else
|
50
|
+
raise ActiveRecord::ConnectionNotEstablished, error.message
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
33
56
|
class TidbAdapter < Mysql2Adapter
|
57
|
+
include ActiveRecord::Sequence::Adapter
|
34
58
|
ADAPTER_NAME = 'Tidb'
|
35
59
|
|
36
60
|
def supports_savepoints?
|
@@ -93,7 +117,7 @@ module ActiveRecord
|
|
93
117
|
end
|
94
118
|
|
95
119
|
def self.database_exists?(config)
|
96
|
-
|
120
|
+
!ActiveRecord::Base.tidb_connection(config).nil?
|
97
121
|
rescue ActiveRecord::NoDatabaseError
|
98
122
|
false
|
99
123
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Sequence
|
5
|
+
module Adapter
|
6
|
+
def check_sequences
|
7
|
+
select_all(
|
8
|
+
'SELECT * FROM information_schema.sequences ORDER BY sequence_name'
|
9
|
+
).to_a
|
10
|
+
end
|
11
|
+
|
12
|
+
def create_sequence(name, options = {})
|
13
|
+
increment = options[:increment] || options[:step]
|
14
|
+
name = quote_column_name(name)
|
15
|
+
|
16
|
+
sql = ["CREATE SEQUENCE IF NOT EXISTS #{name}"]
|
17
|
+
sql << "INCREMENT BY #{increment}" if increment
|
18
|
+
sql << "START WITH #{options[:start]}" if options[:start]
|
19
|
+
sql << if options[:cache]
|
20
|
+
"CACHE #{options[:cache]}"
|
21
|
+
else
|
22
|
+
'NOCACHE'
|
23
|
+
end
|
24
|
+
|
25
|
+
sql << if options[:cycle]
|
26
|
+
'CYCLE'
|
27
|
+
else
|
28
|
+
'NOCYCLE'
|
29
|
+
end
|
30
|
+
|
31
|
+
sql << "MIN_VALUE #{options[:min_value]}" if options[:min_value]
|
32
|
+
|
33
|
+
sql << "COMMENT #{quote(options[:comment].to_s)}" if options[:comment]
|
34
|
+
|
35
|
+
execute(sql.join("\n"))
|
36
|
+
end
|
37
|
+
|
38
|
+
def drop_sequence(name)
|
39
|
+
name = quote_column_name(name)
|
40
|
+
sql = "DROP SEQUENCE IF EXISTS #{name}"
|
41
|
+
execute(sql)
|
42
|
+
end
|
43
|
+
|
44
|
+
def recreate_sequence(name, options = {})
|
45
|
+
drop_sequence(name)
|
46
|
+
create_sequence(name, options)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Sequence
|
5
|
+
module CommandRecorder
|
6
|
+
def create_sequence(name, options = {})
|
7
|
+
record(__method__, [name, options])
|
8
|
+
end
|
9
|
+
|
10
|
+
def drop_sequence(name)
|
11
|
+
record(__method__, [name])
|
12
|
+
end
|
13
|
+
|
14
|
+
def invert_create_sequence(args)
|
15
|
+
name, = args
|
16
|
+
[:drop_sequence, [name]]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Sequence
|
5
|
+
module ModelMethods
|
6
|
+
def nextval(name)
|
7
|
+
name = connection.quote_column_name(name)
|
8
|
+
connection.query_value("SELECT nextval(#{name})")
|
9
|
+
end
|
10
|
+
|
11
|
+
def lastval(name)
|
12
|
+
name = connection.quote_column_name(name)
|
13
|
+
connection.query_value("SELECT lastval(#{name})")
|
14
|
+
end
|
15
|
+
|
16
|
+
def setval(name, value)
|
17
|
+
name = connection.quote_column_name(name)
|
18
|
+
connection.query_value("SELECT setval(#{name}, #{value})")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Sequence
|
5
|
+
module SchemaDumper
|
6
|
+
def header(stream)
|
7
|
+
super
|
8
|
+
sequences(stream)
|
9
|
+
end
|
10
|
+
|
11
|
+
def sequences(stream)
|
12
|
+
sequences = @connection.check_sequences
|
13
|
+
return if sequences.empty?
|
14
|
+
|
15
|
+
sequences.each do |seq|
|
16
|
+
start_value = seq['START']
|
17
|
+
increment = seq['INCREMENT']
|
18
|
+
cache = seq['CACHE']
|
19
|
+
cache_value = seq['CACHE_VALUE']
|
20
|
+
min_value = seq['MIN_VALUE']
|
21
|
+
cycle = seq['CYCLE']
|
22
|
+
comment = seq['COMMENT']
|
23
|
+
|
24
|
+
options = []
|
25
|
+
|
26
|
+
options << "start: #{start_value}" if start_value && Integer(start_value) != 1
|
27
|
+
|
28
|
+
options << "increment: #{increment}" if increment && Integer(increment) != 1
|
29
|
+
|
30
|
+
options << "cache: #{cache_value}" if cache_value && Integer(cache_value) != 0
|
31
|
+
|
32
|
+
options << "min_value: #{min_value}" if min_value
|
33
|
+
|
34
|
+
options << 'cycle: true' if cycle.to_i != 0
|
35
|
+
|
36
|
+
options << "comment: #{comment.inspect}" if comment.present?
|
37
|
+
|
38
|
+
statement = [
|
39
|
+
'create_sequence',
|
40
|
+
seq['SEQUENCE_NAME'].inspect
|
41
|
+
].join(' ')
|
42
|
+
|
43
|
+
if options.any?
|
44
|
+
statement << (options.any? ? ", #{options.join(', ')}" : '')
|
45
|
+
end
|
46
|
+
|
47
|
+
stream.puts " #{statement}"
|
48
|
+
end
|
49
|
+
|
50
|
+
stream.puts
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/all'
|
4
|
+
require 'active_record'
|
5
|
+
require 'active_record/connection_adapters/mysql/schema_dumper'
|
6
|
+
require 'active_record/migration/command_recorder'
|
7
|
+
require 'active_record/schema_dumper'
|
8
|
+
|
9
|
+
module ActiveRecord
|
10
|
+
module Sequence
|
11
|
+
require 'active_record/sequence/command_recorder'
|
12
|
+
require 'active_record/sequence/adapter'
|
13
|
+
require 'active_record/sequence/schema_dumper'
|
14
|
+
require 'active_record/sequence/model_methods'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
ActiveRecord::Migration::CommandRecorder.include(ActiveRecord::Sequence::CommandRecorder)
|
19
|
+
|
20
|
+
ActiveRecord::SchemaDumper.prepend(ActiveRecord::Sequence::SchemaDumper)
|
21
|
+
ActiveRecord::Base.extend(ActiveRecord::Sequence::ModelMethods)
|
data/lib/version.rb
CHANGED
data/testing.sh
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -eo pipefail
|
4
|
+
|
5
|
+
bundle config set --local path '/tmp/buildkite-cache'
|
6
|
+
|
7
|
+
echo "Setup gem mirror"
|
8
|
+
bundle config mirror.https://rubygems.org https://gems.ruby-china.com
|
9
|
+
|
10
|
+
echo "Bundle install"
|
11
|
+
bundle install
|
12
|
+
|
13
|
+
echo "Setup database for testing"
|
14
|
+
tidb=1 ARCONN=tidb bundle exec rake db:tidb:rebuild && tidb=1 ARCONN=tidb bundle exec rake test:tidb
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-tidb-adapter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hooopo Wang
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-08-
|
11
|
+
date: 2021-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '5.2'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '5.2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: mysql2
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,6 +45,10 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
+
- ".buildkite/hooks/pre-command"
|
49
|
+
- ".buildkite/pipeline.yml"
|
50
|
+
- ".github/entrypoint.sh"
|
51
|
+
- ".github/workflows/ci.yml"
|
48
52
|
- ".gitignore"
|
49
53
|
- Gemfile
|
50
54
|
- Gemfile.lock
|
@@ -55,12 +59,20 @@ files:
|
|
55
59
|
- bin/console
|
56
60
|
- bin/setup
|
57
61
|
- config.toml
|
62
|
+
- lib/active_record/connection_adapters/tidb/database_statements.rb
|
58
63
|
- lib/active_record/connection_adapters/tidb/database_tasks.rb
|
64
|
+
- lib/active_record/connection_adapters/tidb/schema_statements.rb
|
59
65
|
- lib/active_record/connection_adapters/tidb/setup.rb
|
60
66
|
- lib/active_record/connection_adapters/tidb/type.rb
|
61
67
|
- lib/active_record/connection_adapters/tidb_adapter.rb
|
68
|
+
- lib/active_record/sequence.rb
|
69
|
+
- lib/active_record/sequence/adapter.rb
|
70
|
+
- lib/active_record/sequence/command_recorder.rb
|
71
|
+
- lib/active_record/sequence/model_methods.rb
|
72
|
+
- lib/active_record/sequence/schema_dumper.rb
|
62
73
|
- lib/activerecord-tidb-adapter.rb
|
63
74
|
- lib/version.rb
|
75
|
+
- testing.sh
|
64
76
|
homepage: https://github.com/pingcap/activerecord-tidb-adapter
|
65
77
|
licenses:
|
66
78
|
- Apache-2.0
|