github.com/matrixorigin/matrixone@v0.7.0/pkg/tests/txn/sql_client.go (about) 1 // Copyright 2021 - 2022 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package txn 16 17 import ( 18 "context" 19 "database/sql" 20 "fmt" 21 "sync" 22 23 _ "github.com/go-sql-driver/mysql" 24 "github.com/matrixorigin/matrixone/pkg/common/moerr" 25 "github.com/matrixorigin/matrixone/pkg/tests/service" 26 "github.com/matrixorigin/matrixone/pkg/txn/client" 27 "go.uber.org/multierr" 28 "go.uber.org/zap" 29 ) 30 31 var ( 32 createDB = `create database if not exists kv_test` 33 useDB = `use kv_test;` 34 createSql = `create table if not exists txn_test_kv (kv_key varchar(20) primary key, kv_value varchar(10))` 35 ) 36 37 // sqlClient use sql client to connect to CN node and use a table to simulate rr test KV operations 38 type sqlClient struct { 39 cn service.CNService 40 } 41 42 func newSQLClient(logger *zap.Logger, env service.Cluster) (Client, error) { 43 cn, err := env.GetCNServiceIndexed(0) 44 if err != nil { 45 return nil, err 46 } 47 48 db, err := sql.Open("mysql", fmt.Sprintf("dump:111@tcp(%s)/", cn.SQLAddress())) 49 if err != nil { 50 return nil, err 51 } 52 53 _, err = db.Exec(createDB) 54 if err != nil { 55 return nil, multierr.Append(err, db.Close()) 56 } 57 58 _, err = db.Exec(useDB) 59 if err != nil { 60 return nil, multierr.Append(err, db.Close()) 61 } 62 63 _, err = db.Exec(createSql) 64 if err != nil { 65 return nil, multierr.Append(err, db.Close()) 66 } 67 68 return &sqlClient{ 69 cn: cn, 70 }, multierr.Append(err, db.Close()) 71 } 72 73 func (c *sqlClient) NewTxn(options ...client.TxnOption) (Txn, error) { 74 return newSQLTxn(c.cn) 75 } 76 77 type sqlTxn struct { 78 db *sql.DB 79 txn *sql.Tx 80 81 mu struct { 82 sync.Mutex 83 closed bool 84 } 85 } 86 87 func newSQLTxn(cn service.CNService) (Txn, error) { 88 db, err := sql.Open("mysql", fmt.Sprintf("dump:111@tcp(%s)/kv_test", cn.SQLAddress())) 89 if err != nil { 90 return nil, err 91 } 92 93 txn, err := db.Begin() 94 if err != nil { 95 return nil, multierr.Append(err, db.Close()) 96 } 97 return &sqlTxn{ 98 db: db, 99 txn: txn, 100 }, nil 101 } 102 103 func (kop *sqlTxn) Commit() error { 104 kop.mu.Lock() 105 defer kop.mu.Unlock() 106 if kop.mu.closed { 107 return moerr.NewTxnClosed(context.Background(), nil) 108 } 109 110 kop.mu.closed = true 111 err := kop.txn.Commit() 112 if err != nil { 113 return multierr.Append(err, kop.db.Close()) 114 } 115 return kop.db.Close() 116 } 117 118 func (kop *sqlTxn) Rollback() error { 119 kop.mu.Lock() 120 defer kop.mu.Unlock() 121 if kop.mu.closed { 122 return nil 123 } 124 125 kop.mu.closed = true 126 err := kop.txn.Rollback() 127 if err != nil { 128 return multierr.Append(err, kop.db.Close()) 129 } 130 return kop.db.Close() 131 } 132 133 func (kop *sqlTxn) Read(key string) (string, error) { 134 rows, err := kop.txn.Query(fmt.Sprintf("select kv_value from txn_test_kv where kv_key = '%s'", key)) 135 if err != nil { 136 return "", err 137 } 138 139 if !rows.Next() { 140 return "", rows.Close() 141 } 142 v := "" 143 if err := rows.Scan(&v); err != nil { 144 return "", multierr.Append(err, rows.Close()) 145 } 146 return v, multierr.Append(err, rows.Close()) 147 } 148 149 func (kop *sqlTxn) Write(key, value string) error { 150 v, err := kop.Read(key) 151 if err != nil { 152 return err 153 } 154 155 if v == "" { 156 return kop.insert(key, value) 157 } 158 return kop.update(key, value) 159 } 160 161 func (kop *sqlTxn) ExecSQL(sql string) (sql.Result, error) { 162 return kop.txn.Exec(sql) 163 } 164 165 func (kop *sqlTxn) ExecSQLQuery(sql string) (*sql.Rows, error) { 166 return kop.txn.Query(sql) 167 } 168 169 func (kop *sqlTxn) insert(key, value string) error { 170 res, err := kop.txn.Exec(fmt.Sprintf("insert into txn_test_kv(kv_key, kv_value) values('%s', '%s')", key, value)) 171 if err != nil { 172 return err 173 } 174 n, err := res.RowsAffected() 175 if err != nil { 176 panic(err) 177 } 178 if n != 1 { 179 panic(n) 180 } 181 return err 182 } 183 184 func (kop *sqlTxn) update(key, value string) error { 185 _, err := kop.txn.Exec(fmt.Sprintf("update txn_test_kv set kv_value = '%s' where kv_key = '%s'", value, key)) 186 return err 187 }