main.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package main
  2. // =============================================================================
  3. // sql_driver — database/sql 驱动演示: 标准库 API 全特性走查 (M1/M2/M3)
  4. //
  5. // go run main.go
  6. //
  7. // 覆盖: CREATE TABLE (含主键/唯一/普通索引) → INSERT (显式/自增主键, NULL) →
  8. // SELECT (投影/WHERE 全条件族/ORDER BY/LIMIT/聚合) → UPDATE → DELETE →
  9. // 事务 (Rollback 与 Commit) → 唯一约束冲突 → 不支持语法的明确报错。
  10. // 任何一步断言失败立即非零退出。
  11. // =============================================================================
  12. import (
  13. "database/sql"
  14. "fmt"
  15. "os"
  16. _ "git.ycl.pub/yl32940/TsDB2/DB/driver"
  17. )
  18. const dbPath = "sql_driver_demo.db"
  19. var failed bool
  20. func check(err error, what string) {
  21. if err != nil {
  22. fmt.Printf("❌ %s: %v\n", what, err)
  23. os.Exit(1)
  24. }
  25. }
  26. func section(s string) { fmt.Printf("\n=== %s ===\n", s) }
  27. func main() {
  28. os.Remove(dbPath)
  29. db, err := sql.Open("vrtx", dbPath)
  30. check(err, "open")
  31. defer db.Close()
  32. // 引擎单写者模型: 连接池串行化, 设 1 路连接避免无谓排队
  33. db.SetMaxOpenConns(1)
  34. // ---------- M3: DDL ----------
  35. section("M3: CREATE TABLE (主键/唯一/普通索引)")
  36. _, err = db.Exec(`CREATE TABLE users (
  37. id BIGINT PRIMARY KEY,
  38. name VARCHAR(32) NOT NULL,
  39. age INT,
  40. email VARCHAR(64) UNIQUE,
  41. city VARCHAR(32)
  42. )`)
  43. check(err, "create table")
  44. _, err = db.Exec(`CREATE INDEX idx_city ON users (city)`)
  45. check(err, "create index")
  46. fmt.Println("✅ 建表 users (id 主键 / email 唯一 / city 普通索引)")
  47. // ---------- M1: INSERT ----------
  48. section("M1: INSERT (显式主键 + 省略列=NULL)")
  49. res, err := db.Exec(`INSERT INTO users (id, name, age, email, city) VALUES (?, ?, ?, ?, ?)`,
  50. 1, "alice", 30, "alice@x.com", "beijing")
  51. check(err, "insert alice")
  52. id, _ := res.LastInsertId()
  53. fmt.Printf("✅ 插入 alice LastInsertId=%d\n", id)
  54. res, err = db.Exec(`INSERT INTO users (id, name, city) VALUES (?, ?, ?)`, 2, "bob", "shanghai") // age/email = NULL
  55. check(err, "insert bob")
  56. id, _ = res.LastInsertId()
  57. fmt.Printf("✅ 插入 bob (age/email 省略 → NULL) LastInsertId=%d\n", id)
  58. // 唯一约束: 重复 email 必须报错
  59. _, err = db.Exec(`INSERT INTO users (id, name, email) VALUES (?, ?, ?)`, 3, "mallory", "alice@x.com")
  60. if err == nil {
  61. fmt.Println("❌ 唯一约束未生效: 重复 email 插入成功")
  62. os.Exit(1)
  63. }
  64. fmt.Printf("✅ 唯一索引拦截重复 email: %v\n", err)
  65. // ---------- M1: SELECT ----------
  66. section("M1: SELECT (投影 + WHERE + ORDER BY + LIMIT)")
  67. rows, err := db.Query(`SELECT id, name, age FROM users WHERE age >= ? ORDER BY age DESC LIMIT 10`, 18)
  68. check(err, "query")
  69. type user struct {
  70. id int64
  71. name string
  72. age sql.NullInt64
  73. }
  74. var users []user
  75. for rows.Next() {
  76. var u user
  77. var nm []byte
  78. check(rows.Scan(&u.id, &nm, &u.age), "scan")
  79. u.name = string(nm)
  80. users = append(users, u)
  81. }
  82. rows.Close()
  83. for _, u := range users {
  84. age := "NULL"
  85. if u.age.Valid {
  86. age = fmt.Sprint(u.age.Int64)
  87. }
  88. fmt.Printf(" id=%d name=%-8s age=%v\n", u.id, u.name, age)
  89. }
  90. // SQL 语义: NULL >= 18 不为真 → bob (age=NULL) 不在结果里
  91. if len(users) != 1 || users[0].name != "alice" || !users[0].age.Valid {
  92. fmt.Println("❌ SELECT 结果不对")
  93. os.Exit(1)
  94. }
  95. fmt.Println("✅ 投影/条件/排序/分页正确 (NULL 不参与比较: bob 被 age>=18 过滤)")
  96. // ---------- M2: WHERE 全条件族 ----------
  97. section("M2: WHERE 条件族 (IN / OR / NOT / IS NULL / LIKE)")
  98. show := func(label, q string, args ...interface{}) int64 {
  99. var n int64
  100. check(db.QueryRow(q, args...).Scan(&n), label)
  101. fmt.Printf(" %-14s = %d\n", label, n)
  102. return n
  103. }
  104. if show("IN", `SELECT COUNT(*) FROM users WHERE id IN (?, ?)`, 1, 2) != 2 ||
  105. show("OR", `SELECT COUNT(*) FROM users WHERE city = ? OR city = ?`, "beijing", "shanghai") != 2 ||
  106. show("NOT", `SELECT COUNT(*) FROM users WHERE NOT (id = ?)`, 1) != 1 ||
  107. show("IS NULL", `SELECT COUNT(*) FROM users WHERE age IS NULL`) != 1 ||
  108. show("LIKE", `SELECT COUNT(*) FROM users WHERE name LIKE ?`, "al%") != 1 {
  109. fmt.Println("❌ WHERE 条件族结果不对")
  110. os.Exit(1)
  111. }
  112. fmt.Println("✅ 全条件族通过")
  113. // ---------- M3: 聚合 ----------
  114. section("M3: 聚合 (COUNT/SUM/AVG/MIN/MAX)")
  115. agg := func(label, q string) float64 {
  116. var v float64
  117. check(db.QueryRow(q).Scan(&v), label)
  118. fmt.Printf(" %-10s = %v\n", label, v)
  119. return v
  120. }
  121. if agg("SUM(age)", `SELECT SUM(age) FROM users`) != 30 ||
  122. agg("COUNT(*)", `SELECT COUNT(*) FROM users`) != 2 ||
  123. agg("AVG(age)", `SELECT AVG(age) FROM users`) != 30 {
  124. fmt.Println("❌ 聚合结果不对")
  125. os.Exit(1)
  126. }
  127. agg("MIN(age)", `SELECT MIN(age) FROM users`)
  128. agg("MAX(age)", `SELECT MAX(age) FROM users`)
  129. fmt.Println("✅ 聚合通过")
  130. // ---------- M2: UPDATE / DELETE ----------
  131. section("M2: UPDATE / DELETE")
  132. res, err = db.Exec(`UPDATE users SET age = ? WHERE name = ?`, 31, "alice")
  133. check(err, "update")
  134. if n, _ := res.RowsAffected(); n != 1 {
  135. fmt.Printf("❌ UPDATE affected=%d\n", n)
  136. os.Exit(1)
  137. }
  138. var age int64
  139. check(db.QueryRow(`SELECT age FROM users WHERE id = ?`, 1).Scan(&age), "select age")
  140. if age != 31 {
  141. fmt.Printf("❌ UPDATE 未生效 age=%d\n", age)
  142. os.Exit(1)
  143. }
  144. fmt.Println("✅ UPDATE 生效 (alice.age 30→31)")
  145. res, err = db.Exec(`DELETE FROM users WHERE city = ?`, "shanghai")
  146. check(err, "delete")
  147. if n, _ := res.RowsAffected(); n != 1 {
  148. fmt.Printf("❌ DELETE affected=%d\n", n)
  149. os.Exit(1)
  150. }
  151. fmt.Println("✅ DELETE 生效 (bob 已删)")
  152. // ---------- M2: 事务 ----------
  153. section("M2: 事务 (Rollback 回滚 / Commit 提交)")
  154. tx, err := db.Begin()
  155. check(err, "begin")
  156. _, err = tx.Exec(`INSERT INTO users (id, name, age) VALUES (?, ?, ?)`, 10, "temp", 99)
  157. check(err, "tx insert")
  158. check(tx.Rollback(), "rollback")
  159. var cnt int64
  160. check(db.QueryRow(`SELECT COUNT(*) FROM users WHERE id = ?`, 10).Scan(&cnt), "count after rollback")
  161. if cnt != 0 {
  162. fmt.Println("❌ Rollback 后 temp 仍在")
  163. os.Exit(1)
  164. }
  165. fmt.Println("✅ Rollback 撤销了事务内插入")
  166. tx2, err := db.Begin()
  167. check(err, "begin2")
  168. _, err = tx2.Exec(`INSERT INTO users (id, name, age) VALUES (?, ?, ?)`, 11, "carol", 22)
  169. check(err, "tx2 insert")
  170. check(tx2.Commit(), "commit")
  171. check(db.QueryRow(`SELECT COUNT(*) FROM users WHERE id = ?`, 11).Scan(&cnt), "count after commit")
  172. if cnt != 1 {
  173. fmt.Println("❌ Commit 后 carol 不在")
  174. os.Exit(1)
  175. }
  176. fmt.Println("✅ Commit 提交了事务内插入")
  177. // ---------- Prepare 路径 ----------
  178. section("附加: Prepare (预编译语句)")
  179. stmt, err := db.Prepare(`SELECT name FROM users WHERE id = ?`)
  180. check(err, "prepare")
  181. defer stmt.Close()
  182. var nm string
  183. check(stmt.QueryRow(11).Scan(&nm), "prepared query")
  184. if nm != "carol" {
  185. fmt.Printf("❌ prepared 查询结果 %q\n", nm)
  186. os.Exit(1)
  187. }
  188. fmt.Println("✅ Prepare/QueryRow 通过")
  189. // ---------- 不支持语法的明确报错 ----------
  190. section("附加: 不支持语法明确报错 (不静默)")
  191. if _, err := db.Query(`SELECT * FROM users GROUP BY city`); err == nil {
  192. fmt.Println("❌ GROUP BY 应报错")
  193. os.Exit(1)
  194. } else {
  195. fmt.Printf("✅ GROUP BY 明确拒绝: %v\n", err)
  196. }
  197. fmt.Println("\n🎉 全部通过 — database/sql 驱动 M1/M2/M3 可用")
  198. _ = failed
  199. }