// Query executes queries that return rows, but don't modify the database. func (db *DB) Query(queries []string, tx, xTime bool) ([]*Rows, error) { type Queryer interface { Query(query string, args []driver.Value) (driver.Rows, error) } var allRows []*Rows err := func() (err error) { var queryer Queryer var t driver.Tx defer func() { // XXX THIS DOESN'T ACTUALLY WORK! Might as WELL JUST COMMIT? if t != nil { if err != nil { t.Rollback() return } t.Commit() } }() queryer = db.sqlite3conn // Create the correct query object, depending on whether a // transaction was requested. if tx { t, err = db.sqlite3conn.Begin() if err != nil { return err } } for _, q := range queries { if q == "" { continue } rows := &Rows{} start := time.Now() rs, err := queryer.Query(q, nil) if err != nil { rows.Error = err.Error() allRows = append(allRows, rows) continue } defer rs.Close() // This adds to all defers, right? Nothing leaks? XXX Could consume memory. Perhaps anon would be best. columns := rs.Columns() rows.Columns = columns rows.Types = rs.(*sqlite3.SQLiteRows).DeclTypes() dest := make([]driver.Value, len(rows.Columns)) for { err := rs.Next(dest) if err != nil { if err != io.EOF { rows.Error = err.Error() } break } values := make([]interface{}, len(rows.Columns)) // Text values come over (from sqlite-go) as []byte instead of strings // for some reason, so we have explicitly convert (but only when type // is "text" so we don't affect BLOB types) for i, v := range dest { if rows.Types[i] == "text" { switch val := v.(type) { case []byte: values[i] = string(val) default: values[i] = val } } else { values[i] = v } } rows.Values = append(rows.Values, values) } if xTime { rows.Time = time.Now().Sub(start).Seconds() } allRows = append(allRows, rows) } return nil }() return allRows, err }
// Query executes queries that return rows, but don't modify the database. func (db *DB) Query(queries []string, tx, xTime bool) ([]*Rows, error) { type Queryer interface { Query(query string, args []driver.Value) (driver.Rows, error) } var allRows []*Rows err := func() (err error) { var queryer Queryer var t driver.Tx defer func() { // XXX THIS DOESN'T ACTUALLY WORK! Might as WELL JUST COMMIT? if t != nil { if err != nil { t.Rollback() return } t.Commit() } }() queryer = db.sqlite3conn // Create the correct query object, depending on whether a // transaction was requested. if tx { t, err = db.sqlite3conn.Begin() if err != nil { return err } } for _, q := range queries { if q == "" { continue } rows := &Rows{} start := time.Now() rs, err := queryer.Query(q, nil) if err != nil { rows.Error = err.Error() allRows = append(allRows, rows) continue } defer rs.Close() // This adds to all defers, right? Nothing leaks? XXX Could consume memory. Perhaps anon would be best. columns := rs.Columns() rows.Columns = columns rows.Types = rs.(*sqlite3.SQLiteRows).DeclTypes() dest := make([]driver.Value, len(rows.Columns)) for { err := rs.Next(dest) if err != nil { if err != io.EOF { rows.Error = err.Error() } break } values := make([]interface{}, len(rows.Columns)) // Special case -- convert []uint8 to string. Perhaps this should be a config option. for i, v := range dest { switch u := v.(type) { case []uint8: values[i] = string(u) default: values[i] = u } } rows.Values = append(rows.Values, values) } if xTime { rows.Time = time.Now().Sub(start).Seconds() } allRows = append(allRows, rows) } return nil }() return allRows, err }
// Execute executes queries that modify the database. func (db *DB) Execute(queries []string, tx, xTime bool) ([]*Result, error) { type Execer interface { Exec(query string, args []driver.Value) (driver.Result, error) } var allResults []*Result err := func() error { var execer Execer var rollback bool var t driver.Tx var err error // Check for the err, if set rollback. defer func() { if t != nil { if rollback { t.Rollback() return } t.Commit() } }() // handleError sets the error field on the given result. It returns // whether the caller should continue processing or break. handleError := func(result *Result, err error) bool { result.Error = err.Error() allResults = append(allResults, result) if tx { rollback = true // Will trigger the rollback. return false } return true } execer = db.sqlite3conn // Create the correct execution object, depending on whether a // transaction was requested. if tx { t, err = db.sqlite3conn.Begin() if err != nil { return err } } // Execute each query. for _, q := range queries { if q == "" { continue } result := &Result{} start := time.Now() r, err := execer.Exec(q, nil) if err != nil { if handleError(result, err) { continue } break } lid, err := r.LastInsertId() if err != nil { if handleError(result, err) { continue } break } result.LastInsertID = lid ra, err := r.RowsAffected() if err != nil { if handleError(result, err) { continue } break } result.RowsAffected = ra if xTime { result.Time = time.Now().Sub(start).Seconds() } allResults = append(allResults, result) } return nil }() return allResults, err }
// Query executes queries that return rows, but don't modify the database. func (db *DB) Query(queries []string, tx, xTime bool) ([]*Rows, error) { stats.Add(numQueries, int64(len(queries))) if tx { stats.Add(numQTx, 1) } type Queryer interface { Query(query string, args []driver.Value) (driver.Rows, error) } var allRows []*Rows err := func() (err error) { var queryer Queryer var t driver.Tx defer func() { // XXX THIS DOESN'T ACTUALLY WORK! Might as WELL JUST COMMIT? if t != nil { if err != nil { t.Rollback() return } t.Commit() } }() queryer = db.sqlite3conn // Create the correct query object, depending on whether a // transaction was requested. if tx { t, err = db.sqlite3conn.Begin() if err != nil { return err } } for _, q := range queries { if q == "" { continue } rows := &Rows{} start := time.Now() rs, err := queryer.Query(q, nil) if err != nil { rows.Error = err.Error() allRows = append(allRows, rows) continue } defer rs.Close() columns := rs.Columns() rows.Columns = columns rows.Types = rs.(*sqlite3.SQLiteRows).DeclTypes() dest := make([]driver.Value, len(rows.Columns)) for { err := rs.Next(dest) if err != nil { if err != io.EOF { rows.Error = err.Error() } break } values := normalizeRowValues(dest, rows.Types) rows.Values = append(rows.Values, values) } if xTime { rows.Time = time.Now().Sub(start).Seconds() } allRows = append(allRows, rows) } return nil }() return allRows, err }