Something went wrong. Try again.
A privacy-first, self-hosted, fully open source personal knowledge management software, written in typescript and golang. (PERSONAL FORK)
Something went wrong. Try again.
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193// SiYuan - Refactor your thinking// Copyright (c) 2020-present, b3log.org//// This program is free software: you can redistribute it and/or modify// it under the terms of the GNU Affero General Public License as published by// the Free Software Foundation, either version 3 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU Affero General Public License for more details.//// You should have received a copy of the GNU Affero General Public License// along with this program. If not, see <https://www.gnu.org/licenses/>.
package sql
import ( "database/sql" "errors" "math" "strconv" "strings"
"github.com/88250/vitess-sqlparser/sqlparser" "github.com/siyuan-note/logging")
func QueryAssetContentNoLimit(stmt string) (ret []map[string]interface{}, err error) { return queryAssetContentRawStmt(stmt, math.MaxInt)}
func queryAssetContentRawStmt(stmt string, limit int) (ret []map[string]interface{}, err error) { rows, err := queryAssetContent(stmt) if err != nil { if strings.Contains(err.Error(), "syntax error") { return } return } defer rows.Close()
cols, err := rows.Columns() if err != nil || nil == cols { return }
noLimit := !containsLimitClause(stmt) var count, errCount int for rows.Next() { columns := make([]interface{}, len(cols)) columnPointers := make([]interface{}, len(cols)) for i := range columns { columnPointers[i] = &columns[i] }
if err = rows.Scan(columnPointers...); err != nil { return }
m := make(map[string]interface{}) for i, colName := range cols { val := columnPointers[i].(*interface{}) m[colName] = *val }
ret = append(ret, m) count++ if (noLimit && limit < count) || 0 < errCount { break } } return}
func SelectAssetContentsRawStmt(stmt string, page, limit int) (ret []*AssetContent) { parsedStmt, err := sqlparser.Parse(stmt) if err != nil { return selectAssetContentsRawStmt(stmt, limit) }
switch parsedStmt.(type) { case *sqlparser.Select: slct := parsedStmt.(*sqlparser.Select) if nil == slct.Limit { slct.Limit = &sqlparser.Limit{ Rowcount: &sqlparser.SQLVal{ Type: sqlparser.IntVal, Val: []byte(strconv.Itoa(limit)), }, } slct.Limit.Offset = &sqlparser.SQLVal{ Type: sqlparser.IntVal, Val: []byte(strconv.Itoa((page - 1) * limit)), } } else { if nil != slct.Limit.Rowcount && 0 < len(slct.Limit.Rowcount.(*sqlparser.SQLVal).Val) { limit, _ = strconv.Atoi(string(slct.Limit.Rowcount.(*sqlparser.SQLVal).Val)) if 0 >= limit { limit = 32 } }
slct.Limit.Rowcount = &sqlparser.SQLVal{ Type: sqlparser.IntVal, Val: []byte(strconv.Itoa(limit)), } slct.Limit.Offset = &sqlparser.SQLVal{ Type: sqlparser.IntVal, Val: []byte(strconv.Itoa((page - 1) * limit)), } }
stmt = sqlparser.String(slct) default: return }
stmt = strings.ReplaceAll(stmt, "\\'", "''") stmt = strings.ReplaceAll(stmt, "\\\"", "\"") stmt = strings.ReplaceAll(stmt, "\\\\*", "\\*") stmt = strings.ReplaceAll(stmt, "from dual", "") rows, err := queryAssetContent(stmt) if err != nil { if strings.Contains(err.Error(), "syntax error") { return } logging.LogWarnf("sql query [%s] failed: %s", stmt, err) return } defer rows.Close() for rows.Next() { if ac := scanAssetContentRows(rows); nil != ac { ret = append(ret, ac) } } return}
func SelectAssetContentsRawStmtNoParse(stmt string, limit int) (ret []*AssetContent) { return selectAssetContentsRawStmt(stmt, limit)}
func selectAssetContentsRawStmt(stmt string, limit int) (ret []*AssetContent) { rows, err := queryAssetContent(stmt) if err != nil { if strings.Contains(err.Error(), "syntax error") { return } return } defer rows.Close()
noLimit := !containsLimitClause(stmt) var count, errCount int for rows.Next() { count++ if ac := scanAssetContentRows(rows); nil != ac { ret = append(ret, ac) } else { logging.LogWarnf("raw sql query [%s] failed", stmt) errCount++ }
if (noLimit && limit < count) || 0 < errCount { break } } return}
func scanAssetContentRows(rows *sql.Rows) (ret *AssetContent) { var ac AssetContent if err := rows.Scan(&ac.ID, &ac.Name, &ac.Ext, &ac.Path, &ac.Size, &ac.Updated, &ac.Content); err != nil { logging.LogErrorf("query scan field failed: %s\n%s", err, logging.ShortStack()) return } ret = &ac return}
func queryAssetContent(query string, args ...interface{}) (*sql.Rows, error) { query = strings.TrimSpace(query) if "" == query { return nil, errors.New("statement is empty") } if nil == assetContentDB { return nil, errors.New("database is nil") } return assetContentDB.Query(query, args...)}