Merge pull request #558 from sauyon/add-sample-queries

Add sample DB-related queries
This commit is contained in:
Chris Smowton
2021-08-12 21:55:14 +01:00
committed by GitHub
37 changed files with 2131 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
package main
import "gorm.io/gorm"
func getUsers(db *gorm.DB, names []string) []User {
res := make([]User, 0, len(names))
for _, name := range names {
var user User
db.Where("name = ?", name).First(&user)
res = append(res, user)
}
return res
}

View File

@@ -0,0 +1,29 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Database calls in loops are slower than running a single query and consume more resources. This
can lead to denial of service attacks if the loop bounds can be controlled by an attacker.</p>
</overview>
<recommendation>
<p>Ensure that where possible, database queries are not run in a loop, instead running a single query to get all relevant data.</p>
</recommendation>
<example>
<p>In the example below, users in a database are queried one by one in a loop:</p>
<sample src="DatabaseCallInLoop.go" />
<p>This is corrected by running a single query that selects all of the users at once:</p>
<sample src="DatabaseCallInLoopGood.go" />
</example>
<references>
</references>
</qhelp>

View File

@@ -0,0 +1,69 @@
/**
* @name Database call in loop
* @description Detects database operations within loops.
* Doing operations in series can be slow and lead to N+1 situations.
* @kind path-problem
* @problem.severity warning
* @precision high
* @id go/examples/database-call-in-loop
*/
import go
class DatabaseAccess extends DataFlow::MethodCallNode {
DatabaseAccess() {
exists(string name |
this.getTarget().hasQualifiedName(Gorm::packagePath(), "DB", name) and
// all terminating Gorm methods
name =
[
"Find", "Take", "Last", "Scan", "Row", "Rows", "ScanRows", "Pluck", "Count", "First",
"FirstOrInit", "FindOrCreate", "Update", "Updates", "UpdateColumn", "UpdateColumns",
"Save", "Create", "Delete", "Exec"
]
)
}
}
class CallGraphNode extends Locatable {
CallGraphNode() {
this instanceof LoopStmt
or
this instanceof CallExpr
or
this instanceof FuncDef
}
}
/**
* Holds if `pred` calls `succ`, i.e. is an edge in the call graph,
* This includes explicit edges from call -> callee, to produce better paths.
*/
predicate callGraphEdge(CallGraphNode pred, CallGraphNode succ) {
// Go from a loop to an enclosed expression.
pred.(LoopStmt).getBody().getAChild*() = succ.(CallExpr)
or
// Go from a call to the called function.
pred.(CallExpr) = succ.(FuncDef).getACall().asExpr()
or
// Go from a function to an enclosed loop.
pred.(FuncDef) = succ.(LoopStmt).getEnclosingFunction()
or
// Go from a function to an enclosed call.
pred.(FuncDef) = succ.(CallExpr).getEnclosingFunction()
}
query predicate edges(CallGraphNode pred, CallGraphNode succ) {
callGraphEdge(pred, succ) and
// Limit the range of edges to only those that are relevant.
// This helps to speed up the query by reducing the size of the outputted path information.
exists(LoopStmt loop, DatabaseAccess dbAccess |
// is between a loop and a db access
callGraphEdge*(loop, pred) and
callGraphEdge*(succ, dbAccess.asExpr())
)
}
from LoopStmt loop, DatabaseAccess dbAccess
where edges*(loop, dbAccess.asExpr())
select dbAccess, loop, dbAccess, "$@ is called in $@", dbAccess, dbAccess.toString(), loop, "a loop"

View File

@@ -0,0 +1,9 @@
package main
import "gorm.io/gorm"
func getUsersGood(db *gorm.DB, names []string) []User {
res := make([]User, 0, len(names))
db.Where("name IN ?", names).Find(&res)
return res
}

View File

@@ -0,0 +1,14 @@
package main
import "os"
func openFiles(filenames []string) {
for _, filename := range filenames {
file, err := os.Open(filename)
defer file.Close()
if err != nil {
// handle error
}
// work on file
}
}

View File

@@ -0,0 +1,32 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>A deferred statement in a loop will not execute until the end of the function. This can lead to unintentionally holding resources open, like file handles or database transactions.</p>
</overview>
<recommendation>
<p>Either run the deferred function manually, or create a subroutine that contains the defer.</p>
</recommendation>
<example>
<p>In the example below, the files opened in the loop are not closed until the end of the function:</p>
<sample src="DeferInLoop.go" />
<p>The corrected version puts the loop body into a function.</p>
<sample src="DeferInLoopGood.go" />
</example>
<references>
<li>
<a href="https://golang.org/ref/spec#Defer_statements">Defer statements</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,18 @@
package main
import "os"
func openFile(filename string) {
file, err := os.Open(filename)
defer file.Close()
if err != nil {
// handle error
}
// work on file
}
func openFilesGood(filenames []string) {
for _, filename := range filenames {
openFile(filename)
}
}

View File

@@ -0,0 +1,9 @@
package main
import "gorm.io/gorm"
func getUserId(db *gorm.DB, name string) int64 {
var user User
db.Where("name = ?", name).First(&user)
return user.Id
}

View File

@@ -0,0 +1,34 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>GORM errors are returned as a field of the return value instead of a separate return value.</p>
<p>It is therefore very easy to miss that an error may occur and omit error handling routines.</p>
</overview>
<recommendation>
<p>Ensure that GORM errors are checked.</p>
</recommendation>
<example>
<p>In the example below, the error from the database query is never checked:</p>
<sample src="GORMErrorNotChecked.go" />
<p>The corrected version checks and handles the error before returning.</p>
<sample src="GORMErrorNotCheckedGood.go" />
</example>
<references>
<li>
<a href="https://gorm.io/docs/error_handling.html">GORM Error Handling</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,35 @@
/**
* @name GORM error not checked
* @description A call that interacts with the database using the GORM library
* without checking whether there was an error.
* @kind problem
* @problem.severity warning
* @id go/examples/gorm-error-not-checked
* @precision high
*/
import go
import semmle.go.frameworks.SQL
from DataFlow::MethodCallNode call
where
exists(string name | call.getTarget().hasQualifiedName(Gorm::packagePath(), "DB", name) |
name != "InstantSet" and
name != "LogMode"
) and
// the value from the call does not:
not exists(DataFlow::Node succ | TaintTracking::localTaintStep*(call, succ) |
// get assigned to any variables
succ = any(Write w).getRhs()
or
// get returned
succ instanceof DataFlow::ResultNode
or
// have any methods chained on it
exists(DataFlow::MethodCallNode m | succ = m.getReceiver())
or
// have its `Error` field read
exists(DataFlow::FieldReadNode fr | fr.readsField(succ, _, _, "Error"))
)
select call,
"This call appears to interact with the database without checking whether an error was encountered."

View File

@@ -0,0 +1,11 @@
package main
import "gorm.io/gorm"
func getUserIdGood(db *gorm.DB, name string) int64 {
var user User
if err := db.Where("name = ?", name).First(&user).Error; err != nil {
// handle errors
}
return user.Id
}

View File

@@ -0,0 +1,13 @@
edges
| DatabaseCallInLoop.go:7:2:11:2 | range statement | DatabaseCallInLoop.go:9:3:9:41 | call to First |
| test.go:10:1:12:1 | function declaration | test.go:11:2:11:13 | call to Take |
| test.go:14:1:16:1 | function declaration | test.go:15:2:15:13 | call to runQuery |
| test.go:15:2:15:13 | call to runQuery | test.go:10:1:12:1 | function declaration |
| test.go:20:2:22:2 | for statement | test.go:21:3:21:14 | call to runQuery |
| test.go:21:3:21:14 | call to runQuery | test.go:10:1:12:1 | function declaration |
| test.go:24:2:26:2 | for statement | test.go:25:3:25:17 | call to runRunQuery |
| test.go:25:3:25:17 | call to runRunQuery | test.go:14:1:16:1 | function declaration |
#select
| DatabaseCallInLoop.go:9:3:9:41 | call to First | DatabaseCallInLoop.go:7:2:11:2 | range statement | DatabaseCallInLoop.go:9:3:9:41 | call to First | $@ is called in $@ | DatabaseCallInLoop.go:9:3:9:41 | call to First | call to First | DatabaseCallInLoop.go:7:2:11:2 | range statement | a loop |
| test.go:11:2:11:13 | call to Take | test.go:20:2:22:2 | for statement | test.go:11:2:11:13 | call to Take | $@ is called in $@ | test.go:11:2:11:13 | call to Take | call to Take | test.go:20:2:22:2 | for statement | a loop |
| test.go:11:2:11:13 | call to Take | test.go:24:2:26:2 | for statement | test.go:11:2:11:13 | call to Take | $@ is called in $@ | test.go:11:2:11:13 | call to Take | call to Take | test.go:24:2:26:2 | for statement | a loop |

View File

@@ -0,0 +1,13 @@
package main
import "gorm.io/gorm"
func getUsers(db *gorm.DB, names []string) []User {
res := make([]User, 0, len(names))
for _, name := range names {
var user User
db.Where("name = ?", name).First(&user)
res = append(res, user)
}
return res
}

View File

@@ -0,0 +1 @@
experimental/CWE-400/DatabaseCallInLoop.ql

View File

@@ -0,0 +1,9 @@
package main
import "gorm.io/gorm"
func getUsersGood(db *gorm.DB, names []string) []User {
res := make([]User, 0, len(names))
db.Where("name IN ?", names).Find(&res)
return res
}

View File

@@ -0,0 +1,5 @@
module query-tests/databasecallinloop
go 1.16
require gorm.io/gorm v1.21.12

View File

@@ -0,0 +1,27 @@
package main
import "gorm.io/gorm"
type User struct {
Id int64
Name string
}
func runQuery(db *gorm.DB) {
db.Take(nil)
}
func runRunQuery(db *gorm.DB) {
runQuery(db)
}
func main() {
var db *gorm.DB
for i := 0; i < 10; i++ {
runQuery(db)
}
for i := 10; i > 0; i-- {
runRunQuery(db)
}
}

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-NOW Jinzhu <wosmvp@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,803 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for gorm.io/gorm, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: gorm.io/gorm (exports: DB; functions: )
// Package gorm is a stub of gorm.io/gorm, generated by depstubber.
package gorm
import (
context "context"
sql "database/sql"
reflect "reflect"
strings "strings"
sync "sync"
time "time"
)
type Association struct {
DB *DB
Relationship interface{}
Error error
}
func (_ *Association) Append(_ ...interface{}) error {
return nil
}
func (_ *Association) Clear() error {
return nil
}
func (_ *Association) Count() int64 {
return 0
}
func (_ *Association) Delete(_ ...interface{}) error {
return nil
}
func (_ *Association) Find(_ interface{}, _ ...interface{}) error {
return nil
}
func (_ *Association) Replace(_ ...interface{}) error {
return nil
}
type ColumnType interface {
DatabaseTypeName() string
DecimalSize() (int64, int64, bool)
Length() (int64, bool)
Name() string
Nullable() (bool, bool)
}
type Config struct {
SkipDefaultTransaction bool
NamingStrategy interface{}
FullSaveAssociations bool
Logger interface{}
NowFunc func() time.Time
DryRun bool
PrepareStmt bool
DisableAutomaticPing bool
DisableForeignKeyConstraintWhenMigrating bool
DisableNestedTransaction bool
AllowGlobalUpdate bool
QueryFields bool
CreateBatchSize int
ClauseBuilders map[string]interface{}
ConnPool ConnPool
Dialector Dialector
Plugins map[string]Plugin
}
func (_ Config) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {}
func (_ Config) DataTypeOf(_ interface{}) string {
return ""
}
func (_ Config) DefaultValueOf(_ interface{}) interface{} {
return nil
}
func (_ Config) Explain(_ string, _ ...interface{}) string {
return ""
}
func (_ Config) Initialize(_ *DB) error {
return nil
}
func (_ Config) Migrator(_ *DB) Migrator {
return nil
}
func (_ Config) Name() string {
return ""
}
func (_ Config) QuoteTo(_ interface{}, _ string) {}
func (_ *Config) AfterInitialize(_ *DB) error {
return nil
}
func (_ *Config) Apply(_ *Config) error {
return nil
}
type ConnPool interface {
ExecContext(_ context.Context, _ string, _ ...interface{}) (sql.Result, error)
PrepareContext(_ context.Context, _ string) (*sql.Stmt, error)
QueryContext(_ context.Context, _ string, _ ...interface{}) (*sql.Rows, error)
QueryRowContext(_ context.Context, _ string, _ ...interface{}) *sql.Row
}
type DB struct {
Config *Config
Error error
RowsAffected int64
Statement *Statement
}
func (_ DB) AfterInitialize(_ *DB) error {
return nil
}
func (_ DB) Apply(_ *Config) error {
return nil
}
func (_ DB) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {}
func (_ DB) DataTypeOf(_ interface{}) string {
return ""
}
func (_ DB) DefaultValueOf(_ interface{}) interface{} {
return nil
}
func (_ DB) Explain(_ string, _ ...interface{}) string {
return ""
}
func (_ DB) Initialize(_ *DB) error {
return nil
}
func (_ DB) Name() string {
return ""
}
func (_ DB) QuoteTo(_ interface{}, _ string) {}
func (_ *DB) AddError(_ error) error {
return nil
}
func (_ *DB) Assign(_ ...interface{}) *DB {
return nil
}
func (_ *DB) Association(_ string) *Association {
return nil
}
func (_ *DB) Attrs(_ ...interface{}) *DB {
return nil
}
func (_ *DB) AutoMigrate(_ ...interface{}) error {
return nil
}
func (_ *DB) Begin(_ ...*sql.TxOptions) *DB {
return nil
}
func (_ *DB) Callback() interface{} {
return nil
}
func (_ *DB) Clauses(_ ...interface{}) *DB {
return nil
}
func (_ *DB) Commit() *DB {
return nil
}
func (_ *DB) Count(_ *int64) *DB {
return nil
}
func (_ *DB) Create(_ interface{}) *DB {
return nil
}
func (_ *DB) CreateInBatches(_ interface{}, _ int) *DB {
return nil
}
func (_ *DB) DB() (*sql.DB, error) {
return nil, nil
}
func (_ *DB) Debug() *DB {
return nil
}
func (_ *DB) Delete(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Distinct(_ ...interface{}) *DB {
return nil
}
func (_ *DB) Exec(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Find(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) FindInBatches(_ interface{}, _ int, _ func(*DB, int) error) *DB {
return nil
}
func (_ *DB) First(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) FirstOrCreate(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) FirstOrInit(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Get(_ string) (interface{}, bool) {
return nil, false
}
func (_ *DB) Group(_ string) *DB {
return nil
}
func (_ *DB) Having(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) InstanceGet(_ string) (interface{}, bool) {
return nil, false
}
func (_ *DB) InstanceSet(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) Joins(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Last(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Limit(_ int) *DB {
return nil
}
func (_ *DB) Migrator() Migrator {
return nil
}
func (_ *DB) Model(_ interface{}) *DB {
return nil
}
func (_ *DB) Not(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Offset(_ int) *DB {
return nil
}
func (_ *DB) Omit(_ ...string) *DB {
return nil
}
func (_ *DB) Or(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Order(_ interface{}) *DB {
return nil
}
func (_ *DB) Pluck(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) Preload(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Raw(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Rollback() *DB {
return nil
}
func (_ *DB) RollbackTo(_ string) *DB {
return nil
}
func (_ *DB) Row() *sql.Row {
return nil
}
func (_ *DB) Rows() (*sql.Rows, error) {
return nil, nil
}
func (_ *DB) Save(_ interface{}) *DB {
return nil
}
func (_ *DB) SavePoint(_ string) *DB {
return nil
}
func (_ *DB) Scan(_ interface{}) *DB {
return nil
}
func (_ *DB) ScanRows(_ *sql.Rows, _ interface{}) error {
return nil
}
func (_ *DB) Scopes(_ ...func(*DB) *DB) *DB {
return nil
}
func (_ *DB) Select(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Session(_ *Session) *DB {
return nil
}
func (_ *DB) Set(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) SetupJoinTable(_ interface{}, _ string, _ interface{}) error {
return nil
}
func (_ *DB) Table(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Take(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Transaction(_ func(*DB) error, _ ...*sql.TxOptions) error {
return nil
}
func (_ *DB) Unscoped() *DB {
return nil
}
func (_ *DB) Update(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) UpdateColumn(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) UpdateColumns(_ interface{}) *DB {
return nil
}
func (_ *DB) Updates(_ interface{}) *DB {
return nil
}
func (_ *DB) Use(_ Plugin) error {
return nil
}
func (_ *DB) Where(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) WithContext(_ context.Context) *DB {
return nil
}
type Dialector interface {
BindVarTo(_ interface{}, _ *Statement, _ interface{})
DataTypeOf(_ interface{}) string
DefaultValueOf(_ interface{}) interface{}
Explain(_ string, _ ...interface{}) string
Initialize(_ *DB) error
Migrator(_ *DB) Migrator
Name() string
QuoteTo(_ interface{}, _ string)
}
type Migrator interface {
AddColumn(_ interface{}, _ string) error
AlterColumn(_ interface{}, _ string) error
AutoMigrate(_ ...interface{}) error
ColumnTypes(_ interface{}) ([]ColumnType, error)
CreateConstraint(_ interface{}, _ string) error
CreateIndex(_ interface{}, _ string) error
CreateTable(_ ...interface{}) error
CreateView(_ string, _ ViewOption) error
CurrentDatabase() string
DropColumn(_ interface{}, _ string) error
DropConstraint(_ interface{}, _ string) error
DropIndex(_ interface{}, _ string) error
DropTable(_ ...interface{}) error
DropView(_ string) error
FullDataTypeOf(_ interface{}) interface{}
HasColumn(_ interface{}, _ string) bool
HasConstraint(_ interface{}, _ string) bool
HasIndex(_ interface{}, _ string) bool
HasTable(_ interface{}) bool
MigrateColumn(_ interface{}, _ interface{}, _ ColumnType) error
RenameColumn(_ interface{}, _ string, _ string) error
RenameIndex(_ interface{}, _ string, _ string) error
RenameTable(_ interface{}, _ interface{}) error
}
type Plugin interface {
Initialize(_ *DB) error
Name() string
}
type Session struct {
DryRun bool
PrepareStmt bool
NewDB bool
SkipHooks bool
SkipDefaultTransaction bool
DisableNestedTransaction bool
AllowGlobalUpdate bool
FullSaveAssociations bool
QueryFields bool
Context context.Context
Logger interface{}
NowFunc func() time.Time
CreateBatchSize int
}
type Statement struct {
DB *DB
TableExpr interface{}
Table string
Model interface{}
Unscoped bool
Dest interface{}
ReflectValue reflect.Value
Clauses map[string]interface{}
BuildClauses []string
Distinct bool
Selects []string
Omits []string
Joins []interface{}
Preloads map[string][]interface{}
Settings sync.Map
ConnPool ConnPool
Schema interface{}
Context context.Context
RaiseErrorOnNotFound bool
SkipHooks bool
SQL strings.Builder
Vars []interface{}
CurDestIndex int
}
func (_ Statement) AddError(_ error) error {
return nil
}
func (_ Statement) AfterInitialize(_ *DB) error {
return nil
}
func (_ Statement) Apply(_ *Config) error {
return nil
}
func (_ Statement) Assign(_ ...interface{}) *DB {
return nil
}
func (_ Statement) Association(_ string) *Association {
return nil
}
func (_ Statement) Attrs(_ ...interface{}) *DB {
return nil
}
func (_ Statement) AutoMigrate(_ ...interface{}) error {
return nil
}
func (_ Statement) Begin(_ ...*sql.TxOptions) *DB {
return nil
}
func (_ Statement) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {}
func (_ Statement) Callback() interface{} {
return nil
}
func (_ Statement) Commit() *DB {
return nil
}
func (_ Statement) Count(_ *int64) *DB {
return nil
}
func (_ Statement) Create(_ interface{}) *DB {
return nil
}
func (_ Statement) CreateInBatches(_ interface{}, _ int) *DB {
return nil
}
func (_ Statement) DataTypeOf(_ interface{}) string {
return ""
}
func (_ Statement) Debug() *DB {
return nil
}
func (_ Statement) DefaultValueOf(_ interface{}) interface{} {
return nil
}
func (_ Statement) Delete(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Exec(_ string, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Explain(_ string, _ ...interface{}) string {
return ""
}
func (_ Statement) Find(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) FindInBatches(_ interface{}, _ int, _ func(*DB, int) error) *DB {
return nil
}
func (_ Statement) First(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) FirstOrCreate(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) FirstOrInit(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Get(_ string) (interface{}, bool) {
return nil, false
}
func (_ Statement) Group(_ string) *DB {
return nil
}
func (_ Statement) Having(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Initialize(_ *DB) error {
return nil
}
func (_ Statement) InstanceGet(_ string) (interface{}, bool) {
return nil, false
}
func (_ Statement) InstanceSet(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) Last(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Limit(_ int) *DB {
return nil
}
func (_ Statement) Migrator() Migrator {
return nil
}
func (_ Statement) Name() string {
return ""
}
func (_ Statement) Not(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Offset(_ int) *DB {
return nil
}
func (_ Statement) Omit(_ ...string) *DB {
return nil
}
func (_ Statement) Or(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Order(_ interface{}) *DB {
return nil
}
func (_ Statement) Pluck(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) Preload(_ string, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Raw(_ string, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Rollback() *DB {
return nil
}
func (_ Statement) RollbackTo(_ string) *DB {
return nil
}
func (_ Statement) Row() *sql.Row {
return nil
}
func (_ Statement) Rows() (*sql.Rows, error) {
return nil, nil
}
func (_ Statement) Save(_ interface{}) *DB {
return nil
}
func (_ Statement) SavePoint(_ string) *DB {
return nil
}
func (_ Statement) Scan(_ interface{}) *DB {
return nil
}
func (_ Statement) ScanRows(_ *sql.Rows, _ interface{}) error {
return nil
}
func (_ Statement) Scopes(_ ...func(*DB) *DB) *DB {
return nil
}
func (_ Statement) Select(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Session(_ *Session) *DB {
return nil
}
func (_ Statement) Set(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) SetupJoinTable(_ interface{}, _ string, _ interface{}) error {
return nil
}
func (_ Statement) Take(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Transaction(_ func(*DB) error, _ ...*sql.TxOptions) error {
return nil
}
func (_ Statement) Update(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) UpdateColumn(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) UpdateColumns(_ interface{}) *DB {
return nil
}
func (_ Statement) Updates(_ interface{}) *DB {
return nil
}
func (_ Statement) Use(_ Plugin) error {
return nil
}
func (_ Statement) Where(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) WithContext(_ context.Context) *DB {
return nil
}
func (_ *Statement) AddClause(_ interface{}) {}
func (_ *Statement) AddClauseIfNotExists(_ interface{}) {}
func (_ *Statement) AddVar(_ interface{}, _ ...interface{}) {}
func (_ *Statement) Build(_ ...string) {}
func (_ *Statement) BuildCondition(_ interface{}, _ ...interface{}) []interface{} {
return nil
}
func (_ *Statement) Changed(_ ...string) bool {
return false
}
func (_ *Statement) Parse(_ interface{}) error {
return nil
}
func (_ *Statement) Quote(_ interface{}) string {
return ""
}
func (_ *Statement) QuoteTo(_ interface{}, _ interface{}) {}
func (_ *Statement) SelectAndOmitColumns(_ bool, _ bool) (map[string]bool, bool) {
return nil, false
}
func (_ *Statement) SetColumn(_ string, _ interface{}, _ ...bool) {}
func (_ *Statement) WriteByte(_ byte) error {
return nil
}
func (_ *Statement) WriteQuoted(_ interface{}) {}
func (_ *Statement) WriteString(_ string) (int, error) {
return 0, nil
}
type ViewOption struct {
Replace bool
CheckOption string
Query *DB
}

View File

@@ -0,0 +1,3 @@
# gorm.io/gorm v1.21.12
## explicit
gorm.io/gorm

View File

@@ -0,0 +1,6 @@
| DeferInLoop.go:8:3:8:20 | defer statement | This defer statement is in a $@. | DeferInLoop.go:6:2:13:2 | range statement | loop |
| test.go:6:3:6:14 | defer statement | This defer statement is in a $@. | test.go:5:2:7:2 | range statement | loop |
| test.go:11:4:11:15 | defer statement | This defer statement is in a $@. | test.go:9:2:13:2 | range statement | loop |
| test.go:16:3:16:14 | defer statement | This defer statement is in a $@. | test.go:15:2:17:2 | for statement | loop |
| test.go:20:3:20:14 | defer statement | This defer statement is in a $@. | test.go:19:2:21:2 | for statement | loop |
| test.go:24:3:24:14 | defer statement | This defer statement is in a $@. | test.go:23:2:25:2 | for statement | loop |

View File

@@ -0,0 +1,14 @@
package main
import "os"
func openFiles(filenames []string) {
for _, filename := range filenames {
file, err := os.Open(filename)
defer file.Close()
if err != nil {
// handle error
}
// work on file
}
}

View File

@@ -0,0 +1 @@
experimental/InconsistentCode/DeferInLoop.ql

View File

@@ -0,0 +1,18 @@
package main
import "os"
func openFile(filename string) {
file, err := os.Open(filename)
defer file.Close()
if err != nil {
// handle error
}
// work on file
}
func openFilesGood(filenames []string) {
for _, filename := range filenames {
openFile(filename)
}
}

View File

@@ -0,0 +1 @@
| GORMErrorNotChecked.go:7:2:7:40 | call to First | This call appears to interact with the database without checking whether an error was encountered. |

View File

@@ -0,0 +1,9 @@
package main
import "gorm.io/gorm"
func getUserId(db *gorm.DB, name string) int64 {
var user User
db.Where("name = ?", name).First(&user)
return user.Id
}

View File

@@ -0,0 +1,35 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>GORM errors are returned as a field of the return value instead of a separate return value.</p>
<p>It is therefore very easy to miss that an error may occur and omit error handling routines.</p>
</overview>
<recommendation>
<p>Ensure that GORM errors are checked.</p>
</recommendation>
<example>
<p>In the example below, </p>
<sample src="MissingErrorCheck.go" />
<p>The corrected version of <code>user</code> checks <code>err</code> before using <code>ptr</code>.</p>
<sample src="MissingErrorCheckGood.go" />
</example>
<references>
<li>
The Go Blog:
<a href="https://blog.golang.org/error-handling-and-go">Error handling and Go</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1 @@
experimental/InconsistentCode/GORMErrorNotChecked.ql

View File

@@ -0,0 +1,11 @@
package main
import "gorm.io/gorm"
func getUserIdGood(db *gorm.DB, name string) int64 {
var user User
if err := db.Where("name = ?", name).First(&user).Error; err != nil {
// handle errors
}
return user.Id
}

View File

@@ -0,0 +1,5 @@
module query-tests/gormerrornotchecked
go 1.16
require gorm.io/gorm v1.21.12

Binary file not shown.

View File

@@ -0,0 +1,26 @@
package main
func test() {
var xs []int
for _ = range xs {
defer test() // not ok
}
for _ = range xs {
if true {
defer test() // not ok
}
}
for i := 0; i < 10; i++ {
defer test()
}
for true {
defer test() // not ok
}
for false {
defer test() // fine but caught
}
}

View File

@@ -0,0 +1,9 @@
package main
type User struct {
Id int64
Name string
}
func main() {
}

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2013-NOW Jinzhu <wosmvp@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,803 @@
// Code generated by depstubber. DO NOT EDIT.
// This is a simple stub for gorm.io/gorm, strictly for use in testing.
// See the LICENSE file for information about the licensing of the original library.
// Source: gorm.io/gorm (exports: DB; functions: )
// Package gorm is a stub of gorm.io/gorm, generated by depstubber.
package gorm
import (
context "context"
sql "database/sql"
reflect "reflect"
strings "strings"
sync "sync"
time "time"
)
type Association struct {
DB *DB
Relationship interface{}
Error error
}
func (_ *Association) Append(_ ...interface{}) error {
return nil
}
func (_ *Association) Clear() error {
return nil
}
func (_ *Association) Count() int64 {
return 0
}
func (_ *Association) Delete(_ ...interface{}) error {
return nil
}
func (_ *Association) Find(_ interface{}, _ ...interface{}) error {
return nil
}
func (_ *Association) Replace(_ ...interface{}) error {
return nil
}
type ColumnType interface {
DatabaseTypeName() string
DecimalSize() (int64, int64, bool)
Length() (int64, bool)
Name() string
Nullable() (bool, bool)
}
type Config struct {
SkipDefaultTransaction bool
NamingStrategy interface{}
FullSaveAssociations bool
Logger interface{}
NowFunc func() time.Time
DryRun bool
PrepareStmt bool
DisableAutomaticPing bool
DisableForeignKeyConstraintWhenMigrating bool
DisableNestedTransaction bool
AllowGlobalUpdate bool
QueryFields bool
CreateBatchSize int
ClauseBuilders map[string]interface{}
ConnPool ConnPool
Dialector Dialector
Plugins map[string]Plugin
}
func (_ Config) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {}
func (_ Config) DataTypeOf(_ interface{}) string {
return ""
}
func (_ Config) DefaultValueOf(_ interface{}) interface{} {
return nil
}
func (_ Config) Explain(_ string, _ ...interface{}) string {
return ""
}
func (_ Config) Initialize(_ *DB) error {
return nil
}
func (_ Config) Migrator(_ *DB) Migrator {
return nil
}
func (_ Config) Name() string {
return ""
}
func (_ Config) QuoteTo(_ interface{}, _ string) {}
func (_ *Config) AfterInitialize(_ *DB) error {
return nil
}
func (_ *Config) Apply(_ *Config) error {
return nil
}
type ConnPool interface {
ExecContext(_ context.Context, _ string, _ ...interface{}) (sql.Result, error)
PrepareContext(_ context.Context, _ string) (*sql.Stmt, error)
QueryContext(_ context.Context, _ string, _ ...interface{}) (*sql.Rows, error)
QueryRowContext(_ context.Context, _ string, _ ...interface{}) *sql.Row
}
type DB struct {
Config *Config
Error error
RowsAffected int64
Statement *Statement
}
func (_ DB) AfterInitialize(_ *DB) error {
return nil
}
func (_ DB) Apply(_ *Config) error {
return nil
}
func (_ DB) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {}
func (_ DB) DataTypeOf(_ interface{}) string {
return ""
}
func (_ DB) DefaultValueOf(_ interface{}) interface{} {
return nil
}
func (_ DB) Explain(_ string, _ ...interface{}) string {
return ""
}
func (_ DB) Initialize(_ *DB) error {
return nil
}
func (_ DB) Name() string {
return ""
}
func (_ DB) QuoteTo(_ interface{}, _ string) {}
func (_ *DB) AddError(_ error) error {
return nil
}
func (_ *DB) Assign(_ ...interface{}) *DB {
return nil
}
func (_ *DB) Association(_ string) *Association {
return nil
}
func (_ *DB) Attrs(_ ...interface{}) *DB {
return nil
}
func (_ *DB) AutoMigrate(_ ...interface{}) error {
return nil
}
func (_ *DB) Begin(_ ...*sql.TxOptions) *DB {
return nil
}
func (_ *DB) Callback() interface{} {
return nil
}
func (_ *DB) Clauses(_ ...interface{}) *DB {
return nil
}
func (_ *DB) Commit() *DB {
return nil
}
func (_ *DB) Count(_ *int64) *DB {
return nil
}
func (_ *DB) Create(_ interface{}) *DB {
return nil
}
func (_ *DB) CreateInBatches(_ interface{}, _ int) *DB {
return nil
}
func (_ *DB) DB() (*sql.DB, error) {
return nil, nil
}
func (_ *DB) Debug() *DB {
return nil
}
func (_ *DB) Delete(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Distinct(_ ...interface{}) *DB {
return nil
}
func (_ *DB) Exec(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Find(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) FindInBatches(_ interface{}, _ int, _ func(*DB, int) error) *DB {
return nil
}
func (_ *DB) First(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) FirstOrCreate(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) FirstOrInit(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Get(_ string) (interface{}, bool) {
return nil, false
}
func (_ *DB) Group(_ string) *DB {
return nil
}
func (_ *DB) Having(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) InstanceGet(_ string) (interface{}, bool) {
return nil, false
}
func (_ *DB) InstanceSet(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) Joins(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Last(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Limit(_ int) *DB {
return nil
}
func (_ *DB) Migrator() Migrator {
return nil
}
func (_ *DB) Model(_ interface{}) *DB {
return nil
}
func (_ *DB) Not(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Offset(_ int) *DB {
return nil
}
func (_ *DB) Omit(_ ...string) *DB {
return nil
}
func (_ *DB) Or(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Order(_ interface{}) *DB {
return nil
}
func (_ *DB) Pluck(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) Preload(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Raw(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Rollback() *DB {
return nil
}
func (_ *DB) RollbackTo(_ string) *DB {
return nil
}
func (_ *DB) Row() *sql.Row {
return nil
}
func (_ *DB) Rows() (*sql.Rows, error) {
return nil, nil
}
func (_ *DB) Save(_ interface{}) *DB {
return nil
}
func (_ *DB) SavePoint(_ string) *DB {
return nil
}
func (_ *DB) Scan(_ interface{}) *DB {
return nil
}
func (_ *DB) ScanRows(_ *sql.Rows, _ interface{}) error {
return nil
}
func (_ *DB) Scopes(_ ...func(*DB) *DB) *DB {
return nil
}
func (_ *DB) Select(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Session(_ *Session) *DB {
return nil
}
func (_ *DB) Set(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) SetupJoinTable(_ interface{}, _ string, _ interface{}) error {
return nil
}
func (_ *DB) Table(_ string, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Take(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) Transaction(_ func(*DB) error, _ ...*sql.TxOptions) error {
return nil
}
func (_ *DB) Unscoped() *DB {
return nil
}
func (_ *DB) Update(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) UpdateColumn(_ string, _ interface{}) *DB {
return nil
}
func (_ *DB) UpdateColumns(_ interface{}) *DB {
return nil
}
func (_ *DB) Updates(_ interface{}) *DB {
return nil
}
func (_ *DB) Use(_ Plugin) error {
return nil
}
func (_ *DB) Where(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ *DB) WithContext(_ context.Context) *DB {
return nil
}
type Dialector interface {
BindVarTo(_ interface{}, _ *Statement, _ interface{})
DataTypeOf(_ interface{}) string
DefaultValueOf(_ interface{}) interface{}
Explain(_ string, _ ...interface{}) string
Initialize(_ *DB) error
Migrator(_ *DB) Migrator
Name() string
QuoteTo(_ interface{}, _ string)
}
type Migrator interface {
AddColumn(_ interface{}, _ string) error
AlterColumn(_ interface{}, _ string) error
AutoMigrate(_ ...interface{}) error
ColumnTypes(_ interface{}) ([]ColumnType, error)
CreateConstraint(_ interface{}, _ string) error
CreateIndex(_ interface{}, _ string) error
CreateTable(_ ...interface{}) error
CreateView(_ string, _ ViewOption) error
CurrentDatabase() string
DropColumn(_ interface{}, _ string) error
DropConstraint(_ interface{}, _ string) error
DropIndex(_ interface{}, _ string) error
DropTable(_ ...interface{}) error
DropView(_ string) error
FullDataTypeOf(_ interface{}) interface{}
HasColumn(_ interface{}, _ string) bool
HasConstraint(_ interface{}, _ string) bool
HasIndex(_ interface{}, _ string) bool
HasTable(_ interface{}) bool
MigrateColumn(_ interface{}, _ interface{}, _ ColumnType) error
RenameColumn(_ interface{}, _ string, _ string) error
RenameIndex(_ interface{}, _ string, _ string) error
RenameTable(_ interface{}, _ interface{}) error
}
type Plugin interface {
Initialize(_ *DB) error
Name() string
}
type Session struct {
DryRun bool
PrepareStmt bool
NewDB bool
SkipHooks bool
SkipDefaultTransaction bool
DisableNestedTransaction bool
AllowGlobalUpdate bool
FullSaveAssociations bool
QueryFields bool
Context context.Context
Logger interface{}
NowFunc func() time.Time
CreateBatchSize int
}
type Statement struct {
DB *DB
TableExpr interface{}
Table string
Model interface{}
Unscoped bool
Dest interface{}
ReflectValue reflect.Value
Clauses map[string]interface{}
BuildClauses []string
Distinct bool
Selects []string
Omits []string
Joins []interface{}
Preloads map[string][]interface{}
Settings sync.Map
ConnPool ConnPool
Schema interface{}
Context context.Context
RaiseErrorOnNotFound bool
SkipHooks bool
SQL strings.Builder
Vars []interface{}
CurDestIndex int
}
func (_ Statement) AddError(_ error) error {
return nil
}
func (_ Statement) AfterInitialize(_ *DB) error {
return nil
}
func (_ Statement) Apply(_ *Config) error {
return nil
}
func (_ Statement) Assign(_ ...interface{}) *DB {
return nil
}
func (_ Statement) Association(_ string) *Association {
return nil
}
func (_ Statement) Attrs(_ ...interface{}) *DB {
return nil
}
func (_ Statement) AutoMigrate(_ ...interface{}) error {
return nil
}
func (_ Statement) Begin(_ ...*sql.TxOptions) *DB {
return nil
}
func (_ Statement) BindVarTo(_ interface{}, _ *Statement, _ interface{}) {}
func (_ Statement) Callback() interface{} {
return nil
}
func (_ Statement) Commit() *DB {
return nil
}
func (_ Statement) Count(_ *int64) *DB {
return nil
}
func (_ Statement) Create(_ interface{}) *DB {
return nil
}
func (_ Statement) CreateInBatches(_ interface{}, _ int) *DB {
return nil
}
func (_ Statement) DataTypeOf(_ interface{}) string {
return ""
}
func (_ Statement) Debug() *DB {
return nil
}
func (_ Statement) DefaultValueOf(_ interface{}) interface{} {
return nil
}
func (_ Statement) Delete(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Exec(_ string, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Explain(_ string, _ ...interface{}) string {
return ""
}
func (_ Statement) Find(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) FindInBatches(_ interface{}, _ int, _ func(*DB, int) error) *DB {
return nil
}
func (_ Statement) First(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) FirstOrCreate(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) FirstOrInit(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Get(_ string) (interface{}, bool) {
return nil, false
}
func (_ Statement) Group(_ string) *DB {
return nil
}
func (_ Statement) Having(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Initialize(_ *DB) error {
return nil
}
func (_ Statement) InstanceGet(_ string) (interface{}, bool) {
return nil, false
}
func (_ Statement) InstanceSet(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) Last(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Limit(_ int) *DB {
return nil
}
func (_ Statement) Migrator() Migrator {
return nil
}
func (_ Statement) Name() string {
return ""
}
func (_ Statement) Not(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Offset(_ int) *DB {
return nil
}
func (_ Statement) Omit(_ ...string) *DB {
return nil
}
func (_ Statement) Or(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Order(_ interface{}) *DB {
return nil
}
func (_ Statement) Pluck(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) Preload(_ string, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Raw(_ string, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Rollback() *DB {
return nil
}
func (_ Statement) RollbackTo(_ string) *DB {
return nil
}
func (_ Statement) Row() *sql.Row {
return nil
}
func (_ Statement) Rows() (*sql.Rows, error) {
return nil, nil
}
func (_ Statement) Save(_ interface{}) *DB {
return nil
}
func (_ Statement) SavePoint(_ string) *DB {
return nil
}
func (_ Statement) Scan(_ interface{}) *DB {
return nil
}
func (_ Statement) ScanRows(_ *sql.Rows, _ interface{}) error {
return nil
}
func (_ Statement) Scopes(_ ...func(*DB) *DB) *DB {
return nil
}
func (_ Statement) Select(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Session(_ *Session) *DB {
return nil
}
func (_ Statement) Set(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) SetupJoinTable(_ interface{}, _ string, _ interface{}) error {
return nil
}
func (_ Statement) Take(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) Transaction(_ func(*DB) error, _ ...*sql.TxOptions) error {
return nil
}
func (_ Statement) Update(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) UpdateColumn(_ string, _ interface{}) *DB {
return nil
}
func (_ Statement) UpdateColumns(_ interface{}) *DB {
return nil
}
func (_ Statement) Updates(_ interface{}) *DB {
return nil
}
func (_ Statement) Use(_ Plugin) error {
return nil
}
func (_ Statement) Where(_ interface{}, _ ...interface{}) *DB {
return nil
}
func (_ Statement) WithContext(_ context.Context) *DB {
return nil
}
func (_ *Statement) AddClause(_ interface{}) {}
func (_ *Statement) AddClauseIfNotExists(_ interface{}) {}
func (_ *Statement) AddVar(_ interface{}, _ ...interface{}) {}
func (_ *Statement) Build(_ ...string) {}
func (_ *Statement) BuildCondition(_ interface{}, _ ...interface{}) []interface{} {
return nil
}
func (_ *Statement) Changed(_ ...string) bool {
return false
}
func (_ *Statement) Parse(_ interface{}) error {
return nil
}
func (_ *Statement) Quote(_ interface{}) string {
return ""
}
func (_ *Statement) QuoteTo(_ interface{}, _ interface{}) {}
func (_ *Statement) SelectAndOmitColumns(_ bool, _ bool) (map[string]bool, bool) {
return nil, false
}
func (_ *Statement) SetColumn(_ string, _ interface{}, _ ...bool) {}
func (_ *Statement) WriteByte(_ byte) error {
return nil
}
func (_ *Statement) WriteQuoted(_ interface{}) {}
func (_ *Statement) WriteString(_ string) (int, error) {
return 0, nil
}
type ViewOption struct {
Replace bool
CheckOption string
Query *DB
}

View File

@@ -0,0 +1,3 @@
# gorm.io/gorm v1.21.12
## explicit
gorm.io/gorm