代码拉取完成,页面将自动刷新
package gbase8s
import (
"context"
"database/sql"
"fmt"
"log"
"os"
"reflect"
"strconv"
"strings"
"sync"
"testing"
"time"
)
// testGetDB connects to the test database and returns the database connection
func testGetDB(params string) *sql.DB {
Driver.Logger = log.New(os.Stderr, "gbase8s ", log.Ldate|log.Ltime|log.LUTC|log.Lshortfile)
var openString string
// [username/[password]@]host[:port][/service_name][?param1=value1&...¶mN=valueN]
if len(TestUsername) > 0 {
if len(TestPassword) > 0 {
openString = TestUsername + "/" + TestPassword + "@"
} else {
openString = TestUsername + "@"
}
}
openString += TestHostValid + params
//openString = "gbase8s://root:rootroot@192.168.43.170:16761/d1?GBASEDBTSERVER=ol_gbasedbt1210_1&PROTOCOL=onsoctcp&sqlmode=oracle&delimident=1&gbasedbtdir=%2Fhome%2Fgtest%2FGBaseGCI_3.5.0_8_20240909_13044d_RHEL6_x86_64%2Frelyon%2F&GCI_FACTORY=4&GoGCILogTrace=0"
db, err := sql.Open("gbase8s", openString)
if err != nil {
fmt.Println("Open error:", err)
return nil
}
if db == nil {
fmt.Println("db is nil")
return nil
}
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
err = db.PingContext(ctx)
cancel()
if err != nil {
fmt.Println("PingContext error:", err)
db.Close()
return nil
}
return db
}
func testDropTable(t *testing.T, tableName string) {
err := testExec(t, "drop table "+tableName, nil)
if err != nil {
t.Errorf("drop table %v error: %v", tableName, err)
}
}
func testExecQuery(t *testing.T, query string, args []interface{}) {
err := testExec(t, query, args)
if err != nil {
t.Errorf("query %v error: %v", query, err)
}
}
// testGetRows runs a statement and returns the rows as [][]interface{}
func testGetRows(t testing.TB, stmt *sql.Stmt, args []interface{}) ([][]interface{}, error) {
// get rows
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
defer cancel()
var rows *sql.Rows
rows, err := stmt.QueryContext(ctx, args...)
if err != nil {
return nil, fmt.Errorf("query error: %v", err)
}
// get column infomration
var columns []string
columns, err = rows.Columns()
if err != nil {
rows.Close()
return nil, fmt.Errorf("columns error: %v", err)
}
// create values
values := make([][]interface{}, 0, 1)
// get values
pRowInterface := make([]interface{}, len(columns))
for rows.Next() {
rowInterface := make([]interface{}, len(columns))
for i := 0; i < len(rowInterface); i++ {
pRowInterface[i] = &rowInterface[i]
}
err = rows.Err()
if err != nil {
rows.Close()
return nil, fmt.Errorf("rows error: %v", err)
}
err = rows.Scan(pRowInterface...)
if err != nil {
rows.Close()
return nil, fmt.Errorf("scan error: %v", err)
}
values = append(values, rowInterface)
}
err = rows.Err()
if err != nil {
rows.Close()
return nil, fmt.Errorf("rows error: %v", err)
}
err = rows.Close()
if err != nil {
return nil, fmt.Errorf("close error: %v", err)
}
// return values
return values, nil
}
// testExec runs an exec query and returns error
func testExec(t *testing.T, query string, args []interface{}) error {
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
return fmt.Errorf("prepare error: %v", err)
}
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx, args...)
cancel()
if err != nil {
stmt.Close()
return fmt.Errorf("exec error: %v", err)
}
err = stmt.Close()
if err != nil {
return fmt.Errorf("stmt close error: %v", err)
}
return nil
}
// testExecRows runs exec query for each arg row and returns error
func testExecRows(t *testing.T, query string, args [][]interface{}) error {
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
return fmt.Errorf("prepare error: %v", err)
}
for i := 0; i < len(args); i++ {
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx, args[i]...)
cancel()
if err != nil {
stmt.Close()
return fmt.Errorf("exec - row %v - error: %v", i, err)
}
}
err = stmt.Close()
if err != nil {
return fmt.Errorf("stmt close error: %v", err)
}
return nil
}
// testRunExecResults runs testRunExecResult for each execResults
func testRunExecResults(t *testing.T, execResults testExecResults) {
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := TestDB.PrepareContext(ctx, execResults.query)
cancel()
if err != nil {
t.Errorf("prepare error: %v - query: %v", err, execResults.query)
return
}
for _, execResult := range execResults.execResults {
testRunExecResult(t, execResult, execResults.query, stmt)
}
err = stmt.Close()
if err != nil {
t.Errorf("close error: %v - query: %v", err, execResults.query)
}
}
// testRunExecResult runs exec query for execResult and tests result
func testRunExecResult(t *testing.T, execResult testExecResult, query string, stmt *sql.Stmt) {
var rv reflect.Value
results := make(map[string]interface{}, len(execResult.args))
// change args to namedArgs
namedArgs := make([]interface{}, 0, len(execResult.args))
for key, value := range execResult.args {
// make pointer
rv = reflect.ValueOf(value.Dest)
out := reflect.New(rv.Type())
if !out.Elem().CanSet() {
t.Fatalf("unable to set pointer: %v - query: %v", key, query)
return
}
out.Elem().Set(rv)
results[key] = out.Interface()
namedArgs = append(namedArgs, sql.Named(key, sql.Out{Dest: out.Interface(), In: value.In}))
}
// exec query with namedArgs
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
_, err := stmt.ExecContext(ctx, namedArgs...)
cancel()
if err != nil {
t.Errorf("exec error: %v - query: %v - args: %v", err, query, execResult.args)
return
}
// check results
for key, value := range execResult.results {
// check if have result
result, ok := results[key]
if !ok {
t.Errorf("result not found: %v - query: %v", key, query)
continue
}
// get result from result pointer
rv = reflect.ValueOf(result)
rv = reflect.Indirect(rv)
result = rv.Interface()
// check if value matches result
if !reflect.DeepEqual(result, value) {
t.Errorf("arg: %v - received: %T, %v - expected: %T, %v - query: %v",
key, result, result, value, value, query)
}
}
}
// testRunQueryResults runs testRunQueryResult for each queryResults
func testRunQueryResults(t *testing.T, queryResults testQueryResults) {
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := TestDB.PrepareContext(ctx, queryResults.query)
cancel()
if err != nil {
t.Errorf("prepare error: %v - query: %v", err, queryResults.query)
return
}
for _, queryResult := range queryResults.queryResults {
testRunQueryResult(t, queryResult, queryResults.query, stmt)
}
err = stmt.Close()
if err != nil {
t.Errorf("close error: %v - query: %v", err, queryResults.query)
}
}
// testRunQueryResult runs a single testQueryResults test
func testRunQueryResult(t *testing.T, queryResult testQueryResult, query string, stmt *sql.Stmt) {
result, err := testGetRows(t, stmt, queryResult.args)
if err != nil {
t.Errorf("get rows error: %v - query: %v", err, query)
return
}
if result == nil && queryResult.results != nil {
t.Errorf("result is nil - query: %v", query)
return
}
if len(result) != len(queryResult.results) {
t.Errorf("result rows len %v not equal to results len %v - query: %v",
len(result), len(queryResult.results), query)
return
}
for i := 0; i < len(result); i++ {
if len(result[i]) != len(queryResult.results[i]) {
t.Errorf("result columns len %v not equal to results len %v - query: %v",
len(result[i]), len(queryResult.results[i]), query)
continue
}
for j := 0; j < len(result[i]); j++ {
bad := false
type1 := reflect.TypeOf(result[i][j])
type2 := reflect.TypeOf(queryResult.results[i][j])
switch {
case type1 == nil || type2 == nil:
if type1 != type2 {
bad = true
}
case type1 == TestTypeTime || type2 == TestTypeTime:
if type1 != type2 {
bad = true
break
}
time1 := result[i][j].(time.Time)
time2 := queryResult.results[i][j].(time.Time)
if !time1.Equal(time2) {
bad = true
}
case type1.Kind() == reflect.Slice || type2.Kind() == reflect.Slice:
if !reflect.DeepEqual(result[i][j], queryResult.results[i][j]) {
bad = true
}
default:
if result[i][j] != queryResult.results[i][j] {
bad = true
}
}
if bad {
t.Errorf("result - row %v, %v - received: %T, %v - expected: %T, %v - query: %v",
i, j, result[i][j], result[i][j], queryResult.results[i][j], queryResult.results[i][j], query)
}
}
}
}
// TestConnect checks basic invalid connection
func TestConnect(t *testing.T) {
if TestDisableDatabase {
t.SkipNow()
}
t.Parallel()
// invalid
db, err := sql.Open("gbase8s", TestHostInvalid)
if err != nil {
t.Fatal("open error:", err)
}
if db == nil {
t.Fatal("db is nil")
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
err = db.PingContext(ctx)
cancel()
if err == nil || len(err.Error()) < 4 || err.Error()[0:4] != "GCI-" {
t.Fatalf("ping error - received: %v - expected GCI- error", err)
}
err = db.Close()
if err != nil {
t.Fatal("close error:", err)
}
// wrong username
db, err = sql.Open("gbase8s", "dFQXYoApiU2YbquMQnfPyqxR2kAoeuWngDvtTpl3@"+TestHostValid)
if err != nil {
t.Fatal("open error:", err)
}
if db == nil {
t.Fatal("db is nil")
}
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
err = db.PingContext(ctx)
cancel()
if err == nil || len(err.Error()) < 4 || err.Error()[0:4] != "GCI-" {
t.Fatalf("ping error - received: %v - expected GCI- error", err)
}
err = db.Close()
if err != nil {
t.Fatal("close error:", err)
}
}
// TestSelectParallel checks parallel select from dual
func TestSelectParallel(t *testing.T) {
if TestDisableDatabase {
t.SkipNow()
}
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := TestDB.PrepareContext(ctx, "select :1 from dual")
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
var waitGroup sync.WaitGroup
waitGroup.Add(50)
for i := 0; i < 50; i++ {
go func(num int) {
defer waitGroup.Done()
var result [][]interface{}
result, err = testGetRows(t, stmt, []interface{}{num})
if err != nil {
t.Fatal("get rows error:", err)
}
if result == nil {
t.Fatal("result is nil")
}
if len(result) != 1 {
t.Fatal("len result not equal to 1")
}
if len(result[0]) != 1 {
t.Fatal("len result[0] not equal to 1")
}
data, ok := result[0][0].(float64)
if !ok {
t.Fatal("result not float64")
}
if data != float64(num) {
t.Fatal("result not equal to:", num)
}
}(i)
}
waitGroup.Wait()
err = stmt.Close()
if err != nil {
t.Fatal("stmt close error:", err)
}
}
// TestContextTimeoutBreak checks that ExecContext timeout works
func TestContextTimeoutBreak(t *testing.T) {
if TestDisableDatabase {
t.SkipNow()
}
t.Parallel()
// define
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
_, err := TestDB.ExecContext(ctx, `
create or replace function SLEEP_SECONDS (p_seconds number) return integer is
begin
dbms_lock.sleep(p_seconds);
return 1;
end;
`)
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
// exec
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := TestDB.PrepareContext(ctx, "begin SYS.DBMS_LOCK.SLEEP(1); end;")
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
ctx, cancel = context.WithTimeout(context.Background(), 200*time.Millisecond)
_, err = stmt.ExecContext(ctx)
cancel()
expected := "GCI-01013"
if err == nil || len(err.Error()) < len(expected) || !strings.Contains(err.Error(), expected) {
t.Fatalf("stmt exec - expected: %v - received: %v", expected, err)
}
err = stmt.Close()
if err != nil {
t.Fatal("stmt close error:", err)
}
// query
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err = TestDB.PrepareContext(ctx, "select SLEEP_SECONDS(1) from dual")
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
ctx, cancel = context.WithTimeout(context.Background(), 200*time.Millisecond)
_, err = stmt.QueryContext(ctx)
cancel()
if err == nil || len(err.Error()) < len(expected) || !strings.Contains(err.Error(), expected) {
t.Fatalf("stmt query - expected: %v - received: %v", expected, err)
}
err = stmt.Close()
if err != nil {
t.Fatal("stmt close error:", err)
}
}
// TestDestructiveTransaction tests a transaction
func TestDestructiveTransaction(t *testing.T) {
if TestDisableDatabase || TestDisableDestructive {
t.SkipNow()
}
err := testExec(t, "create table TRANSACTION_"+TestTimeString+
" ( A INT, B INT, C INT )", nil)
if err != nil {
t.Fatal("create table error:", err)
}
defer testExecQuery(t, "drop table TRANSACTION_"+TestTimeString, nil)
err = testExecRows(t, "insert into TRANSACTION_"+TestTimeString+" ( A, B, C ) values (:1, :2, :3)",
[][]interface{}{
{1, 2, 3},
{4, 5, 6},
{6, 7, 8},
})
if err != nil {
t.Fatal("insert error:", err)
}
// TODO: How should context work? Probably should have more context create and cancel.
var tx1 *sql.Tx
var tx2 *sql.Tx
ctx, cancel := context.WithTimeout(context.Background(), 2*TestContextTimeout)
defer cancel()
tx1, err = TestDB.BeginTx(ctx, nil)
if err != nil {
t.Fatal("begin tx error:", err)
}
tx2, err = TestDB.BeginTx(ctx, nil)
if err != nil {
t.Fatal("begin tx error:", err)
}
queryResults := testQueryResults{
query: "select A, B, C from TRANSACTION_" + TestTimeString + " order by A",
queryResults: []testQueryResult{
{
results: [][]interface{}{
{int64(1), int64(2), int64(3)},
{int64(4), int64(5), int64(6)},
{int64(6), int64(7), int64(8)},
},
},
},
}
testRunQueryResults(t, queryResults)
var result sql.Result
result, err = tx1.ExecContext(ctx, "update TRANSACTION_"+TestTimeString+" set B = :1 where A = :2", []interface{}{22, 1}...)
if err != nil {
t.Fatal("exec error:", err)
}
var count int64
count, err = result.RowsAffected()
if err != nil {
t.Fatal("rows affected error:", err)
}
if count != 1 {
t.Fatalf("rows affected %v not equal to 1", count)
}
result, err = tx2.ExecContext(ctx, "update TRANSACTION_"+TestTimeString+" set B = :1 where A = :2", []interface{}{55, 4}...)
if err != nil {
t.Fatal("exec error:", err)
}
count, err = result.RowsAffected()
if err != nil {
t.Fatal("rows affected error:", err)
}
if count != 1 {
t.Fatalf("rows affected %v not equal to 1", count)
}
queryResults = testQueryResults{
query: "select A, B, C from TRANSACTION_" + TestTimeString + " order by A",
queryResults: []testQueryResult{
{
results: [][]interface{}{
{int64(1), int64(2), int64(3)},
{int64(4), int64(5), int64(6)},
{int64(6), int64(7), int64(8)},
},
},
},
}
testRunQueryResults(t, queryResults)
// tx1 with rows A = 1
var stmt *sql.Stmt
stmt, err = tx1.PrepareContext(ctx, "select A, B, C from TRANSACTION_"+TestTimeString+" where A = :1")
if err != nil {
t.Fatal("prepare error:", err)
}
var rows [][]interface{}
rows, err = testGetRows(t, stmt, []interface{}{1})
if err != nil {
t.Fatal("get rows error:", err)
}
if result == nil {
t.Fatal("rows is nil")
}
if len(rows) != 1 {
t.Fatal("len rows not equal to 1")
}
if len(rows[0]) != 3 {
t.Fatal("len rows[0] not equal to 3")
}
data, ok := rows[0][0].(int64)
if !ok {
t.Fatal("rows not int64")
}
expected := int64(1)
if data != expected {
t.Fatal("rows not equal to:", expected)
}
data, ok = rows[0][1].(int64)
if !ok {
t.Fatal("rows not int64")
}
expected = int64(22)
if data != expected {
t.Fatal("rows not equal to:", expected)
}
data, ok = rows[0][2].(int64)
if !ok {
t.Fatal("rows not int64")
}
expected = int64(3)
if data != expected {
t.Fatal("rows not equal to:", expected)
}
// tx1 with rows A = 4
rows, err = testGetRows(t, stmt, []interface{}{4})
if err != nil {
t.Fatal("get rows error:", err)
}
if rows == nil {
t.Fatal("rows is nil")
}
if len(rows) != 1 {
t.Fatal("len rows not equal to 1")
}
if len(rows[0]) != 3 {
t.Fatal("len rows[0] not equal to 3")
}
data, ok = rows[0][0].(int64)
if !ok {
t.Fatal("rows not int64")
}
expected = int64(4)
if data != expected {
t.Fatal("rows not equal to:", expected)
}
data, ok = rows[0][1].(int64)
if !ok {
t.Fatal("rows not int64")
}
expected = int64(5)
if data != expected {
t.Fatal("rows not equal to:", expected)
}
data, ok = rows[0][2].(int64)
if !ok {
t.Fatal("rows not int64")
}
expected = int64(6)
if data != expected {
t.Fatal("rows not equal to:", expected)
}
// tx2 with rows A = 1
stmt, err = tx2.PrepareContext(ctx, "select A, B, C from TRANSACTION_"+TestTimeString+" where A = :1")
if err != nil {
t.Fatal("prepare error:", err)
}
rows, err = testGetRows(t, stmt, []interface{}{1})
if err != nil {
t.Fatal("get rows error:", err)
}
if rows == nil {
t.Fatal("rows is nil")
}
if len(rows) != 1 {
t.Fatal("len rows not equal to 1")
}
if len(rows[0]) != 3 {
t.Fatal("len rows[0] not equal to 3")
}
data, ok = rows[0][0].(int64)
if !ok {
t.Fatal("rows not int64")
}
expected = int64(1)
if data != expected {
t.Fatal("rows not equal to:", expected)
}
data, ok = rows[0][1].(int64)
if !ok {
t.Fatal("rows not int64")
}
expected = int64(2)
if data != expected {
t.Fatal("rows not equal to:", expected)
}
data, ok = rows[0][2].(int64)
if !ok {
t.Fatal("rows not int64")
}
expected = int64(3)
if data != expected {
t.Fatal("rows not equal to:", expected)
}
// tx2 with rows A = 4
rows, err = testGetRows(t, stmt, []interface{}{4})
if err != nil {
t.Fatal("get rows error:", err)
}
if result == nil {
t.Fatal("rows is nil")
}
if len(rows) != 1 {
t.Fatal("len rows not equal to 1")
}
if len(rows[0]) != 3 {
t.Fatal("len rows[0] not equal to 3")
}
data, ok = rows[0][0].(int64)
if !ok {
t.Fatal("rows not int64")
}
expected = int64(4)
if data != expected {
t.Fatal("rows not equal to:", expected)
}
data, ok = rows[0][1].(int64)
if !ok {
t.Fatal("rows not int64")
}
expected = int64(55)
if data != expected {
t.Fatal("rows not equal to:", expected)
}
data, ok = rows[0][2].(int64)
if !ok {
t.Fatal("rows not int64")
}
expected = int64(6)
if data != expected {
t.Fatal("rows not equal to:", expected)
}
err = tx1.Commit()
if err != nil {
t.Fatal("commit err:", err)
}
err = tx2.Commit()
if err != nil {
t.Fatal("commit err:", err)
}
queryResults = testQueryResults{
query: "select A, B, C from TRANSACTION_" + TestTimeString + " order by A",
queryResults: []testQueryResult{
{
results: [][]interface{}{
{int64(1), int64(22), int64(3)},
{int64(4), int64(55), int64(6)},
{int64(6), int64(7), int64(8)},
},
},
},
}
testRunQueryResults(t, queryResults)
// Run new transactions after the others finished successfully.
var tx3 *sql.Tx
var tx4 *sql.Tx
tx3, err = TestDB.BeginTx(ctx, nil)
if err != nil {
t.Fatal("begin tx error:", err)
}
tx4, err = TestDB.BeginTx(ctx, nil)
if err != nil {
t.Fatal("begin tx error:", err)
}
result, err = tx4.ExecContext(ctx, "update TRANSACTION_"+TestTimeString+" set B = :1 where A = :2", []interface{}{99, 1}...)
if err != nil {
t.Fatal("exec error:", err)
}
count, err = result.RowsAffected()
if err != nil {
t.Fatal("rows affected error:", err)
}
if count != 1 {
t.Fatalf("rows affected %v not equal to 1", count)
}
result, err = tx3.ExecContext(ctx, "update TRANSACTION_"+TestTimeString+" set B = :1 where A = :2", []interface{}{88, 6}...)
if err != nil {
t.Fatal("exec error:", err)
}
count, err = result.RowsAffected()
if err != nil {
t.Fatal("rows affected error:", err)
}
if count != 1 {
t.Fatalf("rows affected %v not equal to 1", count)
}
queryResults = testQueryResults{
query: "select A, B, C from TRANSACTION_" + TestTimeString + " order by A",
queryResults: []testQueryResult{
{
results: [][]interface{}{
{int64(1), int64(22), int64(3)},
{int64(4), int64(55), int64(6)},
{int64(6), int64(7), int64(8)},
},
},
},
}
testRunQueryResults(t, queryResults)
err = tx3.Commit()
if err != nil {
t.Fatal("commit err:", err)
}
err = tx4.Rollback()
if err != nil {
t.Fatal("commit err:", err)
}
queryResults = testQueryResults{
query: "select A, B, C from TRANSACTION_" + TestTimeString + " order by A",
queryResults: []testQueryResult{
{
results: [][]interface{}{
{int64(1), int64(22), int64(3)},
{int64(4), int64(55), int64(6)},
{int64(6), int64(88), int64(8)},
},
},
},
}
testRunQueryResults(t, queryResults)
}
// TestSelectDualNull checks null from dual
func TestSelectDualNull(t *testing.T) {
if TestDisableDatabase {
t.SkipNow()
}
t.Parallel()
queryResults := testQueryResults{
query: "select null from dual",
queryResults: []testQueryResult{{
results: [][]interface{}{{nil}}}}}
testRunQueryResults(t, queryResults)
}
func TestInsertRowid(t *testing.T) {
if TestDisableDatabase || TestDisableDestructive {
t.SkipNow()
}
// INSERT_ROWID
tableName := "INSERT_ROWID_" + TestTimeString
query := "create table " + tableName + " ( A INTEGER )"
// create table
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx)
cancel()
if err != nil {
stmt.Close()
t.Fatal("exec error:", err)
}
err = stmt.Close()
if err != nil {
t.Fatal("stmt close error:", err)
}
// drop table
defer func() {
query = "drop table " + tableName
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err = TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx)
cancel()
if err != nil {
stmt.Close()
t.Fatal("exec error:", err)
}
err = stmt.Close()
if err != nil {
t.Fatal("stmt close error:", err)
}
}()
// insert into table
query = "insert into " + tableName + " ( A ) values (:1) returning rowid into :rowid2"
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err = TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
rowids := make([]string, 3)
var result sql.Result
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
result, err = stmt.ExecContext(ctx, 1, sql.Named("rowid2", sql.Out{Dest: &rowids[0]}))
cancel()
if err != nil {
stmt.Close()
t.Fatal("exec error:", err)
}
var id int64
id, err = result.LastInsertId()
if err != nil {
stmt.Close()
t.Fatal("exec error:", err)
}
rowids[1] = GetLastInsertId(id)
err = stmt.Close()
if err != nil {
t.Fatal("stmt close error", err)
}
// get select rowid
query = "select rowid from " + tableName
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err = TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
var rows *sql.Rows
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
rows, err = stmt.QueryContext(ctx)
if err != nil {
cancel()
stmt.Close()
t.Fatal("query error:", err)
}
if !rows.Next() {
cancel()
rows.Close()
stmt.Close()
t.Fatal("expected row")
}
err = rows.Scan(&rowids[2])
if err != nil {
cancel()
rows.Close()
stmt.Close()
t.Fatal("scan error:", err)
}
if rows.Next() {
cancel()
rows.Close()
stmt.Close()
t.Fatal("more than one row")
}
err = rows.Err()
if err != nil {
cancel()
rows.Close()
stmt.Close()
t.Fatal("rows error:", err)
}
cancel()
err = rows.Close()
if err != nil {
stmt.Close()
t.Fatal("rows close error", err)
}
err = stmt.Close()
if err != nil {
t.Fatal("stmt close error", err)
}
// select rowids
query = "select A from " + tableName + " where rowid = :1"
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err = TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
var data int64
for _, rowid := range rowids {
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
rows, err = stmt.QueryContext(ctx, rowid)
if err != nil {
cancel()
stmt.Close()
t.Fatal("query error:", err)
}
if !rows.Next() {
cancel()
rows.Close()
stmt.Close()
t.Fatal("expected row")
}
err = rows.Scan(&data)
if err != nil {
cancel()
rows.Close()
stmt.Close()
t.Fatal("scan error:", err)
}
if data != 1 {
cancel()
rows.Close()
stmt.Close()
t.Fatal("row not equal to 1")
}
if rows.Next() {
cancel()
rows.Close()
stmt.Close()
t.Fatal("more than one row")
}
err = rows.Err()
if err != nil {
cancel()
rows.Close()
stmt.Close()
t.Fatal("rows error:", err)
}
cancel()
err = rows.Close()
if err != nil {
stmt.Close()
t.Fatal("rows close error", err)
}
}
err = stmt.Close()
if err != nil {
t.Fatal("stmt close error", err)
}
}
// TestNullBool tests NullBool
func TestNullBool(t *testing.T) {
if TestDisableDatabase {
t.SkipNow()
}
t.Parallel()
query := `
declare
function GET_BOOL(p_bool1 NUMERIC) return NUMERIC as
begin
if p_bool1 is null then
return 1;
end if;
return 0;
end GET_BOOL;
begin
:bool1 := GET_BOOL(:bool1);
end;`
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
var nullBool1 sql.NullBool
nullBool1.Bool = false
nullBool1.Valid = false
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx, sql.Named("bool1", sql.Out{Dest: &nullBool1, In: true}))
cancel()
if err != nil {
t.Fatal("exec error:", err)
}
if !nullBool1.Valid {
t.Fatal("nullBool1 not Valid")
}
if !nullBool1.Bool {
t.Fatal("nullBool1 is false")
}
nullBool1.Bool = true
nullBool1.Valid = true
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx, sql.Named("bool1", sql.Out{Dest: &nullBool1, In: true}))
cancel()
if err != nil {
t.Fatal("exec error:", err)
}
if !nullBool1.Valid {
t.Fatal("nullBool1 not Valid")
}
if nullBool1.Bool {
t.Fatal("nullBool1 is true")
}
query = `
declare
function GET_BOOL(p_bool1 NUMERIC) return NUMERIC as
begin
return null;
end GET_BOOL;
begin
:bool1 := GET_BOOL(:bool1);
end;`
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err = TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
nullBool1.Bool = true
nullBool1.Valid = true
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx, sql.Named("bool1", sql.Out{Dest: &nullBool1, In: true}))
cancel()
if err != nil {
t.Fatal("exec error:", err)
}
if nullBool1.Valid {
t.Fatal("nullBool1 is Valid")
}
if nullBool1.Bool {
t.Fatal("nullBool1 is true")
}
}
// TestQuestionMark tests question mark placeholder
func TestQuestionMark(t *testing.T) {
if TestDisableDatabase {
t.SkipNow()
}
t.Parallel()
var err error
db := testGetDB("?questionph=true")
if db == nil {
t.Fatal("db is null")
}
defer func() {
err = db.Close()
if err != nil {
t.Fatal("db close error:", err)
}
}()
var stmt *sql.Stmt
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err = db.PrepareContext(ctx, "select ?, ?, ? from dual")
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
var result [][]interface{}
result, err = testGetRows(t, stmt, []interface{}{1, 2.25, "three"})
if err != nil {
t.Fatal("get rows error:", err)
}
if result == nil {
t.Fatal("result is nil")
}
if len(result) != 1 {
t.Fatal("len result not equal to 1")
}
if len(result[0]) != 3 {
t.Fatal("len result[0] not equal to 3")
}
float, ok := result[0][0].(float64)
if !ok {
t.Fatal("result not float64")
}
if float != float64(1) {
t.Fatal("result not equal:", float)
}
float, ok = result[0][1].(float64)
if !ok {
t.Fatal("result not float64")
}
if float != float64(2.25) {
t.Fatal("result not equal:", float)
}
var aString string
aString, ok = result[0][2].(string)
if !ok {
t.Fatal("result not string")
}
if aString != "three" {
t.Fatal("result not equal:", aString)
}
}
func BenchmarkSimpleInsert(b *testing.B) {
if TestDisableDatabase || TestDisableDestructive {
b.SkipNow()
}
b.StopTimer()
// SIMPLE_INSERT
tableName := "SIMPLE_INSERT_" + TestTimeString
query := "create table " + tableName + " ( A INTEGER )"
// create table
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
b.Fatal("prepare error:", err)
}
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx)
cancel()
if err != nil {
stmt.Close()
b.Fatal("exec error:", err)
}
err = stmt.Close()
if err != nil {
b.Fatal("stmt close error:", err)
}
// drop table
defer func() {
query = "drop table " + tableName
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err = TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
b.Fatal("prepare error:", err)
}
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx)
cancel()
if err != nil {
stmt.Close()
b.Fatal("exec error:", err)
}
err = stmt.Close()
if err != nil {
b.Fatal("stmt close error:", err)
}
}()
// insert into table
query = "insert into " + tableName + " ( A ) values (:1)"
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err = TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
b.Fatal("prepare error:", err)
}
b.ResetTimer()
b.StartTimer()
for n := 0; n < b.N; n++ {
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx, n)
cancel()
if err != nil {
stmt.Close()
b.Fatal("exec error:", err)
}
}
err = stmt.Close()
if err != nil {
b.Fatal("stmt close error", err)
}
}
func benchmarkSelectSetup(b *testing.B) {
fmt.Println("benchmark select setup start")
benchmarkSelectTableName = "BM_SELECT_" + TestTimeString
// create table
tableName := benchmarkSelectTableName
query := "create table " + tableName +
"( A INTEGER, B INTEGER, C INTEGER, D INTEGER, E VARCHAR2(255), F VARCHAR2(255), G VARCHAR2(255), H VARCHAR2(255) )"
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
b.Fatal("prepare error:", err)
}
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx)
cancel()
if err != nil {
stmt.Close()
b.Fatal("exec error:", err)
}
// enable drop table in TestMain
benchmarkSelectTableCreated = true
err = stmt.Close()
if err != nil {
b.Fatal("stmt close error:", err)
}
// insert into table
query = "insert into " + tableName + ` ( A, B, C, D, E, F, G, H )
select :1, :2, :3, :4, :5, :6, :7, :8 from dual
union all select :9, :10, :11, :12, :13, :14, :15, :16 from dual
union all select :17, :18, :19, :20, :21, :22, :23, :24 from dual
union all select :25, :26, :27, :28, :29, :30, :31, :32 from dual
union all select :33, :34, :35, :36, :37, :38, :39, :40 from dual
union all select :41, :42, :43, :44, :45, :46, :47, :48 from dual
union all select :49, :50, :51, :52, :53, :54, :55, :56 from dual
union all select :57, :58, :59, :60, :61, :62, :63, :64 from dual
union all select :65, :66, :67, :68, :69, :70, :71, :72 from dual
union all select :73, :74, :75, :76, :77, :78, :79, :80 from dual`
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err = TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
b.Fatal("prepare error:", err)
}
insertString := strings.Repeat("a", 255)
for i := 0; i < 5000; i += 10 {
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
_, err = stmt.ExecContext(ctx,
i, i+20000, i+40000, i+60000, insertString, insertString, insertString, insertString,
i+1, i+20001, i+40001, i+60001, insertString, insertString, insertString, insertString,
i+2, i+20002, i+40002, i+60002, insertString, insertString, insertString, insertString,
i+3, i+20003, i+40003, i+60003, insertString, insertString, insertString, insertString,
i+4, i+20004, i+40004, i+60004, insertString, insertString, insertString, insertString,
i+5, i+20005, i+40005, i+60005, insertString, insertString, insertString, insertString,
i+6, i+20006, i+40006, i+60006, insertString, insertString, insertString, insertString,
i+7, i+20007, i+40007, i+60007, insertString, insertString, insertString, insertString,
i+8, i+20008, i+40008, i+60008, insertString, insertString, insertString, insertString,
i+9, i+20009, i+40009, i+60009, insertString, insertString, insertString, insertString)
cancel()
if err != nil {
stmt.Close()
b.Fatal("exec error:", err)
}
}
err = stmt.Close()
if err != nil {
b.Fatal("stmt close error", err)
}
// select from table to warm up database cache
query = "select A, B, C, D, E, F, G, H from " + tableName
ctx, cancel = context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err = TestDB.PrepareContext(ctx, query)
cancel()
if err != nil {
b.Fatal("prepare error:", err)
}
defer func() {
err = stmt.Close()
if err != nil {
b.Fatal("stmt close error", err)
}
}()
var rows *sql.Rows
ctx, cancel = context.WithTimeout(context.Background(), 20*TestContextTimeout)
defer cancel()
rows, err = stmt.QueryContext(ctx)
if err != nil {
b.Fatal("exec error:", err)
}
defer func() {
err = rows.Close()
if err != nil {
b.Fatal("row close error:", err)
}
}()
var data1 int64
var data2 int64
var data3 int64
var data4 int64
var data5 string
var data6 string
var data7 string
var data8 string
var count int64
for rows.Next() {
err = rows.Scan(&data1, &data2, &data3, &data4, &data5, &data6, &data7, &data8)
if err != nil {
b.Fatal("scan error:", err)
}
count++
}
fmt.Printf("select data is %v bytes\n", (count*4*8)+(count*4*255))
err = rows.Err()
if err != nil {
b.Fatal("err error:", err)
}
b.ResetTimer()
fmt.Println("benchmark select setup end")
}
func benchmarkPrefetchSelect(b *testing.B, prefetchRows int64, prefetchMemory int64, n *int) {
benchmarkSelectTableOnce.Do(func() { benchmarkSelectSetup(b) })
var err error
db := testGetDB("?prefetch_rows=" + strconv.FormatInt(prefetchRows, 10) + "&prefetch_memory=" + strconv.FormatInt(prefetchMemory, 10))
if db == nil {
b.Fatal("db is null")
}
defer func() {
err = db.Close()
if err != nil {
b.Fatal("db close error:", err)
}
}()
b.StartTimer()
var stmt *sql.Stmt
tableName := benchmarkSelectTableName
query := "select A, B, C, D, E, F, G, H from " + tableName
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err = db.PrepareContext(ctx, query)
cancel()
if err != nil {
b.Fatal("prepare error:", err)
}
defer func() {
err = stmt.Close()
if err != nil {
b.Fatal("stmt close error", err)
}
}()
var rows *sql.Rows
ctx, cancel = context.WithTimeout(context.Background(), 20*TestContextTimeout)
defer cancel()
rows, err = stmt.QueryContext(ctx)
if err != nil {
b.Fatal("exec error:", err)
}
defer func() {
err = rows.Close()
if err != nil {
b.Fatal("row close error:", err)
}
}()
var data1 int64
var data2 int64
var data3 int64
var data4 int64
var data5 string
var data6 string
var data7 string
var data8 string
for ; rows.Next() && *n < b.N; *n++ {
err = rows.Scan(&data1, &data2, &data3, &data4, &data5, &data6, &data7, &data8)
if err != nil {
b.Fatal("scan error:", err)
}
}
b.StopTimer()
err = rows.Err()
if err != nil {
b.Fatal("err error:", err)
}
}
// TestSelectParallelWithStatementCaching checks parallel select from dual but with statement caching enabled
func TestSelectParallelWithStatementCaching(t *testing.T) {
if TestDisableDatabase {
t.SkipNow()
}
db := testGetDB("?stmt_cache_size=100")
if db == nil {
t.Fatal("db is null")
}
var waitGroup sync.WaitGroup
waitGroup.Add(50)
for i := 0; i < 50; i++ {
go func(num int) {
defer waitGroup.Done()
selectNumFromDual(t, db, float64(num))
}(i)
}
waitGroup.Wait()
}
// selectNumFromDual will execute a "select :1 from dual" where the parameter is the num param of this function
func selectNumFromDual(t testing.TB, db *sql.DB, num float64) {
ctx, cancel := context.WithTimeout(context.Background(), TestContextTimeout)
stmt, err := db.PrepareContext(ctx, "select :1 from dual")
cancel()
if err != nil {
t.Fatal("prepare error:", err)
}
defer func() {
if stmt != nil {
err := stmt.Close()
if err != nil {
t.Fatal("stmt close error:", err)
}
}
}()
var result [][]interface{}
result, err = testGetRows(t, stmt, []interface{}{num})
if err != nil {
t.Fatal("get rows error:", err)
}
if result == nil {
t.Fatal("result is nil")
}
if len(result) != 1 {
t.Fatal("len result not equal to 1")
}
if len(result[0]) != 1 {
t.Fatal("len result[0] not equal to 1")
}
data, ok := result[0][0].(float64)
if !ok {
t.Fatal("result not float64")
}
if data != num {
t.Fatal("result not equal to:", num)
}
}
func BenchmarkSelectNoCaching(b *testing.B) {
if TestDisableDatabase || TestDisableDestructive {
b.SkipNow()
}
for i := 0; i < b.N; i++ {
selectNumFromDual(b, TestDB, float64(i))
}
}
func BenchmarkSelectWithCaching(b *testing.B) {
b.StopTimer()
if TestDisableDatabase || TestDisableDestructive {
b.SkipNow()
}
db := testGetDB("?stmt_cache_size=100")
if db == nil {
b.Fatal("db is null")
}
defer func() {
err := db.Close()
if err != nil {
b.Fatal("db close error:", err)
}
}()
b.StartTimer()
for i := 0; i < b.N; i++ {
selectNumFromDual(b, db, float64(i))
}
}
func BenchmarkPrefetchR0M32768(b *testing.B) {
b.StopTimer()
if TestDisableDatabase || TestDisableDestructive {
b.SkipNow()
}
for n := 0; n < b.N; {
benchmarkPrefetchSelect(b, 0, 32768, &n)
}
}
func BenchmarkPrefetchR0M16384(b *testing.B) {
b.StopTimer()
if TestDisableDatabase || TestDisableDestructive {
b.SkipNow()
}
for n := 0; n < b.N; {
benchmarkPrefetchSelect(b, 0, 16384, &n)
}
}
func BenchmarkPrefetchR0M8192(b *testing.B) {
b.StopTimer()
if TestDisableDatabase || TestDisableDestructive {
b.SkipNow()
}
for n := 0; n < b.N; {
benchmarkPrefetchSelect(b, 0, 8192, &n)
}
}
func BenchmarkPrefetchR0M4096(b *testing.B) {
b.StopTimer()
if TestDisableDatabase || TestDisableDestructive {
b.SkipNow()
}
for n := 0; n < b.N; {
benchmarkPrefetchSelect(b, 0, 4096, &n)
}
}
func BenchmarkPrefetchR1000M0(b *testing.B) {
b.StopTimer()
if TestDisableDatabase || TestDisableDestructive {
b.SkipNow()
}
for n := 0; n < b.N; {
benchmarkPrefetchSelect(b, 1000, 0, &n)
}
}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。