asset_content_query.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  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. "database/sql"
  19. "errors"
  20. "math"
  21. "strconv"
  22. "strings"
  23. "github.com/88250/vitess-sqlparser/sqlparser"
  24. "github.com/siyuan-note/logging"
  25. )
  26. func QueryAssetContentNoLimit(stmt string) (ret []map[string]interface{}, err error) {
  27. return queryAssetContentRawStmt(stmt, math.MaxInt)
  28. }
  29. func queryAssetContentRawStmt(stmt string, limit int) (ret []map[string]interface{}, err error) {
  30. rows, err := queryAssetContent(stmt)
  31. if nil != err {
  32. if strings.Contains(err.Error(), "syntax error") {
  33. return
  34. }
  35. return
  36. }
  37. defer rows.Close()
  38. cols, err := rows.Columns()
  39. if nil != err || nil == cols {
  40. return
  41. }
  42. noLimit := !containsLimitClause(stmt)
  43. var count, errCount int
  44. for rows.Next() {
  45. columns := make([]interface{}, len(cols))
  46. columnPointers := make([]interface{}, len(cols))
  47. for i := range columns {
  48. columnPointers[i] = &columns[i]
  49. }
  50. if err = rows.Scan(columnPointers...); nil != err {
  51. return
  52. }
  53. m := make(map[string]interface{})
  54. for i, colName := range cols {
  55. val := columnPointers[i].(*interface{})
  56. m[colName] = *val
  57. }
  58. ret = append(ret, m)
  59. count++
  60. if (noLimit && limit < count) || 0 < errCount {
  61. break
  62. }
  63. }
  64. return
  65. }
  66. func SelectAssetContentsRawStmt(stmt string, page, limit int) (ret []*AssetContent) {
  67. parsedStmt, err := sqlparser.Parse(stmt)
  68. if nil != err {
  69. return selectAssetContentsRawStmt(stmt, limit)
  70. }
  71. switch parsedStmt.(type) {
  72. case *sqlparser.Select:
  73. slct := parsedStmt.(*sqlparser.Select)
  74. if nil == slct.Limit {
  75. slct.Limit = &sqlparser.Limit{
  76. Rowcount: &sqlparser.SQLVal{
  77. Type: sqlparser.IntVal,
  78. Val: []byte(strconv.Itoa(limit)),
  79. },
  80. }
  81. slct.Limit.Offset = &sqlparser.SQLVal{
  82. Type: sqlparser.IntVal,
  83. Val: []byte(strconv.Itoa((page - 1) * limit)),
  84. }
  85. } else {
  86. if nil != slct.Limit.Rowcount && 0 < len(slct.Limit.Rowcount.(*sqlparser.SQLVal).Val) {
  87. limit, _ = strconv.Atoi(string(slct.Limit.Rowcount.(*sqlparser.SQLVal).Val))
  88. if 0 >= limit {
  89. limit = 32
  90. }
  91. }
  92. slct.Limit.Rowcount = &sqlparser.SQLVal{
  93. Type: sqlparser.IntVal,
  94. Val: []byte(strconv.Itoa(limit)),
  95. }
  96. slct.Limit.Offset = &sqlparser.SQLVal{
  97. Type: sqlparser.IntVal,
  98. Val: []byte(strconv.Itoa((page - 1) * limit)),
  99. }
  100. }
  101. stmt = sqlparser.String(slct)
  102. default:
  103. return
  104. }
  105. stmt = strings.ReplaceAll(stmt, "\\'", "''")
  106. stmt = strings.ReplaceAll(stmt, "\\\"", "\"")
  107. stmt = strings.ReplaceAll(stmt, "\\\\*", "\\*")
  108. stmt = strings.ReplaceAll(stmt, "from dual", "")
  109. rows, err := queryAssetContent(stmt)
  110. if nil != err {
  111. if strings.Contains(err.Error(), "syntax error") {
  112. return
  113. }
  114. logging.LogWarnf("sql query [%s] failed: %s", stmt, err)
  115. return
  116. }
  117. defer rows.Close()
  118. for rows.Next() {
  119. if ac := scanAssetContentRows(rows); nil != ac {
  120. ret = append(ret, ac)
  121. }
  122. }
  123. return
  124. }
  125. func SelectAssetContentsRawStmtNoParse(stmt string, limit int) (ret []*AssetContent) {
  126. return selectAssetContentsRawStmt(stmt, limit)
  127. }
  128. func selectAssetContentsRawStmt(stmt string, limit int) (ret []*AssetContent) {
  129. rows, err := queryAssetContent(stmt)
  130. if nil != err {
  131. if strings.Contains(err.Error(), "syntax error") {
  132. return
  133. }
  134. return
  135. }
  136. defer rows.Close()
  137. noLimit := !containsLimitClause(stmt)
  138. var count, errCount int
  139. for rows.Next() {
  140. count++
  141. if ac := scanAssetContentRows(rows); nil != ac {
  142. ret = append(ret, ac)
  143. } else {
  144. logging.LogWarnf("raw sql query [%s] failed", stmt)
  145. errCount++
  146. }
  147. if (noLimit && limit < count) || 0 < errCount {
  148. break
  149. }
  150. }
  151. return
  152. }
  153. func scanAssetContentRows(rows *sql.Rows) (ret *AssetContent) {
  154. var ac AssetContent
  155. if err := rows.Scan(&ac.ID, &ac.Name, &ac.Ext, &ac.Path, &ac.Size, &ac.Updated, &ac.Content); nil != err {
  156. logging.LogErrorf("query scan field failed: %s\n%s", err, logging.ShortStack())
  157. return
  158. }
  159. ret = &ac
  160. return
  161. }
  162. func queryAssetContent(query string, args ...interface{}) (*sql.Rows, error) {
  163. query = strings.TrimSpace(query)
  164. if "" == query {
  165. return nil, errors.New("statement is empty")
  166. }
  167. return assetContentDB.Query(query, args...)
  168. }