block_query.go 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848
  1. // SiYuan - Refactor your thinking
  2. // Copyright (c) 2020-present, b3log.org
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Affero General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Affero General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Affero General Public License
  15. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  16. package sql
  17. import (
  18. "bytes"
  19. "database/sql"
  20. "math"
  21. "sort"
  22. "strconv"
  23. "strings"
  24. "github.com/88250/lute/ast"
  25. "github.com/88250/vitess-sqlparser/sqlparser"
  26. "github.com/emirpasic/gods/sets/hashset"
  27. sqlparser2 "github.com/rqlite/sql"
  28. "github.com/siyuan-note/logging"
  29. "github.com/siyuan-note/siyuan/kernel/treenode"
  30. "github.com/siyuan-note/siyuan/kernel/util"
  31. )
  32. func QueryEmptyContentEmbedBlocks() (ret []*Block) {
  33. stmt := "SELECT * FROM blocks WHERE type = 'query_embed' AND content = ''"
  34. rows, err := query(stmt)
  35. if nil != err {
  36. logging.LogErrorf("sql query [%s] failed: %s", stmt, err)
  37. return
  38. }
  39. defer rows.Close()
  40. for rows.Next() {
  41. if block := scanBlockRows(rows); nil != block {
  42. ret = append(ret, block)
  43. }
  44. }
  45. return
  46. }
  47. func queryBlockHashes(rootID string) (ret map[string]string) {
  48. stmt := "SELECT id, hash FROM blocks WHERE root_id = ?"
  49. rows, err := query(stmt, rootID)
  50. if nil != err {
  51. logging.LogErrorf("sql query [%s] failed: %s", stmt, err)
  52. return
  53. }
  54. defer rows.Close()
  55. ret = map[string]string{}
  56. for rows.Next() {
  57. var id, hash string
  58. if err = rows.Scan(&id, &hash); nil != err {
  59. logging.LogErrorf("query scan field failed: %s", err)
  60. return
  61. }
  62. ret[id] = hash
  63. }
  64. return
  65. }
  66. func QueryRootBlockByCondition(condition string) (ret []*Block) {
  67. sqlStmt := "SELECT *, length(hpath) - length(replace(hpath, '/', '')) AS lv FROM blocks WHERE type = 'd' AND " + condition + " ORDER BY box DESC,lv ASC LIMIT 128"
  68. rows, err := query(sqlStmt)
  69. if nil != err {
  70. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  71. return
  72. }
  73. defer rows.Close()
  74. for rows.Next() {
  75. var block Block
  76. var sepCount int
  77. if err = rows.Scan(&block.ID, &block.ParentID, &block.RootID, &block.Hash, &block.Box, &block.Path, &block.HPath, &block.Name, &block.Alias, &block.Memo, &block.Tag, &block.Content, &block.FContent, &block.Markdown, &block.Length, &block.Type, &block.SubType, &block.IAL, &block.Sort, &block.Created, &block.Updated, &sepCount); nil != err {
  78. logging.LogErrorf("query scan field failed: %s", err)
  79. return
  80. }
  81. ret = append(ret, &block)
  82. }
  83. return
  84. }
  85. func (block *Block) IsContainerBlock() bool {
  86. switch block.Type {
  87. case "d", "b", "l", "i", "s":
  88. return true
  89. }
  90. return false
  91. }
  92. func queryBlockChildrenIDs(id string) (ret []string) {
  93. ret = append(ret, id)
  94. childIDs := queryBlockIDByParentID(id)
  95. for _, childID := range childIDs {
  96. ret = append(ret, queryBlockChildrenIDs(childID)...)
  97. }
  98. return
  99. }
  100. func queryBlockIDByParentID(parentID string) (ret []string) {
  101. sqlStmt := "SELECT id FROM blocks WHERE parent_id = ?"
  102. rows, err := query(sqlStmt, parentID)
  103. if nil != err {
  104. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  105. return
  106. }
  107. defer rows.Close()
  108. for rows.Next() {
  109. var id string
  110. rows.Scan(&id)
  111. ret = append(ret, id)
  112. }
  113. return
  114. }
  115. func QueryRecentUpdatedBlocks() (ret []*Block) {
  116. sqlStmt := "SELECT * FROM blocks WHERE type = 'p' AND length > 1 ORDER BY updated DESC LIMIT 16"
  117. if util.ContainerIOS == util.Container || util.ContainerAndroid == util.Container {
  118. sqlStmt = "SELECT * FROM blocks WHERE type = 'd' ORDER BY updated DESC LIMIT 16"
  119. }
  120. rows, err := query(sqlStmt)
  121. if nil != err {
  122. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  123. return
  124. }
  125. defer rows.Close()
  126. for rows.Next() {
  127. if block := scanBlockRows(rows); nil != block {
  128. ret = append(ret, block)
  129. }
  130. }
  131. return
  132. }
  133. func QueryBlockByNameOrAlias(rootID, text string) (ret *Block) {
  134. sqlStmt := "SELECT * FROM blocks WHERE root_id = ? AND (alias LIKE ? OR name = ?)"
  135. row := queryRow(sqlStmt, rootID, "%"+text+"%", text)
  136. ret = scanBlockRow(row)
  137. return
  138. }
  139. func QueryBlockAliases(rootID string) (ret []string) {
  140. sqlStmt := "SELECT alias FROM blocks WHERE root_id = ? AND alias != ''"
  141. rows, err := query(sqlStmt, rootID)
  142. if nil != err {
  143. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  144. return
  145. }
  146. defer rows.Close()
  147. var aliasesRows []string
  148. for rows.Next() {
  149. var name string
  150. rows.Scan(&name)
  151. aliasesRows = append(aliasesRows, name)
  152. }
  153. for _, aliasStr := range aliasesRows {
  154. aliases := strings.Split(aliasStr, ",")
  155. for _, alias := range aliases {
  156. var exist bool
  157. for _, retAlias := range ret {
  158. if retAlias == alias {
  159. exist = true
  160. }
  161. }
  162. if !exist {
  163. ret = append(ret, alias)
  164. }
  165. }
  166. }
  167. return
  168. }
  169. func queryNames() (ret []string) {
  170. ret = []string{}
  171. sqlStmt := "SELECT name FROM blocks WHERE name != '' LIMIT ?"
  172. rows, err := query(sqlStmt, 10240)
  173. if nil != err {
  174. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  175. return
  176. }
  177. defer rows.Close()
  178. var namesRows []string
  179. for rows.Next() {
  180. var name string
  181. rows.Scan(&name)
  182. namesRows = append(namesRows, name)
  183. }
  184. set := hashset.New()
  185. for _, namesStr := range namesRows {
  186. names := strings.Split(namesStr, ",")
  187. for _, name := range names {
  188. if "" == strings.TrimSpace(name) {
  189. continue
  190. }
  191. set.Add(name)
  192. }
  193. }
  194. for _, v := range set.Values() {
  195. ret = append(ret, v.(string))
  196. }
  197. return
  198. }
  199. func queryAliases() (ret []string) {
  200. ret = []string{}
  201. sqlStmt := "SELECT alias FROM blocks WHERE alias != '' LIMIT ?"
  202. rows, err := query(sqlStmt, 10240)
  203. if nil != err {
  204. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  205. return
  206. }
  207. defer rows.Close()
  208. var aliasesRows []string
  209. for rows.Next() {
  210. var alias string
  211. rows.Scan(&alias)
  212. aliasesRows = append(aliasesRows, alias)
  213. }
  214. set := hashset.New()
  215. for _, aliasStr := range aliasesRows {
  216. aliases := strings.Split(aliasStr, ",")
  217. for _, alias := range aliases {
  218. if "" == strings.TrimSpace(alias) {
  219. continue
  220. }
  221. set.Add(alias)
  222. }
  223. }
  224. for _, v := range set.Values() {
  225. ret = append(ret, v.(string))
  226. }
  227. return
  228. }
  229. func queryDocIDsByTitle(title string, excludeIDs []string) (ret []string) {
  230. ret = []string{}
  231. notIn := "('" + strings.Join(excludeIDs, "','") + "')"
  232. sqlStmt := "SELECT id FROM blocks WHERE type = 'd' AND content LIKE ? AND id NOT IN " + notIn + " LIMIT ?"
  233. if caseSensitive {
  234. sqlStmt = "SELECT id FROM blocks WHERE type = 'd' AND content = ? AND id NOT IN " + notIn + " LIMIT ?"
  235. }
  236. rows, err := query(sqlStmt, title, 32)
  237. if nil != err {
  238. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  239. return
  240. }
  241. defer rows.Close()
  242. set := hashset.New()
  243. for rows.Next() {
  244. var id string
  245. rows.Scan(&id)
  246. set.Add(id)
  247. }
  248. for _, v := range set.Values() {
  249. ret = append(ret, v.(string))
  250. }
  251. return
  252. }
  253. func queryDocTitles() (ret []string) {
  254. ret = []string{}
  255. sqlStmt := "SELECT content FROM blocks WHERE type = 'd'"
  256. rows, err := query(sqlStmt)
  257. if nil != err {
  258. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  259. return
  260. }
  261. defer rows.Close()
  262. var docNamesRows []string
  263. for rows.Next() {
  264. var name string
  265. rows.Scan(&name)
  266. docNamesRows = append(docNamesRows, name)
  267. }
  268. set := hashset.New()
  269. for _, nameStr := range docNamesRows {
  270. names := strings.Split(nameStr, ",")
  271. for _, name := range names {
  272. if "" == strings.TrimSpace(name) {
  273. continue
  274. }
  275. set.Add(name)
  276. }
  277. }
  278. for _, v := range set.Values() {
  279. ret = append(ret, v.(string))
  280. }
  281. return
  282. }
  283. func QueryBlockNamesByRootID(rootID string) (ret []string) {
  284. sqlStmt := "SELECT DISTINCT name FROM blocks WHERE root_id = ? AND name != ''"
  285. rows, err := query(sqlStmt, rootID)
  286. if nil != err {
  287. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  288. return
  289. }
  290. defer rows.Close()
  291. for rows.Next() {
  292. var name string
  293. rows.Scan(&name)
  294. ret = append(ret, name)
  295. }
  296. return
  297. }
  298. func QueryBookmarkBlocksByKeyword(bookmark string) (ret []*Block) {
  299. sqlStmt := "SELECT * FROM blocks WHERE ial LIKE ?"
  300. rows, err := query(sqlStmt, "%bookmark=%")
  301. if nil != err {
  302. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  303. return
  304. }
  305. defer rows.Close()
  306. for rows.Next() {
  307. if block := scanBlockRows(rows); nil != block {
  308. ret = append(ret, block)
  309. }
  310. }
  311. return
  312. }
  313. func QueryBookmarkBlocks() (ret []*Block) {
  314. sqlStmt := "SELECT * FROM blocks WHERE ial LIKE ?"
  315. rows, err := query(sqlStmt, "%bookmark=%")
  316. if nil != err {
  317. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  318. return
  319. }
  320. defer rows.Close()
  321. for rows.Next() {
  322. if block := scanBlockRows(rows); nil != block {
  323. ret = append(ret, block)
  324. }
  325. }
  326. return
  327. }
  328. func QueryBookmarkLabels() (ret []string) {
  329. ret = []string{}
  330. sqlStmt := "SELECT * FROM blocks WHERE ial LIKE ?"
  331. rows, err := query(sqlStmt, "%bookmark=%")
  332. if nil != err {
  333. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  334. return
  335. }
  336. defer rows.Close()
  337. labels := map[string]bool{}
  338. for rows.Next() {
  339. if block := scanBlockRows(rows); nil != block {
  340. if v := ialAttr(block.IAL, "bookmark"); "" != v {
  341. labels[v] = true
  342. }
  343. }
  344. }
  345. for label := range labels {
  346. ret = append(ret, label)
  347. }
  348. sort.Strings(ret)
  349. return
  350. }
  351. func QueryNoLimit(stmt string) (ret []map[string]interface{}, err error) {
  352. return queryRawStmt(stmt, math.MaxInt)
  353. }
  354. func Query(stmt string, limit int) (ret []map[string]interface{}, err error) {
  355. // Kernel API `/api/query/sql` support `||` operator https://github.com/siyuan-note/siyuan/issues/9662
  356. // 这里为了支持 || 操作符,使用了另一个 sql 解析器,但是这个解析器无法处理 UNION https://github.com/siyuan-note/siyuan/issues/8226
  357. // 考虑到 UNION 的使用场景不多,这里还是以支持 || 操作符为主
  358. p := sqlparser2.NewParser(strings.NewReader(stmt))
  359. parsedStmt2, err := p.ParseStatement()
  360. if nil != err {
  361. if !strings.Contains(stmt, "||") {
  362. // 这个解析器无法处理 || 连接字符串操作符
  363. parsedStmt, err2 := sqlparser.Parse(stmt)
  364. if nil != err2 {
  365. return queryRawStmt(stmt, limit)
  366. }
  367. switch parsedStmt.(type) {
  368. case *sqlparser.Select:
  369. limitClause := getLimitClause(parsedStmt, limit)
  370. slct := parsedStmt.(*sqlparser.Select)
  371. slct.Limit = limitClause
  372. stmt = sqlparser.String(slct)
  373. case *sqlparser.Union:
  374. // Kernel API `/api/query/sql` support `UNION` statement https://github.com/siyuan-note/siyuan/issues/8226
  375. limitClause := getLimitClause(parsedStmt, limit)
  376. union := parsedStmt.(*sqlparser.Union)
  377. union.Limit = limitClause
  378. stmt = sqlparser.String(union)
  379. default:
  380. return queryRawStmt(stmt, limit)
  381. }
  382. } else {
  383. return queryRawStmt(stmt, limit)
  384. }
  385. } else {
  386. switch parsedStmt2.(type) {
  387. case *sqlparser2.SelectStatement:
  388. slct := parsedStmt2.(*sqlparser2.SelectStatement)
  389. if nil == slct.LimitExpr {
  390. slct.LimitExpr = &sqlparser2.NumberLit{Value: strconv.Itoa(limit)}
  391. }
  392. stmt = slct.String()
  393. default:
  394. return queryRawStmt(stmt, limit)
  395. }
  396. }
  397. ret = []map[string]interface{}{}
  398. rows, err := query(stmt)
  399. if nil != err {
  400. logging.LogWarnf("sql query [%s] failed: %s", stmt, err)
  401. return
  402. }
  403. defer rows.Close()
  404. cols, _ := rows.Columns()
  405. if nil == cols {
  406. return
  407. }
  408. for rows.Next() {
  409. columns := make([]interface{}, len(cols))
  410. columnPointers := make([]interface{}, len(cols))
  411. for i := range columns {
  412. columnPointers[i] = &columns[i]
  413. }
  414. if err = rows.Scan(columnPointers...); nil != err {
  415. return
  416. }
  417. m := make(map[string]interface{})
  418. for i, colName := range cols {
  419. val := columnPointers[i].(*interface{})
  420. m[colName] = *val
  421. }
  422. ret = append(ret, m)
  423. }
  424. return
  425. }
  426. func getLimitClause(parsedStmt sqlparser.Statement, limit int) (ret *sqlparser.Limit) {
  427. switch parsedStmt.(type) {
  428. case *sqlparser.Select:
  429. slct := parsedStmt.(*sqlparser.Select)
  430. if nil != slct.Limit {
  431. ret = slct.Limit
  432. }
  433. case *sqlparser.Union:
  434. union := parsedStmt.(*sqlparser.Union)
  435. if nil != union.Limit {
  436. ret = union.Limit
  437. }
  438. }
  439. if nil == ret || nil == ret.Rowcount {
  440. ret = &sqlparser.Limit{
  441. Rowcount: &sqlparser.SQLVal{
  442. Type: sqlparser.IntVal,
  443. Val: []byte(strconv.Itoa(limit)),
  444. },
  445. }
  446. }
  447. return
  448. }
  449. func queryRawStmt(stmt string, limit int) (ret []map[string]interface{}, err error) {
  450. rows, err := query(stmt)
  451. if nil != err {
  452. if strings.Contains(err.Error(), "syntax error") {
  453. return
  454. }
  455. return
  456. }
  457. defer rows.Close()
  458. cols, err := rows.Columns()
  459. if nil != err || nil == cols {
  460. return
  461. }
  462. noLimit := !containsLimitClause(stmt)
  463. var count, errCount int
  464. for rows.Next() {
  465. columns := make([]interface{}, len(cols))
  466. columnPointers := make([]interface{}, len(cols))
  467. for i := range columns {
  468. columnPointers[i] = &columns[i]
  469. }
  470. if err = rows.Scan(columnPointers...); nil != err {
  471. return
  472. }
  473. m := make(map[string]interface{})
  474. for i, colName := range cols {
  475. val := columnPointers[i].(*interface{})
  476. m[colName] = *val
  477. }
  478. ret = append(ret, m)
  479. count++
  480. if (noLimit && limit < count) || 0 < errCount {
  481. break
  482. }
  483. }
  484. return
  485. }
  486. func SelectBlocksRawStmtNoParse(stmt string, limit int) (ret []*Block) {
  487. return selectBlocksRawStmt(stmt, limit)
  488. }
  489. func SelectBlocksRawStmt(stmt string, page, limit int) (ret []*Block) {
  490. parsedStmt, err := sqlparser.Parse(stmt)
  491. if nil != err {
  492. return selectBlocksRawStmt(stmt, limit)
  493. }
  494. switch parsedStmt.(type) {
  495. case *sqlparser.Select:
  496. slct := parsedStmt.(*sqlparser.Select)
  497. if nil == slct.Limit {
  498. slct.Limit = &sqlparser.Limit{
  499. Rowcount: &sqlparser.SQLVal{
  500. Type: sqlparser.IntVal,
  501. Val: []byte(strconv.Itoa(limit)),
  502. },
  503. }
  504. slct.Limit.Offset = &sqlparser.SQLVal{
  505. Type: sqlparser.IntVal,
  506. Val: []byte(strconv.Itoa((page - 1) * limit)),
  507. }
  508. } else {
  509. if nil != slct.Limit.Rowcount && 0 < len(slct.Limit.Rowcount.(*sqlparser.SQLVal).Val) {
  510. limit, _ = strconv.Atoi(string(slct.Limit.Rowcount.(*sqlparser.SQLVal).Val))
  511. if 0 >= limit {
  512. limit = 32
  513. }
  514. }
  515. slct.Limit.Rowcount = &sqlparser.SQLVal{
  516. Type: sqlparser.IntVal,
  517. Val: []byte(strconv.Itoa(limit)),
  518. }
  519. slct.Limit.Offset = &sqlparser.SQLVal{
  520. Type: sqlparser.IntVal,
  521. Val: []byte(strconv.Itoa((page - 1) * limit)),
  522. }
  523. }
  524. stmt = sqlparser.String(slct)
  525. default:
  526. return
  527. }
  528. stmt = strings.ReplaceAll(stmt, "\\'", "''")
  529. stmt = strings.ReplaceAll(stmt, "\\\"", "\"")
  530. stmt = strings.ReplaceAll(stmt, "\\\\*", "\\*")
  531. stmt = strings.ReplaceAll(stmt, "from dual", "")
  532. rows, err := query(stmt)
  533. if nil != err {
  534. if strings.Contains(err.Error(), "syntax error") {
  535. return
  536. }
  537. logging.LogWarnf("sql query [%s] failed: %s", stmt, err)
  538. return
  539. }
  540. defer rows.Close()
  541. for rows.Next() {
  542. if block := scanBlockRows(rows); nil != block {
  543. ret = append(ret, block)
  544. }
  545. }
  546. return
  547. }
  548. func selectBlocksRawStmt(stmt string, limit int) (ret []*Block) {
  549. rows, err := query(stmt)
  550. if nil != err {
  551. if strings.Contains(err.Error(), "syntax error") {
  552. return
  553. }
  554. return
  555. }
  556. defer rows.Close()
  557. noLimit := !containsLimitClause(stmt)
  558. var count, errCount int
  559. for rows.Next() {
  560. count++
  561. if block := scanBlockRows(rows); nil != block {
  562. ret = append(ret, block)
  563. } else {
  564. logging.LogWarnf("raw sql query [%s] failed", stmt)
  565. errCount++
  566. }
  567. if (noLimit && limit < count) || 0 < errCount {
  568. break
  569. }
  570. }
  571. return
  572. }
  573. func scanBlockRows(rows *sql.Rows) (ret *Block) {
  574. var block Block
  575. if err := rows.Scan(&block.ID, &block.ParentID, &block.RootID, &block.Hash, &block.Box, &block.Path, &block.HPath, &block.Name, &block.Alias, &block.Memo, &block.Tag, &block.Content, &block.FContent, &block.Markdown, &block.Length, &block.Type, &block.SubType, &block.IAL, &block.Sort, &block.Created, &block.Updated); nil != err {
  576. logging.LogErrorf("query scan field failed: %s\n%s", err, logging.ShortStack())
  577. return
  578. }
  579. ret = &block
  580. putBlockCache(ret)
  581. return
  582. }
  583. func scanBlockRow(row *sql.Row) (ret *Block) {
  584. var block Block
  585. if err := row.Scan(&block.ID, &block.ParentID, &block.RootID, &block.Hash, &block.Box, &block.Path, &block.HPath, &block.Name, &block.Alias, &block.Memo, &block.Tag, &block.Content, &block.FContent, &block.Markdown, &block.Length, &block.Type, &block.SubType, &block.IAL, &block.Sort, &block.Created, &block.Updated); nil != err {
  586. if sql.ErrNoRows != err {
  587. logging.LogErrorf("query scan field failed: %s\n%s", err, logging.ShortStack())
  588. }
  589. return
  590. }
  591. ret = &block
  592. putBlockCache(ret)
  593. return
  594. }
  595. func GetChildBlocks(parentID, condition string) (ret []*Block) {
  596. blockIDs := queryBlockChildrenIDs(parentID)
  597. var params []string
  598. for _, id := range blockIDs {
  599. params = append(params, "\""+id+"\"")
  600. }
  601. ret = []*Block{}
  602. sqlStmt := "SELECT * FROM blocks AS ref WHERE ref.id IN (" + strings.Join(params, ",") + ")"
  603. if "" != condition {
  604. sqlStmt += " AND " + condition
  605. }
  606. rows, err := query(sqlStmt)
  607. if nil != err {
  608. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  609. return
  610. }
  611. defer rows.Close()
  612. for rows.Next() {
  613. if block := scanBlockRows(rows); nil != block {
  614. ret = append(ret, block)
  615. }
  616. }
  617. return
  618. }
  619. func GetAllChildBlocks(rootIDs []string, condition string) (ret []*Block) {
  620. ret = []*Block{}
  621. sqlStmt := "SELECT * FROM blocks AS ref WHERE ref.root_id IN ('" + strings.Join(rootIDs, "','") + "')"
  622. if "" != condition {
  623. sqlStmt += " AND " + condition
  624. }
  625. rows, err := query(sqlStmt)
  626. if nil != err {
  627. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  628. return
  629. }
  630. defer rows.Close()
  631. for rows.Next() {
  632. if block := scanBlockRows(rows); nil != block {
  633. ret = append(ret, block)
  634. }
  635. }
  636. return
  637. }
  638. func GetBlock(id string) (ret *Block) {
  639. ret = getBlockCache(id)
  640. if nil != ret {
  641. return
  642. }
  643. row := queryRow("SELECT * FROM blocks WHERE id = ?", id)
  644. ret = scanBlockRow(row)
  645. if nil != ret {
  646. putBlockCache(ret)
  647. }
  648. return
  649. }
  650. func GetRootUpdated() (ret map[string]string, err error) {
  651. rows, err := query("SELECT root_id, updated FROM `blocks` WHERE type = 'd'")
  652. if nil != err {
  653. logging.LogErrorf("sql query failed: %s", err)
  654. return
  655. }
  656. defer rows.Close()
  657. ret = map[string]string{}
  658. for rows.Next() {
  659. var rootID, updated string
  660. rows.Scan(&rootID, &updated)
  661. ret[rootID] = updated
  662. }
  663. return
  664. }
  665. func GetDuplicatedRootIDs(blocksTable string) (ret []string) {
  666. rows, err := query("SELECT DISTINCT root_id FROM `" + blocksTable + "` GROUP BY id HAVING COUNT(*) > 1")
  667. if nil != err {
  668. logging.LogErrorf("sql query failed: %s", err)
  669. return
  670. }
  671. defer rows.Close()
  672. for rows.Next() {
  673. var id string
  674. rows.Scan(&id)
  675. ret = append(ret, id)
  676. }
  677. return
  678. }
  679. func GetAllRootBlocks() (ret []*Block) {
  680. stmt := "SELECT * FROM blocks WHERE type = 'd'"
  681. rows, err := query(stmt)
  682. if nil != err {
  683. logging.LogErrorf("sql query [%s] failed: %s", stmt, err)
  684. return
  685. }
  686. defer rows.Close()
  687. for rows.Next() {
  688. if block := scanBlockRows(rows); nil != block {
  689. ret = append(ret, block)
  690. }
  691. }
  692. return
  693. }
  694. func GetBlocks(ids []string) (ret []*Block) {
  695. var notHitIDs []string
  696. cached := map[string]*Block{}
  697. for _, id := range ids {
  698. b := getBlockCache(id)
  699. if nil != b {
  700. cached[id] = b
  701. } else {
  702. notHitIDs = append(notHitIDs, id)
  703. }
  704. }
  705. if 1 > len(notHitIDs) {
  706. for _, id := range ids {
  707. ret = append(ret, cached[id])
  708. }
  709. return
  710. }
  711. length := len(notHitIDs)
  712. stmtBuilder := bytes.Buffer{}
  713. stmtBuilder.WriteString("SELECT * FROM blocks WHERE id IN (")
  714. var args []interface{}
  715. for i, id := range notHitIDs {
  716. args = append(args, id)
  717. stmtBuilder.WriteByte('?')
  718. if i < length-1 {
  719. stmtBuilder.WriteByte(',')
  720. }
  721. }
  722. stmtBuilder.WriteString(")")
  723. sqlStmt := stmtBuilder.String()
  724. rows, err := query(sqlStmt, args...)
  725. if nil != err {
  726. logging.LogErrorf("sql query [%s] failed: %s", sqlStmt, err)
  727. return
  728. }
  729. defer rows.Close()
  730. for rows.Next() {
  731. if block := scanBlockRows(rows); nil != block {
  732. putBlockCache(block)
  733. cached[block.ID] = block
  734. }
  735. }
  736. for _, id := range ids {
  737. ret = append(ret, cached[id])
  738. }
  739. return
  740. }
  741. func GetContainerText(container *ast.Node) string {
  742. buf := &bytes.Buffer{}
  743. buf.Grow(4096)
  744. leaf := treenode.FirstLeafBlock(container)
  745. if nil == leaf {
  746. return ""
  747. }
  748. ast.Walk(leaf, func(n *ast.Node, entering bool) ast.WalkStatus {
  749. if !entering {
  750. return ast.WalkContinue
  751. }
  752. switch n.Type {
  753. case ast.NodeText, ast.NodeLinkText, ast.NodeFileAnnotationRefText, ast.NodeCodeBlockCode, ast.NodeMathBlockContent:
  754. buf.Write(n.Tokens)
  755. case ast.NodeTextMark:
  756. buf.WriteString(n.Content())
  757. case ast.NodeBlockRef:
  758. if anchor := n.ChildByType(ast.NodeBlockRefText); nil != anchor {
  759. buf.WriteString(anchor.Text())
  760. } else if anchor = n.ChildByType(ast.NodeBlockRefDynamicText); nil != anchor {
  761. buf.WriteString(anchor.Text())
  762. } else {
  763. text := GetRefText(n.TokensStr())
  764. buf.WriteString(text)
  765. }
  766. return ast.WalkSkipChildren
  767. }
  768. return ast.WalkContinue
  769. })
  770. return buf.String()
  771. }
  772. func containsLimitClause(stmt string) bool {
  773. return strings.Contains(strings.ToLower(stmt), " limit ") ||
  774. strings.Contains(strings.ToLower(stmt), "\nlimit ") ||
  775. strings.Contains(strings.ToLower(stmt), "\tlimit ")
  776. }