mirror of
https://github.com/github/codeql.git
synced 2026-01-30 06:42:57 +01:00
Merge branch 'main' into standard-lib-pt-24
This commit is contained in:
4
Makefile
4
Makefile
@@ -31,11 +31,11 @@ DATAFLOW_BRANCH=master
|
||||
|
||||
autoformat:
|
||||
find ql/src -name "*.ql" -or -name "*.qll" | xargs codeql query format -qq -i
|
||||
git ls-files | grep \\.go$$ | xargs grep -L "//\s*autoformat-ignore" | xargs gofmt -w
|
||||
git ls-files | grep \\.go$$ | grep -v ^vendor/ | xargs grep -L "//\s*autoformat-ignore" | xargs gofmt -w
|
||||
|
||||
check-formatting:
|
||||
find ql/src -name "*.ql" -or -name "*.qll" | xargs codeql query format --check-only
|
||||
test -z "$$(git ls-files | grep \\.go$ | xargs grep -L "//\s*autoformat-ignore" | xargs gofmt -l)"
|
||||
test -z "$$(git ls-files | grep \\.go$ | grep -v ^vendor/ | xargs grep -L "//\s*autoformat-ignore" | xargs gofmt -l)"
|
||||
|
||||
tools: $(addsuffix $(EXE),$(addprefix tools/bin/,$(BINARIES))) tools/tokenizer.jar
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
lgtm,codescanning
|
||||
* The query "Size computation for allocation may overflow" has been improved to recognize more
|
||||
cases where the value should be considered to be safe, which should lead to fewer false
|
||||
positive results.
|
||||
4
change-notes/2020-09-10-gorm-model-improved.md
Normal file
4
change-notes/2020-09-10-gorm-model-improved.md
Normal file
@@ -0,0 +1,4 @@
|
||||
lgtm,codescanning
|
||||
* Support for the [GORM](https://github.com/go-gorm/gorm) ORM library (specifically, its SQL
|
||||
statement building facilities) has been improved, which may lead to more results from the
|
||||
security queries.
|
||||
2
change-notes/2020-09-10-xss-false-positives.md
Normal file
2
change-notes/2020-09-10-xss-false-positives.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* The query "Reflected cross-site scripting" (`go/reflected-xss`) now recognizes more cases of JSON marshaled data, which cannot serve as a vector for an XSS attack. This may reduce false-positive results for this query.
|
||||
@@ -34,7 +34,7 @@ This behavior can be further customized using environment variables: setting LGT
|
||||
to 'false' disables the GOPATH set-up, CODEQL_EXTRACTOR_GO_BUILD_COMMAND (or alternatively
|
||||
LGTM_INDEX_BUILD_COMMAND), can be set to a newline-separated list of commands to run in order to
|
||||
install dependencies, and LGTM_INDEX_IMPORT_PATH can be used to override the package import path,
|
||||
which is otherwise inferred from the SEMMLE_REPO_URL environment variable.
|
||||
which is otherwise inferred from the SEMMLE_REPO_URL or GITHUB_REPOSITORY environment variables.
|
||||
|
||||
In resource-constrained environments, the environment variable CODEQL_EXTRACTOR_GO_MAX_GOROUTINES
|
||||
(or its legacy alias SEMMLE_MAX_GOROUTINES) can be used to limit the number of parallel goroutines
|
||||
@@ -100,13 +100,19 @@ func getImportPath() (importpath string) {
|
||||
if importpath == "" {
|
||||
repourl := os.Getenv("SEMMLE_REPO_URL")
|
||||
if repourl == "" {
|
||||
log.Printf("Unable to determine import path, as neither LGTM_INDEX_IMPORT_PATH nor SEMMLE_REPO_URL is set\n")
|
||||
return ""
|
||||
}
|
||||
importpath = getImportPathFromRepoURL(repourl)
|
||||
if importpath == "" {
|
||||
log.Printf("Failed to determine import path from SEMMLE_REPO_URL '%s'\n", repourl)
|
||||
return
|
||||
githubrepo := os.Getenv("GITHUB_REPOSITORY")
|
||||
if githubrepo == "" {
|
||||
log.Printf("Unable to determine import path, as neither LGTM_INDEX_IMPORT_PATH nor GITHUB_REPOSITORY is set\n")
|
||||
return ""
|
||||
} else {
|
||||
importpath = "github.com/" + githubrepo
|
||||
}
|
||||
} else {
|
||||
importpath = getImportPathFromRepoURL(repourl)
|
||||
if importpath == "" {
|
||||
log.Printf("Failed to determine import path from SEMMLE_REPO_URL '%s'\n", repourl)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
log.Printf("Import path is '%s'\n", importpath)
|
||||
|
||||
@@ -379,6 +379,10 @@ func normalizedPath(ast *ast.File, fset *token.FileSet) string {
|
||||
// extractFile extracts AST information for the given file
|
||||
func extractFile(ast *ast.File, pkg *packages.Package, fdSem *semaphore) error {
|
||||
fset := pkg.Fset
|
||||
if ast.Package == token.NoPos {
|
||||
log.Printf("Skipping extracting a file without a 'package' declaration")
|
||||
return nil
|
||||
}
|
||||
path := normalizedPath(ast, fset)
|
||||
|
||||
fdSem.acquire(3)
|
||||
|
||||
@@ -168,7 +168,7 @@ func extractGoModComments(tw *trap.Writer, expr modfile.Expr, exprlbl trap.Label
|
||||
var first bool = true
|
||||
idx := 0
|
||||
for _, comment := range allComments {
|
||||
commentToken := strings.TrimSuffix(comment.Token, "\r")
|
||||
commentToken := strings.TrimSuffix(strings.TrimSuffix(comment.Token, "\n"), "\r")
|
||||
extractGoModComment(tw, comment, commentToken, grouplbl, idx)
|
||||
idx++
|
||||
commentEndCol := comment.Start.LineRune + (len(commentToken) - 1)
|
||||
|
||||
9
go.mod
9
go.mod
@@ -3,6 +3,11 @@ module github.com/github/codeql-go
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.2.0
|
||||
golang.org/x/tools v0.0.0-20200302225559-9b52d559c609
|
||||
github.com/ChrisTrenkamp/goxpath v0.0.0-20190607011252-c5096ec8773d
|
||||
github.com/Masterminds/squirrel v1.4.0
|
||||
github.com/lib/pq v1.8.0
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||
golang.org/x/mod v0.3.0
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||
golang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3
|
||||
)
|
||||
|
||||
38
go.sum
38
go.sum
@@ -1,17 +1,55 @@
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/ChrisTrenkamp/goxpath v0.0.0-20190607011252-c5096ec8773d h1:W1diKnDQkXxNDhghdBSbQ4LI/E1aJNTwpqPp3KtlB8w=
|
||||
github.com/ChrisTrenkamp/goxpath v0.0.0-20190607011252-c5096ec8773d/go.mod h1:nuWgzSkT5PnyOd+272uUmV0dnAnAn42Mk7PiQC5VzN4=
|
||||
github.com/Masterminds/squirrel v1.4.0 h1:he5i/EXixZxrBUWcxzDYMiju9WZ3ld/l7QBNuo/eN3w=
|
||||
github.com/Masterminds/squirrel v1.4.0/go.mod h1:yaPeOnPG5ZRwL9oKdTsO/prlkPbXWZlRVMQ/gGlzIuA=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
|
||||
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.2.0 h1:KU7oHjnv3XNWfa5COkzUifxZmxp1TyI7ImMXqFxLwvQ=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200302225559-9b52d559c609 h1:3/QY44rOqJoMLCsQz9bAgInYa08qsu+dH52Uk4DWH3w=
|
||||
golang.org/x/tools v0.0.0-20200302225559-9b52d559c609/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3 h1:r3P/5xOq/dK1991B65Oy6E1fRF/2d/fSYZJ/fXGVfJc=
|
||||
golang.org/x/tools v0.0.0-20200827010519-17fd2f27a9e3/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898 h1:/atklqdjdhuosWIl6AIbOeHJjicWYPqR9bpxqxYG2pA=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
|
||||
@@ -34,6 +34,7 @@ import semmle.go.frameworks.HTTP
|
||||
import semmle.go.frameworks.Macaron
|
||||
import semmle.go.frameworks.Mux
|
||||
import semmle.go.frameworks.NoSQL
|
||||
import semmle.go.frameworks.Protobuf
|
||||
import semmle.go.frameworks.SQL
|
||||
import semmle.go.frameworks.Stdlib
|
||||
import semmle.go.frameworks.SystemCommandExecutors
|
||||
|
||||
@@ -165,6 +165,13 @@ module ControlFlow {
|
||||
self.getRhs() = rhs.asInstruction()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if this node sets any field or element of `base` to `rhs`.
|
||||
*/
|
||||
predicate writesComponent(DataFlow::Node base, DataFlow::Node rhs) {
|
||||
writesElement(base, _, rhs) or writesField(base, _, rhs)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -253,23 +253,32 @@ module IR {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR instruction that reads a component from a composite object.
|
||||
*
|
||||
* This is either a field of a struct, or an element of an array, map, slice or string.
|
||||
*/
|
||||
class ComponentReadInstruction extends ReadInstruction, EvalInstruction {
|
||||
ComponentReadInstruction() {
|
||||
e instanceof IndexExpr
|
||||
or
|
||||
e.(SelectorExpr).getBase() instanceof ValueExpr and
|
||||
not e.(SelectorExpr).getSelector() = any(Method method).getAReference()
|
||||
}
|
||||
|
||||
/** Gets the instruction computing the base value on which the field or element is read. */
|
||||
Instruction getBase() { result = selectorBase(e) }
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR instruction that reads the value of a field.
|
||||
*
|
||||
* On snapshots with incomplete type information, method expressions may sometimes be
|
||||
* misclassified as field reads.
|
||||
*/
|
||||
class FieldReadInstruction extends ReadInstruction, EvalInstruction {
|
||||
class FieldReadInstruction extends ComponentReadInstruction {
|
||||
override SelectorExpr e;
|
||||
|
||||
FieldReadInstruction() {
|
||||
e.getBase() instanceof ValueExpr and
|
||||
not e.getSelector() = any(Method method).getAReference()
|
||||
}
|
||||
|
||||
/** Gets the instruction computing the base value on which the field is read. */
|
||||
Instruction getBase() { result = selectorBase(e) }
|
||||
|
||||
/** Gets the field being read. */
|
||||
Field getField() { e.getSelector() = result.getAReference() }
|
||||
|
||||
@@ -299,12 +308,9 @@ module IR {
|
||||
/**
|
||||
* An IR instruction that reads an element of an array, slice, map or string.
|
||||
*/
|
||||
class ElementReadInstruction extends ReadInstruction, EvalInstruction {
|
||||
class ElementReadInstruction extends ComponentReadInstruction {
|
||||
override IndexExpr e;
|
||||
|
||||
/** Gets the instruction computing the base value on which the element is looked up. */
|
||||
Instruction getBase() { result = selectorBase(e) }
|
||||
|
||||
/** Gets the instruction computing the index of the element being looked up. */
|
||||
Instruction getIndex() { result = evalExprInstruction(e.getIndex()) }
|
||||
|
||||
|
||||
@@ -416,6 +416,18 @@ class ReceiverNode extends ParameterNode {
|
||||
predicate isReceiverOf(MethodDecl m) { parm.isReceiverOf(m) }
|
||||
}
|
||||
|
||||
private Node getADirectlyWrittenNode() {
|
||||
exists(Write w | w.writesField(result, _, _) or w.writesElement(result, _, _))
|
||||
}
|
||||
|
||||
private DataFlow::Node getAccessPathPredecessor(DataFlow::Node node) {
|
||||
result = node.(PointerDereferenceNode).getOperand()
|
||||
or
|
||||
result = node.(ComponentReadNode).getBase()
|
||||
}
|
||||
|
||||
private Node getAWrittenNode() { result = getAccessPathPredecessor*(getADirectlyWrittenNode()) }
|
||||
|
||||
/**
|
||||
* A node associated with an object after an operation that might have
|
||||
* changed its state.
|
||||
@@ -439,13 +451,7 @@ class PostUpdateNode extends Node {
|
||||
or
|
||||
preupd = any(PointerDereferenceNode deref).getOperand()
|
||||
or
|
||||
exists(Write w, DataFlow::Node base |
|
||||
w.writesField(base, _, _) or w.writesElement(base, _, _)
|
||||
|
|
||||
preupd = base
|
||||
or
|
||||
preupd = base.(PointerDereferenceNode).getOperand()
|
||||
)
|
||||
preupd = getAWrittenNode()
|
||||
or
|
||||
preupd instanceof ArgumentNode and
|
||||
mutableType(preupd.getType())
|
||||
@@ -590,15 +596,22 @@ class ReadNode extends InstructionNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that reads the value of a field from a struct, or an element from an array, slice, map or string.
|
||||
*/
|
||||
class ComponentReadNode extends ReadNode {
|
||||
override IR::ComponentReadInstruction insn;
|
||||
|
||||
/** Gets the data-flow node representing the base from which the field or element is read. */
|
||||
Node getBase() { result = instructionNode(insn.getBase()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A data-flow node that reads an element of an array, map, slice or string.
|
||||
*/
|
||||
class ElementReadNode extends ReadNode {
|
||||
class ElementReadNode extends ComponentReadNode {
|
||||
override IR::ElementReadInstruction insn;
|
||||
|
||||
/** Gets the data-flow node representing the base from which the element is read. */
|
||||
Node getBase() { result = instructionNode(insn.getBase()) }
|
||||
|
||||
/** Gets the data-flow node representing the index of the element being read. */
|
||||
Node getIndex() { result = instructionNode(insn.getIndex()) }
|
||||
|
||||
@@ -744,12 +757,9 @@ class AddressOperationNode extends UnaryOperationNode, ExprNode {
|
||||
/**
|
||||
* A data-flow node that reads the value of a field.
|
||||
*/
|
||||
class FieldReadNode extends ReadNode {
|
||||
class FieldReadNode extends ComponentReadNode {
|
||||
override IR::FieldReadInstruction insn;
|
||||
|
||||
/** Gets the base node from which the field is read. */
|
||||
Node getBase() { result = instructionNode(insn.getBase()) }
|
||||
|
||||
/** Gets the field this node reads. */
|
||||
Field getField() { result = insn.getField() }
|
||||
|
||||
|
||||
174
ql/src/semmle/go/frameworks/Protobuf.qll
Normal file
174
ql/src/semmle/go/frameworks/Protobuf.qll
Normal file
@@ -0,0 +1,174 @@
|
||||
/** Provides models of commonly used functions and types in the protobuf packages. */
|
||||
|
||||
import go
|
||||
|
||||
/** Provides models of commonly used functions and types in the protobuf packages. */
|
||||
module Protobuf {
|
||||
/** Gets the name of the modern protobuf top-level implementation package. */
|
||||
string modernProtobufPackage() { result = "google.golang.org/protobuf/proto" }
|
||||
|
||||
/** Gets the name of the modern protobuf implementation's `protoiface` subpackage. */
|
||||
string protobufIfacePackage() { result = "google.golang.org/protobuf/runtime/protoiface" }
|
||||
|
||||
/** Gets the name of the modern protobuf implementation's `protoreflect` subpackage. */
|
||||
string protobufReflectPackage() { result = "google.golang.org/protobuf/reflect/protoreflect" }
|
||||
|
||||
/** Gets the name of a top-level protobuf implementation package. */
|
||||
string protobufPackages() {
|
||||
result in ["github.com/golang/protobuf/proto", modernProtobufPackage()]
|
||||
}
|
||||
|
||||
/** The `Marshal` and `MarshalAppend` functions in the protobuf packages. */
|
||||
private class MarshalFunction extends TaintTracking::FunctionModel, MarshalingFunction::Range {
|
||||
string name;
|
||||
|
||||
MarshalFunction() {
|
||||
name = ["Marshal", "MarshalAppend"] and
|
||||
(
|
||||
this.hasQualifiedName(protobufPackages(), name) or
|
||||
this.(Method).hasQualifiedName(modernProtobufPackage(), "MarshalOptions", name)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(DataFlow::FunctionInput inp, DataFlow::FunctionOutput outp) {
|
||||
inp = getAnInput() and outp = getOutput()
|
||||
}
|
||||
|
||||
override DataFlow::FunctionInput getAnInput() {
|
||||
if name = "MarshalAppend" then result.isParameter(1) else result.isParameter(0)
|
||||
}
|
||||
|
||||
override DataFlow::FunctionOutput getOutput() {
|
||||
name = "MarshalAppend" and result.isParameter(0)
|
||||
or
|
||||
result.isResult(0)
|
||||
}
|
||||
|
||||
override string getFormat() { result = "protobuf" }
|
||||
}
|
||||
|
||||
private Field inputMessageField() {
|
||||
result.hasQualifiedName(protobufIfacePackage(), "MarshalInput", "Message")
|
||||
}
|
||||
|
||||
private Method marshalStateMethod() {
|
||||
result.hasQualifiedName(protobufIfacePackage(), "MarshalOptions", "MarshalState")
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional taint-flow step modelling flow from `MarshalInput.Message` to `MarshalOutput`,
|
||||
* mediated by a `MarshalOptions.MarshalState` call.
|
||||
*
|
||||
* Note we can taint the whole `MarshalOutput` as it only has one field (`Buf`), and taint-
|
||||
* tracking always considers a field of a tainted struct to itself be tainted.
|
||||
*/
|
||||
private class MarshalStateStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
exists(DataFlow::PostUpdateNode marshalInput, DataFlow::CallNode marshalStateCall |
|
||||
marshalStateCall = marshalStateMethod().getACall() and
|
||||
// pred -> marshalInput.Message
|
||||
any(DataFlow::Write w)
|
||||
.writesField(marshalInput.getPreUpdateNode(), inputMessageField(), pred) and
|
||||
// marshalInput -> marshalStateCall
|
||||
marshalStateCall.getArgument(0) = globalValueNumber(marshalInput).getANode() and
|
||||
// marshalStateCall -> succ
|
||||
marshalStateCall.getResult() = succ
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The `Unmarshal` function in the protobuf packages. */
|
||||
class UnmarshalFunction extends TaintTracking::FunctionModel, UnmarshalingFunction::Range {
|
||||
UnmarshalFunction() {
|
||||
this.hasQualifiedName(protobufPackages(), "Unmarshal") or
|
||||
this.(Method).hasQualifiedName(modernProtobufPackage(), "UnmarshalOptions", "Unmarshal")
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(DataFlow::FunctionInput inp, DataFlow::FunctionOutput outp) {
|
||||
inp = getAnInput() and outp = getOutput()
|
||||
}
|
||||
|
||||
override DataFlow::FunctionInput getAnInput() { result.isParameter(0) }
|
||||
|
||||
override DataFlow::FunctionOutput getOutput() { result.isParameter(1) }
|
||||
|
||||
override string getFormat() { result = "protobuf" }
|
||||
}
|
||||
|
||||
/** The `Merge` function in the protobuf packages. */
|
||||
private class MergeFunction extends TaintTracking::FunctionModel {
|
||||
MergeFunction() { this.hasQualifiedName(protobufPackages(), "Merge") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput inp, FunctionOutput outp) {
|
||||
inp.isParameter(1) and outp.isParameter(0)
|
||||
}
|
||||
}
|
||||
|
||||
/** A protobuf `Message` type. */
|
||||
class MessageType extends Type {
|
||||
MessageType() { this.implements(protobufReflectPackage(), "ProtoMessage") }
|
||||
}
|
||||
|
||||
/** The `Clone` function in the protobuf packages. */
|
||||
private class MessageCloneFunction extends TaintTracking::FunctionModel {
|
||||
MessageCloneFunction() { this.hasQualifiedName(protobufPackages(), "Clone") }
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput inp, FunctionOutput outp) {
|
||||
inp.isParameter(0) and outp.isResult()
|
||||
}
|
||||
}
|
||||
|
||||
/** A `Get` method of a protobuf `Message` type. */
|
||||
private class GetMethod extends DataFlow::FunctionModel, Method {
|
||||
GetMethod() {
|
||||
exists(string name | name.matches("Get%") | this = any(MessageType msg).getMethod(name))
|
||||
}
|
||||
|
||||
override predicate hasDataFlow(FunctionInput inp, FunctionOutput outp) {
|
||||
inp.isReceiver() and outp.isResult()
|
||||
}
|
||||
}
|
||||
|
||||
/** A `ProtoReflect` method of a protobuf `Message` type. */
|
||||
private class ProtoReflectMethod extends DataFlow::FunctionModel, Method {
|
||||
ProtoReflectMethod() { this = any(MessageType msg).getMethod("ProtoReflect") }
|
||||
|
||||
override predicate hasDataFlow(FunctionInput inp, FunctionOutput outp) {
|
||||
inp.isReceiver() and outp.isResult()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base of `node`, looking through any dereference node found.
|
||||
*/
|
||||
private DataFlow::Node getBaseLookingThroughDerefs(DataFlow::ComponentReadNode node) {
|
||||
result = node.getBase().(DataFlow::PointerDereferenceNode).getOperand()
|
||||
or
|
||||
result = node.getBase() and not node.getBase() instanceof DataFlow::PointerDereferenceNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data-flow node representing the bottom of a stack of zero or more `ComponentReadNode`s
|
||||
* perhaps with interleaved dereferences.
|
||||
*
|
||||
* For example, in the expression a.b[c].d[e], this would return the dataflow node for the read from `a`.
|
||||
*/
|
||||
private DataFlow::Node getUnderlyingNode(DataFlow::ReadNode read) {
|
||||
(result = read or result = getBaseLookingThroughDerefs+(read)) and
|
||||
not result instanceof DataFlow::ComponentReadNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional taint step tainting a Message when taint is written to any of its fields and/or elements.
|
||||
*/
|
||||
private class WriteMessageFieldStep extends TaintTracking::AdditionalTaintStep {
|
||||
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
|
||||
[succ.getType(), succ.getType().getPointerType()] instanceof MessageType and
|
||||
exists(DataFlow::ReadNode base |
|
||||
succ.(DataFlow::PostUpdateNode).getPreUpdateNode() = getUnderlyingNode(base)
|
||||
|
|
||||
any(DataFlow::Write w).writesComponent(base, pred)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,13 +161,15 @@ module SQL {
|
||||
}
|
||||
}
|
||||
|
||||
/** A model for sinks of github.com/jinzhu/gorm. */
|
||||
/** A model for sinks of GORM. */
|
||||
private class GormSink extends SQL::QueryString::Range {
|
||||
GormSink() {
|
||||
exists(Method meth, string name |
|
||||
meth.hasQualifiedName("github.com/jinzhu/gorm", "DB", name) and
|
||||
exists(Method meth, string package, string name |
|
||||
meth.hasQualifiedName(package, "DB", name) and
|
||||
this = meth.getACall().getArgument(0) and
|
||||
name in ["Where", "Raw", "Order", "Not", "Or", "Select", "Table", "Group", "Having", "Joins"]
|
||||
package in ["github.com/jinzhu/gorm", "github.com/go-gorm/gorm", "gorm.io/gorm"] and
|
||||
name in ["Where", "Raw", "Order", "Not", "Or", "Select", "Table", "Group", "Having",
|
||||
"Joins", "Exec", "Distinct", "Pluck"]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import semmle.go.frameworks.stdlib.CompressLzw
|
||||
import semmle.go.frameworks.stdlib.CompressZlib
|
||||
import semmle.go.frameworks.stdlib.Path
|
||||
import semmle.go.frameworks.stdlib.PathFilepath
|
||||
import semmle.go.frameworks.stdlib.Reflect
|
||||
import semmle.go.frameworks.stdlib.TextScanner
|
||||
import semmle.go.frameworks.stdlib.TextTabwriter
|
||||
import semmle.go.frameworks.stdlib.TextTemplate
|
||||
|
||||
186
ql/src/semmle/go/frameworks/stdlib/Reflect.qll
Normal file
186
ql/src/semmle/go/frameworks/stdlib/Reflect.qll
Normal file
@@ -0,0 +1,186 @@
|
||||
/**
|
||||
* Provides classes modeling security-relevant aspects of the `reflect` package.
|
||||
*/
|
||||
|
||||
import go
|
||||
|
||||
/** Provides models of commonly used functions in the `reflect` package. */
|
||||
module Reflect {
|
||||
private class FunctionModels extends TaintTracking::FunctionModel {
|
||||
FunctionInput inp;
|
||||
FunctionOutput outp;
|
||||
|
||||
FunctionModels() {
|
||||
// signature: func Append(s Value, x ...Value) Value
|
||||
hasQualifiedName("reflect", "Append") and
|
||||
(inp.isParameter(_) and outp.isResult())
|
||||
or
|
||||
// signature: func AppendSlice(s Value, t Value) Value
|
||||
hasQualifiedName("reflect", "AppendSlice") and
|
||||
(inp.isParameter(_) and outp.isResult())
|
||||
or
|
||||
// signature: func Copy(dst Value, src Value) int
|
||||
hasQualifiedName("reflect", "Copy") and
|
||||
(inp.isParameter(1) and outp.isParameter(0))
|
||||
or
|
||||
// signature: func Indirect(v Value) Value
|
||||
hasQualifiedName("reflect", "Indirect") and
|
||||
(inp.isParameter(0) and outp.isResult())
|
||||
or
|
||||
// signature: func ValueOf(i interface{}) Value
|
||||
hasQualifiedName("reflect", "ValueOf") and
|
||||
(inp.isParameter(0) and outp.isResult())
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = inp and output = outp
|
||||
}
|
||||
}
|
||||
|
||||
private class MethodModels extends TaintTracking::FunctionModel, Method {
|
||||
FunctionInput inp;
|
||||
FunctionOutput outp;
|
||||
|
||||
MethodModels() {
|
||||
// signature: func (*MapIter).Key() Value
|
||||
this.hasQualifiedName("reflect", "MapIter", "Key") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (*MapIter).Value() Value
|
||||
this.hasQualifiedName("reflect", "MapIter", "Value") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (StructTag).Get(key string) string
|
||||
this.hasQualifiedName("reflect", "StructTag", "Get") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (StructTag).Lookup(key string) (value string, ok bool)
|
||||
this.hasQualifiedName("reflect", "StructTag", "Lookup") and
|
||||
(inp.isReceiver() and outp.isResult(0))
|
||||
or
|
||||
// signature: func (Value).Addr() Value
|
||||
this.hasQualifiedName("reflect", "Value", "Addr") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).Bytes() []byte
|
||||
this.hasQualifiedName("reflect", "Value", "Bytes") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).Convert(t Type) Value
|
||||
this.hasQualifiedName("reflect", "Value", "Convert") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).Elem() Value
|
||||
this.hasQualifiedName("reflect", "Value", "Elem") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).Field(i int) Value
|
||||
this.hasQualifiedName("reflect", "Value", "Field") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).FieldByIndex(index []int) Value
|
||||
this.hasQualifiedName("reflect", "Value", "FieldByIndex") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).FieldByName(name string) Value
|
||||
this.hasQualifiedName("reflect", "Value", "FieldByName") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).FieldByNameFunc(match func(string) bool) Value
|
||||
this.hasQualifiedName("reflect", "Value", "FieldByNameFunc") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).Index(i int) Value
|
||||
this.hasQualifiedName("reflect", "Value", "Index") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).Interface() (i interface{})
|
||||
this.hasQualifiedName("reflect", "Value", "Interface") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).InterfaceData() [2]uintptr
|
||||
this.hasQualifiedName("reflect", "Value", "InterfaceData") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).MapIndex(key Value) Value
|
||||
this.hasQualifiedName("reflect", "Value", "MapIndex") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).MapKeys() []Value
|
||||
this.hasQualifiedName("reflect", "Value", "MapKeys") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).MapRange() *MapIter
|
||||
this.hasQualifiedName("reflect", "Value", "MapRange") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).Method(i int) Value
|
||||
this.hasQualifiedName("reflect", "Value", "Method") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).MethodByName(name string) Value
|
||||
this.hasQualifiedName("reflect", "Value", "MethodByName") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).Pointer() uintptr
|
||||
this.hasQualifiedName("reflect", "Value", "Pointer") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).Recv() (x Value, ok bool)
|
||||
this.hasQualifiedName("reflect", "Value", "Recv") and
|
||||
(inp.isReceiver() and outp.isResult(0))
|
||||
or
|
||||
// signature: func (Value).Send(x Value)
|
||||
this.hasQualifiedName("reflect", "Value", "Send") and
|
||||
(inp.isParameter(0) and outp.isReceiver())
|
||||
or
|
||||
// signature: func (Value).Set(x Value)
|
||||
this.hasQualifiedName("reflect", "Value", "Set") and
|
||||
(inp.isParameter(0) and outp.isReceiver())
|
||||
or
|
||||
// signature: func (Value).SetBytes(x []byte)
|
||||
this.hasQualifiedName("reflect", "Value", "SetBytes") and
|
||||
(inp.isParameter(0) and outp.isReceiver())
|
||||
or
|
||||
// signature: func (Value).SetMapIndex(key Value, elem Value)
|
||||
this.hasQualifiedName("reflect", "Value", "SetMapIndex") and
|
||||
(inp.isParameter(_) and outp.isReceiver())
|
||||
or
|
||||
// signature: func (Value).SetPointer(x unsafe.Pointer)
|
||||
this.hasQualifiedName("reflect", "Value", "SetPointer") and
|
||||
(inp.isParameter(0) and outp.isReceiver())
|
||||
or
|
||||
// signature: func (Value).SetString(x string)
|
||||
this.hasQualifiedName("reflect", "Value", "SetString") and
|
||||
(inp.isParameter(0) and outp.isReceiver())
|
||||
or
|
||||
// signature: func (Value).Slice(i int, j int) Value
|
||||
this.hasQualifiedName("reflect", "Value", "Slice") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).Slice3(i int, j int, k int) Value
|
||||
this.hasQualifiedName("reflect", "Value", "Slice3") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).String() string
|
||||
this.hasQualifiedName("reflect", "Value", "String") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
or
|
||||
// signature: func (Value).TryRecv() (x Value, ok bool)
|
||||
this.hasQualifiedName("reflect", "Value", "TryRecv") and
|
||||
(inp.isReceiver() and outp.isResult(0))
|
||||
or
|
||||
// signature: func (Value).TrySend(x Value) bool
|
||||
this.hasQualifiedName("reflect", "Value", "TrySend") and
|
||||
(inp.isParameter(0) and outp.isReceiver())
|
||||
or
|
||||
// signature: func (Value).UnsafeAddr() uintptr
|
||||
this.hasQualifiedName("reflect", "Value", "UnsafeAddr") and
|
||||
(inp.isReceiver() and outp.isResult())
|
||||
}
|
||||
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input = inp and output = outp
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -76,9 +76,6 @@ module ReflectedXss {
|
||||
// https://mimesniff.spec.whatwg.org/#whitespace-byte) cannot cause an HTML content type to
|
||||
// be detected.
|
||||
pred.getStringValue().regexpMatch("(?s)[\\t\\n\\x0c\\r ]*+[^<].*")
|
||||
or
|
||||
// json data cannot begin with `<`
|
||||
exists(EncodingJson::MarshalFunction mf | pred = mf.getOutput().getNode(mf.getACall()))
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -117,4 +114,16 @@ module ReflectedXss {
|
||||
outcome = this.getPolarity()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A JSON marshaler, acting to sanitize a possible XSS vulnerability because the
|
||||
* marshaled value is very unlikely to be returned as an HTML content-type.
|
||||
*/
|
||||
class JsonMarshalSanitizer extends Sanitizer {
|
||||
JsonMarshalSanitizer() {
|
||||
exists(MarshalingFunction mf | mf.getFormat() = "JSON" |
|
||||
this = mf.getOutput().getNode(mf.getACall())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
| test.go:19:2:19:2 | definition of a |
|
||||
| test.go:20:11:20:14 | &... |
|
||||
| test.go:20:12:20:14 | selection of b |
|
||||
| test.go:21:2:21:5 | selection of bs |
|
||||
| test.go:21:2:21:8 | index expression |
|
||||
| test.go:21:17:21:20 | &... |
|
||||
| test.go:21:18:21:20 | struct literal |
|
||||
| test.go:22:2:22:5 | selection of bs |
|
||||
| test.go:22:2:22:8 | index expression |
|
||||
| test.go:22:2:22:13 | implicit dereference |
|
||||
| test.go:22:2:22:13 | selection of cptr |
|
||||
| test.go:23:2:23:7 | implicit dereference |
|
||||
| test.go:23:2:23:7 | selection of bptr |
|
||||
| test.go:23:2:23:12 | implicit dereference |
|
||||
| test.go:23:2:23:12 | selection of cptr |
|
||||
@@ -0,0 +1,25 @@
|
||||
package a
|
||||
|
||||
type C struct {
|
||||
field int
|
||||
}
|
||||
|
||||
type B struct {
|
||||
cptr *C
|
||||
}
|
||||
|
||||
type A struct {
|
||||
b B
|
||||
bptr *B
|
||||
bs [5]B
|
||||
}
|
||||
|
||||
func f() {
|
||||
|
||||
a := A{}
|
||||
a.bptr = &a.b
|
||||
a.bs[3].cptr = &C{}
|
||||
a.bs[3].cptr.field = 100
|
||||
a.bptr.cptr.field = 101
|
||||
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import go
|
||||
|
||||
from DataFlow::PostUpdateNode pun
|
||||
select pun
|
||||
@@ -0,0 +1,33 @@
|
||||
| testDeprecatedApi.go:22:22:22:41 | call to getUntrustedString : string | testDeprecatedApi.go:26:12:26:21 | serialized |
|
||||
| testDeprecatedApi.go:31:22:31:41 | call to getUntrustedString : string | testDeprecatedApi.go:37:12:37:21 | serialized |
|
||||
| testDeprecatedApi.go:41:25:41:43 | call to getUntrustedBytes : slice type | testDeprecatedApi.go:45:13:45:29 | selection of Description |
|
||||
| testDeprecatedApi.go:49:25:49:43 | call to getUntrustedBytes : slice type | testDeprecatedApi.go:53:13:53:34 | call to GetDescription |
|
||||
| testDeprecatedApi.go:58:23:58:42 | call to getUntrustedString : string | testDeprecatedApi.go:65:12:65:21 | serialized |
|
||||
| testDeprecatedApi.go:70:14:70:33 | call to getUntrustedString : string | testDeprecatedApi.go:77:12:77:21 | serialized |
|
||||
| testDeprecatedApi.go:85:24:85:43 | call to getUntrustedString : string | testDeprecatedApi.go:89:12:89:21 | serialized |
|
||||
| testDeprecatedApi.go:93:25:93:43 | call to getUntrustedBytes : slice type | testDeprecatedApi.go:97:13:97:31 | selection of Msg |
|
||||
| testDeprecatedApi.go:104:22:104:41 | call to getUntrustedString : string | testDeprecatedApi.go:105:13:105:20 | selection of Id |
|
||||
| testDeprecatedApi.go:112:22:112:41 | call to getUntrustedString : string | testDeprecatedApi.go:117:12:117:21 | serialized |
|
||||
| testDeprecatedApi.go:133:29:133:48 | call to getUntrustedString : string | testDeprecatedApi.go:137:12:137:21 | serialized |
|
||||
| testDeprecatedApi.go:143:20:143:39 | call to getUntrustedString : string | testDeprecatedApi.go:148:12:148:21 | serialized |
|
||||
| testDeprecatedApi.go:152:25:152:43 | call to getUntrustedBytes : slice type | testDeprecatedApi.go:157:13:157:36 | index expression |
|
||||
| testDeprecatedApi.go:161:25:161:43 | call to getUntrustedBytes : slice type | testDeprecatedApi.go:168:13:168:25 | index expression |
|
||||
| testDeprecatedApi.go:176:24:176:43 | call to getUntrustedString : string | testDeprecatedApi.go:180:12:180:21 | serialized |
|
||||
| testModernApi.go:11:22:11:41 | call to getUntrustedString : string | testModernApi.go:15:12:15:21 | serialized |
|
||||
| testModernApi.go:20:22:20:41 | call to getUntrustedString : string | testModernApi.go:26:12:26:21 | serialized |
|
||||
| testModernApi.go:30:25:30:43 | call to getUntrustedBytes : slice type | testModernApi.go:34:13:34:29 | selection of Description |
|
||||
| testModernApi.go:38:25:38:43 | call to getUntrustedBytes : slice type | testModernApi.go:42:13:42:34 | call to GetDescription |
|
||||
| testModernApi.go:47:23:47:42 | call to getUntrustedString : string | testModernApi.go:54:12:54:21 | serialized |
|
||||
| testModernApi.go:59:22:59:41 | call to getUntrustedString : string | testModernApi.go:64:12:64:21 | serialized |
|
||||
| testModernApi.go:71:22:71:41 | call to getUntrustedString : string | testModernApi.go:77:12:77:21 | serialized |
|
||||
| testModernApi.go:98:14:98:33 | call to getUntrustedString : string | testModernApi.go:105:12:105:21 | serialized |
|
||||
| testModernApi.go:113:24:113:43 | call to getUntrustedString : string | testModernApi.go:117:12:117:21 | serialized |
|
||||
| testModernApi.go:121:25:121:43 | call to getUntrustedBytes : slice type | testModernApi.go:125:13:125:31 | selection of Msg |
|
||||
| testModernApi.go:131:25:131:43 | call to getUntrustedBytes : slice type | testModernApi.go:135:13:135:29 | selection of Description |
|
||||
| testModernApi.go:142:22:142:41 | call to getUntrustedString : string | testModernApi.go:143:13:143:20 | selection of Id |
|
||||
| testModernApi.go:150:22:150:41 | call to getUntrustedString : string | testModernApi.go:155:12:155:21 | serialized |
|
||||
| testModernApi.go:190:29:190:48 | call to getUntrustedString : string | testModernApi.go:194:12:194:21 | serialized |
|
||||
| testModernApi.go:200:20:200:39 | call to getUntrustedString : string | testModernApi.go:205:12:205:21 | serialized |
|
||||
| testModernApi.go:209:25:209:43 | call to getUntrustedBytes : slice type | testModernApi.go:214:13:214:36 | index expression |
|
||||
| testModernApi.go:218:25:218:43 | call to getUntrustedBytes : slice type | testModernApi.go:225:13:225:25 | index expression |
|
||||
| testModernApi.go:233:24:233:43 | call to getUntrustedString : string | testModernApi.go:237:12:237:21 | serialized |
|
||||
@@ -0,0 +1,27 @@
|
||||
import go
|
||||
|
||||
class UntrustedFunction extends Function {
|
||||
UntrustedFunction() { this.getName() = ["getUntrustedString", "getUntrustedBytes"] }
|
||||
}
|
||||
|
||||
class UntrustedSource extends DataFlow::Node, UntrustedFlowSource::Range {
|
||||
UntrustedSource() { this = any(UntrustedFunction f).getACall() }
|
||||
}
|
||||
|
||||
class SinkFunction extends Function {
|
||||
SinkFunction() { this.getName() = ["sinkString", "sinkBytes"] }
|
||||
}
|
||||
|
||||
class TestConfig extends TaintTracking::Configuration {
|
||||
TestConfig() { this = "testconfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof UntrustedFlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink = any(SinkFunction f).getACall().getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
from TaintTracking::Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
|
||||
where config.hasFlowPath(source, sink)
|
||||
select source, sink
|
||||
@@ -0,0 +1,9 @@
|
||||
module codeql-go-tests/protobuf
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/golang/protobuf v1.4.2
|
||||
google.golang.org/protobuf v1.23.0
|
||||
)
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
syntax = "proto3";
|
||||
option go_package = "protos/query";
|
||||
|
||||
message Query {
|
||||
string description = 1;
|
||||
string id = 2;
|
||||
|
||||
enum Severity {
|
||||
ERROR = 0;
|
||||
WARNING = 1;
|
||||
}
|
||||
|
||||
message Alert {
|
||||
string msg = 1;
|
||||
int64 loc = 2;
|
||||
}
|
||||
|
||||
repeated Alert alerts = 4;
|
||||
|
||||
map<int32, string> keyValuePairs = 5;
|
||||
}
|
||||
|
||||
message QuerySuite {
|
||||
repeated Query queries = 1;
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.25.0-devel
|
||||
// protoc v3.12.4
|
||||
// source: query.proto
|
||||
|
||||
package query
|
||||
|
||||
import (
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// This is a compile-time assertion that a sufficiently up-to-date version
|
||||
// of the legacy proto package is being used.
|
||||
const _ = proto.ProtoPackageIsVersion4
|
||||
|
||||
type Query_Severity int32
|
||||
|
||||
const (
|
||||
Query_ERROR Query_Severity = 0
|
||||
Query_WARNING Query_Severity = 1
|
||||
)
|
||||
|
||||
// Enum value maps for Query_Severity.
|
||||
var (
|
||||
Query_Severity_name = map[int32]string{
|
||||
0: "ERROR",
|
||||
1: "WARNING",
|
||||
}
|
||||
Query_Severity_value = map[string]int32{
|
||||
"ERROR": 0,
|
||||
"WARNING": 1,
|
||||
}
|
||||
)
|
||||
|
||||
func (x Query_Severity) Enum() *Query_Severity {
|
||||
p := new(Query_Severity)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x Query_Severity) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (Query_Severity) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_query_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (Query_Severity) Type() protoreflect.EnumType {
|
||||
return &file_query_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x Query_Severity) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Query_Severity.Descriptor instead.
|
||||
func (Query_Severity) EnumDescriptor() ([]byte, []int) {
|
||||
return file_query_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Description string `protobuf:"bytes,1,opt,name=description,proto3" json:"description,omitempty"`
|
||||
Id string `protobuf:"bytes,2,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Alerts []*Query_Alert `protobuf:"bytes,4,rep,name=alerts,proto3" json:"alerts,omitempty"`
|
||||
KeyValuePairs map[int32]string `protobuf:"bytes,5,rep,name=keyValuePairs,proto3" json:"keyValuePairs,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
}
|
||||
|
||||
func (x *Query) Reset() {
|
||||
*x = Query{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_query_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Query) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Query) ProtoMessage() {}
|
||||
|
||||
func (x *Query) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_query_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Query.ProtoReflect.Descriptor instead.
|
||||
func (*Query) Descriptor() ([]byte, []int) {
|
||||
return file_query_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Query) GetDescription() string {
|
||||
if x != nil {
|
||||
return x.Description
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Query) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Query) GetAlerts() []*Query_Alert {
|
||||
if x != nil {
|
||||
return x.Alerts
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Query) GetKeyValuePairs() map[int32]string {
|
||||
if x != nil {
|
||||
return x.KeyValuePairs
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type QuerySuite struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Queries []*Query `protobuf:"bytes,1,rep,name=queries,proto3" json:"queries,omitempty"`
|
||||
}
|
||||
|
||||
func (x *QuerySuite) Reset() {
|
||||
*x = QuerySuite{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_query_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *QuerySuite) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*QuerySuite) ProtoMessage() {}
|
||||
|
||||
func (x *QuerySuite) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_query_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use QuerySuite.ProtoReflect.Descriptor instead.
|
||||
func (*QuerySuite) Descriptor() ([]byte, []int) {
|
||||
return file_query_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *QuerySuite) GetQueries() []*Query {
|
||||
if x != nil {
|
||||
return x.Queries
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Query_Alert struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Msg string `protobuf:"bytes,1,opt,name=msg,proto3" json:"msg,omitempty"`
|
||||
Loc int64 `protobuf:"varint,2,opt,name=loc,proto3" json:"loc,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Query_Alert) Reset() {
|
||||
*x = Query_Alert{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_query_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Query_Alert) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Query_Alert) ProtoMessage() {}
|
||||
|
||||
func (x *Query_Alert) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_query_proto_msgTypes[2]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Query_Alert.ProtoReflect.Descriptor instead.
|
||||
func (*Query_Alert) Descriptor() ([]byte, []int) {
|
||||
return file_query_proto_rawDescGZIP(), []int{0, 0}
|
||||
}
|
||||
|
||||
func (x *Query_Alert) GetMsg() string {
|
||||
if x != nil {
|
||||
return x.Msg
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Query_Alert) GetLoc() int64 {
|
||||
if x != nil {
|
||||
return x.Loc
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var File_query_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_query_proto_rawDesc = []byte{
|
||||
0x0a, 0x0b, 0x71, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xb3, 0x02,
|
||||
0x0a, 0x05, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72,
|
||||
0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65,
|
||||
0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x24, 0x0a, 0x06, 0x61, 0x6c, 0x65,
|
||||
0x72, 0x74, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x51, 0x75, 0x65, 0x72,
|
||||
0x79, 0x2e, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x52, 0x06, 0x61, 0x6c, 0x65, 0x72, 0x74, 0x73, 0x12,
|
||||
0x3f, 0x0a, 0x0d, 0x6b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73,
|
||||
0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x2e, 0x4b,
|
||||
0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x45, 0x6e, 0x74, 0x72,
|
||||
0x79, 0x52, 0x0d, 0x6b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73,
|
||||
0x1a, 0x2b, 0x0a, 0x05, 0x41, 0x6c, 0x65, 0x72, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x6d, 0x73, 0x67,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6d, 0x73, 0x67, 0x12, 0x10, 0x0a, 0x03, 0x6c,
|
||||
0x6f, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6c, 0x6f, 0x63, 0x1a, 0x40, 0x0a,
|
||||
0x12, 0x4b, 0x65, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x50, 0x61, 0x69, 0x72, 0x73, 0x45, 0x6e,
|
||||
0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
|
||||
0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22,
|
||||
0x22, 0x0a, 0x08, 0x53, 0x65, 0x76, 0x65, 0x72, 0x69, 0x74, 0x79, 0x12, 0x09, 0x0a, 0x05, 0x45,
|
||||
0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e,
|
||||
0x47, 0x10, 0x01, 0x22, 0x2e, 0x0a, 0x0a, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x75, 0x69, 0x74,
|
||||
0x65, 0x12, 0x20, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x06, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72,
|
||||
0x69, 0x65, 0x73, 0x42, 0x0e, 0x5a, 0x0c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x71, 0x75,
|
||||
0x65, 0x72, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_query_proto_rawDescOnce sync.Once
|
||||
file_query_proto_rawDescData = file_query_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_query_proto_rawDescGZIP() []byte {
|
||||
file_query_proto_rawDescOnce.Do(func() {
|
||||
file_query_proto_rawDescData = protoimpl.X.CompressGZIP(file_query_proto_rawDescData)
|
||||
})
|
||||
return file_query_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_query_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_query_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||
var file_query_proto_goTypes = []interface{}{
|
||||
(Query_Severity)(0), // 0: Query.Severity
|
||||
(*Query)(nil), // 1: Query
|
||||
(*QuerySuite)(nil), // 2: QuerySuite
|
||||
(*Query_Alert)(nil), // 3: Query.Alert
|
||||
nil, // 4: Query.KeyValuePairsEntry
|
||||
}
|
||||
var file_query_proto_depIdxs = []int32{
|
||||
3, // 0: Query.alerts:type_name -> Query.Alert
|
||||
4, // 1: Query.keyValuePairs:type_name -> Query.KeyValuePairsEntry
|
||||
1, // 2: QuerySuite.queries:type_name -> Query
|
||||
3, // [3:3] is the sub-list for method output_type
|
||||
3, // [3:3] is the sub-list for method input_type
|
||||
3, // [3:3] is the sub-list for extension type_name
|
||||
3, // [3:3] is the sub-list for extension extendee
|
||||
0, // [0:3] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_query_proto_init() }
|
||||
func file_query_proto_init() {
|
||||
if File_query_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_query_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Query); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_query_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*QuerySuite); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_query_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Query_Alert); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_query_proto_rawDesc,
|
||||
NumEnums: 1,
|
||||
NumMessages: 4,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_query_proto_goTypes,
|
||||
DependencyIndexes: file_query_proto_depIdxs,
|
||||
EnumInfos: file_query_proto_enumTypes,
|
||||
MessageInfos: file_query_proto_msgTypes,
|
||||
}.Build()
|
||||
File_query_proto = out.File
|
||||
file_query_proto_rawDesc = nil
|
||||
file_query_proto_goTypes = nil
|
||||
file_query_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"codeql-go-tests/protobuf/protos/query"
|
||||
"github.com/golang/protobuf/proto"
|
||||
)
|
||||
|
||||
func getUntrustedString() string {
|
||||
return "trouble"
|
||||
}
|
||||
|
||||
func getUntrustedBytes() []byte {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
func sinkString(_ string) {}
|
||||
|
||||
func sinkBytes(_ []byte) {}
|
||||
|
||||
func testMarshal() {
|
||||
query := &query.Query{}
|
||||
query.Description = getUntrustedString()
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD
|
||||
}
|
||||
|
||||
func testCloneThenMarshal() {
|
||||
query := &query.Query{}
|
||||
query.Description = getUntrustedString()
|
||||
|
||||
queryClone := proto.Clone(query)
|
||||
|
||||
serialized, _ := proto.Marshal(queryClone)
|
||||
|
||||
sinkBytes(serialized) // BAD
|
||||
}
|
||||
|
||||
func testUnmarshalFieldAccess() {
|
||||
untrustedSerialized := getUntrustedBytes()
|
||||
query := &query.Query{}
|
||||
proto.Unmarshal(untrustedSerialized, query)
|
||||
|
||||
sinkString(query.Description) // BAD
|
||||
}
|
||||
|
||||
func testUnmarshalGetter() {
|
||||
untrustedSerialized := getUntrustedBytes()
|
||||
query := &query.Query{}
|
||||
proto.Unmarshal(untrustedSerialized, query)
|
||||
|
||||
sinkString(query.GetDescription()) // BAD
|
||||
}
|
||||
|
||||
func testMergeThenMarshal() {
|
||||
query1 := &query.Query{}
|
||||
query1.Description = getUntrustedString()
|
||||
|
||||
query2 := &query.Query{}
|
||||
proto.Merge(query2, query1)
|
||||
|
||||
serialized, _ := proto.Marshal(query2)
|
||||
|
||||
sinkBytes(serialized) // BAD
|
||||
}
|
||||
|
||||
func testTaintedSubmessage() {
|
||||
alert := &query.Query_Alert{}
|
||||
alert.Msg = getUntrustedString()
|
||||
|
||||
query := &query.Query{}
|
||||
query.Alerts = append(query.Alerts, alert)
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD
|
||||
}
|
||||
|
||||
func testTaintedSubmessageInPlace() {
|
||||
alert := &query.Query_Alert{}
|
||||
|
||||
query := &query.Query{}
|
||||
query.Alerts = append(query.Alerts, alert)
|
||||
query.Alerts[0].Msg = getUntrustedString()
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD
|
||||
}
|
||||
|
||||
func testUnmarshalTaintedSubmessage() {
|
||||
untrustedSerialized := getUntrustedBytes()
|
||||
query := &query.Query{}
|
||||
proto.Unmarshal(untrustedSerialized, query)
|
||||
|
||||
sinkString(query.Alerts[0].Msg) // BAD
|
||||
}
|
||||
|
||||
// This test should be ok, but is flagged because writing taint to a field of a Message
|
||||
// taints the entire Message structure in our current implementation.
|
||||
func testFieldConflationFalsePositive() {
|
||||
query := &query.Query{}
|
||||
query.Description = getUntrustedString()
|
||||
sinkString(query.Id) // OK (but incorrectly tainted)
|
||||
}
|
||||
|
||||
// This test should be ok, but it flagged because our current implementation doesn't notice
|
||||
// that the taint applied to `query` is overwritten.
|
||||
func testMessageReuseFalsePositive() {
|
||||
query := &query.Query{}
|
||||
query.Description = getUntrustedString()
|
||||
query.Description = "clean"
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // OK (but incorrectly tainted)
|
||||
}
|
||||
|
||||
// This test should be flagged, but we don't notice tainting via an alias of a field.
|
||||
func testSubmessageAliasFalseNegative() {
|
||||
query := &query.Query{}
|
||||
alias := &query.Description
|
||||
*alias = getUntrustedString()
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD (but not noticed by our current implementation)
|
||||
}
|
||||
|
||||
func testTaintedMapFieldWrite() {
|
||||
query := &query.Query{}
|
||||
query.KeyValuePairs[123] = getUntrustedString()
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD
|
||||
}
|
||||
|
||||
func testTaintedMapWriteWholeMap() {
|
||||
query := &query.Query{}
|
||||
taintedMap := map[int32]string{}
|
||||
taintedMap[123] = getUntrustedString()
|
||||
query.KeyValuePairs = taintedMap
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD
|
||||
}
|
||||
|
||||
func testTaintedMapFieldRead() {
|
||||
untrustedSerialized := getUntrustedBytes()
|
||||
query := &query.Query{}
|
||||
|
||||
proto.Unmarshal(untrustedSerialized, query)
|
||||
|
||||
sinkString(query.KeyValuePairs[123]) // BAD
|
||||
}
|
||||
|
||||
func testTaintedMapFieldReadViaAlias() {
|
||||
untrustedSerialized := getUntrustedBytes()
|
||||
query := &query.Query{}
|
||||
|
||||
proto.Unmarshal(untrustedSerialized, query)
|
||||
|
||||
alias := &query.KeyValuePairs
|
||||
|
||||
sinkString((*alias)[123]) // BAD
|
||||
}
|
||||
|
||||
func testTaintedSubmessageInPlaceNonPointerBase() {
|
||||
alert := query.Query_Alert{}
|
||||
|
||||
query := query.Query{}
|
||||
query.Alerts = append(query.Alerts, &alert)
|
||||
query.Alerts[0].Msg = getUntrustedString()
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD (but not detected by our current analysis)
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"codeql-go-tests/protobuf/protos/query"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/runtime/protoiface"
|
||||
)
|
||||
|
||||
func testMarshalModern() {
|
||||
query := &query.Query{}
|
||||
query.Description = getUntrustedString()
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized)
|
||||
}
|
||||
|
||||
func testCloneThenMarshalModern() {
|
||||
query := &query.Query{}
|
||||
query.Description = getUntrustedString()
|
||||
|
||||
queryClone := proto.Clone(query)
|
||||
|
||||
serialized, _ := proto.Marshal(queryClone)
|
||||
|
||||
sinkBytes(serialized)
|
||||
}
|
||||
|
||||
func testUnmarshalFieldAccessModern() {
|
||||
untrustedSerialized := getUntrustedBytes()
|
||||
query := &query.Query{}
|
||||
proto.Unmarshal(untrustedSerialized, query)
|
||||
|
||||
sinkString(query.Description)
|
||||
}
|
||||
|
||||
func testUnmarshalGetterModern() {
|
||||
untrustedSerialized := getUntrustedBytes()
|
||||
query := &query.Query{}
|
||||
proto.Unmarshal(untrustedSerialized, query)
|
||||
|
||||
sinkString(query.GetDescription())
|
||||
}
|
||||
|
||||
func testMergeThenMarshalModern() {
|
||||
query1 := &query.Query{}
|
||||
query1.Description = getUntrustedString()
|
||||
|
||||
query2 := &query.Query{}
|
||||
proto.Merge(query2, query1)
|
||||
|
||||
serialized, _ := proto.Marshal(query2)
|
||||
|
||||
sinkBytes(serialized)
|
||||
}
|
||||
|
||||
func testMarshalWithOptionsModern() {
|
||||
query := &query.Query{}
|
||||
query.Description = getUntrustedString()
|
||||
|
||||
options := proto.MarshalOptions{}
|
||||
serialized, _ := options.Marshal(query)
|
||||
|
||||
sinkBytes(serialized)
|
||||
}
|
||||
|
||||
// Tests only applicable to the modern API:
|
||||
|
||||
func testMarshalAppend() {
|
||||
query := &query.Query{}
|
||||
query.Description = getUntrustedString()
|
||||
|
||||
options := proto.MarshalOptions{}
|
||||
emptyArray := []byte{}
|
||||
serialized, _ := options.MarshalAppend(emptyArray, query)
|
||||
|
||||
sinkBytes(serialized)
|
||||
}
|
||||
|
||||
func testMarshalState() {
|
||||
query := &query.Query{}
|
||||
query.Description = getUntrustedString()
|
||||
|
||||
options := proto.MarshalOptions{}
|
||||
emptyArray := []byte{}
|
||||
marshalState := protoiface.MarshalInput{
|
||||
Message: query.ProtoReflect(),
|
||||
Buf: emptyArray,
|
||||
Flags: 0,
|
||||
}
|
||||
serialized, _ := options.MarshalState(marshalState)
|
||||
|
||||
sinkBytes(serialized.Buf)
|
||||
}
|
||||
|
||||
func testTaintedSubmessageModern() {
|
||||
alert := &query.Query_Alert{}
|
||||
alert.Msg = getUntrustedString()
|
||||
|
||||
query := &query.Query{}
|
||||
query.Alerts = append(query.Alerts, alert)
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD
|
||||
}
|
||||
|
||||
func testTaintedSubmessageInPlaceModern() {
|
||||
alert := &query.Query_Alert{}
|
||||
|
||||
query := &query.Query{}
|
||||
query.Alerts = append(query.Alerts, alert)
|
||||
query.Alerts[0].Msg = getUntrustedString()
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD
|
||||
}
|
||||
|
||||
func testUnmarshalTaintedSubmessageModern() {
|
||||
untrustedSerialized := getUntrustedBytes()
|
||||
query := &query.Query{}
|
||||
proto.Unmarshal(untrustedSerialized, query)
|
||||
|
||||
sinkString(query.Alerts[0].Msg) // BAD
|
||||
}
|
||||
|
||||
func testUnmarshalOptions() {
|
||||
options := proto.UnmarshalOptions{}
|
||||
|
||||
untrustedSerialized := getUntrustedBytes()
|
||||
query := &query.Query{}
|
||||
options.Unmarshal(untrustedSerialized, query)
|
||||
|
||||
sinkString(query.Description) // BAD
|
||||
}
|
||||
|
||||
// This test should be ok, but is flagged because writing taint to a field of a Message
|
||||
// taints the entire Message structure in our current implementation.
|
||||
func testFieldConflationFalsePositiveModern() {
|
||||
query := &query.Query{}
|
||||
query.Description = getUntrustedString()
|
||||
sinkString(query.Id) // OK (but incorrectly tainted)
|
||||
}
|
||||
|
||||
// This test should be ok, but it flagged because our current implementation doesn't notice
|
||||
// that the taint applied to `query` is overwritten.
|
||||
func testMessageReuseFalsePositiveModern() {
|
||||
query := &query.Query{}
|
||||
query.Description = getUntrustedString()
|
||||
query.Description = "clean"
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // OK (but incorrectly tainted)
|
||||
}
|
||||
|
||||
// This test should be flagged, but we don't notice tainting via an alias of a field.
|
||||
func testSubmessageAliasFalseNegativeModern() {
|
||||
query := &query.Query{}
|
||||
alias := &query.Description
|
||||
*alias = getUntrustedString()
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD (but not noticed by our current implementation)
|
||||
}
|
||||
|
||||
// This test should be flagged, but we don't notice that marshalState2.Message is the
|
||||
// same as marshalState.Message.
|
||||
func testMarshalStateFalseNegative() {
|
||||
query := &query.Query{}
|
||||
query.Description = getUntrustedString()
|
||||
|
||||
options := proto.MarshalOptions{}
|
||||
emptyArray := []byte{}
|
||||
marshalState := protoiface.MarshalInput{
|
||||
Message: query.ProtoReflect(),
|
||||
Buf: emptyArray,
|
||||
Flags: 0,
|
||||
}
|
||||
marshalState2 := marshalState
|
||||
serialized, _ := options.MarshalState(marshalState2)
|
||||
|
||||
sinkBytes(serialized.Buf) // BAD (but not noticed by our current implementation)
|
||||
}
|
||||
|
||||
func testTaintedMapFieldWriteModern() {
|
||||
query := &query.Query{}
|
||||
query.KeyValuePairs[123] = getUntrustedString()
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD
|
||||
}
|
||||
|
||||
func testTaintedMapWriteWholeMapModern() {
|
||||
query := &query.Query{}
|
||||
taintedMap := map[int32]string{}
|
||||
taintedMap[123] = getUntrustedString()
|
||||
query.KeyValuePairs = taintedMap
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD
|
||||
}
|
||||
|
||||
func testTaintedMapFieldReadModern() {
|
||||
untrustedSerialized := getUntrustedBytes()
|
||||
query := &query.Query{}
|
||||
|
||||
proto.Unmarshal(untrustedSerialized, query)
|
||||
|
||||
sinkString(query.KeyValuePairs[123]) // BAD
|
||||
}
|
||||
|
||||
func testTaintedMapFieldReadViaAliasModern() {
|
||||
untrustedSerialized := getUntrustedBytes()
|
||||
query := &query.Query{}
|
||||
|
||||
proto.Unmarshal(untrustedSerialized, query)
|
||||
|
||||
alias := &query.KeyValuePairs
|
||||
|
||||
sinkString((*alias)[123]) // BAD
|
||||
}
|
||||
|
||||
func testTaintedSubmessageInPlaceNonPointerBaseModern() {
|
||||
alert := query.Query_Alert{}
|
||||
|
||||
query := query.Query{}
|
||||
query.Alerts = append(query.Alerts, &alert)
|
||||
query.Alerts[0].Msg = getUntrustedString()
|
||||
|
||||
serialized, _ := proto.Marshal(query)
|
||||
|
||||
sinkBytes(serialized) // BAD (but not detected by our current implementation)
|
||||
}
|
||||
28
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/github.com/golang/protobuf/LICENSE
generated
vendored
Normal file
28
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/github.com/golang/protobuf/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
Copyright 2010 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
29
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/github.com/golang/protobuf/proto/stub.go
generated
vendored
Normal file
29
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/github.com/golang/protobuf/proto/stub.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// This is a simple stub for github.com/golang/protobuf/proto, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: github.com/golang/protobuf/proto (exports: Message; functions: Marshal,Unmarshal,ProtoPackageIsVersion4)
|
||||
|
||||
// Package proto is a stub of github.com/golang/protobuf/proto
|
||||
package proto
|
||||
|
||||
import (
|
||||
protoiface "google.golang.org/protobuf/runtime/protoiface"
|
||||
)
|
||||
|
||||
func Marshal(_ interface{}) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type Message = protoiface.MessageV1
|
||||
|
||||
const ProtoPackageIsVersion4 bool = false
|
||||
|
||||
func Unmarshal(_ []byte, _ interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Clone(_ Message) Message {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Merge(_, _ Message) {}
|
||||
27
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/LICENSE
generated
vendored
Normal file
27
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2018 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
132
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/internal/impl/stub.go
generated
vendored
Normal file
132
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/internal/impl/stub.go
generated
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
// This is a simple stub for google.golang.org/protobuf/internal/impl, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: google.golang.org/protobuf/internal/impl (exports: MessageState,Pointer; functions: )
|
||||
|
||||
// Package impl is a stub of google.golang.org/protobuf/internal/impl.
|
||||
package impl
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
type MessageState struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
DoNotCompare interface{}
|
||||
DoNotCopy interface{}
|
||||
}
|
||||
|
||||
type Pointer interface{}
|
||||
|
||||
type MessageInfo struct {
|
||||
Exporter interface{}
|
||||
}
|
||||
|
||||
func (*MessageInfo) MessageOf(_ interface{}) protoreflect.Message { return nil }
|
||||
|
||||
type EnumInfo struct{}
|
||||
|
||||
func (_ *EnumInfo) Descriptor() protoreflect.EnumDescriptor { return nil }
|
||||
func (_ *EnumInfo) New(_ protoreflect.EnumNumber) protoreflect.Enum { return nil }
|
||||
|
||||
type DescBuilder struct {
|
||||
GoPackagePath string
|
||||
RawDescriptor []byte
|
||||
NumEnums int
|
||||
NumMessages int
|
||||
NumExtensions int
|
||||
NumServices int
|
||||
}
|
||||
|
||||
type TypeBuilder struct {
|
||||
File DescBuilder
|
||||
GoTypes []interface{}
|
||||
DependencyIndexes []int32
|
||||
EnumInfos []EnumInfo
|
||||
MessageInfos []MessageInfo
|
||||
}
|
||||
|
||||
type BuilderOut struct {
|
||||
File protoreflect.FileDescriptor
|
||||
}
|
||||
|
||||
func (tb TypeBuilder) Build() BuilderOut {
|
||||
return BuilderOut{nil}
|
||||
}
|
||||
|
||||
func (ms *MessageState) LoadMessageInfo() *MessageInfo { return nil }
|
||||
func (ms *MessageState) StoreMessageInfo(mi *MessageInfo) {}
|
||||
|
||||
func (ms *MessageState) Clear(_ protoreflect.FieldDescriptor) {}
|
||||
func (ms *MessageState) Descriptor() protoreflect.MessageDescriptor { return nil }
|
||||
func (ms *MessageState) Get(_ protoreflect.FieldDescriptor) protoreflect.Value {
|
||||
return protoreflect.Value{}
|
||||
}
|
||||
func (ms *MessageState) GetUnknown() protoreflect.RawFields { return nil }
|
||||
func (ms *MessageState) Has(_ protoreflect.FieldDescriptor) bool { return false }
|
||||
func (ms *MessageState) Interface() protoreflect.ProtoMessage { return nil }
|
||||
func (ms *MessageState) IsValid() bool { return false }
|
||||
func (ms *MessageState) Mutable(_ protoreflect.FieldDescriptor) protoreflect.Value {
|
||||
return protoreflect.Value{}
|
||||
}
|
||||
func (ms *MessageState) New() protoreflect.Message { return nil }
|
||||
func (ms *MessageState) NewField(_ protoreflect.FieldDescriptor) protoreflect.Value {
|
||||
return protoreflect.Value{}
|
||||
}
|
||||
func (ms *MessageState) ProtoMethods() *struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Flags uint64
|
||||
Size func(struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Message protoreflect.Message
|
||||
Flags byte
|
||||
}) struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Size int
|
||||
}
|
||||
Marshal func(struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Message protoreflect.Message
|
||||
Buf []byte
|
||||
Flags byte
|
||||
}) (struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Buf []byte
|
||||
}, error)
|
||||
Unmarshal func(struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Message protoreflect.Message
|
||||
Buf []byte
|
||||
Flags byte
|
||||
Resolver interface {
|
||||
FindExtensionByName(_ protoreflect.FullName) (protoreflect.ExtensionType, error)
|
||||
FindExtensionByNumber(_ protoreflect.FullName, _ interface{}) (protoreflect.ExtensionType, error)
|
||||
}
|
||||
}) (struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Flags byte
|
||||
}, error)
|
||||
Merge func(struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Source protoreflect.Message
|
||||
Destination protoreflect.Message
|
||||
}) struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Flags byte
|
||||
}
|
||||
CheckInitialized func(struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Message protoreflect.Message
|
||||
}) (struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
}, error)
|
||||
} {
|
||||
return nil
|
||||
}
|
||||
func (ms *MessageState) Range(_ func(protoreflect.FieldDescriptor, protoreflect.Value) bool) {}
|
||||
func (ms *MessageState) Set(_ protoreflect.FieldDescriptor, _ protoreflect.Value) {}
|
||||
func (ms *MessageState) SetUnknown(_ protoreflect.RawFields) {}
|
||||
func (ms *MessageState) Type() protoreflect.MessageType { return nil }
|
||||
func (ms *MessageState) WhichOneof(_ protoreflect.OneofDescriptor) protoreflect.FieldDescriptor {
|
||||
return nil
|
||||
}
|
||||
68
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/proto/stub.go
generated
vendored
Normal file
68
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/proto/stub.go
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
// This is a simple stub for github.com/golang/protobuf/proto, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: github.com/golang/protobuf/proto (exports: Message; functions: Marshal,Unmarshal,ProtoPackageIsVersion4)
|
||||
|
||||
// Package proto is a stub of github.com/golang/protobuf/proto.
|
||||
package proto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoiface "google.golang.org/protobuf/runtime/protoiface"
|
||||
)
|
||||
|
||||
func Marshal(_ interface{}) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type Message = protoreflect.ProtoMessage
|
||||
|
||||
var ProtoPackageIsVersion4 bool = false
|
||||
|
||||
func Unmarshal(_ []byte, _ interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type MarshalOptions struct {
|
||||
AllowPartial bool
|
||||
Deterministic bool
|
||||
UseCachedSize bool
|
||||
}
|
||||
|
||||
func (_ MarshalOptions) Marshal(_ Message) ([]byte, error) { return nil, nil }
|
||||
func (_ MarshalOptions) MarshalAppend(b []byte, m Message) ([]byte, error) { return nil, nil }
|
||||
func (_ MarshalOptions) MarshalState(in protoiface.MarshalInput) (protoiface.MarshalOutput, error) {
|
||||
return protoiface.MarshalOutput{nil}, nil
|
||||
}
|
||||
|
||||
type UnmarshalOptions struct {
|
||||
// Merge merges the input into the destination message.
|
||||
// The default behavior is to always reset the message before unmarshaling,
|
||||
// unless Merge is specified.
|
||||
Merge bool
|
||||
|
||||
// AllowPartial accepts input for messages that will result in missing
|
||||
// required fields. If AllowPartial is false (the default), Unmarshal will
|
||||
// return an error if there are any missing required fields.
|
||||
AllowPartial bool
|
||||
|
||||
// If DiscardUnknown is set, unknown fields are ignored.
|
||||
DiscardUnknown bool
|
||||
|
||||
// Resolver is used for looking up types when unmarshaling extension fields.
|
||||
// If nil, this defaults to using protoregistry.GlobalTypes.
|
||||
Resolver interface {
|
||||
FindExtensionByName(field protoreflect.FullName) (protoreflect.ExtensionType, error)
|
||||
FindExtensionByNumber(message protoreflect.FullName, field protoreflect.FieldNumber) (protoreflect.ExtensionType, error)
|
||||
}
|
||||
}
|
||||
|
||||
func (o UnmarshalOptions) Unmarshal(b []byte, m Message) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Clone(_ Message) Message {
|
||||
return nil
|
||||
}
|
||||
|
||||
func Merge(_, _ Message) {}
|
||||
683
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/reflect/protoreflect/stub.go
generated
vendored
Normal file
683
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/reflect/protoreflect/stub.go
generated
vendored
Normal file
@@ -0,0 +1,683 @@
|
||||
// Code generated by depstubber. DO NOT EDIT.
|
||||
// This is a simple stub for google.golang.org/protobuf/reflect/protoreflect, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: google.golang.org/protobuf/reflect/protoreflect (exports: EnumDescriptor,EnumType,EnumNumber,Message,FileDescriptor; functions: )
|
||||
|
||||
// Package protoreflect is a stub of google.golang.org/protobuf/reflect/protoreflect, generated by depstubber.
|
||||
package protoreflect
|
||||
|
||||
import ()
|
||||
|
||||
type Cardinality int8
|
||||
|
||||
func (_ Cardinality) GoString() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ Cardinality) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ Cardinality) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type Descriptor interface {
|
||||
FullName() FullName
|
||||
Index() int
|
||||
IsPlaceholder() bool
|
||||
Name() Name
|
||||
Options() ProtoMessage
|
||||
Parent() Descriptor
|
||||
ParentFile() FileDescriptor
|
||||
ProtoInternal(_ interface{})
|
||||
Syntax() Syntax
|
||||
}
|
||||
|
||||
type Enum interface {
|
||||
Descriptor() EnumDescriptor
|
||||
Number() EnumNumber
|
||||
Type() EnumType
|
||||
}
|
||||
|
||||
type EnumDescriptor interface {
|
||||
FullName() FullName
|
||||
Index() int
|
||||
IsPlaceholder() bool
|
||||
Name() Name
|
||||
Options() ProtoMessage
|
||||
Parent() Descriptor
|
||||
ParentFile() FileDescriptor
|
||||
ProtoInternal(_ interface{})
|
||||
ProtoType(_ EnumDescriptor)
|
||||
ReservedNames() Names
|
||||
ReservedRanges() EnumRanges
|
||||
Syntax() Syntax
|
||||
Values() EnumValueDescriptors
|
||||
}
|
||||
|
||||
type EnumDescriptors interface {
|
||||
ByName(_ Name) EnumDescriptor
|
||||
Get(_ int) EnumDescriptor
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type EnumNumber int32
|
||||
|
||||
type EnumRanges interface {
|
||||
Get(_ int) [2]EnumNumber
|
||||
Has(_ EnumNumber) bool
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type EnumType interface {
|
||||
Descriptor() EnumDescriptor
|
||||
New(_ EnumNumber) Enum
|
||||
}
|
||||
|
||||
type EnumValueDescriptor interface {
|
||||
FullName() FullName
|
||||
Index() int
|
||||
IsPlaceholder() bool
|
||||
Name() Name
|
||||
Number() EnumNumber
|
||||
Options() ProtoMessage
|
||||
Parent() Descriptor
|
||||
ParentFile() FileDescriptor
|
||||
ProtoInternal(_ interface{})
|
||||
ProtoType(_ EnumValueDescriptor)
|
||||
Syntax() Syntax
|
||||
}
|
||||
|
||||
type EnumValueDescriptors interface {
|
||||
ByName(_ Name) EnumValueDescriptor
|
||||
ByNumber(_ EnumNumber) EnumValueDescriptor
|
||||
Get(_ int) EnumValueDescriptor
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type ExtensionDescriptors interface {
|
||||
ByName(_ Name) FieldDescriptor
|
||||
Get(_ int) FieldDescriptor
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type ExtensionType interface {
|
||||
InterfaceOf(_ Value) interface{}
|
||||
IsValidInterface(_ interface{}) bool
|
||||
IsValidValue(_ Value) bool
|
||||
New() Value
|
||||
TypeDescriptor() ExtensionTypeDescriptor
|
||||
ValueOf(_ interface{}) Value
|
||||
Zero() Value
|
||||
}
|
||||
|
||||
type ExtensionTypeDescriptor interface {
|
||||
Cardinality() Cardinality
|
||||
ContainingMessage() MessageDescriptor
|
||||
ContainingOneof() OneofDescriptor
|
||||
Default() Value
|
||||
DefaultEnumValue() EnumValueDescriptor
|
||||
Descriptor() FieldDescriptor
|
||||
Enum() EnumDescriptor
|
||||
FullName() FullName
|
||||
HasDefault() bool
|
||||
HasJSONName() bool
|
||||
HasOptionalKeyword() bool
|
||||
HasPresence() bool
|
||||
Index() int
|
||||
IsExtension() bool
|
||||
IsList() bool
|
||||
IsMap() bool
|
||||
IsPacked() bool
|
||||
IsPlaceholder() bool
|
||||
IsWeak() bool
|
||||
JSONName() string
|
||||
Kind() Kind
|
||||
MapKey() FieldDescriptor
|
||||
MapValue() FieldDescriptor
|
||||
Message() MessageDescriptor
|
||||
Name() Name
|
||||
Number() interface{}
|
||||
Options() ProtoMessage
|
||||
Parent() Descriptor
|
||||
ParentFile() FileDescriptor
|
||||
ProtoInternal(_ interface{})
|
||||
ProtoType(_ FieldDescriptor)
|
||||
Syntax() Syntax
|
||||
Type() ExtensionType
|
||||
}
|
||||
|
||||
type FieldDescriptor interface {
|
||||
Cardinality() Cardinality
|
||||
ContainingMessage() MessageDescriptor
|
||||
ContainingOneof() OneofDescriptor
|
||||
Default() Value
|
||||
DefaultEnumValue() EnumValueDescriptor
|
||||
Enum() EnumDescriptor
|
||||
FullName() FullName
|
||||
HasDefault() bool
|
||||
HasJSONName() bool
|
||||
HasOptionalKeyword() bool
|
||||
HasPresence() bool
|
||||
Index() int
|
||||
IsExtension() bool
|
||||
IsList() bool
|
||||
IsMap() bool
|
||||
IsPacked() bool
|
||||
IsPlaceholder() bool
|
||||
IsWeak() bool
|
||||
JSONName() string
|
||||
Kind() Kind
|
||||
MapKey() FieldDescriptor
|
||||
MapValue() FieldDescriptor
|
||||
Message() MessageDescriptor
|
||||
Name() Name
|
||||
Number() interface{}
|
||||
Options() ProtoMessage
|
||||
Parent() Descriptor
|
||||
ParentFile() FileDescriptor
|
||||
ProtoInternal(_ interface{})
|
||||
ProtoType(_ FieldDescriptor)
|
||||
Syntax() Syntax
|
||||
}
|
||||
|
||||
type FieldDescriptors interface {
|
||||
ByJSONName(_ string) FieldDescriptor
|
||||
ByName(_ Name) FieldDescriptor
|
||||
ByNumber(_ interface{}) FieldDescriptor
|
||||
Get(_ int) FieldDescriptor
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type FieldNumber int32
|
||||
|
||||
type FieldNumbers interface {
|
||||
Get(_ int) interface{}
|
||||
Has(_ interface{}) bool
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type FieldRanges interface {
|
||||
Get(_ int) [2]interface{}
|
||||
Has(_ interface{}) bool
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type FileDescriptor interface {
|
||||
Enums() EnumDescriptors
|
||||
Extensions() ExtensionDescriptors
|
||||
FullName() FullName
|
||||
Imports() FileImports
|
||||
Index() int
|
||||
IsPlaceholder() bool
|
||||
Messages() MessageDescriptors
|
||||
Name() Name
|
||||
Options() ProtoMessage
|
||||
Package() FullName
|
||||
Parent() Descriptor
|
||||
ParentFile() FileDescriptor
|
||||
Path() string
|
||||
ProtoInternal(_ interface{})
|
||||
ProtoType(_ FileDescriptor)
|
||||
Services() ServiceDescriptors
|
||||
SourceLocations() SourceLocations
|
||||
Syntax() Syntax
|
||||
}
|
||||
|
||||
type FileImport struct {
|
||||
FileDescriptor FileDescriptor
|
||||
IsPublic bool
|
||||
IsWeak bool
|
||||
}
|
||||
|
||||
func (_ FileImport) Enums() EnumDescriptors {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ FileImport) Extensions() ExtensionDescriptors {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ FileImport) FullName() FullName {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ FileImport) Imports() FileImports {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ FileImport) Index() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ FileImport) IsPlaceholder() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ FileImport) Messages() MessageDescriptors {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ FileImport) Name() Name {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ FileImport) Options() ProtoMessage {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ FileImport) Package() FullName {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ FileImport) Parent() Descriptor {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ FileImport) ParentFile() FileDescriptor {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ FileImport) Path() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ FileImport) ProtoInternal(_ interface{}) {}
|
||||
|
||||
func (_ FileImport) ProtoType(_ FileDescriptor) {}
|
||||
|
||||
func (_ FileImport) Services() ServiceDescriptors {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ FileImport) SourceLocations() SourceLocations {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ FileImport) Syntax() Syntax {
|
||||
return 0
|
||||
}
|
||||
|
||||
type FileImports interface {
|
||||
Get(_ int) FileImport
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type FullName string
|
||||
|
||||
func (_ FullName) Append(_ Name) FullName {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ FullName) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ FullName) Name() Name {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ FullName) Parent() FullName {
|
||||
return ""
|
||||
}
|
||||
|
||||
type Kind int8
|
||||
|
||||
func (_ Kind) GoString() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ Kind) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ Kind) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type List interface {
|
||||
Append(_ Value)
|
||||
AppendMutable() Value
|
||||
Get(_ int) Value
|
||||
IsValid() bool
|
||||
Len() int
|
||||
NewElement() Value
|
||||
Set(_ int, _ Value)
|
||||
Truncate(_ int)
|
||||
}
|
||||
|
||||
type Map interface {
|
||||
Clear(_ MapKey)
|
||||
Get(_ MapKey) Value
|
||||
Has(_ MapKey) bool
|
||||
IsValid() bool
|
||||
Len() int
|
||||
Mutable(_ MapKey) Value
|
||||
NewValue() Value
|
||||
Range(_ func(MapKey, Value) bool)
|
||||
Set(_ MapKey, _ Value)
|
||||
}
|
||||
|
||||
type MapKey struct {
|
||||
DoNotCompare interface{}
|
||||
}
|
||||
|
||||
func (_ MapKey) Bool() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ MapKey) Int() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ MapKey) Interface() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ MapKey) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ MapKey) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ MapKey) Uint() uint64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ MapKey) Value() Value {
|
||||
return Value{}
|
||||
}
|
||||
|
||||
type Message interface {
|
||||
Clear(_ FieldDescriptor)
|
||||
Descriptor() MessageDescriptor
|
||||
Get(_ FieldDescriptor) Value
|
||||
GetUnknown() RawFields
|
||||
Has(_ FieldDescriptor) bool
|
||||
Interface() ProtoMessage
|
||||
IsValid() bool
|
||||
Mutable(_ FieldDescriptor) Value
|
||||
New() Message
|
||||
NewField(_ FieldDescriptor) Value
|
||||
ProtoMethods() *struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Flags uint64
|
||||
Size func(struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Message Message
|
||||
Flags byte
|
||||
}) struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Size int
|
||||
}
|
||||
Marshal func(struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Message Message
|
||||
Buf []byte
|
||||
Flags byte
|
||||
}) (struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Buf []byte
|
||||
}, error)
|
||||
Unmarshal func(struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Message Message
|
||||
Buf []byte
|
||||
Flags byte
|
||||
Resolver interface {
|
||||
FindExtensionByName(_ FullName) (ExtensionType, error)
|
||||
FindExtensionByNumber(_ FullName, _ interface{}) (ExtensionType, error)
|
||||
}
|
||||
}) (struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Flags byte
|
||||
}, error)
|
||||
Merge func(struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Source Message
|
||||
Destination Message
|
||||
}) struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Flags byte
|
||||
}
|
||||
CheckInitialized func(struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
Message Message
|
||||
}) (struct {
|
||||
NoUnkeyedLiterals interface{}
|
||||
}, error)
|
||||
}
|
||||
Range(_ func(FieldDescriptor, Value) bool)
|
||||
Set(_ FieldDescriptor, _ Value)
|
||||
SetUnknown(_ RawFields)
|
||||
Type() MessageType
|
||||
WhichOneof(_ OneofDescriptor) FieldDescriptor
|
||||
}
|
||||
|
||||
type MessageDescriptor interface {
|
||||
Enums() EnumDescriptors
|
||||
ExtensionRangeOptions(_ int) ProtoMessage
|
||||
ExtensionRanges() FieldRanges
|
||||
Extensions() ExtensionDescriptors
|
||||
Fields() FieldDescriptors
|
||||
FullName() FullName
|
||||
Index() int
|
||||
IsMapEntry() bool
|
||||
IsPlaceholder() bool
|
||||
Messages() MessageDescriptors
|
||||
Name() Name
|
||||
Oneofs() OneofDescriptors
|
||||
Options() ProtoMessage
|
||||
Parent() Descriptor
|
||||
ParentFile() FileDescriptor
|
||||
ProtoInternal(_ interface{})
|
||||
ProtoType(_ MessageDescriptor)
|
||||
RequiredNumbers() FieldNumbers
|
||||
ReservedNames() Names
|
||||
ReservedRanges() FieldRanges
|
||||
Syntax() Syntax
|
||||
}
|
||||
|
||||
type MessageDescriptors interface {
|
||||
ByName(_ Name) MessageDescriptor
|
||||
Get(_ int) MessageDescriptor
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type MessageType interface {
|
||||
Descriptor() MessageDescriptor
|
||||
New() Message
|
||||
Zero() Message
|
||||
}
|
||||
|
||||
type MethodDescriptor interface {
|
||||
FullName() FullName
|
||||
Index() int
|
||||
Input() MessageDescriptor
|
||||
IsPlaceholder() bool
|
||||
IsStreamingClient() bool
|
||||
IsStreamingServer() bool
|
||||
Name() Name
|
||||
Options() ProtoMessage
|
||||
Output() MessageDescriptor
|
||||
Parent() Descriptor
|
||||
ParentFile() FileDescriptor
|
||||
ProtoInternal(_ interface{})
|
||||
ProtoType(_ MethodDescriptor)
|
||||
Syntax() Syntax
|
||||
}
|
||||
|
||||
type MethodDescriptors interface {
|
||||
ByName(_ Name) MethodDescriptor
|
||||
Get(_ int) MethodDescriptor
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type Name string
|
||||
|
||||
func (_ Name) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type Names interface {
|
||||
Get(_ int) Name
|
||||
Has(_ Name) bool
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type OneofDescriptor interface {
|
||||
Fields() FieldDescriptors
|
||||
FullName() FullName
|
||||
Index() int
|
||||
IsPlaceholder() bool
|
||||
IsSynthetic() bool
|
||||
Name() Name
|
||||
Options() ProtoMessage
|
||||
Parent() Descriptor
|
||||
ParentFile() FileDescriptor
|
||||
ProtoInternal(_ interface{})
|
||||
ProtoType(_ OneofDescriptor)
|
||||
Syntax() Syntax
|
||||
}
|
||||
|
||||
type OneofDescriptors interface {
|
||||
ByName(_ Name) OneofDescriptor
|
||||
Get(_ int) OneofDescriptor
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type ProtoMessage interface {
|
||||
ProtoReflect() Message
|
||||
}
|
||||
|
||||
type RawFields []byte
|
||||
|
||||
func (_ RawFields) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
type ServiceDescriptor interface {
|
||||
FullName() FullName
|
||||
Index() int
|
||||
IsPlaceholder() bool
|
||||
Methods() MethodDescriptors
|
||||
Name() Name
|
||||
Options() ProtoMessage
|
||||
Parent() Descriptor
|
||||
ParentFile() FileDescriptor
|
||||
ProtoInternal(_ interface{})
|
||||
ProtoType(_ ServiceDescriptor)
|
||||
Syntax() Syntax
|
||||
}
|
||||
|
||||
type ServiceDescriptors interface {
|
||||
ByName(_ Name) ServiceDescriptor
|
||||
Get(_ int) ServiceDescriptor
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type SourceLocation struct {
|
||||
Path SourcePath
|
||||
StartLine int
|
||||
StartColumn int
|
||||
EndLine int
|
||||
EndColumn int
|
||||
LeadingDetachedComments []string
|
||||
LeadingComments string
|
||||
TrailingComments string
|
||||
}
|
||||
|
||||
type SourceLocations interface {
|
||||
Get(_ int) SourceLocation
|
||||
Len() int
|
||||
ProtoInternal(_ interface{})
|
||||
}
|
||||
|
||||
type SourcePath []int32
|
||||
|
||||
type Syntax int8
|
||||
|
||||
func (_ Syntax) GoString() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ Syntax) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ Syntax) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type Value struct {
|
||||
DoNotCompare interface{}
|
||||
}
|
||||
|
||||
func (_ Value) Bool() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ Value) Bytes() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Value) Enum() EnumNumber {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ Value) Float() float64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ Value) Int() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (_ Value) Interface() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Value) IsValid() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (_ Value) List() List {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Value) Map() Map {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Value) MapKey() MapKey {
|
||||
return MapKey{}
|
||||
}
|
||||
|
||||
func (_ Value) Message() Message {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (_ Value) String() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (_ Value) Uint() uint64 {
|
||||
return 0
|
||||
}
|
||||
29
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/runtime/protoiface/stub.go
generated
vendored
Normal file
29
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/runtime/protoiface/stub.go
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
// This is a simple stub for google.golang.org/protobuf/runtime/protoiface, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: google.golang.org/protobuf/runtime/protoiface (exports: MessageV1; functions: )
|
||||
|
||||
// Package protoiface is a stub of google.golang.org/protobuf/runtime/protoiface.
|
||||
package protoiface
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
)
|
||||
|
||||
type MessageV1 interface {
|
||||
ProtoMessage()
|
||||
Reset()
|
||||
String() string
|
||||
}
|
||||
|
||||
type MarshalInputFlags = uint8
|
||||
|
||||
type MarshalInput struct {
|
||||
Message protoreflect.Message
|
||||
Buf []byte // output is appended to this buffer
|
||||
Flags MarshalInputFlags
|
||||
}
|
||||
|
||||
type MarshalOutput struct {
|
||||
Buf []byte // contains marshaled message
|
||||
}
|
||||
107
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/runtime/protoimpl/stub.go
generated
vendored
Normal file
107
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/google.golang.org/protobuf/runtime/protoimpl/stub.go
generated
vendored
Normal file
@@ -0,0 +1,107 @@
|
||||
// This is a simple stub for google.golang.org/protobuf/runtime/protoimpl, strictly for use in testing.
|
||||
|
||||
// See the LICENSE file for information about the licensing of the original library.
|
||||
// Source: google.golang.org/protobuf/runtime/protoimpl (exports: MessageState,SizeCache,UnknownFields,Pointer,EnforceVersion; functions: MinVersion,MaxVersion,UnsafeEnabled,X)
|
||||
|
||||
// Package protoimpl is a stub of google.golang.org/protobuf/runtime/protoimpl.
|
||||
package protoimpl
|
||||
|
||||
import (
|
||||
impl "google.golang.org/protobuf/internal/impl"
|
||||
)
|
||||
|
||||
type EnforceVersion uint
|
||||
|
||||
const MaxVersion int = 20
|
||||
|
||||
type MessageState = impl.MessageState
|
||||
|
||||
const MinVersion int = 20
|
||||
|
||||
type Pointer = impl.Pointer
|
||||
|
||||
type SizeCache = int32
|
||||
|
||||
type UnknownFields = []byte
|
||||
|
||||
var UnsafeEnabled bool = false
|
||||
|
||||
// Export is a zero-length named type that exists only to export a set of
|
||||
// functions that we do not want to appear in godoc.
|
||||
type Export struct{}
|
||||
|
||||
var X Export = Export{}
|
||||
|
||||
func (Export) NewError(f string, x ...interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type enum = interface{}
|
||||
|
||||
func (Export) EnumOf(e enum) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Export) EnumDescriptorOf(e enum) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Export) EnumTypeOf(e enum) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Export) EnumStringOf(ed interface{}, n interface{}) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type message = interface{}
|
||||
|
||||
type legacyMessageWrapper struct{ m interface{} }
|
||||
|
||||
func (m legacyMessageWrapper) Reset() {}
|
||||
func (m legacyMessageWrapper) String() string { return "" }
|
||||
func (m legacyMessageWrapper) ProtoMessage() {}
|
||||
|
||||
func (Export) ProtoMessageV1Of(m message) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Export) protoMessageV2Of(m message) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Export) ProtoMessageV2Of(m message) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Export) MessageOf(m message) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Export) MessageDescriptorOf(m message) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Export) MessageTypeOf(m message) interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Export) MessageStringOf(m interface{}) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (Export) MessageStateOf(p Pointer) *MessageState {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Export) CompressGZIP(_ []byte) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
type EnumInfo = impl.EnumInfo
|
||||
|
||||
type MessageInfo = impl.MessageInfo
|
||||
|
||||
type TypeBuilder = impl.TypeBuilder
|
||||
|
||||
type DescBuilder = impl.DescBuilder
|
||||
6
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/modules.txt
vendored
Normal file
6
ql/test/library-tests/semmle/go/frameworks/Protobuf/vendor/modules.txt
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
# github.com/golang/protobuf v1.4.2
|
||||
## explicit
|
||||
github.com/golang/protobuf
|
||||
# google.golang.org/protobuf v1.23.0
|
||||
## explicit
|
||||
google.golang.org/protobuf
|
||||
@@ -3,5 +3,6 @@ module gormtest
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/jinzhu/gorm v1.9.15
|
||||
github.com/jinzhu/gorm v1.9.16
|
||||
gorm.io/gorm v1.20.0
|
||||
)
|
||||
|
||||
@@ -1,9 +1,25 @@
|
||||
| gorm.go:15:11:15:19 | untrusted |
|
||||
| gorm.go:16:9:16:17 | untrusted |
|
||||
| gorm.go:17:11:17:19 | untrusted |
|
||||
| gorm.go:18:8:18:16 | untrusted |
|
||||
| gorm.go:19:12:19:20 | untrusted |
|
||||
| gorm.go:20:11:20:19 | untrusted |
|
||||
| gorm.go:21:11:21:19 | untrusted |
|
||||
| gorm.go:22:12:22:20 | untrusted |
|
||||
| gorm.go:23:11:23:19 | untrusted |
|
||||
| gorm.go:20:12:20:20 | untrusted | github.com/jinzhu/gorm | DB | Where |
|
||||
| gorm.go:21:10:21:18 | untrusted | github.com/jinzhu/gorm | DB | Raw |
|
||||
| gorm.go:22:10:22:18 | untrusted | github.com/jinzhu/gorm | DB | Not |
|
||||
| gorm.go:23:12:23:20 | untrusted | github.com/jinzhu/gorm | DB | Order |
|
||||
| gorm.go:24:9:24:17 | untrusted | github.com/jinzhu/gorm | DB | Or |
|
||||
| gorm.go:25:13:25:21 | untrusted | github.com/jinzhu/gorm | DB | Select |
|
||||
| gorm.go:26:12:26:20 | untrusted | github.com/jinzhu/gorm | DB | Table |
|
||||
| gorm.go:27:12:27:20 | untrusted | github.com/jinzhu/gorm | DB | Group |
|
||||
| gorm.go:28:13:28:21 | untrusted | github.com/jinzhu/gorm | DB | Having |
|
||||
| gorm.go:29:12:29:20 | untrusted | github.com/jinzhu/gorm | DB | Joins |
|
||||
| gorm.go:30:11:30:19 | untrusted | github.com/jinzhu/gorm | DB | Exec |
|
||||
| gorm.go:31:12:31:20 | untrusted | github.com/jinzhu/gorm | DB | Pluck |
|
||||
| gorm.go:34:12:34:20 | untrusted | gorm.io/gorm | DB | Where |
|
||||
| gorm.go:35:10:35:18 | untrusted | gorm.io/gorm | DB | Raw |
|
||||
| gorm.go:36:10:36:18 | untrusted | gorm.io/gorm | DB | Not |
|
||||
| gorm.go:37:12:37:20 | untrusted | gorm.io/gorm | DB | Order |
|
||||
| gorm.go:38:9:38:17 | untrusted | gorm.io/gorm | DB | Or |
|
||||
| gorm.go:39:13:39:21 | untrusted | gorm.io/gorm | DB | Select |
|
||||
| gorm.go:40:12:40:20 | untrusted | gorm.io/gorm | DB | Table |
|
||||
| gorm.go:41:12:41:20 | untrusted | gorm.io/gorm | DB | Group |
|
||||
| gorm.go:42:13:42:21 | untrusted | gorm.io/gorm | DB | Having |
|
||||
| gorm.go:43:12:43:20 | untrusted | gorm.io/gorm | DB | Joins |
|
||||
| gorm.go:44:11:44:19 | untrusted | gorm.io/gorm | DB | Exec |
|
||||
| gorm.go:45:15:45:23 | untrusted | gorm.io/gorm | DB | Distinct |
|
||||
| gorm.go:46:12:46:20 | untrusted | gorm.io/gorm | DB | Pluck |
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
package gormtest
|
||||
|
||||
//go:generate depstubber -vendor github.com/jinzhu/gorm DB
|
||||
//go:generate depstubber -vendor gorm.io/gorm DB
|
||||
|
||||
import (
|
||||
"github.com/jinzhu/gorm"
|
||||
gorm1 "github.com/jinzhu/gorm"
|
||||
gorm2 "gorm.io/gorm"
|
||||
)
|
||||
|
||||
func getUntrustedString() string {
|
||||
@@ -10,16 +14,35 @@ func getUntrustedString() string {
|
||||
|
||||
func main() {
|
||||
|
||||
db := gorm.DB{}
|
||||
untrusted := getUntrustedString()
|
||||
db.Where(untrusted)
|
||||
db.Not(untrusted)
|
||||
db.Order(untrusted)
|
||||
db.Or(untrusted)
|
||||
db.Select(untrusted)
|
||||
db.Table(untrusted)
|
||||
db.Group(untrusted)
|
||||
db.Having(untrusted)
|
||||
db.Joins(untrusted)
|
||||
|
||||
db1 := gorm1.DB{}
|
||||
db1.Where(untrusted)
|
||||
db1.Raw(untrusted)
|
||||
db1.Not(untrusted)
|
||||
db1.Order(untrusted)
|
||||
db1.Or(untrusted)
|
||||
db1.Select(untrusted)
|
||||
db1.Table(untrusted)
|
||||
db1.Group(untrusted)
|
||||
db1.Having(untrusted)
|
||||
db1.Joins(untrusted)
|
||||
db1.Exec(untrusted)
|
||||
db1.Pluck(untrusted, nil)
|
||||
|
||||
db2 := gorm2.DB{}
|
||||
db2.Where(untrusted)
|
||||
db2.Raw(untrusted)
|
||||
db2.Not(untrusted)
|
||||
db2.Order(untrusted)
|
||||
db2.Or(untrusted)
|
||||
db2.Select(untrusted)
|
||||
db2.Table(untrusted)
|
||||
db2.Group(untrusted)
|
||||
db2.Having(untrusted)
|
||||
db2.Joins(untrusted)
|
||||
db2.Exec(untrusted)
|
||||
db2.Distinct(untrusted)
|
||||
db2.Pluck(untrusted, nil)
|
||||
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import go
|
||||
|
||||
from SQL::QueryString qs
|
||||
select qs
|
||||
from SQL::QueryString qs, Method meth, string a, string b, string c
|
||||
where meth.hasQualifiedName(a, b, c) and qs = meth.getACall().getArgument(0)
|
||||
select qs, a, b, c
|
||||
|
||||
753
ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/vendor/gorm.io/gorm/stub.go
generated
vendored
Normal file
753
ql/test/library-tests/semmle/go/frameworks/SQL/Gorm/vendor/gorm.io/gorm/stub.go
generated
vendored
Normal file
@@ -0,0 +1,753 @@
|
||||
// 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 Config struct {
|
||||
SkipDefaultTransaction bool
|
||||
NamingStrategy interface{}
|
||||
Logger interface{}
|
||||
NowFunc func() time.Time
|
||||
DryRun bool
|
||||
PrepareStmt bool
|
||||
DisableAutomaticPing bool
|
||||
DisableForeignKeyConstraintWhenMigrating bool
|
||||
AllowGlobalUpdate bool
|
||||
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) {}
|
||||
|
||||
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) 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) 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{}) ([]*sql.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{}, _ *sql.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
|
||||
WithConditions bool
|
||||
SkipDefaultTransaction bool
|
||||
AllowGlobalUpdate bool
|
||||
Context context.Context
|
||||
Logger interface{}
|
||||
NowFunc func() time.Time
|
||||
}
|
||||
|
||||
type Statement struct {
|
||||
DB *DB
|
||||
TableExpr interface{}
|
||||
Table string
|
||||
Model interface{}
|
||||
Unscoped bool
|
||||
Dest interface{}
|
||||
ReflectValue reflect.Value
|
||||
Clauses map[string]interface{}
|
||||
Distinct bool
|
||||
Selects []string
|
||||
Omits []string
|
||||
Joins []interface{}
|
||||
Preloads map[string][]interface{}
|
||||
Settings sync.Map
|
||||
ConnPool ConnPool
|
||||
Schema interface{}
|
||||
Context context.Context
|
||||
RaiseErrorOnNotFound bool
|
||||
UpdatingColumn bool
|
||||
SQL strings.Builder
|
||||
Vars []interface{}
|
||||
CurDestIndex int
|
||||
}
|
||||
|
||||
func (_ Statement) AddError(_ error) 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) 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{}) {}
|
||||
|
||||
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
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
# github.com/jinzhu/gorm v1.9.15
|
||||
# github.com/jinzhu/gorm v1.9.16
|
||||
## explicit
|
||||
github.com/jinzhu/gorm
|
||||
# gorm.io/gorm v1.20.0
|
||||
## explicit
|
||||
gorm.io/gorm
|
||||
|
||||
@@ -0,0 +1,482 @@
|
||||
// Code generated by https://github.com/gagliardetto/codebox. DO NOT EDIT.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func TaintStepTest_ReflectAppend_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue656 := sourceCQL.(reflect.Value)
|
||||
intoValue414 := reflect.Append(fromValue656, reflect.Value{})
|
||||
return intoValue414
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectAppend_B0I1O0(sourceCQL interface{}) interface{} {
|
||||
fromValue518 := sourceCQL.(reflect.Value)
|
||||
intoValue650 := reflect.Append(reflect.Value{}, fromValue518)
|
||||
return intoValue650
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectAppendSlice_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue784 := sourceCQL.(reflect.Value)
|
||||
intoValue957 := reflect.AppendSlice(fromValue784, reflect.Value{})
|
||||
return intoValue957
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectAppendSlice_B0I1O0(sourceCQL interface{}) interface{} {
|
||||
fromValue520 := sourceCQL.(reflect.Value)
|
||||
intoValue443 := reflect.AppendSlice(reflect.Value{}, fromValue520)
|
||||
return intoValue443
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectCopy_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue127 := sourceCQL.(reflect.Value)
|
||||
var intoValue483 reflect.Value
|
||||
reflect.Copy(intoValue483, fromValue127)
|
||||
return intoValue483
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectIndirect_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue989 := sourceCQL.(reflect.Value)
|
||||
intoValue982 := reflect.Indirect(fromValue989)
|
||||
return intoValue982
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueOf_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromInterface417 := sourceCQL.(interface{})
|
||||
intoValue584 := reflect.ValueOf(fromInterface417)
|
||||
return intoValue584
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectMapIterKey_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromMapIter991 := sourceCQL.(reflect.MapIter)
|
||||
intoValue881 := fromMapIter991.Key()
|
||||
return intoValue881
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectMapIterValue_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromMapIter186 := sourceCQL.(reflect.MapIter)
|
||||
intoValue284 := fromMapIter186.Value()
|
||||
return intoValue284
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectStructTagGet_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromStructTag908 := sourceCQL.(reflect.StructTag)
|
||||
intoString137 := fromStructTag908.Get("")
|
||||
return intoString137
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectStructTagLookup_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromStructTag494 := sourceCQL.(reflect.StructTag)
|
||||
intoString873, _ := fromStructTag494.Lookup("")
|
||||
return intoString873
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueAddr_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue599 := sourceCQL.(reflect.Value)
|
||||
intoValue409 := fromValue599.Addr()
|
||||
return intoValue409
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueBytes_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue246 := sourceCQL.(reflect.Value)
|
||||
intoByte898 := fromValue246.Bytes()
|
||||
return intoByte898
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueConvert_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue598 := sourceCQL.(reflect.Value)
|
||||
intoValue631 := fromValue598.Convert(nil)
|
||||
return intoValue631
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueElem_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue165 := sourceCQL.(reflect.Value)
|
||||
intoValue150 := fromValue165.Elem()
|
||||
return intoValue150
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueField_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue340 := sourceCQL.(reflect.Value)
|
||||
intoValue471 := fromValue340.Field(0)
|
||||
return intoValue471
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueFieldByIndex_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue290 := sourceCQL.(reflect.Value)
|
||||
intoValue758 := fromValue290.FieldByIndex(nil)
|
||||
return intoValue758
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueFieldByName_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue396 := sourceCQL.(reflect.Value)
|
||||
intoValue707 := fromValue396.FieldByName("")
|
||||
return intoValue707
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueFieldByNameFunc_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue912 := sourceCQL.(reflect.Value)
|
||||
intoValue718 := fromValue912.FieldByNameFunc(nil)
|
||||
return intoValue718
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueIndex_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue972 := sourceCQL.(reflect.Value)
|
||||
intoValue633 := fromValue972.Index(0)
|
||||
return intoValue633
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueInterface_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue316 := sourceCQL.(reflect.Value)
|
||||
intoInterface145 := fromValue316.Interface()
|
||||
return intoInterface145
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueInterfaceData_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue817 := sourceCQL.(reflect.Value)
|
||||
intoUintptr474 := fromValue817.InterfaceData()
|
||||
return intoUintptr474
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueMapIndex_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue832 := sourceCQL.(reflect.Value)
|
||||
intoValue378 := fromValue832.MapIndex(reflect.Value{})
|
||||
return intoValue378
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueMapKeys_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue541 := sourceCQL.(reflect.Value)
|
||||
intoValue139 := fromValue541.MapKeys()
|
||||
return intoValue139
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueMapRange_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue814 := sourceCQL.(reflect.Value)
|
||||
intoMapIter768 := fromValue814.MapRange()
|
||||
return intoMapIter768
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueMethod_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue468 := sourceCQL.(reflect.Value)
|
||||
intoValue736 := fromValue468.Method(0)
|
||||
return intoValue736
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueMethodByName_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue516 := sourceCQL.(reflect.Value)
|
||||
intoValue246 := fromValue516.MethodByName("")
|
||||
return intoValue246
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValuePointer_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue679 := sourceCQL.(reflect.Value)
|
||||
intoUintptr736 := fromValue679.Pointer()
|
||||
return intoUintptr736
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueRecv_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue839 := sourceCQL.(reflect.Value)
|
||||
intoValue273, _ := fromValue839.Recv()
|
||||
return intoValue273
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueSend_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue982 := sourceCQL.(reflect.Value)
|
||||
var intoValue458 reflect.Value
|
||||
intoValue458.Send(fromValue982)
|
||||
return intoValue458
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueSet_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue506 := sourceCQL.(reflect.Value)
|
||||
var intoValue213 reflect.Value
|
||||
intoValue213.Set(fromValue506)
|
||||
return intoValue213
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueSetBytes_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromByte468 := sourceCQL.([]byte)
|
||||
var intoValue219 reflect.Value
|
||||
intoValue219.SetBytes(fromByte468)
|
||||
return intoValue219
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueSetMapIndex_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue265 := sourceCQL.(reflect.Value)
|
||||
var intoValue971 reflect.Value
|
||||
intoValue971.SetMapIndex(fromValue265, reflect.Value{})
|
||||
return intoValue971
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueSetMapIndex_B0I1O0(sourceCQL interface{}) interface{} {
|
||||
fromValue320 := sourceCQL.(reflect.Value)
|
||||
var intoValue545 reflect.Value
|
||||
intoValue545.SetMapIndex(reflect.Value{}, fromValue320)
|
||||
return intoValue545
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueSetPointer_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromPointer566 := sourceCQL.(unsafe.Pointer)
|
||||
var intoValue497 reflect.Value
|
||||
intoValue497.SetPointer(fromPointer566)
|
||||
return intoValue497
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueSetString_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromString274 := sourceCQL.(string)
|
||||
var intoValue783 reflect.Value
|
||||
intoValue783.SetString(fromString274)
|
||||
return intoValue783
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueSlice_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue905 := sourceCQL.(reflect.Value)
|
||||
intoValue389 := fromValue905.Slice(0, 0)
|
||||
return intoValue389
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueSlice3_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue198 := sourceCQL.(reflect.Value)
|
||||
intoValue477 := fromValue198.Slice3(0, 0, 0)
|
||||
return intoValue477
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueString_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue544 := sourceCQL.(reflect.Value)
|
||||
intoString382 := fromValue544.String()
|
||||
return intoString382
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueTryRecv_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue715 := sourceCQL.(reflect.Value)
|
||||
intoValue179, _ := fromValue715.TryRecv()
|
||||
return intoValue179
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueTrySend_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue366 := sourceCQL.(reflect.Value)
|
||||
var intoValue648 reflect.Value
|
||||
intoValue648.TrySend(fromValue366)
|
||||
return intoValue648
|
||||
}
|
||||
|
||||
func TaintStepTest_ReflectValueUnsafeAddr_B0I0O0(sourceCQL interface{}) interface{} {
|
||||
fromValue544 := sourceCQL.(reflect.Value)
|
||||
intoUintptr484 := fromValue544.UnsafeAddr()
|
||||
return intoUintptr484
|
||||
}
|
||||
|
||||
func RunAllTaints_Reflect() {
|
||||
{
|
||||
source := newSource(0)
|
||||
out := TaintStepTest_ReflectAppend_B0I0O0(source)
|
||||
sink(0, out)
|
||||
}
|
||||
{
|
||||
source := newSource(1)
|
||||
out := TaintStepTest_ReflectAppend_B0I1O0(source)
|
||||
sink(1, out)
|
||||
}
|
||||
{
|
||||
source := newSource(2)
|
||||
out := TaintStepTest_ReflectAppendSlice_B0I0O0(source)
|
||||
sink(2, out)
|
||||
}
|
||||
{
|
||||
source := newSource(3)
|
||||
out := TaintStepTest_ReflectAppendSlice_B0I1O0(source)
|
||||
sink(3, out)
|
||||
}
|
||||
{
|
||||
source := newSource(4)
|
||||
out := TaintStepTest_ReflectCopy_B0I0O0(source)
|
||||
sink(4, out)
|
||||
}
|
||||
{
|
||||
source := newSource(5)
|
||||
out := TaintStepTest_ReflectIndirect_B0I0O0(source)
|
||||
sink(5, out)
|
||||
}
|
||||
{
|
||||
source := newSource(6)
|
||||
out := TaintStepTest_ReflectValueOf_B0I0O0(source)
|
||||
sink(6, out)
|
||||
}
|
||||
{
|
||||
source := newSource(7)
|
||||
out := TaintStepTest_ReflectMapIterKey_B0I0O0(source)
|
||||
sink(7, out)
|
||||
}
|
||||
{
|
||||
source := newSource(8)
|
||||
out := TaintStepTest_ReflectMapIterValue_B0I0O0(source)
|
||||
sink(8, out)
|
||||
}
|
||||
{
|
||||
source := newSource(9)
|
||||
out := TaintStepTest_ReflectStructTagGet_B0I0O0(source)
|
||||
sink(9, out)
|
||||
}
|
||||
{
|
||||
source := newSource(10)
|
||||
out := TaintStepTest_ReflectStructTagLookup_B0I0O0(source)
|
||||
sink(10, out)
|
||||
}
|
||||
{
|
||||
source := newSource(11)
|
||||
out := TaintStepTest_ReflectValueAddr_B0I0O0(source)
|
||||
sink(11, out)
|
||||
}
|
||||
{
|
||||
source := newSource(12)
|
||||
out := TaintStepTest_ReflectValueBytes_B0I0O0(source)
|
||||
sink(12, out)
|
||||
}
|
||||
{
|
||||
source := newSource(13)
|
||||
out := TaintStepTest_ReflectValueConvert_B0I0O0(source)
|
||||
sink(13, out)
|
||||
}
|
||||
{
|
||||
source := newSource(14)
|
||||
out := TaintStepTest_ReflectValueElem_B0I0O0(source)
|
||||
sink(14, out)
|
||||
}
|
||||
{
|
||||
source := newSource(15)
|
||||
out := TaintStepTest_ReflectValueField_B0I0O0(source)
|
||||
sink(15, out)
|
||||
}
|
||||
{
|
||||
source := newSource(16)
|
||||
out := TaintStepTest_ReflectValueFieldByIndex_B0I0O0(source)
|
||||
sink(16, out)
|
||||
}
|
||||
{
|
||||
source := newSource(17)
|
||||
out := TaintStepTest_ReflectValueFieldByName_B0I0O0(source)
|
||||
sink(17, out)
|
||||
}
|
||||
{
|
||||
source := newSource(18)
|
||||
out := TaintStepTest_ReflectValueFieldByNameFunc_B0I0O0(source)
|
||||
sink(18, out)
|
||||
}
|
||||
{
|
||||
source := newSource(19)
|
||||
out := TaintStepTest_ReflectValueIndex_B0I0O0(source)
|
||||
sink(19, out)
|
||||
}
|
||||
{
|
||||
source := newSource(20)
|
||||
out := TaintStepTest_ReflectValueInterface_B0I0O0(source)
|
||||
sink(20, out)
|
||||
}
|
||||
{
|
||||
source := newSource(21)
|
||||
out := TaintStepTest_ReflectValueInterfaceData_B0I0O0(source)
|
||||
sink(21, out)
|
||||
}
|
||||
{
|
||||
source := newSource(22)
|
||||
out := TaintStepTest_ReflectValueMapIndex_B0I0O0(source)
|
||||
sink(22, out)
|
||||
}
|
||||
{
|
||||
source := newSource(23)
|
||||
out := TaintStepTest_ReflectValueMapKeys_B0I0O0(source)
|
||||
sink(23, out)
|
||||
}
|
||||
{
|
||||
source := newSource(24)
|
||||
out := TaintStepTest_ReflectValueMapRange_B0I0O0(source)
|
||||
sink(24, out)
|
||||
}
|
||||
{
|
||||
source := newSource(25)
|
||||
out := TaintStepTest_ReflectValueMethod_B0I0O0(source)
|
||||
sink(25, out)
|
||||
}
|
||||
{
|
||||
source := newSource(26)
|
||||
out := TaintStepTest_ReflectValueMethodByName_B0I0O0(source)
|
||||
sink(26, out)
|
||||
}
|
||||
{
|
||||
source := newSource(27)
|
||||
out := TaintStepTest_ReflectValuePointer_B0I0O0(source)
|
||||
sink(27, out)
|
||||
}
|
||||
{
|
||||
source := newSource(28)
|
||||
out := TaintStepTest_ReflectValueRecv_B0I0O0(source)
|
||||
sink(28, out)
|
||||
}
|
||||
{
|
||||
source := newSource(29)
|
||||
out := TaintStepTest_ReflectValueSend_B0I0O0(source)
|
||||
sink(29, out)
|
||||
}
|
||||
{
|
||||
source := newSource(30)
|
||||
out := TaintStepTest_ReflectValueSet_B0I0O0(source)
|
||||
sink(30, out)
|
||||
}
|
||||
{
|
||||
source := newSource(31)
|
||||
out := TaintStepTest_ReflectValueSetBytes_B0I0O0(source)
|
||||
sink(31, out)
|
||||
}
|
||||
{
|
||||
source := newSource(32)
|
||||
out := TaintStepTest_ReflectValueSetMapIndex_B0I0O0(source)
|
||||
sink(32, out)
|
||||
}
|
||||
{
|
||||
source := newSource(33)
|
||||
out := TaintStepTest_ReflectValueSetMapIndex_B0I1O0(source)
|
||||
sink(33, out)
|
||||
}
|
||||
{
|
||||
source := newSource(34)
|
||||
out := TaintStepTest_ReflectValueSetPointer_B0I0O0(source)
|
||||
sink(34, out)
|
||||
}
|
||||
{
|
||||
source := newSource(35)
|
||||
out := TaintStepTest_ReflectValueSetString_B0I0O0(source)
|
||||
sink(35, out)
|
||||
}
|
||||
{
|
||||
source := newSource(36)
|
||||
out := TaintStepTest_ReflectValueSlice_B0I0O0(source)
|
||||
sink(36, out)
|
||||
}
|
||||
{
|
||||
source := newSource(37)
|
||||
out := TaintStepTest_ReflectValueSlice3_B0I0O0(source)
|
||||
sink(37, out)
|
||||
}
|
||||
{
|
||||
source := newSource(38)
|
||||
out := TaintStepTest_ReflectValueString_B0I0O0(source)
|
||||
sink(38, out)
|
||||
}
|
||||
{
|
||||
source := newSource(39)
|
||||
out := TaintStepTest_ReflectValueTryRecv_B0I0O0(source)
|
||||
sink(39, out)
|
||||
}
|
||||
{
|
||||
source := newSource(40)
|
||||
out := TaintStepTest_ReflectValueTrySend_B0I0O0(source)
|
||||
sink(40, out)
|
||||
}
|
||||
{
|
||||
source := newSource(41)
|
||||
out := TaintStepTest_ReflectValueUnsafeAddr_B0I0O0(source)
|
||||
sink(41, out)
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
edges
|
||||
| ReflectedXss.go:11:15:11:20 | selection of Form : Values | ReflectedXss.go:14:44:14:51 | username |
|
||||
| ReflectedXss.go:12:15:12:20 | selection of Form : Values | ReflectedXss.go:15:44:15:51 | username |
|
||||
| contenttype.go:11:11:11:16 | selection of Form : Values | contenttype.go:17:11:17:22 | type conversion |
|
||||
| contenttype.go:49:11:49:16 | selection of Form : Values | contenttype.go:53:34:53:37 | data |
|
||||
| contenttype.go:63:10:63:28 | call to FormValue : string | contenttype.go:64:52:64:55 | data |
|
||||
@@ -15,8 +15,8 @@ edges
|
||||
| websocketXss.go:50:3:50:10 | definition of gorilla2 : slice type | websocketXss.go:52:24:52:31 | gorilla2 |
|
||||
| websocketXss.go:54:3:54:38 | ... := ...[1] : slice type | websocketXss.go:55:24:55:31 | gorilla3 |
|
||||
nodes
|
||||
| ReflectedXss.go:11:15:11:20 | selection of Form : Values | semmle.label | selection of Form : Values |
|
||||
| ReflectedXss.go:14:44:14:51 | username | semmle.label | username |
|
||||
| ReflectedXss.go:12:15:12:20 | selection of Form : Values | semmle.label | selection of Form : Values |
|
||||
| ReflectedXss.go:15:44:15:51 | username | semmle.label | username |
|
||||
| contenttype.go:11:11:11:16 | selection of Form : Values | semmle.label | selection of Form : Values |
|
||||
| contenttype.go:17:11:17:22 | type conversion | semmle.label | type conversion |
|
||||
| contenttype.go:49:11:49:16 | selection of Form : Values | semmle.label | selection of Form : Values |
|
||||
@@ -46,7 +46,7 @@ nodes
|
||||
| websocketXss.go:54:3:54:38 | ... := ...[1] : slice type | semmle.label | ... := ...[1] : slice type |
|
||||
| websocketXss.go:55:24:55:31 | gorilla3 | semmle.label | gorilla3 |
|
||||
#select
|
||||
| ReflectedXss.go:14:44:14:51 | username | ReflectedXss.go:11:15:11:20 | selection of Form : Values | ReflectedXss.go:14:44:14:51 | username | Cross-site scripting vulnerability due to $@. | ReflectedXss.go:11:15:11:20 | selection of Form | user-provided value |
|
||||
| ReflectedXss.go:15:44:15:51 | username | ReflectedXss.go:12:15:12:20 | selection of Form : Values | ReflectedXss.go:15:44:15:51 | username | Cross-site scripting vulnerability due to $@. | ReflectedXss.go:12:15:12:20 | selection of Form | user-provided value |
|
||||
| contenttype.go:17:11:17:22 | type conversion | contenttype.go:11:11:11:16 | selection of Form : Values | contenttype.go:17:11:17:22 | type conversion | Cross-site scripting vulnerability due to $@. | contenttype.go:11:11:11:16 | selection of Form | user-provided value |
|
||||
| contenttype.go:53:34:53:37 | data | contenttype.go:49:11:49:16 | selection of Form : Values | contenttype.go:53:34:53:37 | data | Cross-site scripting vulnerability due to $@. | contenttype.go:49:11:49:16 | selection of Form | user-provided value |
|
||||
| contenttype.go:64:52:64:55 | data | contenttype.go:63:10:63:28 | call to FormValue : string | contenttype.go:64:52:64:55 | data | Cross-site scripting vulnerability due to $@. | contenttype.go:63:10:63:28 | call to FormValue | user-provided value |
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
@@ -18,3 +19,25 @@ func serve() {
|
||||
})
|
||||
http.ListenAndServe(":80", nil)
|
||||
}
|
||||
|
||||
func encode(s string) ([]byte, error) {
|
||||
|
||||
return json.Marshal(s)
|
||||
|
||||
}
|
||||
|
||||
func ServeJsonIndirect(w http.ResponseWriter, r http.Request) {
|
||||
|
||||
tainted := r.Header.Get("Origin")
|
||||
noLongerTainted, _ := encode(tainted)
|
||||
w.Write(noLongerTainted)
|
||||
|
||||
}
|
||||
|
||||
func ServeJsonDirect(w http.ResponseWriter, r http.Request) {
|
||||
|
||||
tainted := r.Header.Get("Origin")
|
||||
noLongerTainted, _ := json.Marshal(tainted)
|
||||
w.Write(noLongerTainted)
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,44 @@ edges
|
||||
| stdlib.go:44:13:44:18 | selection of Form : Values | stdlib.go:46:23:46:28 | target |
|
||||
| stdlib.go:64:13:64:18 | selection of Form : Values | stdlib.go:67:23:67:40 | ...+... |
|
||||
| stdlib.go:89:13:89:18 | selection of Form : Values | stdlib.go:92:23:92:28 | target |
|
||||
| stdlib.go:107:54:107:54 | definition of r [pointer, URL, ... (3)] | stdlib.go:112:4:112:4 | r [pointer, URL, ... (3)] |
|
||||
| stdlib.go:107:54:107:54 | definition of r [pointer, URL, ... (3)] | stdlib.go:112:4:112:4 | r [pointer, URL, ... (3)] |
|
||||
| stdlib.go:107:54:107:54 | definition of r [pointer, URL] | stdlib.go:112:4:112:4 | r [pointer, URL] |
|
||||
| stdlib.go:107:54:107:54 | definition of r [pointer, URL] | stdlib.go:112:4:112:4 | r [pointer, URL] |
|
||||
| stdlib.go:107:54:107:54 | definition of r [pointer, URL] | stdlib.go:113:24:113:24 | r [pointer, URL] |
|
||||
| stdlib.go:107:54:107:54 | definition of r [pointer, URL] | stdlib.go:113:24:113:24 | r [pointer, URL] |
|
||||
| stdlib.go:112:4:112:4 | implicit dereference [URL, pointer] | stdlib.go:107:54:107:54 | definition of r [pointer, URL, ... (3)] |
|
||||
| stdlib.go:112:4:112:4 | implicit dereference [URL, pointer] | stdlib.go:107:54:107:54 | definition of r [pointer, URL, ... (3)] |
|
||||
| stdlib.go:112:4:112:4 | implicit dereference [URL, pointer] | stdlib.go:112:4:112:8 | selection of URL [pointer] : URL |
|
||||
| stdlib.go:112:4:112:4 | implicit dereference [URL, pointer] | stdlib.go:112:4:112:8 | selection of URL [pointer] : URL |
|
||||
| stdlib.go:112:4:112:4 | implicit dereference [URL] : pointer type | stdlib.go:107:54:107:54 | definition of r [pointer, URL] |
|
||||
| stdlib.go:112:4:112:4 | implicit dereference [URL] : pointer type | stdlib.go:107:54:107:54 | definition of r [pointer, URL] |
|
||||
| stdlib.go:112:4:112:4 | implicit dereference [URL] : pointer type | stdlib.go:112:4:112:8 | selection of URL : pointer type |
|
||||
| stdlib.go:112:4:112:4 | implicit dereference [URL] : pointer type | stdlib.go:112:4:112:8 | selection of URL : pointer type |
|
||||
| stdlib.go:112:4:112:4 | r [pointer, URL, ... (3)] | stdlib.go:112:4:112:4 | implicit dereference [URL, pointer] |
|
||||
| stdlib.go:112:4:112:4 | r [pointer, URL, ... (3)] | stdlib.go:112:4:112:4 | implicit dereference [URL, pointer] |
|
||||
| stdlib.go:112:4:112:4 | r [pointer, URL] | stdlib.go:112:4:112:4 | implicit dereference [URL] : pointer type |
|
||||
| stdlib.go:112:4:112:4 | r [pointer, URL] | stdlib.go:112:4:112:4 | implicit dereference [URL] : pointer type |
|
||||
| stdlib.go:112:4:112:8 | implicit dereference : URL | stdlib.go:112:4:112:8 | implicit dereference : URL |
|
||||
| stdlib.go:112:4:112:8 | implicit dereference : URL | stdlib.go:112:4:112:8 | implicit dereference : URL |
|
||||
| stdlib.go:112:4:112:8 | implicit dereference : URL | stdlib.go:112:4:112:8 | selection of URL : pointer type |
|
||||
| stdlib.go:112:4:112:8 | implicit dereference : URL | stdlib.go:112:4:112:8 | selection of URL : pointer type |
|
||||
| stdlib.go:112:4:112:8 | implicit dereference : URL | stdlib.go:112:4:112:8 | selection of URL [pointer] : URL |
|
||||
| stdlib.go:112:4:112:8 | implicit dereference : URL | stdlib.go:112:4:112:8 | selection of URL [pointer] : URL |
|
||||
| stdlib.go:112:4:112:8 | selection of URL : pointer type | stdlib.go:112:4:112:4 | implicit dereference [URL] : pointer type |
|
||||
| stdlib.go:112:4:112:8 | selection of URL : pointer type | stdlib.go:112:4:112:4 | implicit dereference [URL] : pointer type |
|
||||
| stdlib.go:112:4:112:8 | selection of URL : pointer type | stdlib.go:112:4:112:8 | implicit dereference : URL |
|
||||
| stdlib.go:112:4:112:8 | selection of URL : pointer type | stdlib.go:112:4:112:8 | implicit dereference : URL |
|
||||
| stdlib.go:112:4:112:8 | selection of URL : pointer type | stdlib.go:112:4:112:8 | selection of URL : pointer type |
|
||||
| stdlib.go:112:4:112:8 | selection of URL : pointer type | stdlib.go:112:4:112:8 | selection of URL : pointer type |
|
||||
| stdlib.go:112:4:112:8 | selection of URL [pointer] : URL | stdlib.go:112:4:112:4 | implicit dereference [URL, pointer] |
|
||||
| stdlib.go:112:4:112:8 | selection of URL [pointer] : URL | stdlib.go:112:4:112:4 | implicit dereference [URL, pointer] |
|
||||
| stdlib.go:112:4:112:8 | selection of URL [pointer] : URL | stdlib.go:112:4:112:8 | implicit dereference : URL |
|
||||
| stdlib.go:112:4:112:8 | selection of URL [pointer] : URL | stdlib.go:112:4:112:8 | implicit dereference : URL |
|
||||
| stdlib.go:113:24:113:24 | implicit dereference [URL] : pointer type | stdlib.go:113:24:113:28 | selection of URL : pointer type |
|
||||
| stdlib.go:113:24:113:24 | implicit dereference [URL] : pointer type | stdlib.go:113:24:113:28 | selection of URL : pointer type |
|
||||
| stdlib.go:113:24:113:24 | r [pointer, URL] | stdlib.go:113:24:113:24 | implicit dereference [URL] : pointer type |
|
||||
| stdlib.go:113:24:113:24 | r [pointer, URL] | stdlib.go:113:24:113:24 | implicit dereference [URL] : pointer type |
|
||||
| stdlib.go:113:24:113:28 | selection of URL : pointer type | stdlib.go:113:24:113:37 | call to String |
|
||||
| stdlib.go:113:24:113:28 | selection of URL : pointer type | stdlib.go:113:24:113:37 | call to String |
|
||||
| stdlib.go:146:13:146:18 | selection of Form : Values | stdlib.go:152:23:152:28 | target |
|
||||
@@ -37,6 +75,28 @@ nodes
|
||||
| stdlib.go:67:23:67:40 | ...+... | semmle.label | ...+... |
|
||||
| stdlib.go:89:13:89:18 | selection of Form : Values | semmle.label | selection of Form : Values |
|
||||
| stdlib.go:92:23:92:28 | target | semmle.label | target |
|
||||
| stdlib.go:107:54:107:54 | definition of r [pointer, URL, ... (3)] | semmle.label | definition of r [pointer, URL, ... (3)] |
|
||||
| stdlib.go:107:54:107:54 | definition of r [pointer, URL, ... (3)] | semmle.label | definition of r [pointer, URL, ... (3)] |
|
||||
| stdlib.go:107:54:107:54 | definition of r [pointer, URL] | semmle.label | definition of r [pointer, URL] |
|
||||
| stdlib.go:107:54:107:54 | definition of r [pointer, URL] | semmle.label | definition of r [pointer, URL] |
|
||||
| stdlib.go:112:4:112:4 | implicit dereference [URL, pointer] | semmle.label | implicit dereference [URL, pointer] |
|
||||
| stdlib.go:112:4:112:4 | implicit dereference [URL, pointer] | semmle.label | implicit dereference [URL, pointer] |
|
||||
| stdlib.go:112:4:112:4 | implicit dereference [URL] : pointer type | semmle.label | implicit dereference [URL] : pointer type |
|
||||
| stdlib.go:112:4:112:4 | implicit dereference [URL] : pointer type | semmle.label | implicit dereference [URL] : pointer type |
|
||||
| stdlib.go:112:4:112:4 | r [pointer, URL, ... (3)] | semmle.label | r [pointer, URL, ... (3)] |
|
||||
| stdlib.go:112:4:112:4 | r [pointer, URL, ... (3)] | semmle.label | r [pointer, URL, ... (3)] |
|
||||
| stdlib.go:112:4:112:4 | r [pointer, URL] | semmle.label | r [pointer, URL] |
|
||||
| stdlib.go:112:4:112:4 | r [pointer, URL] | semmle.label | r [pointer, URL] |
|
||||
| stdlib.go:112:4:112:8 | implicit dereference : URL | semmle.label | implicit dereference : URL |
|
||||
| stdlib.go:112:4:112:8 | implicit dereference : URL | semmle.label | implicit dereference : URL |
|
||||
| stdlib.go:112:4:112:8 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
|
||||
| stdlib.go:112:4:112:8 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
|
||||
| stdlib.go:112:4:112:8 | selection of URL [pointer] : URL | semmle.label | selection of URL [pointer] : URL |
|
||||
| stdlib.go:112:4:112:8 | selection of URL [pointer] : URL | semmle.label | selection of URL [pointer] : URL |
|
||||
| stdlib.go:113:24:113:24 | implicit dereference [URL] : pointer type | semmle.label | implicit dereference [URL] : pointer type |
|
||||
| stdlib.go:113:24:113:24 | implicit dereference [URL] : pointer type | semmle.label | implicit dereference [URL] : pointer type |
|
||||
| stdlib.go:113:24:113:24 | r [pointer, URL] | semmle.label | r [pointer, URL] |
|
||||
| stdlib.go:113:24:113:24 | r [pointer, URL] | semmle.label | r [pointer, URL] |
|
||||
| stdlib.go:113:24:113:28 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
|
||||
| stdlib.go:113:24:113:28 | selection of URL : pointer type | semmle.label | selection of URL : pointer type |
|
||||
| stdlib.go:113:24:113:37 | call to String | semmle.label | call to String |
|
||||
|
||||
16
vendor/github.com/ChrisTrenkamp/goxpath/.travis.yml
generated
vendored
Normal file
16
vendor/github.com/ChrisTrenkamp/goxpath/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.6
|
||||
|
||||
before_install:
|
||||
- go get -u github.com/ChrisTrenkamp/goxpath
|
||||
- go get -u github.com/ChrisTrenkamp/goxpath/cmd/goxpath
|
||||
- go get -u github.com/wadey/gocovmerge
|
||||
|
||||
script:
|
||||
- go list -f '{{if gt (len .TestGoFiles) 0}}"go test -covermode count -coverprofile {{.Name}}.coverprofile -coverpkg ./... {{.ImportPath}}"{{end}}' ./... | xargs -I {} bash -c {}
|
||||
- gocovmerge `ls *.coverprofile` > coverage.txt
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
22
vendor/github.com/ChrisTrenkamp/goxpath/LICENSE
generated
vendored
Normal file
22
vendor/github.com/ChrisTrenkamp/goxpath/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 ChrisTrenkamp
|
||||
|
||||
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.
|
||||
|
||||
2
vendor/github.com/ChrisTrenkamp/goxpath/README.md
generated
vendored
Normal file
2
vendor/github.com/ChrisTrenkamp/goxpath/README.md
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
# goxpath [](https://godoc.org/github.com/ChrisTrenkamp/goxpath) [](https://travis-ci.org/ChrisTrenkamp/goxpath) [](https://codecov.io/github/ChrisTrenkamp/goxpath?branch=master) [](https://goreportcard.com/report/github.com/ChrisTrenkamp/goxpath)
|
||||
An XPath 1.0 implementation written in Go. See the [wiki](https://github.com/ChrisTrenkamp/goxpath/wiki) for more information.
|
||||
17
vendor/github.com/ChrisTrenkamp/goxpath/coverage.sh
generated
vendored
Normal file
17
vendor/github.com/ChrisTrenkamp/goxpath/coverage.sh
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
cd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
go get github.com/ChrisTrenkamp/goxpath/cmd/goxpath
|
||||
if [ $? != 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
go test >/dev/null 2>&1
|
||||
if [ $? != 0 ]; then
|
||||
go test
|
||||
exit 1
|
||||
fi
|
||||
gometalinter --deadline=1m ./...
|
||||
go list -f '{{if gt (len .TestGoFiles) 0}}"go test -covermode count -coverprofile {{.Name}}.coverprofile -coverpkg ./... {{.ImportPath}}"{{end}} >/dev/null' ./... | xargs -I {} bash -c {} 2>/dev/null
|
||||
gocovmerge `ls *.coverprofile` > coverage.txt
|
||||
go tool cover -html=coverage.txt -o coverage.html
|
||||
firefox coverage.html
|
||||
rm coverage.html coverage.txt *.coverprofile
|
||||
117
vendor/github.com/ChrisTrenkamp/goxpath/goxpath.go
generated
vendored
Normal file
117
vendor/github.com/ChrisTrenkamp/goxpath/goxpath.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
package goxpath
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/internal/execxp"
|
||||
"github.com/ChrisTrenkamp/goxpath/parser"
|
||||
"github.com/ChrisTrenkamp/goxpath/tree"
|
||||
)
|
||||
|
||||
//Opts defines namespace mappings and custom functions for XPath expressions.
|
||||
type Opts struct {
|
||||
NS map[string]string
|
||||
Funcs map[xml.Name]tree.Wrap
|
||||
Vars map[string]tree.Result
|
||||
}
|
||||
|
||||
//FuncOpts is a function wrapper for Opts.
|
||||
type FuncOpts func(*Opts)
|
||||
|
||||
//XPathExec is the XPath executor, compiled from an XPath string
|
||||
type XPathExec struct {
|
||||
n *parser.Node
|
||||
}
|
||||
|
||||
//Parse parses the XPath expression, xp, returning an XPath executor.
|
||||
func Parse(xp string) (XPathExec, error) {
|
||||
n, err := parser.Parse(xp)
|
||||
return XPathExec{n: n}, err
|
||||
}
|
||||
|
||||
//MustParse is like Parse, but panics instead of returning an error.
|
||||
func MustParse(xp string) XPathExec {
|
||||
ret, err := Parse(xp)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
//Exec executes the XPath expression, xp, against the tree, t, with the
|
||||
//namespace mappings, ns, and returns the result as a stringer.
|
||||
func (xp XPathExec) Exec(t tree.Node, opts ...FuncOpts) (tree.Result, error) {
|
||||
o := &Opts{
|
||||
NS: make(map[string]string),
|
||||
Funcs: make(map[xml.Name]tree.Wrap),
|
||||
Vars: make(map[string]tree.Result),
|
||||
}
|
||||
for _, i := range opts {
|
||||
i(o)
|
||||
}
|
||||
return execxp.Exec(xp.n, t, o.NS, o.Funcs, o.Vars)
|
||||
}
|
||||
|
||||
//ExecBool is like Exec, except it will attempt to convert the result to its boolean value.
|
||||
func (xp XPathExec) ExecBool(t tree.Node, opts ...FuncOpts) (bool, error) {
|
||||
res, err := xp.Exec(t, opts...)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
b, ok := res.(tree.IsBool)
|
||||
if !ok {
|
||||
return false, fmt.Errorf("Cannot convert result to a boolean")
|
||||
}
|
||||
|
||||
return bool(b.Bool()), nil
|
||||
}
|
||||
|
||||
//ExecNum is like Exec, except it will attempt to convert the result to its number value.
|
||||
func (xp XPathExec) ExecNum(t tree.Node, opts ...FuncOpts) (float64, error) {
|
||||
res, err := xp.Exec(t, opts...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
n, ok := res.(tree.IsNum)
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("Cannot convert result to a number")
|
||||
}
|
||||
|
||||
return float64(n.Num()), nil
|
||||
}
|
||||
|
||||
//ExecNode is like Exec, except it will attempt to return the result as a node-set.
|
||||
func (xp XPathExec) ExecNode(t tree.Node, opts ...FuncOpts) (tree.NodeSet, error) {
|
||||
res, err := xp.Exec(t, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
n, ok := res.(tree.NodeSet)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Cannot convert result to a node-set")
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
|
||||
//MustExec is like Exec, but panics instead of returning an error.
|
||||
func (xp XPathExec) MustExec(t tree.Node, opts ...FuncOpts) tree.Result {
|
||||
res, err := xp.Exec(t, opts...)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
//ParseExec parses the XPath string, xpstr, and runs Exec.
|
||||
func ParseExec(xpstr string, t tree.Node, opts ...FuncOpts) (tree.Result, error) {
|
||||
xp, err := Parse(xpstr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return xp.Exec(t, opts...)
|
||||
}
|
||||
27
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/execxp.go
generated
vendored
Normal file
27
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/execxp.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package execxp
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/parser"
|
||||
"github.com/ChrisTrenkamp/goxpath/tree"
|
||||
)
|
||||
|
||||
//Exec executes the XPath expression, xp, against the tree, t, with the
|
||||
//namespace mappings, ns.
|
||||
func Exec(n *parser.Node, t tree.Node, ns map[string]string, fns map[xml.Name]tree.Wrap, v map[string]tree.Result) (tree.Result, error) {
|
||||
f := xpFilt{
|
||||
t: t,
|
||||
ns: ns,
|
||||
ctx: tree.NodeSet{t},
|
||||
fns: fns,
|
||||
variables: v,
|
||||
}
|
||||
|
||||
return exec(&f, n)
|
||||
}
|
||||
|
||||
func exec(f *xpFilt, n *parser.Node) (tree.Result, error) {
|
||||
err := xfExec(f, n)
|
||||
return f.ctx, err
|
||||
}
|
||||
307
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil/findUtil.go
generated
vendored
Normal file
307
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil/findUtil.go
generated
vendored
Normal file
@@ -0,0 +1,307 @@
|
||||
package findutil
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/parser/pathexpr"
|
||||
"github.com/ChrisTrenkamp/goxpath/tree"
|
||||
"github.com/ChrisTrenkamp/goxpath/xconst"
|
||||
)
|
||||
|
||||
const (
|
||||
wildcard = "*"
|
||||
)
|
||||
|
||||
type findFunc func(tree.Node, *pathexpr.PathExpr, *[]tree.Node)
|
||||
|
||||
var findMap = map[string]findFunc{
|
||||
xconst.AxisAncestor: findAncestor,
|
||||
xconst.AxisAncestorOrSelf: findAncestorOrSelf,
|
||||
xconst.AxisAttribute: findAttribute,
|
||||
xconst.AxisChild: findChild,
|
||||
xconst.AxisDescendent: findDescendent,
|
||||
xconst.AxisDescendentOrSelf: findDescendentOrSelf,
|
||||
xconst.AxisFollowing: findFollowing,
|
||||
xconst.AxisFollowingSibling: findFollowingSibling,
|
||||
xconst.AxisNamespace: findNamespace,
|
||||
xconst.AxisParent: findParent,
|
||||
xconst.AxisPreceding: findPreceding,
|
||||
xconst.AxisPrecedingSibling: findPrecedingSibling,
|
||||
xconst.AxisSelf: findSelf,
|
||||
}
|
||||
|
||||
//Find finds nodes based on the pathexpr.PathExpr
|
||||
func Find(x tree.Node, p pathexpr.PathExpr) []tree.Node {
|
||||
ret := []tree.Node{}
|
||||
|
||||
if p.Axis == "" {
|
||||
findChild(x, &p, &ret)
|
||||
return ret
|
||||
}
|
||||
|
||||
f := findMap[p.Axis]
|
||||
f(x, &p, &ret)
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func findAncestor(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
if x.GetNodeType() == tree.NtRoot {
|
||||
return
|
||||
}
|
||||
|
||||
addNode(x.GetParent(), p, ret)
|
||||
findAncestor(x.GetParent(), p, ret)
|
||||
}
|
||||
|
||||
func findAncestorOrSelf(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
findSelf(x, p, ret)
|
||||
findAncestor(x, p, ret)
|
||||
}
|
||||
|
||||
func findAttribute(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
if ele, ok := x.(tree.Elem); ok {
|
||||
for _, i := range ele.GetAttrs() {
|
||||
addNode(i, p, ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findChild(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
if ele, ok := x.(tree.Elem); ok {
|
||||
ch := ele.GetChildren()
|
||||
for i := range ch {
|
||||
addNode(ch[i], p, ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findDescendent(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
if ele, ok := x.(tree.Elem); ok {
|
||||
ch := ele.GetChildren()
|
||||
for i := range ch {
|
||||
addNode(ch[i], p, ret)
|
||||
findDescendent(ch[i], p, ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findDescendentOrSelf(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
findSelf(x, p, ret)
|
||||
findDescendent(x, p, ret)
|
||||
}
|
||||
|
||||
func findFollowing(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
if x.GetNodeType() == tree.NtRoot {
|
||||
return
|
||||
}
|
||||
par := x.GetParent()
|
||||
ch := par.GetChildren()
|
||||
i := 0
|
||||
for x != ch[i] {
|
||||
i++
|
||||
}
|
||||
i++
|
||||
for i < len(ch) {
|
||||
findDescendentOrSelf(ch[i], p, ret)
|
||||
i++
|
||||
}
|
||||
findFollowing(par, p, ret)
|
||||
}
|
||||
|
||||
func findFollowingSibling(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
if x.GetNodeType() == tree.NtRoot {
|
||||
return
|
||||
}
|
||||
par := x.GetParent()
|
||||
ch := par.GetChildren()
|
||||
i := 0
|
||||
for x != ch[i] {
|
||||
i++
|
||||
}
|
||||
i++
|
||||
for i < len(ch) {
|
||||
findSelf(ch[i], p, ret)
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
func findNamespace(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
if ele, ok := x.(tree.NSElem); ok {
|
||||
ns := tree.BuildNS(ele)
|
||||
for _, i := range ns {
|
||||
addNode(i, p, ret)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findParent(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
if x.GetNodeType() != tree.NtRoot {
|
||||
addNode(x.GetParent(), p, ret)
|
||||
}
|
||||
}
|
||||
|
||||
func findPreceding(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
if x.GetNodeType() == tree.NtRoot {
|
||||
return
|
||||
}
|
||||
par := x.GetParent()
|
||||
ch := par.GetChildren()
|
||||
i := len(ch) - 1
|
||||
for x != ch[i] {
|
||||
i--
|
||||
}
|
||||
i--
|
||||
for i >= 0 {
|
||||
findDescendentOrSelf(ch[i], p, ret)
|
||||
i--
|
||||
}
|
||||
findPreceding(par, p, ret)
|
||||
}
|
||||
|
||||
func findPrecedingSibling(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
if x.GetNodeType() == tree.NtRoot {
|
||||
return
|
||||
}
|
||||
par := x.GetParent()
|
||||
ch := par.GetChildren()
|
||||
i := len(ch) - 1
|
||||
for x != ch[i] {
|
||||
i--
|
||||
}
|
||||
i--
|
||||
for i >= 0 {
|
||||
findSelf(ch[i], p, ret)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
func findSelf(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
addNode(x, p, ret)
|
||||
}
|
||||
|
||||
func addNode(x tree.Node, p *pathexpr.PathExpr, ret *[]tree.Node) {
|
||||
add := false
|
||||
tok := x.GetToken()
|
||||
|
||||
switch x.GetNodeType() {
|
||||
case tree.NtAttr:
|
||||
add = evalAttr(p, tok.(xml.Attr))
|
||||
case tree.NtChd:
|
||||
add = evalChd(p)
|
||||
case tree.NtComm:
|
||||
add = evalComm(p)
|
||||
case tree.NtElem, tree.NtRoot:
|
||||
add = evalEle(p, tok.(xml.StartElement))
|
||||
case tree.NtNs:
|
||||
add = evalNS(p, tok.(xml.Attr))
|
||||
case tree.NtPi:
|
||||
add = evalPI(p)
|
||||
}
|
||||
|
||||
if add {
|
||||
*ret = append(*ret, x)
|
||||
}
|
||||
}
|
||||
|
||||
func evalAttr(p *pathexpr.PathExpr, a xml.Attr) bool {
|
||||
if p.NodeType == "" {
|
||||
if p.Name.Space != wildcard {
|
||||
if a.Name.Space != p.NS[p.Name.Space] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if p.Name.Local == wildcard && p.Axis == xconst.AxisAttribute {
|
||||
return true
|
||||
}
|
||||
|
||||
if p.Name.Local == a.Name.Local {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
if p.NodeType == xconst.NodeTypeNode {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func evalChd(p *pathexpr.PathExpr) bool {
|
||||
if p.NodeType == xconst.NodeTypeText || p.NodeType == xconst.NodeTypeNode {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func evalComm(p *pathexpr.PathExpr) bool {
|
||||
if p.NodeType == xconst.NodeTypeComment || p.NodeType == xconst.NodeTypeNode {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func evalEle(p *pathexpr.PathExpr, ele xml.StartElement) bool {
|
||||
if p.NodeType == "" {
|
||||
return checkNameAndSpace(p, ele)
|
||||
}
|
||||
|
||||
if p.NodeType == xconst.NodeTypeNode {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func checkNameAndSpace(p *pathexpr.PathExpr, ele xml.StartElement) bool {
|
||||
if p.Name.Local == wildcard && p.Name.Space == "" {
|
||||
return true
|
||||
}
|
||||
|
||||
if p.Name.Space != wildcard && ele.Name.Space != p.NS[p.Name.Space] {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.Name.Local == wildcard && p.Axis != xconst.AxisAttribute && p.Axis != xconst.AxisNamespace {
|
||||
return true
|
||||
}
|
||||
|
||||
if p.Name.Local == ele.Name.Local {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func evalNS(p *pathexpr.PathExpr, ns xml.Attr) bool {
|
||||
if p.NodeType == "" {
|
||||
if p.Name.Space != "" && p.Name.Space != wildcard {
|
||||
return false
|
||||
}
|
||||
|
||||
if p.Name.Local == wildcard && p.Axis == xconst.AxisNamespace {
|
||||
return true
|
||||
}
|
||||
|
||||
if p.Name.Local == ns.Name.Local {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
if p.NodeType == xconst.NodeTypeNode {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func evalPI(p *pathexpr.PathExpr) bool {
|
||||
if p.NodeType == xconst.NodeTypeProcInst || p.NodeType == xconst.NodeTypeNode {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
74
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/boolfns.go
generated
vendored
Normal file
74
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/boolfns.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
package intfns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/tree"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func boolean(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
if b, ok := args[0].(tree.IsBool); ok {
|
||||
return b.Bool(), nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Cannot convert object to a boolean")
|
||||
}
|
||||
|
||||
func not(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
b, ok := args[0].(tree.IsBool)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Cannot convert object to a boolean")
|
||||
}
|
||||
return !b.Bool(), nil
|
||||
}
|
||||
|
||||
func _true(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
return tree.Bool(true), nil
|
||||
}
|
||||
|
||||
func _false(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
return tree.Bool(false), nil
|
||||
}
|
||||
|
||||
func lang(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
lStr := args[0].String()
|
||||
|
||||
var n tree.Elem
|
||||
|
||||
for _, i := range c.NodeSet {
|
||||
if i.GetNodeType() == tree.NtElem {
|
||||
n = i.(tree.Elem)
|
||||
} else {
|
||||
n = i.GetParent()
|
||||
}
|
||||
|
||||
for n.GetNodeType() != tree.NtRoot {
|
||||
if attr, ok := tree.GetAttribute(n, "lang", tree.XMLSpace); ok {
|
||||
return checkLang(lStr, attr.Value), nil
|
||||
}
|
||||
n = n.GetParent()
|
||||
}
|
||||
}
|
||||
|
||||
return tree.Bool(false), nil
|
||||
}
|
||||
|
||||
func checkLang(srcStr, targStr string) tree.Bool {
|
||||
srcLang := language.Make(srcStr)
|
||||
srcRegion, srcRegionConf := srcLang.Region()
|
||||
|
||||
targLang := language.Make(targStr)
|
||||
targRegion, targRegionConf := targLang.Region()
|
||||
|
||||
if srcRegionConf == language.Exact && targRegionConf != language.Exact {
|
||||
return tree.Bool(false)
|
||||
}
|
||||
|
||||
if srcRegion != targRegion && srcRegionConf == language.Exact && targRegionConf == language.Exact {
|
||||
return tree.Bool(false)
|
||||
}
|
||||
|
||||
_, _, conf := language.NewMatcher([]language.Tag{srcLang}).Match(targLang)
|
||||
return tree.Bool(conf >= language.High)
|
||||
}
|
||||
41
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/intfns.go
generated
vendored
Normal file
41
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/intfns.go
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
package intfns
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/tree"
|
||||
)
|
||||
|
||||
//BuiltIn contains the list of built-in XPath functions
|
||||
var BuiltIn = map[xml.Name]tree.Wrap{
|
||||
//String functions
|
||||
{Local: "string"}: {Fn: _string, NArgs: 1, LastArgOpt: tree.Optional},
|
||||
{Local: "concat"}: {Fn: concat, NArgs: 3, LastArgOpt: tree.Variadic},
|
||||
{Local: "starts-with"}: {Fn: startsWith, NArgs: 2},
|
||||
{Local: "contains"}: {Fn: contains, NArgs: 2},
|
||||
{Local: "substring-before"}: {Fn: substringBefore, NArgs: 2},
|
||||
{Local: "substring-after"}: {Fn: substringAfter, NArgs: 2},
|
||||
{Local: "substring"}: {Fn: substring, NArgs: 3, LastArgOpt: tree.Optional},
|
||||
{Local: "string-length"}: {Fn: stringLength, NArgs: 1, LastArgOpt: tree.Optional},
|
||||
{Local: "normalize-space"}: {Fn: normalizeSpace, NArgs: 1, LastArgOpt: tree.Optional},
|
||||
{Local: "translate"}: {Fn: translate, NArgs: 3},
|
||||
//Node set functions
|
||||
{Local: "last"}: {Fn: last},
|
||||
{Local: "position"}: {Fn: position},
|
||||
{Local: "count"}: {Fn: count, NArgs: 1},
|
||||
{Local: "local-name"}: {Fn: localName, NArgs: 1, LastArgOpt: tree.Optional},
|
||||
{Local: "namespace-uri"}: {Fn: namespaceURI, NArgs: 1, LastArgOpt: tree.Optional},
|
||||
{Local: "name"}: {Fn: name, NArgs: 1, LastArgOpt: tree.Optional},
|
||||
//boolean functions
|
||||
{Local: "boolean"}: {Fn: boolean, NArgs: 1},
|
||||
{Local: "not"}: {Fn: not, NArgs: 1},
|
||||
{Local: "true"}: {Fn: _true},
|
||||
{Local: "false"}: {Fn: _false},
|
||||
{Local: "lang"}: {Fn: lang, NArgs: 1},
|
||||
//number functions
|
||||
{Local: "number"}: {Fn: number, NArgs: 1, LastArgOpt: tree.Optional},
|
||||
{Local: "sum"}: {Fn: sum, NArgs: 1},
|
||||
{Local: "floor"}: {Fn: floor, NArgs: 1},
|
||||
{Local: "ceiling"}: {Fn: ceiling, NArgs: 1},
|
||||
{Local: "round"}: {Fn: round, NArgs: 1},
|
||||
}
|
||||
131
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/nodesetfns.go
generated
vendored
Normal file
131
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/nodesetfns.go
generated
vendored
Normal file
@@ -0,0 +1,131 @@
|
||||
package intfns
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/tree"
|
||||
)
|
||||
|
||||
func last(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
return tree.Num(c.Size), nil
|
||||
}
|
||||
|
||||
func position(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
return tree.Num(c.Pos), nil
|
||||
}
|
||||
|
||||
func count(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
n, ok := args[0].(tree.NodeSet)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Cannot convert object to a node-set")
|
||||
}
|
||||
|
||||
return tree.Num(len(n)), nil
|
||||
}
|
||||
|
||||
func localName(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
var n tree.NodeSet
|
||||
ok := true
|
||||
if len(args) == 1 {
|
||||
n, ok = args[0].(tree.NodeSet)
|
||||
} else {
|
||||
n = c.NodeSet
|
||||
}
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Cannot convert object to a node-set")
|
||||
}
|
||||
|
||||
ret := ""
|
||||
if len(n) == 0 {
|
||||
return tree.String(ret), nil
|
||||
}
|
||||
node := n[0]
|
||||
|
||||
tok := node.GetToken()
|
||||
|
||||
switch node.GetNodeType() {
|
||||
case tree.NtElem:
|
||||
ret = tok.(xml.StartElement).Name.Local
|
||||
case tree.NtAttr:
|
||||
ret = tok.(xml.Attr).Name.Local
|
||||
case tree.NtPi:
|
||||
ret = tok.(xml.ProcInst).Target
|
||||
}
|
||||
|
||||
return tree.String(ret), nil
|
||||
}
|
||||
|
||||
func namespaceURI(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
var n tree.NodeSet
|
||||
ok := true
|
||||
if len(args) == 1 {
|
||||
n, ok = args[0].(tree.NodeSet)
|
||||
} else {
|
||||
n = c.NodeSet
|
||||
}
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Cannot convert object to a node-set")
|
||||
}
|
||||
|
||||
ret := ""
|
||||
if len(n) == 0 {
|
||||
return tree.String(ret), nil
|
||||
}
|
||||
node := n[0]
|
||||
|
||||
tok := node.GetToken()
|
||||
|
||||
switch node.GetNodeType() {
|
||||
case tree.NtElem:
|
||||
ret = tok.(xml.StartElement).Name.Space
|
||||
case tree.NtAttr:
|
||||
ret = tok.(xml.Attr).Name.Space
|
||||
}
|
||||
|
||||
return tree.String(ret), nil
|
||||
}
|
||||
|
||||
func name(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
var n tree.NodeSet
|
||||
ok := true
|
||||
if len(args) == 1 {
|
||||
n, ok = args[0].(tree.NodeSet)
|
||||
} else {
|
||||
n = c.NodeSet
|
||||
}
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Cannot convert object to a node-set")
|
||||
}
|
||||
|
||||
ret := ""
|
||||
if len(n) == 0 {
|
||||
return tree.String(ret), nil
|
||||
}
|
||||
node := n[0]
|
||||
|
||||
switch node.GetNodeType() {
|
||||
case tree.NtElem:
|
||||
t := node.GetToken().(xml.StartElement)
|
||||
space := ""
|
||||
|
||||
if t.Name.Space != "" {
|
||||
space = fmt.Sprintf("{%s}", t.Name.Space)
|
||||
}
|
||||
|
||||
ret = fmt.Sprintf("%s%s", space, t.Name.Local)
|
||||
case tree.NtAttr:
|
||||
t := node.GetToken().(xml.Attr)
|
||||
space := ""
|
||||
|
||||
if t.Name.Space != "" {
|
||||
space = fmt.Sprintf("{%s}", t.Name.Space)
|
||||
}
|
||||
|
||||
ret = fmt.Sprintf("%s%s", space, t.Name.Local)
|
||||
case tree.NtPi:
|
||||
ret = fmt.Sprintf("%s", node.GetToken().(xml.ProcInst).Target)
|
||||
}
|
||||
|
||||
return tree.String(ret), nil
|
||||
}
|
||||
71
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/numfns.go
generated
vendored
Normal file
71
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/numfns.go
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
package intfns
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/tree"
|
||||
)
|
||||
|
||||
func number(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
if b, ok := args[0].(tree.IsNum); ok {
|
||||
return b.Num(), nil
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("Cannot convert object to a number")
|
||||
}
|
||||
|
||||
func sum(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
n, ok := args[0].(tree.NodeSet)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Cannot convert object to a node-set")
|
||||
}
|
||||
|
||||
ret := 0.0
|
||||
for _, i := range n {
|
||||
ret += float64(tree.GetNodeNum(i))
|
||||
}
|
||||
|
||||
return tree.Num(ret), nil
|
||||
}
|
||||
|
||||
func floor(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
n, ok := args[0].(tree.IsNum)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Cannot convert object to a number")
|
||||
}
|
||||
|
||||
return tree.Num(math.Floor(float64(n.Num()))), nil
|
||||
}
|
||||
|
||||
func ceiling(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
n, ok := args[0].(tree.IsNum)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Cannot convert object to a number")
|
||||
}
|
||||
|
||||
return tree.Num(math.Ceil(float64(n.Num()))), nil
|
||||
}
|
||||
|
||||
func round(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
isn, ok := args[0].(tree.IsNum)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("Cannot convert object to a number")
|
||||
}
|
||||
|
||||
n := isn.Num()
|
||||
|
||||
if math.IsNaN(float64(n)) || math.IsInf(float64(n), 0) {
|
||||
return n, nil
|
||||
}
|
||||
|
||||
if n < -0.5 {
|
||||
n = tree.Num(int(n - 0.5))
|
||||
} else if n > 0.5 {
|
||||
n = tree.Num(int(n + 0.5))
|
||||
} else {
|
||||
n = 0
|
||||
}
|
||||
|
||||
return n, nil
|
||||
}
|
||||
141
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/stringfns.go
generated
vendored
Normal file
141
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns/stringfns.go
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
package intfns
|
||||
|
||||
import (
|
||||
"math"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/tree"
|
||||
)
|
||||
|
||||
func _string(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
if len(args) == 1 {
|
||||
return tree.String(args[0].String()), nil
|
||||
}
|
||||
|
||||
return tree.String(c.NodeSet.String()), nil
|
||||
}
|
||||
|
||||
func concat(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
ret := ""
|
||||
|
||||
for _, i := range args {
|
||||
ret += i.String()
|
||||
}
|
||||
|
||||
return tree.String(ret), nil
|
||||
}
|
||||
|
||||
func startsWith(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
return tree.Bool(strings.Index(args[0].String(), args[1].String()) == 0), nil
|
||||
}
|
||||
|
||||
func contains(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
return tree.Bool(strings.Contains(args[0].String(), args[1].String())), nil
|
||||
}
|
||||
|
||||
func substringBefore(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
ind := strings.Index(args[0].String(), args[1].String())
|
||||
if ind == -1 {
|
||||
return tree.String(""), nil
|
||||
}
|
||||
|
||||
return tree.String(args[0].String()[:ind]), nil
|
||||
}
|
||||
|
||||
func substringAfter(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
ind := strings.Index(args[0].String(), args[1].String())
|
||||
if ind == -1 {
|
||||
return tree.String(""), nil
|
||||
}
|
||||
|
||||
return tree.String(args[0].String()[ind+len(args[1].String()):]), nil
|
||||
}
|
||||
|
||||
func substring(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
str := args[0].String()
|
||||
|
||||
bNum, bErr := round(c, args[1])
|
||||
if bErr != nil {
|
||||
return nil, bErr
|
||||
}
|
||||
|
||||
b := bNum.(tree.Num).Num()
|
||||
|
||||
if float64(b-1) >= float64(len(str)) || math.IsNaN(float64(b)) {
|
||||
return tree.String(""), nil
|
||||
}
|
||||
|
||||
if len(args) == 2 {
|
||||
if b <= 1 {
|
||||
b = 1
|
||||
}
|
||||
|
||||
return tree.String(str[int(b)-1:]), nil
|
||||
}
|
||||
|
||||
eNum, eErr := round(c, args[2])
|
||||
if eErr != nil {
|
||||
return nil, eErr
|
||||
}
|
||||
|
||||
e := eNum.(tree.Num).Num()
|
||||
|
||||
if e <= 0 || math.IsNaN(float64(e)) || (math.IsInf(float64(b), 0) && math.IsInf(float64(e), 0)) {
|
||||
return tree.String(""), nil
|
||||
}
|
||||
|
||||
if b <= 1 {
|
||||
e = b + e - 1
|
||||
b = 1
|
||||
}
|
||||
|
||||
if float64(b+e-1) >= float64(len(str)) {
|
||||
e = tree.Num(len(str)) - b + 1
|
||||
}
|
||||
|
||||
return tree.String(str[int(b)-1 : int(b+e)-1]), nil
|
||||
}
|
||||
|
||||
func stringLength(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
var str string
|
||||
if len(args) == 1 {
|
||||
str = args[0].String()
|
||||
} else {
|
||||
str = c.NodeSet.String()
|
||||
}
|
||||
|
||||
return tree.Num(len(str)), nil
|
||||
}
|
||||
|
||||
var spaceTrim = regexp.MustCompile(`\s+`)
|
||||
|
||||
func normalizeSpace(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
var str string
|
||||
if len(args) == 1 {
|
||||
str = args[0].String()
|
||||
} else {
|
||||
str = c.NodeSet.String()
|
||||
}
|
||||
|
||||
str = strings.TrimSpace(str)
|
||||
|
||||
return tree.String(spaceTrim.ReplaceAllString(str, " ")), nil
|
||||
}
|
||||
|
||||
func translate(c tree.Ctx, args ...tree.Result) (tree.Result, error) {
|
||||
ret := args[0].String()
|
||||
src := args[1].String()
|
||||
repl := args[2].String()
|
||||
|
||||
for i := range src {
|
||||
r := ""
|
||||
if i < len(repl) {
|
||||
r = string(repl[i])
|
||||
}
|
||||
|
||||
ret = strings.Replace(ret, string(src[i]), r, -1)
|
||||
}
|
||||
|
||||
return tree.String(ret), nil
|
||||
}
|
||||
212
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/operators.go
generated
vendored
Normal file
212
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/operators.go
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
package execxp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/tree"
|
||||
)
|
||||
|
||||
func bothNodeOperator(left tree.NodeSet, right tree.NodeSet, f *xpFilt, op string) error {
|
||||
var err error
|
||||
for _, l := range left {
|
||||
for _, r := range right {
|
||||
lStr := l.ResValue()
|
||||
rStr := r.ResValue()
|
||||
|
||||
if eqOps[op] {
|
||||
err = equalsOperator(tree.String(lStr), tree.String(rStr), f, op)
|
||||
if err == nil && f.ctx.String() == tree.True {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
err = numberOperator(tree.String(lStr), tree.String(rStr), f, op)
|
||||
if err == nil && f.ctx.String() == tree.True {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f.ctx = tree.Bool(false)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func leftNodeOperator(left tree.NodeSet, right tree.Result, f *xpFilt, op string) error {
|
||||
var err error
|
||||
for _, l := range left {
|
||||
lStr := l.ResValue()
|
||||
|
||||
if eqOps[op] {
|
||||
err = equalsOperator(tree.String(lStr), right, f, op)
|
||||
if err == nil && f.ctx.String() == tree.True {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
err = numberOperator(tree.String(lStr), right, f, op)
|
||||
if err == nil && f.ctx.String() == tree.True {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f.ctx = tree.Bool(false)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func rightNodeOperator(left tree.Result, right tree.NodeSet, f *xpFilt, op string) error {
|
||||
var err error
|
||||
for _, r := range right {
|
||||
rStr := r.ResValue()
|
||||
|
||||
if eqOps[op] {
|
||||
err = equalsOperator(left, tree.String(rStr), f, op)
|
||||
if err == nil && f.ctx.String() == "true" {
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
err = numberOperator(left, tree.String(rStr), f, op)
|
||||
if err == nil && f.ctx.String() == "true" {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f.ctx = tree.Bool(false)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func equalsOperator(left, right tree.Result, f *xpFilt, op string) error {
|
||||
_, lOK := left.(tree.Bool)
|
||||
_, rOK := right.(tree.Bool)
|
||||
|
||||
if lOK || rOK {
|
||||
lTest, lt := left.(tree.IsBool)
|
||||
rTest, rt := right.(tree.IsBool)
|
||||
if !lt || !rt {
|
||||
return fmt.Errorf("Cannot convert argument to boolean")
|
||||
}
|
||||
|
||||
if op == "=" {
|
||||
f.ctx = tree.Bool(lTest.Bool() == rTest.Bool())
|
||||
} else {
|
||||
f.ctx = tree.Bool(lTest.Bool() != rTest.Bool())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
_, lOK = left.(tree.Num)
|
||||
_, rOK = right.(tree.Num)
|
||||
if lOK || rOK {
|
||||
return numberOperator(left, right, f, op)
|
||||
}
|
||||
|
||||
lStr := left.String()
|
||||
rStr := right.String()
|
||||
|
||||
if op == "=" {
|
||||
f.ctx = tree.Bool(lStr == rStr)
|
||||
} else {
|
||||
f.ctx = tree.Bool(lStr != rStr)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func numberOperator(left, right tree.Result, f *xpFilt, op string) error {
|
||||
lt, lOK := left.(tree.IsNum)
|
||||
rt, rOK := right.(tree.IsNum)
|
||||
if !lOK || !rOK {
|
||||
return fmt.Errorf("Cannot convert data type to number")
|
||||
}
|
||||
|
||||
ln, rn := lt.Num(), rt.Num()
|
||||
|
||||
switch op {
|
||||
case "*":
|
||||
f.ctx = ln * rn
|
||||
case "div":
|
||||
if rn != 0 {
|
||||
f.ctx = ln / rn
|
||||
} else {
|
||||
if ln == 0 {
|
||||
f.ctx = tree.Num(math.NaN())
|
||||
} else {
|
||||
if math.Signbit(float64(ln)) == math.Signbit(float64(rn)) {
|
||||
f.ctx = tree.Num(math.Inf(1))
|
||||
} else {
|
||||
f.ctx = tree.Num(math.Inf(-1))
|
||||
}
|
||||
}
|
||||
}
|
||||
case "mod":
|
||||
f.ctx = tree.Num(int(ln) % int(rn))
|
||||
case "+":
|
||||
f.ctx = ln + rn
|
||||
case "-":
|
||||
f.ctx = ln - rn
|
||||
case "=":
|
||||
f.ctx = tree.Bool(ln == rn)
|
||||
case "!=":
|
||||
f.ctx = tree.Bool(ln != rn)
|
||||
case "<":
|
||||
f.ctx = tree.Bool(ln < rn)
|
||||
case "<=":
|
||||
f.ctx = tree.Bool(ln <= rn)
|
||||
case ">":
|
||||
f.ctx = tree.Bool(ln > rn)
|
||||
case ">=":
|
||||
f.ctx = tree.Bool(ln >= rn)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func andOrOperator(left, right tree.Result, f *xpFilt, op string) error {
|
||||
lt, lOK := left.(tree.IsBool)
|
||||
rt, rOK := right.(tree.IsBool)
|
||||
|
||||
if !lOK || !rOK {
|
||||
return fmt.Errorf("Cannot convert argument to boolean")
|
||||
}
|
||||
|
||||
l, r := lt.Bool(), rt.Bool()
|
||||
|
||||
if op == "and" {
|
||||
f.ctx = l && r
|
||||
} else {
|
||||
f.ctx = l || r
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func unionOperator(left, right tree.Result, f *xpFilt, op string) error {
|
||||
lNode, lOK := left.(tree.NodeSet)
|
||||
rNode, rOK := right.(tree.NodeSet)
|
||||
|
||||
if !lOK || !rOK {
|
||||
return fmt.Errorf("Cannot convert data type to node-set")
|
||||
}
|
||||
|
||||
uniq := make(map[int]tree.Node)
|
||||
for _, i := range lNode {
|
||||
uniq[i.Pos()] = i
|
||||
}
|
||||
for _, i := range rNode {
|
||||
uniq[i.Pos()] = i
|
||||
}
|
||||
|
||||
res := make(tree.NodeSet, 0, len(uniq))
|
||||
for _, v := range uniq {
|
||||
res = append(res, v)
|
||||
}
|
||||
|
||||
f.ctx = res
|
||||
|
||||
return nil
|
||||
}
|
||||
396
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go
generated
vendored
Normal file
396
vendor/github.com/ChrisTrenkamp/goxpath/internal/execxp/paths.go
generated
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
package execxp
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/internal/execxp/findutil"
|
||||
"github.com/ChrisTrenkamp/goxpath/internal/execxp/intfns"
|
||||
"github.com/ChrisTrenkamp/goxpath/internal/xsort"
|
||||
"github.com/ChrisTrenkamp/goxpath/lexer"
|
||||
"github.com/ChrisTrenkamp/goxpath/parser"
|
||||
"github.com/ChrisTrenkamp/goxpath/parser/pathexpr"
|
||||
"github.com/ChrisTrenkamp/goxpath/tree"
|
||||
"github.com/ChrisTrenkamp/goxpath/xconst"
|
||||
)
|
||||
|
||||
type xpFilt struct {
|
||||
t tree.Node
|
||||
ctx tree.Result
|
||||
expr pathexpr.PathExpr
|
||||
ns map[string]string
|
||||
ctxPos int
|
||||
ctxSize int
|
||||
proxPos map[int]int
|
||||
fns map[xml.Name]tree.Wrap
|
||||
variables map[string]tree.Result
|
||||
}
|
||||
|
||||
type xpExecFn func(*xpFilt, string)
|
||||
|
||||
var xpFns = map[lexer.XItemType]xpExecFn{
|
||||
lexer.XItemAbsLocPath: xfAbsLocPath,
|
||||
lexer.XItemAbbrAbsLocPath: xfAbbrAbsLocPath,
|
||||
lexer.XItemRelLocPath: xfRelLocPath,
|
||||
lexer.XItemAbbrRelLocPath: xfAbbrRelLocPath,
|
||||
lexer.XItemAxis: xfAxis,
|
||||
lexer.XItemAbbrAxis: xfAbbrAxis,
|
||||
lexer.XItemNCName: xfNCName,
|
||||
lexer.XItemQName: xfQName,
|
||||
lexer.XItemNodeType: xfNodeType,
|
||||
lexer.XItemProcLit: xfProcInstLit,
|
||||
lexer.XItemStrLit: xfStrLit,
|
||||
lexer.XItemNumLit: xfNumLit,
|
||||
}
|
||||
|
||||
func xfExec(f *xpFilt, n *parser.Node) (err error) {
|
||||
for n != nil {
|
||||
if fn, ok := xpFns[n.Val.Typ]; ok {
|
||||
fn(f, n.Val.Val)
|
||||
n = n.Left
|
||||
} else if n.Val.Typ == lexer.XItemPredicate {
|
||||
if err = xfPredicate(f, n.Left); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
n = n.Right
|
||||
} else if n.Val.Typ == lexer.XItemFunction {
|
||||
if err = xfFunction(f, n); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
n = n.Right
|
||||
} else if n.Val.Typ == lexer.XItemOperator {
|
||||
lf := xpFilt{
|
||||
t: f.t,
|
||||
ns: f.ns,
|
||||
ctx: f.ctx,
|
||||
ctxPos: f.ctxPos,
|
||||
ctxSize: f.ctxSize,
|
||||
proxPos: f.proxPos,
|
||||
fns: f.fns,
|
||||
variables: f.variables,
|
||||
}
|
||||
left, err := exec(&lf, n.Left)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rf := xpFilt{
|
||||
t: f.t,
|
||||
ns: f.ns,
|
||||
ctx: f.ctx,
|
||||
fns: f.fns,
|
||||
variables: f.variables,
|
||||
}
|
||||
right, err := exec(&rf, n.Right)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return xfOperator(left, right, f, n.Val.Val)
|
||||
} else if n.Val.Typ == lexer.XItemVariable {
|
||||
if res, ok := f.variables[n.Val.Val]; ok {
|
||||
f.ctx = res
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("Invalid variable '%s'", n.Val.Val)
|
||||
} else if string(n.Val.Typ) == "" {
|
||||
n = n.Left
|
||||
//} else {
|
||||
// return fmt.Errorf("Cannot process " + string(n.Val.Typ))
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func xfPredicate(f *xpFilt, n *parser.Node) (err error) {
|
||||
res := f.ctx.(tree.NodeSet)
|
||||
newRes := make(tree.NodeSet, 0, len(res))
|
||||
|
||||
for i := range res {
|
||||
pf := xpFilt{
|
||||
t: f.t,
|
||||
ns: f.ns,
|
||||
ctxPos: i,
|
||||
ctxSize: f.ctxSize,
|
||||
ctx: tree.NodeSet{res[i]},
|
||||
fns: f.fns,
|
||||
variables: f.variables,
|
||||
}
|
||||
|
||||
predRes, err := exec(&pf, n)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ok, err := checkPredRes(predRes, f, res[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ok {
|
||||
newRes = append(newRes, res[i])
|
||||
}
|
||||
}
|
||||
|
||||
f.proxPos = make(map[int]int)
|
||||
for pos, j := range newRes {
|
||||
f.proxPos[j.Pos()] = pos + 1
|
||||
}
|
||||
|
||||
f.ctx = newRes
|
||||
f.ctxSize = len(newRes)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func checkPredRes(ret tree.Result, f *xpFilt, node tree.Node) (bool, error) {
|
||||
if num, ok := ret.(tree.Num); ok {
|
||||
if float64(f.proxPos[node.Pos()]) == float64(num) {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if b, ok := ret.(tree.IsBool); ok {
|
||||
return bool(b.Bool()), nil
|
||||
}
|
||||
|
||||
return false, fmt.Errorf("Cannot convert argument to boolean")
|
||||
}
|
||||
|
||||
func xfFunction(f *xpFilt, n *parser.Node) error {
|
||||
spl := strings.Split(n.Val.Val, ":")
|
||||
var name xml.Name
|
||||
if len(spl) == 1 {
|
||||
name.Local = spl[0]
|
||||
} else {
|
||||
name.Space = f.ns[spl[0]]
|
||||
name.Local = spl[1]
|
||||
}
|
||||
fn, ok := intfns.BuiltIn[name]
|
||||
if !ok {
|
||||
fn, ok = f.fns[name]
|
||||
}
|
||||
|
||||
if ok {
|
||||
args := []tree.Result{}
|
||||
param := n.Left
|
||||
|
||||
for param != nil {
|
||||
pf := xpFilt{
|
||||
t: f.t,
|
||||
ctx: f.ctx,
|
||||
ns: f.ns,
|
||||
ctxPos: f.ctxPos,
|
||||
ctxSize: f.ctxSize,
|
||||
fns: f.fns,
|
||||
variables: f.variables,
|
||||
}
|
||||
res, err := exec(&pf, param.Left)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
args = append(args, res)
|
||||
param = param.Right
|
||||
}
|
||||
|
||||
filt, err := fn.Call(tree.Ctx{NodeSet: f.ctx.(tree.NodeSet), Size: f.ctxSize, Pos: f.ctxPos + 1}, args...)
|
||||
f.ctx = filt
|
||||
return err
|
||||
}
|
||||
|
||||
return fmt.Errorf("Unknown function: %s", n.Val.Val)
|
||||
}
|
||||
|
||||
var eqOps = map[string]bool{
|
||||
"=": true,
|
||||
"!=": true,
|
||||
}
|
||||
|
||||
var booleanOps = map[string]bool{
|
||||
"=": true,
|
||||
"!=": true,
|
||||
"<": true,
|
||||
"<=": true,
|
||||
">": true,
|
||||
">=": true,
|
||||
}
|
||||
|
||||
var numOps = map[string]bool{
|
||||
"*": true,
|
||||
"div": true,
|
||||
"mod": true,
|
||||
"+": true,
|
||||
"-": true,
|
||||
"=": true,
|
||||
"!=": true,
|
||||
"<": true,
|
||||
"<=": true,
|
||||
">": true,
|
||||
">=": true,
|
||||
}
|
||||
|
||||
var andOrOps = map[string]bool{
|
||||
"and": true,
|
||||
"or": true,
|
||||
}
|
||||
|
||||
func xfOperator(left, right tree.Result, f *xpFilt, op string) error {
|
||||
if booleanOps[op] {
|
||||
lNode, lOK := left.(tree.NodeSet)
|
||||
rNode, rOK := right.(tree.NodeSet)
|
||||
if lOK && rOK {
|
||||
return bothNodeOperator(lNode, rNode, f, op)
|
||||
}
|
||||
|
||||
if lOK {
|
||||
return leftNodeOperator(lNode, right, f, op)
|
||||
}
|
||||
|
||||
if rOK {
|
||||
return rightNodeOperator(left, rNode, f, op)
|
||||
}
|
||||
|
||||
if eqOps[op] {
|
||||
return equalsOperator(left, right, f, op)
|
||||
}
|
||||
}
|
||||
|
||||
if numOps[op] {
|
||||
return numberOperator(left, right, f, op)
|
||||
}
|
||||
|
||||
if andOrOps[op] {
|
||||
return andOrOperator(left, right, f, op)
|
||||
}
|
||||
|
||||
//if op == "|" {
|
||||
return unionOperator(left, right, f, op)
|
||||
//}
|
||||
|
||||
//return fmt.Errorf("Unknown operator " + op)
|
||||
}
|
||||
|
||||
func xfAbsLocPath(f *xpFilt, val string) {
|
||||
i := f.t
|
||||
for i.GetNodeType() != tree.NtRoot {
|
||||
i = i.GetParent()
|
||||
}
|
||||
f.ctx = tree.NodeSet{i}
|
||||
}
|
||||
|
||||
func xfAbbrAbsLocPath(f *xpFilt, val string) {
|
||||
i := f.t
|
||||
for i.GetNodeType() != tree.NtRoot {
|
||||
i = i.GetParent()
|
||||
}
|
||||
f.ctx = tree.NodeSet{i}
|
||||
f.expr = abbrPathExpr()
|
||||
find(f)
|
||||
}
|
||||
|
||||
func xfRelLocPath(f *xpFilt, val string) {
|
||||
}
|
||||
|
||||
func xfAbbrRelLocPath(f *xpFilt, val string) {
|
||||
f.expr = abbrPathExpr()
|
||||
find(f)
|
||||
}
|
||||
|
||||
func xfAxis(f *xpFilt, val string) {
|
||||
f.expr.Axis = val
|
||||
}
|
||||
|
||||
func xfAbbrAxis(f *xpFilt, val string) {
|
||||
f.expr.Axis = xconst.AxisAttribute
|
||||
}
|
||||
|
||||
func xfNCName(f *xpFilt, val string) {
|
||||
f.expr.Name.Space = val
|
||||
}
|
||||
|
||||
func xfQName(f *xpFilt, val string) {
|
||||
f.expr.Name.Local = val
|
||||
find(f)
|
||||
}
|
||||
|
||||
func xfNodeType(f *xpFilt, val string) {
|
||||
f.expr.NodeType = val
|
||||
find(f)
|
||||
}
|
||||
|
||||
func xfProcInstLit(f *xpFilt, val string) {
|
||||
filt := tree.NodeSet{}
|
||||
for _, i := range f.ctx.(tree.NodeSet) {
|
||||
if i.GetToken().(xml.ProcInst).Target == val {
|
||||
filt = append(filt, i)
|
||||
}
|
||||
}
|
||||
f.ctx = filt
|
||||
}
|
||||
|
||||
func xfStrLit(f *xpFilt, val string) {
|
||||
f.ctx = tree.String(val)
|
||||
}
|
||||
|
||||
func xfNumLit(f *xpFilt, val string) {
|
||||
num, _ := strconv.ParseFloat(val, 64)
|
||||
f.ctx = tree.Num(num)
|
||||
}
|
||||
|
||||
func abbrPathExpr() pathexpr.PathExpr {
|
||||
return pathexpr.PathExpr{
|
||||
Name: xml.Name{},
|
||||
Axis: xconst.AxisDescendentOrSelf,
|
||||
NodeType: xconst.NodeTypeNode,
|
||||
}
|
||||
}
|
||||
|
||||
func find(f *xpFilt) {
|
||||
dupFilt := make(map[int]tree.Node)
|
||||
f.proxPos = make(map[int]int)
|
||||
|
||||
if f.expr.Axis == "" && f.expr.NodeType == "" && f.expr.Name.Space == "" {
|
||||
if f.expr.Name.Local == "." {
|
||||
f.expr = pathexpr.PathExpr{
|
||||
Name: xml.Name{},
|
||||
Axis: xconst.AxisSelf,
|
||||
NodeType: xconst.NodeTypeNode,
|
||||
}
|
||||
}
|
||||
|
||||
if f.expr.Name.Local == ".." {
|
||||
f.expr = pathexpr.PathExpr{
|
||||
Name: xml.Name{},
|
||||
Axis: xconst.AxisParent,
|
||||
NodeType: xconst.NodeTypeNode,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f.expr.NS = f.ns
|
||||
|
||||
for _, i := range f.ctx.(tree.NodeSet) {
|
||||
for pos, j := range findutil.Find(i, f.expr) {
|
||||
dupFilt[j.Pos()] = j
|
||||
f.proxPos[j.Pos()] = pos + 1
|
||||
}
|
||||
}
|
||||
|
||||
res := make(tree.NodeSet, 0, len(dupFilt))
|
||||
for _, i := range dupFilt {
|
||||
res = append(res, i)
|
||||
}
|
||||
|
||||
xsort.SortNodes(res)
|
||||
|
||||
f.expr = pathexpr.PathExpr{}
|
||||
f.ctxSize = len(res)
|
||||
f.ctx = res
|
||||
}
|
||||
20
vendor/github.com/ChrisTrenkamp/goxpath/internal/xsort/xsort.go
generated
vendored
Normal file
20
vendor/github.com/ChrisTrenkamp/goxpath/internal/xsort/xsort.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
package xsort
|
||||
|
||||
import (
|
||||
"sort"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/tree"
|
||||
)
|
||||
|
||||
type nodeSort []tree.Node
|
||||
|
||||
func (ns nodeSort) Len() int { return len(ns) }
|
||||
func (ns nodeSort) Swap(i, j int) { ns[i], ns[j] = ns[j], ns[i] }
|
||||
func (ns nodeSort) Less(i, j int) bool {
|
||||
return ns[i].Pos() < ns[j].Pos()
|
||||
}
|
||||
|
||||
//SortNodes sorts the array by the node document order
|
||||
func SortNodes(res []tree.Node) {
|
||||
sort.Sort(nodeSort(res))
|
||||
}
|
||||
419
vendor/github.com/ChrisTrenkamp/goxpath/lexer/lexer.go
generated
vendored
Normal file
419
vendor/github.com/ChrisTrenkamp/goxpath/lexer/lexer.go
generated
vendored
Normal file
@@ -0,0 +1,419 @@
|
||||
package lexer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
const (
|
||||
//XItemError is an error with the parser input
|
||||
XItemError XItemType = "Error"
|
||||
//XItemAbsLocPath is an absolute path
|
||||
XItemAbsLocPath = "Absolute path"
|
||||
//XItemAbbrAbsLocPath represents an abbreviated absolute path
|
||||
XItemAbbrAbsLocPath = "Abbreviated absolute path"
|
||||
//XItemAbbrRelLocPath marks the start of a path expression
|
||||
XItemAbbrRelLocPath = "Abbreviated relative path"
|
||||
//XItemRelLocPath represents a relative location path
|
||||
XItemRelLocPath = "Relative path"
|
||||
//XItemEndPath marks the end of a path
|
||||
XItemEndPath = "End path instruction"
|
||||
//XItemAxis marks an axis specifier of a path
|
||||
XItemAxis = "Axis"
|
||||
//XItemAbbrAxis marks an abbreviated axis specifier (just @ at this point)
|
||||
XItemAbbrAxis = "Abbreviated attribute axis"
|
||||
//XItemNCName marks a namespace name in a node test
|
||||
XItemNCName = "Namespace"
|
||||
//XItemQName marks the local name in an a node test
|
||||
XItemQName = "Local name"
|
||||
//XItemNodeType marks a node type in a node test
|
||||
XItemNodeType = "Node type"
|
||||
//XItemProcLit marks a processing-instruction literal
|
||||
XItemProcLit = "processing-instruction"
|
||||
//XItemFunction marks a function call
|
||||
XItemFunction = "function"
|
||||
//XItemArgument marks a function argument
|
||||
XItemArgument = "function argument"
|
||||
//XItemEndFunction marks the end of a function
|
||||
XItemEndFunction = "end of function"
|
||||
//XItemPredicate marks a predicate in an axis
|
||||
XItemPredicate = "predicate"
|
||||
//XItemEndPredicate marks a predicate in an axis
|
||||
XItemEndPredicate = "end of predicate"
|
||||
//XItemStrLit marks a string literal
|
||||
XItemStrLit = "string literal"
|
||||
//XItemNumLit marks a numeric literal
|
||||
XItemNumLit = "numeric literal"
|
||||
//XItemOperator marks an operator
|
||||
XItemOperator = "operator"
|
||||
//XItemVariable marks a variable reference
|
||||
XItemVariable = "variable"
|
||||
)
|
||||
|
||||
const (
|
||||
eof = -(iota + 1)
|
||||
)
|
||||
|
||||
//XItemType is the parser token types
|
||||
type XItemType string
|
||||
|
||||
//XItem is the token emitted from the parser
|
||||
type XItem struct {
|
||||
Typ XItemType
|
||||
Val string
|
||||
}
|
||||
|
||||
type stateFn func(*Lexer) stateFn
|
||||
|
||||
//Lexer lexes out XPath expressions
|
||||
type Lexer struct {
|
||||
input string
|
||||
start int
|
||||
pos int
|
||||
width int
|
||||
items chan XItem
|
||||
}
|
||||
|
||||
//Lex an XPath expresion on the io.Reader
|
||||
func Lex(xpath string) chan XItem {
|
||||
l := &Lexer{
|
||||
input: xpath,
|
||||
items: make(chan XItem),
|
||||
}
|
||||
go l.run()
|
||||
return l.items
|
||||
}
|
||||
|
||||
func (l *Lexer) run() {
|
||||
for state := startState; state != nil; {
|
||||
state = state(l)
|
||||
}
|
||||
|
||||
if l.peek() != eof {
|
||||
l.errorf("Malformed XPath expression")
|
||||
}
|
||||
|
||||
close(l.items)
|
||||
}
|
||||
|
||||
func (l *Lexer) emit(t XItemType) {
|
||||
l.items <- XItem{t, l.input[l.start:l.pos]}
|
||||
l.start = l.pos
|
||||
}
|
||||
|
||||
func (l *Lexer) emitVal(t XItemType, val string) {
|
||||
l.items <- XItem{t, val}
|
||||
l.start = l.pos
|
||||
}
|
||||
|
||||
func (l *Lexer) next() (r rune) {
|
||||
if l.pos >= len(l.input) {
|
||||
l.width = 0
|
||||
return eof
|
||||
}
|
||||
|
||||
r, l.width = utf8.DecodeRuneInString(l.input[l.pos:])
|
||||
|
||||
l.pos += l.width
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (l *Lexer) ignore() {
|
||||
l.start = l.pos
|
||||
}
|
||||
|
||||
func (l *Lexer) backup() {
|
||||
l.pos -= l.width
|
||||
}
|
||||
|
||||
func (l *Lexer) peek() rune {
|
||||
r := l.next()
|
||||
|
||||
l.backup()
|
||||
return r
|
||||
}
|
||||
|
||||
func (l *Lexer) peekAt(n int) rune {
|
||||
if n <= 1 {
|
||||
return l.peek()
|
||||
}
|
||||
|
||||
width := 0
|
||||
var ret rune
|
||||
|
||||
for count := 0; count < n; count++ {
|
||||
r, s := utf8.DecodeRuneInString(l.input[l.pos+width:])
|
||||
width += s
|
||||
|
||||
if l.pos+width > len(l.input) {
|
||||
return eof
|
||||
}
|
||||
|
||||
ret = r
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func (l *Lexer) accept(valid string) bool {
|
||||
if strings.ContainsRune(valid, l.next()) {
|
||||
return true
|
||||
}
|
||||
|
||||
l.backup()
|
||||
return false
|
||||
}
|
||||
|
||||
func (l *Lexer) acceptRun(valid string) {
|
||||
for strings.ContainsRune(valid, l.next()) {
|
||||
}
|
||||
l.backup()
|
||||
}
|
||||
|
||||
func (l *Lexer) skip(num int) {
|
||||
for i := 0; i < num; i++ {
|
||||
l.next()
|
||||
}
|
||||
l.ignore()
|
||||
}
|
||||
|
||||
func (l *Lexer) skipWS(ig bool) {
|
||||
for {
|
||||
n := l.next()
|
||||
|
||||
if n == eof || !unicode.IsSpace(n) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
l.backup()
|
||||
|
||||
if ig {
|
||||
l.ignore()
|
||||
}
|
||||
}
|
||||
|
||||
func (l *Lexer) errorf(format string, args ...interface{}) stateFn {
|
||||
l.items <- XItem{
|
||||
XItemError,
|
||||
fmt.Sprintf(format, args...),
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isElemChar(r rune) bool {
|
||||
return string(r) != ":" && string(r) != "/" &&
|
||||
(unicode.Is(first, r) || unicode.Is(second, r) || string(r) == "*") &&
|
||||
r != eof
|
||||
}
|
||||
|
||||
func startState(l *Lexer) stateFn {
|
||||
l.skipWS(true)
|
||||
|
||||
if string(l.peek()) == "/" {
|
||||
l.next()
|
||||
l.ignore()
|
||||
|
||||
if string(l.next()) == "/" {
|
||||
l.ignore()
|
||||
return abbrAbsLocPathState
|
||||
}
|
||||
|
||||
l.backup()
|
||||
return absLocPathState
|
||||
} else if string(l.peek()) == `'` || string(l.peek()) == `"` {
|
||||
if err := getStrLit(l, XItemStrLit); err != nil {
|
||||
return l.errorf(err.Error())
|
||||
}
|
||||
|
||||
if l.peek() != eof {
|
||||
return startState
|
||||
}
|
||||
} else if getNumLit(l) {
|
||||
l.skipWS(true)
|
||||
if l.peek() != eof {
|
||||
return startState
|
||||
}
|
||||
} else if string(l.peek()) == "$" {
|
||||
l.next()
|
||||
l.ignore()
|
||||
r := l.peek()
|
||||
for unicode.Is(first, r) || unicode.Is(second, r) {
|
||||
l.next()
|
||||
r = l.peek()
|
||||
}
|
||||
tok := l.input[l.start:l.pos]
|
||||
if len(tok) == 0 {
|
||||
return l.errorf("Empty variable name")
|
||||
}
|
||||
l.emit(XItemVariable)
|
||||
l.skipWS(true)
|
||||
if l.peek() != eof {
|
||||
return startState
|
||||
}
|
||||
} else if st := findOperatorState(l); st != nil {
|
||||
return st
|
||||
} else {
|
||||
if isElemChar(l.peek()) {
|
||||
colons := 0
|
||||
|
||||
for {
|
||||
if isElemChar(l.peek()) {
|
||||
l.next()
|
||||
} else if string(l.peek()) == ":" {
|
||||
l.next()
|
||||
colons++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if string(l.peek()) == "(" && colons <= 1 {
|
||||
tok := l.input[l.start:l.pos]
|
||||
err := procFunc(l, tok)
|
||||
if err != nil {
|
||||
return l.errorf(err.Error())
|
||||
}
|
||||
|
||||
l.skipWS(true)
|
||||
|
||||
if string(l.peek()) == "/" {
|
||||
l.next()
|
||||
l.ignore()
|
||||
|
||||
if string(l.next()) == "/" {
|
||||
l.ignore()
|
||||
return abbrRelLocPathState
|
||||
}
|
||||
|
||||
l.backup()
|
||||
return relLocPathState
|
||||
}
|
||||
|
||||
return startState
|
||||
}
|
||||
|
||||
l.pos = l.start
|
||||
return relLocPathState
|
||||
} else if string(l.peek()) == "@" {
|
||||
return relLocPathState
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func strPeek(str string, l *Lexer) bool {
|
||||
for i := 0; i < len(str); i++ {
|
||||
if string(l.peekAt(i+1)) != string(str[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func findOperatorState(l *Lexer) stateFn {
|
||||
l.skipWS(true)
|
||||
|
||||
switch string(l.peek()) {
|
||||
case ">", "<", "!":
|
||||
l.next()
|
||||
if string(l.peek()) == "=" {
|
||||
l.next()
|
||||
}
|
||||
l.emit(XItemOperator)
|
||||
return startState
|
||||
case "|", "+", "-", "*", "=":
|
||||
l.next()
|
||||
l.emit(XItemOperator)
|
||||
return startState
|
||||
case "(":
|
||||
l.next()
|
||||
l.emit(XItemOperator)
|
||||
for state := startState; state != nil; {
|
||||
state = state(l)
|
||||
}
|
||||
l.skipWS(true)
|
||||
if string(l.next()) != ")" {
|
||||
return l.errorf("Missing end )")
|
||||
}
|
||||
l.emit(XItemOperator)
|
||||
return startState
|
||||
}
|
||||
|
||||
if strPeek("and", l) {
|
||||
l.next()
|
||||
l.next()
|
||||
l.next()
|
||||
l.emit(XItemOperator)
|
||||
return startState
|
||||
}
|
||||
|
||||
if strPeek("or", l) {
|
||||
l.next()
|
||||
l.next()
|
||||
l.emit(XItemOperator)
|
||||
return startState
|
||||
}
|
||||
|
||||
if strPeek("mod", l) {
|
||||
l.next()
|
||||
l.next()
|
||||
l.next()
|
||||
l.emit(XItemOperator)
|
||||
return startState
|
||||
}
|
||||
|
||||
if strPeek("div", l) {
|
||||
l.next()
|
||||
l.next()
|
||||
l.next()
|
||||
l.emit(XItemOperator)
|
||||
return startState
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStrLit(l *Lexer, tok XItemType) error {
|
||||
q := l.next()
|
||||
var r rune
|
||||
|
||||
l.ignore()
|
||||
|
||||
for r != q {
|
||||
r = l.next()
|
||||
if r == eof {
|
||||
return fmt.Errorf("Unexpected end of string literal.")
|
||||
}
|
||||
}
|
||||
|
||||
l.backup()
|
||||
l.emit(tok)
|
||||
l.next()
|
||||
l.ignore()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getNumLit(l *Lexer) bool {
|
||||
const dig = "0123456789"
|
||||
l.accept("-")
|
||||
start := l.pos
|
||||
l.acceptRun(dig)
|
||||
|
||||
if l.pos == start {
|
||||
return false
|
||||
}
|
||||
|
||||
if l.accept(".") {
|
||||
l.acceptRun(dig)
|
||||
}
|
||||
|
||||
l.emit(XItemNumLit)
|
||||
return true
|
||||
}
|
||||
219
vendor/github.com/ChrisTrenkamp/goxpath/lexer/paths.go
generated
vendored
Normal file
219
vendor/github.com/ChrisTrenkamp/goxpath/lexer/paths.go
generated
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
package lexer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/xconst"
|
||||
)
|
||||
|
||||
func absLocPathState(l *Lexer) stateFn {
|
||||
l.emit(XItemAbsLocPath)
|
||||
return stepState
|
||||
}
|
||||
|
||||
func abbrAbsLocPathState(l *Lexer) stateFn {
|
||||
l.emit(XItemAbbrAbsLocPath)
|
||||
return stepState
|
||||
}
|
||||
|
||||
func relLocPathState(l *Lexer) stateFn {
|
||||
l.emit(XItemRelLocPath)
|
||||
return stepState
|
||||
}
|
||||
|
||||
func abbrRelLocPathState(l *Lexer) stateFn {
|
||||
l.emit(XItemAbbrRelLocPath)
|
||||
return stepState
|
||||
}
|
||||
|
||||
func stepState(l *Lexer) stateFn {
|
||||
l.skipWS(true)
|
||||
r := l.next()
|
||||
|
||||
for isElemChar(r) {
|
||||
r = l.next()
|
||||
}
|
||||
|
||||
l.backup()
|
||||
tok := l.input[l.start:l.pos]
|
||||
|
||||
state, err := parseSeparators(l, tok)
|
||||
if err != nil {
|
||||
return l.errorf(err.Error())
|
||||
}
|
||||
|
||||
return getNextPathState(l, state)
|
||||
}
|
||||
|
||||
func parseSeparators(l *Lexer, tok string) (XItemType, error) {
|
||||
l.skipWS(false)
|
||||
state := XItemType(XItemQName)
|
||||
r := l.peek()
|
||||
|
||||
if string(r) == ":" && string(l.peekAt(2)) == ":" {
|
||||
var err error
|
||||
if state, err = getAxis(l, tok); err != nil {
|
||||
return state, fmt.Errorf(err.Error())
|
||||
}
|
||||
} else if string(r) == ":" {
|
||||
state = XItemNCName
|
||||
l.emitVal(state, tok)
|
||||
l.skip(1)
|
||||
l.skipWS(true)
|
||||
} else if string(r) == "@" {
|
||||
state = XItemAbbrAxis
|
||||
l.emitVal(state, tok)
|
||||
l.skip(1)
|
||||
l.skipWS(true)
|
||||
} else if string(r) == "(" {
|
||||
var err error
|
||||
if state, err = getNT(l, tok); err != nil {
|
||||
return state, fmt.Errorf(err.Error())
|
||||
}
|
||||
} else if len(tok) > 0 {
|
||||
l.emitVal(state, tok)
|
||||
}
|
||||
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func getAxis(l *Lexer, tok string) (XItemType, error) {
|
||||
var state XItemType
|
||||
for i := range xconst.AxisNames {
|
||||
if tok == xconst.AxisNames[i] {
|
||||
state = XItemAxis
|
||||
}
|
||||
}
|
||||
if state != XItemAxis {
|
||||
return state, fmt.Errorf("Invalid Axis specifier, %s", tok)
|
||||
}
|
||||
l.emitVal(state, tok)
|
||||
l.skip(2)
|
||||
l.skipWS(true)
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func getNT(l *Lexer, tok string) (XItemType, error) {
|
||||
isNT := false
|
||||
for _, i := range xconst.NodeTypes {
|
||||
if tok == i {
|
||||
isNT = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if isNT {
|
||||
return procNT(l, tok)
|
||||
}
|
||||
|
||||
return XItemError, fmt.Errorf("Invalid node-type " + tok)
|
||||
}
|
||||
|
||||
func procNT(l *Lexer, tok string) (XItemType, error) {
|
||||
state := XItemType(XItemNodeType)
|
||||
l.emitVal(state, tok)
|
||||
l.skip(1)
|
||||
l.skipWS(true)
|
||||
n := l.peek()
|
||||
if tok == xconst.NodeTypeProcInst && (string(n) == `"` || string(n) == `'`) {
|
||||
if err := getStrLit(l, XItemProcLit); err != nil {
|
||||
return state, fmt.Errorf(err.Error())
|
||||
}
|
||||
l.skipWS(true)
|
||||
n = l.next()
|
||||
}
|
||||
|
||||
if string(n) != ")" {
|
||||
return state, fmt.Errorf("Missing ) at end of NodeType declaration.")
|
||||
}
|
||||
|
||||
l.skip(1)
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func procFunc(l *Lexer, tok string) error {
|
||||
state := XItemType(XItemFunction)
|
||||
l.emitVal(state, tok)
|
||||
l.skip(1)
|
||||
l.skipWS(true)
|
||||
if string(l.peek()) != ")" {
|
||||
l.emit(XItemArgument)
|
||||
for {
|
||||
for state := startState; state != nil; {
|
||||
state = state(l)
|
||||
}
|
||||
l.skipWS(true)
|
||||
|
||||
if string(l.peek()) == "," {
|
||||
l.emit(XItemArgument)
|
||||
l.skip(1)
|
||||
} else if string(l.peek()) == ")" {
|
||||
l.emit(XItemEndFunction)
|
||||
l.skip(1)
|
||||
break
|
||||
} else if l.peek() == eof {
|
||||
return fmt.Errorf("Missing ) at end of function declaration.")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
l.emit(XItemEndFunction)
|
||||
l.skip(1)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getNextPathState(l *Lexer, state XItemType) stateFn {
|
||||
isMultiPart := state == XItemAxis || state == XItemAbbrAxis || state == XItemNCName
|
||||
|
||||
l.skipWS(true)
|
||||
|
||||
for string(l.peek()) == "[" {
|
||||
if err := getPred(l); err != nil {
|
||||
return l.errorf(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
if string(l.peek()) == "/" && !isMultiPart {
|
||||
l.skip(1)
|
||||
if string(l.peek()) == "/" {
|
||||
l.skip(1)
|
||||
return abbrRelLocPathState
|
||||
}
|
||||
l.skipWS(true)
|
||||
return relLocPathState
|
||||
} else if isMultiPart && isElemChar(l.peek()) {
|
||||
return stepState
|
||||
}
|
||||
|
||||
if isMultiPart {
|
||||
return l.errorf("Step is not complete")
|
||||
}
|
||||
|
||||
l.emit(XItemEndPath)
|
||||
return findOperatorState
|
||||
}
|
||||
|
||||
func getPred(l *Lexer) error {
|
||||
l.emit(XItemPredicate)
|
||||
l.skip(1)
|
||||
l.skipWS(true)
|
||||
|
||||
if string(l.peek()) == "]" {
|
||||
return fmt.Errorf("Missing content in predicate.")
|
||||
}
|
||||
|
||||
for state := startState; state != nil; {
|
||||
state = state(l)
|
||||
}
|
||||
|
||||
l.skipWS(true)
|
||||
if string(l.peek()) != "]" {
|
||||
return fmt.Errorf("Missing ] at end of predicate.")
|
||||
}
|
||||
l.skip(1)
|
||||
l.emit(XItemEndPredicate)
|
||||
l.skipWS(true)
|
||||
|
||||
return nil
|
||||
}
|
||||
316
vendor/github.com/ChrisTrenkamp/goxpath/lexer/xmlchars.go
generated
vendored
Normal file
316
vendor/github.com/ChrisTrenkamp/goxpath/lexer/xmlchars.go
generated
vendored
Normal file
@@ -0,0 +1,316 @@
|
||||
package lexer
|
||||
|
||||
import "unicode"
|
||||
|
||||
//first and second was copied from src/encoding/xml/xml.go
|
||||
var first = &unicode.RangeTable{
|
||||
R16: []unicode.Range16{
|
||||
{0x003A, 0x003A, 1},
|
||||
{0x0041, 0x005A, 1},
|
||||
{0x005F, 0x005F, 1},
|
||||
{0x0061, 0x007A, 1},
|
||||
{0x00C0, 0x00D6, 1},
|
||||
{0x00D8, 0x00F6, 1},
|
||||
{0x00F8, 0x00FF, 1},
|
||||
{0x0100, 0x0131, 1},
|
||||
{0x0134, 0x013E, 1},
|
||||
{0x0141, 0x0148, 1},
|
||||
{0x014A, 0x017E, 1},
|
||||
{0x0180, 0x01C3, 1},
|
||||
{0x01CD, 0x01F0, 1},
|
||||
{0x01F4, 0x01F5, 1},
|
||||
{0x01FA, 0x0217, 1},
|
||||
{0x0250, 0x02A8, 1},
|
||||
{0x02BB, 0x02C1, 1},
|
||||
{0x0386, 0x0386, 1},
|
||||
{0x0388, 0x038A, 1},
|
||||
{0x038C, 0x038C, 1},
|
||||
{0x038E, 0x03A1, 1},
|
||||
{0x03A3, 0x03CE, 1},
|
||||
{0x03D0, 0x03D6, 1},
|
||||
{0x03DA, 0x03E0, 2},
|
||||
{0x03E2, 0x03F3, 1},
|
||||
{0x0401, 0x040C, 1},
|
||||
{0x040E, 0x044F, 1},
|
||||
{0x0451, 0x045C, 1},
|
||||
{0x045E, 0x0481, 1},
|
||||
{0x0490, 0x04C4, 1},
|
||||
{0x04C7, 0x04C8, 1},
|
||||
{0x04CB, 0x04CC, 1},
|
||||
{0x04D0, 0x04EB, 1},
|
||||
{0x04EE, 0x04F5, 1},
|
||||
{0x04F8, 0x04F9, 1},
|
||||
{0x0531, 0x0556, 1},
|
||||
{0x0559, 0x0559, 1},
|
||||
{0x0561, 0x0586, 1},
|
||||
{0x05D0, 0x05EA, 1},
|
||||
{0x05F0, 0x05F2, 1},
|
||||
{0x0621, 0x063A, 1},
|
||||
{0x0641, 0x064A, 1},
|
||||
{0x0671, 0x06B7, 1},
|
||||
{0x06BA, 0x06BE, 1},
|
||||
{0x06C0, 0x06CE, 1},
|
||||
{0x06D0, 0x06D3, 1},
|
||||
{0x06D5, 0x06D5, 1},
|
||||
{0x06E5, 0x06E6, 1},
|
||||
{0x0905, 0x0939, 1},
|
||||
{0x093D, 0x093D, 1},
|
||||
{0x0958, 0x0961, 1},
|
||||
{0x0985, 0x098C, 1},
|
||||
{0x098F, 0x0990, 1},
|
||||
{0x0993, 0x09A8, 1},
|
||||
{0x09AA, 0x09B0, 1},
|
||||
{0x09B2, 0x09B2, 1},
|
||||
{0x09B6, 0x09B9, 1},
|
||||
{0x09DC, 0x09DD, 1},
|
||||
{0x09DF, 0x09E1, 1},
|
||||
{0x09F0, 0x09F1, 1},
|
||||
{0x0A05, 0x0A0A, 1},
|
||||
{0x0A0F, 0x0A10, 1},
|
||||
{0x0A13, 0x0A28, 1},
|
||||
{0x0A2A, 0x0A30, 1},
|
||||
{0x0A32, 0x0A33, 1},
|
||||
{0x0A35, 0x0A36, 1},
|
||||
{0x0A38, 0x0A39, 1},
|
||||
{0x0A59, 0x0A5C, 1},
|
||||
{0x0A5E, 0x0A5E, 1},
|
||||
{0x0A72, 0x0A74, 1},
|
||||
{0x0A85, 0x0A8B, 1},
|
||||
{0x0A8D, 0x0A8D, 1},
|
||||
{0x0A8F, 0x0A91, 1},
|
||||
{0x0A93, 0x0AA8, 1},
|
||||
{0x0AAA, 0x0AB0, 1},
|
||||
{0x0AB2, 0x0AB3, 1},
|
||||
{0x0AB5, 0x0AB9, 1},
|
||||
{0x0ABD, 0x0AE0, 0x23},
|
||||
{0x0B05, 0x0B0C, 1},
|
||||
{0x0B0F, 0x0B10, 1},
|
||||
{0x0B13, 0x0B28, 1},
|
||||
{0x0B2A, 0x0B30, 1},
|
||||
{0x0B32, 0x0B33, 1},
|
||||
{0x0B36, 0x0B39, 1},
|
||||
{0x0B3D, 0x0B3D, 1},
|
||||
{0x0B5C, 0x0B5D, 1},
|
||||
{0x0B5F, 0x0B61, 1},
|
||||
{0x0B85, 0x0B8A, 1},
|
||||
{0x0B8E, 0x0B90, 1},
|
||||
{0x0B92, 0x0B95, 1},
|
||||
{0x0B99, 0x0B9A, 1},
|
||||
{0x0B9C, 0x0B9C, 1},
|
||||
{0x0B9E, 0x0B9F, 1},
|
||||
{0x0BA3, 0x0BA4, 1},
|
||||
{0x0BA8, 0x0BAA, 1},
|
||||
{0x0BAE, 0x0BB5, 1},
|
||||
{0x0BB7, 0x0BB9, 1},
|
||||
{0x0C05, 0x0C0C, 1},
|
||||
{0x0C0E, 0x0C10, 1},
|
||||
{0x0C12, 0x0C28, 1},
|
||||
{0x0C2A, 0x0C33, 1},
|
||||
{0x0C35, 0x0C39, 1},
|
||||
{0x0C60, 0x0C61, 1},
|
||||
{0x0C85, 0x0C8C, 1},
|
||||
{0x0C8E, 0x0C90, 1},
|
||||
{0x0C92, 0x0CA8, 1},
|
||||
{0x0CAA, 0x0CB3, 1},
|
||||
{0x0CB5, 0x0CB9, 1},
|
||||
{0x0CDE, 0x0CDE, 1},
|
||||
{0x0CE0, 0x0CE1, 1},
|
||||
{0x0D05, 0x0D0C, 1},
|
||||
{0x0D0E, 0x0D10, 1},
|
||||
{0x0D12, 0x0D28, 1},
|
||||
{0x0D2A, 0x0D39, 1},
|
||||
{0x0D60, 0x0D61, 1},
|
||||
{0x0E01, 0x0E2E, 1},
|
||||
{0x0E30, 0x0E30, 1},
|
||||
{0x0E32, 0x0E33, 1},
|
||||
{0x0E40, 0x0E45, 1},
|
||||
{0x0E81, 0x0E82, 1},
|
||||
{0x0E84, 0x0E84, 1},
|
||||
{0x0E87, 0x0E88, 1},
|
||||
{0x0E8A, 0x0E8D, 3},
|
||||
{0x0E94, 0x0E97, 1},
|
||||
{0x0E99, 0x0E9F, 1},
|
||||
{0x0EA1, 0x0EA3, 1},
|
||||
{0x0EA5, 0x0EA7, 2},
|
||||
{0x0EAA, 0x0EAB, 1},
|
||||
{0x0EAD, 0x0EAE, 1},
|
||||
{0x0EB0, 0x0EB0, 1},
|
||||
{0x0EB2, 0x0EB3, 1},
|
||||
{0x0EBD, 0x0EBD, 1},
|
||||
{0x0EC0, 0x0EC4, 1},
|
||||
{0x0F40, 0x0F47, 1},
|
||||
{0x0F49, 0x0F69, 1},
|
||||
{0x10A0, 0x10C5, 1},
|
||||
{0x10D0, 0x10F6, 1},
|
||||
{0x1100, 0x1100, 1},
|
||||
{0x1102, 0x1103, 1},
|
||||
{0x1105, 0x1107, 1},
|
||||
{0x1109, 0x1109, 1},
|
||||
{0x110B, 0x110C, 1},
|
||||
{0x110E, 0x1112, 1},
|
||||
{0x113C, 0x1140, 2},
|
||||
{0x114C, 0x1150, 2},
|
||||
{0x1154, 0x1155, 1},
|
||||
{0x1159, 0x1159, 1},
|
||||
{0x115F, 0x1161, 1},
|
||||
{0x1163, 0x1169, 2},
|
||||
{0x116D, 0x116E, 1},
|
||||
{0x1172, 0x1173, 1},
|
||||
{0x1175, 0x119E, 0x119E - 0x1175},
|
||||
{0x11A8, 0x11AB, 0x11AB - 0x11A8},
|
||||
{0x11AE, 0x11AF, 1},
|
||||
{0x11B7, 0x11B8, 1},
|
||||
{0x11BA, 0x11BA, 1},
|
||||
{0x11BC, 0x11C2, 1},
|
||||
{0x11EB, 0x11F0, 0x11F0 - 0x11EB},
|
||||
{0x11F9, 0x11F9, 1},
|
||||
{0x1E00, 0x1E9B, 1},
|
||||
{0x1EA0, 0x1EF9, 1},
|
||||
{0x1F00, 0x1F15, 1},
|
||||
{0x1F18, 0x1F1D, 1},
|
||||
{0x1F20, 0x1F45, 1},
|
||||
{0x1F48, 0x1F4D, 1},
|
||||
{0x1F50, 0x1F57, 1},
|
||||
{0x1F59, 0x1F5B, 0x1F5B - 0x1F59},
|
||||
{0x1F5D, 0x1F5D, 1},
|
||||
{0x1F5F, 0x1F7D, 1},
|
||||
{0x1F80, 0x1FB4, 1},
|
||||
{0x1FB6, 0x1FBC, 1},
|
||||
{0x1FBE, 0x1FBE, 1},
|
||||
{0x1FC2, 0x1FC4, 1},
|
||||
{0x1FC6, 0x1FCC, 1},
|
||||
{0x1FD0, 0x1FD3, 1},
|
||||
{0x1FD6, 0x1FDB, 1},
|
||||
{0x1FE0, 0x1FEC, 1},
|
||||
{0x1FF2, 0x1FF4, 1},
|
||||
{0x1FF6, 0x1FFC, 1},
|
||||
{0x2126, 0x2126, 1},
|
||||
{0x212A, 0x212B, 1},
|
||||
{0x212E, 0x212E, 1},
|
||||
{0x2180, 0x2182, 1},
|
||||
{0x3007, 0x3007, 1},
|
||||
{0x3021, 0x3029, 1},
|
||||
{0x3041, 0x3094, 1},
|
||||
{0x30A1, 0x30FA, 1},
|
||||
{0x3105, 0x312C, 1},
|
||||
{0x4E00, 0x9FA5, 1},
|
||||
{0xAC00, 0xD7A3, 1},
|
||||
},
|
||||
}
|
||||
|
||||
var second = &unicode.RangeTable{
|
||||
R16: []unicode.Range16{
|
||||
{0x002D, 0x002E, 1},
|
||||
{0x0030, 0x0039, 1},
|
||||
{0x00B7, 0x00B7, 1},
|
||||
{0x02D0, 0x02D1, 1},
|
||||
{0x0300, 0x0345, 1},
|
||||
{0x0360, 0x0361, 1},
|
||||
{0x0387, 0x0387, 1},
|
||||
{0x0483, 0x0486, 1},
|
||||
{0x0591, 0x05A1, 1},
|
||||
{0x05A3, 0x05B9, 1},
|
||||
{0x05BB, 0x05BD, 1},
|
||||
{0x05BF, 0x05BF, 1},
|
||||
{0x05C1, 0x05C2, 1},
|
||||
{0x05C4, 0x0640, 0x0640 - 0x05C4},
|
||||
{0x064B, 0x0652, 1},
|
||||
{0x0660, 0x0669, 1},
|
||||
{0x0670, 0x0670, 1},
|
||||
{0x06D6, 0x06DC, 1},
|
||||
{0x06DD, 0x06DF, 1},
|
||||
{0x06E0, 0x06E4, 1},
|
||||
{0x06E7, 0x06E8, 1},
|
||||
{0x06EA, 0x06ED, 1},
|
||||
{0x06F0, 0x06F9, 1},
|
||||
{0x0901, 0x0903, 1},
|
||||
{0x093C, 0x093C, 1},
|
||||
{0x093E, 0x094C, 1},
|
||||
{0x094D, 0x094D, 1},
|
||||
{0x0951, 0x0954, 1},
|
||||
{0x0962, 0x0963, 1},
|
||||
{0x0966, 0x096F, 1},
|
||||
{0x0981, 0x0983, 1},
|
||||
{0x09BC, 0x09BC, 1},
|
||||
{0x09BE, 0x09BF, 1},
|
||||
{0x09C0, 0x09C4, 1},
|
||||
{0x09C7, 0x09C8, 1},
|
||||
{0x09CB, 0x09CD, 1},
|
||||
{0x09D7, 0x09D7, 1},
|
||||
{0x09E2, 0x09E3, 1},
|
||||
{0x09E6, 0x09EF, 1},
|
||||
{0x0A02, 0x0A3C, 0x3A},
|
||||
{0x0A3E, 0x0A3F, 1},
|
||||
{0x0A40, 0x0A42, 1},
|
||||
{0x0A47, 0x0A48, 1},
|
||||
{0x0A4B, 0x0A4D, 1},
|
||||
{0x0A66, 0x0A6F, 1},
|
||||
{0x0A70, 0x0A71, 1},
|
||||
{0x0A81, 0x0A83, 1},
|
||||
{0x0ABC, 0x0ABC, 1},
|
||||
{0x0ABE, 0x0AC5, 1},
|
||||
{0x0AC7, 0x0AC9, 1},
|
||||
{0x0ACB, 0x0ACD, 1},
|
||||
{0x0AE6, 0x0AEF, 1},
|
||||
{0x0B01, 0x0B03, 1},
|
||||
{0x0B3C, 0x0B3C, 1},
|
||||
{0x0B3E, 0x0B43, 1},
|
||||
{0x0B47, 0x0B48, 1},
|
||||
{0x0B4B, 0x0B4D, 1},
|
||||
{0x0B56, 0x0B57, 1},
|
||||
{0x0B66, 0x0B6F, 1},
|
||||
{0x0B82, 0x0B83, 1},
|
||||
{0x0BBE, 0x0BC2, 1},
|
||||
{0x0BC6, 0x0BC8, 1},
|
||||
{0x0BCA, 0x0BCD, 1},
|
||||
{0x0BD7, 0x0BD7, 1},
|
||||
{0x0BE7, 0x0BEF, 1},
|
||||
{0x0C01, 0x0C03, 1},
|
||||
{0x0C3E, 0x0C44, 1},
|
||||
{0x0C46, 0x0C48, 1},
|
||||
{0x0C4A, 0x0C4D, 1},
|
||||
{0x0C55, 0x0C56, 1},
|
||||
{0x0C66, 0x0C6F, 1},
|
||||
{0x0C82, 0x0C83, 1},
|
||||
{0x0CBE, 0x0CC4, 1},
|
||||
{0x0CC6, 0x0CC8, 1},
|
||||
{0x0CCA, 0x0CCD, 1},
|
||||
{0x0CD5, 0x0CD6, 1},
|
||||
{0x0CE6, 0x0CEF, 1},
|
||||
{0x0D02, 0x0D03, 1},
|
||||
{0x0D3E, 0x0D43, 1},
|
||||
{0x0D46, 0x0D48, 1},
|
||||
{0x0D4A, 0x0D4D, 1},
|
||||
{0x0D57, 0x0D57, 1},
|
||||
{0x0D66, 0x0D6F, 1},
|
||||
{0x0E31, 0x0E31, 1},
|
||||
{0x0E34, 0x0E3A, 1},
|
||||
{0x0E46, 0x0E46, 1},
|
||||
{0x0E47, 0x0E4E, 1},
|
||||
{0x0E50, 0x0E59, 1},
|
||||
{0x0EB1, 0x0EB1, 1},
|
||||
{0x0EB4, 0x0EB9, 1},
|
||||
{0x0EBB, 0x0EBC, 1},
|
||||
{0x0EC6, 0x0EC6, 1},
|
||||
{0x0EC8, 0x0ECD, 1},
|
||||
{0x0ED0, 0x0ED9, 1},
|
||||
{0x0F18, 0x0F19, 1},
|
||||
{0x0F20, 0x0F29, 1},
|
||||
{0x0F35, 0x0F39, 2},
|
||||
{0x0F3E, 0x0F3F, 1},
|
||||
{0x0F71, 0x0F84, 1},
|
||||
{0x0F86, 0x0F8B, 1},
|
||||
{0x0F90, 0x0F95, 1},
|
||||
{0x0F97, 0x0F97, 1},
|
||||
{0x0F99, 0x0FAD, 1},
|
||||
{0x0FB1, 0x0FB7, 1},
|
||||
{0x0FB9, 0x0FB9, 1},
|
||||
{0x20D0, 0x20DC, 1},
|
||||
{0x20E1, 0x3005, 0x3005 - 0x20E1},
|
||||
{0x302A, 0x302F, 1},
|
||||
{0x3031, 0x3035, 1},
|
||||
{0x3099, 0x309A, 1},
|
||||
{0x309D, 0x309E, 1},
|
||||
{0x30FC, 0x30FE, 1},
|
||||
},
|
||||
}
|
||||
105
vendor/github.com/ChrisTrenkamp/goxpath/marshal.go
generated
vendored
Normal file
105
vendor/github.com/ChrisTrenkamp/goxpath/marshal.go
generated
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
package goxpath
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/xml"
|
||||
"io"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/tree"
|
||||
)
|
||||
|
||||
//Marshal prints the result tree, r, in XML form to w.
|
||||
func Marshal(n tree.Node, w io.Writer) error {
|
||||
return marshal(n, w)
|
||||
}
|
||||
|
||||
//MarshalStr is like Marhal, but returns a string.
|
||||
func MarshalStr(n tree.Node) (string, error) {
|
||||
ret := bytes.NewBufferString("")
|
||||
err := marshal(n, ret)
|
||||
|
||||
return ret.String(), err
|
||||
}
|
||||
|
||||
func marshal(n tree.Node, w io.Writer) error {
|
||||
e := xml.NewEncoder(w)
|
||||
err := encTok(n, e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return e.Flush()
|
||||
}
|
||||
|
||||
func encTok(n tree.Node, e *xml.Encoder) error {
|
||||
switch n.GetNodeType() {
|
||||
case tree.NtAttr:
|
||||
return encAttr(n.GetToken().(xml.Attr), e)
|
||||
case tree.NtElem:
|
||||
return encEle(n.(tree.Elem), e)
|
||||
case tree.NtNs:
|
||||
return encNS(n.GetToken().(xml.Attr), e)
|
||||
case tree.NtRoot:
|
||||
for _, i := range n.(tree.Elem).GetChildren() {
|
||||
err := encTok(i, e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//case tree.NtChd, tree.NtComm, tree.NtPi:
|
||||
return e.EncodeToken(n.GetToken())
|
||||
}
|
||||
|
||||
func encAttr(a xml.Attr, e *xml.Encoder) error {
|
||||
str := a.Name.Local + `="` + a.Value + `"`
|
||||
|
||||
if a.Name.Space != "" {
|
||||
str += ` xmlns="` + a.Name.Space + `"`
|
||||
}
|
||||
|
||||
pi := xml.ProcInst{
|
||||
Target: "attribute",
|
||||
Inst: ([]byte)(str),
|
||||
}
|
||||
|
||||
return e.EncodeToken(pi)
|
||||
}
|
||||
|
||||
func encNS(ns xml.Attr, e *xml.Encoder) error {
|
||||
pi := xml.ProcInst{
|
||||
Target: "namespace",
|
||||
Inst: ([]byte)(ns.Value),
|
||||
}
|
||||
return e.EncodeToken(pi)
|
||||
}
|
||||
|
||||
func encEle(n tree.Elem, e *xml.Encoder) error {
|
||||
ele := xml.StartElement{
|
||||
Name: n.GetToken().(xml.StartElement).Name,
|
||||
}
|
||||
|
||||
attrs := n.GetAttrs()
|
||||
ele.Attr = make([]xml.Attr, len(attrs))
|
||||
for i := range attrs {
|
||||
ele.Attr[i] = attrs[i].GetToken().(xml.Attr)
|
||||
}
|
||||
|
||||
err := e.EncodeToken(ele)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if x, ok := n.(tree.Elem); ok {
|
||||
for _, i := range x.GetChildren() {
|
||||
err := encTok(i, e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return e.EncodeToken(ele.End())
|
||||
}
|
||||
113
vendor/github.com/ChrisTrenkamp/goxpath/parser/ast.go
generated
vendored
Normal file
113
vendor/github.com/ChrisTrenkamp/goxpath/parser/ast.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
package parser
|
||||
|
||||
import "github.com/ChrisTrenkamp/goxpath/lexer"
|
||||
|
||||
//NodeType enumerations
|
||||
const (
|
||||
Empty lexer.XItemType = ""
|
||||
)
|
||||
|
||||
//Node builds an AST tree for operating on XPath expressions
|
||||
type Node struct {
|
||||
Val lexer.XItem
|
||||
Left *Node
|
||||
Right *Node
|
||||
Parent *Node
|
||||
next *Node
|
||||
}
|
||||
|
||||
var beginPathType = map[lexer.XItemType]bool{
|
||||
lexer.XItemAbsLocPath: true,
|
||||
lexer.XItemAbbrAbsLocPath: true,
|
||||
lexer.XItemAbbrRelLocPath: true,
|
||||
lexer.XItemRelLocPath: true,
|
||||
lexer.XItemFunction: true,
|
||||
}
|
||||
|
||||
func (n *Node) add(i lexer.XItem) {
|
||||
if n.Val.Typ == Empty {
|
||||
n.Val = i
|
||||
} else if n.Left == nil && n.Right == nil {
|
||||
n.Left = &Node{Val: n.Val, Parent: n}
|
||||
n.Val = i
|
||||
} else if beginPathType[n.Val.Typ] {
|
||||
next := &Node{Val: n.Val, Left: n.Left, Right: n.Right, Parent: n}
|
||||
n.Left, n.Right = next, nil
|
||||
n.Val = i
|
||||
} else if n.Right == nil {
|
||||
n.Right = &Node{Val: i, Parent: n}
|
||||
} else {
|
||||
next := &Node{Val: n.Val, Left: n.Left, Right: n.Right, Parent: n}
|
||||
n.Left, n.Right = next, nil
|
||||
n.Val = i
|
||||
}
|
||||
n.next = n
|
||||
}
|
||||
|
||||
func (n *Node) push(i lexer.XItem) {
|
||||
if n.Left == nil {
|
||||
n.Left = &Node{Val: i, Parent: n}
|
||||
n.next = n.Left
|
||||
} else if n.Right == nil {
|
||||
n.Right = &Node{Val: i, Parent: n}
|
||||
n.next = n.Right
|
||||
} else {
|
||||
next := &Node{Val: i, Left: n.Right, Parent: n}
|
||||
n.Right = next
|
||||
n.next = n.Right
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Node) pushNotEmpty(i lexer.XItem) {
|
||||
if n.Val.Typ == Empty {
|
||||
n.add(i)
|
||||
} else {
|
||||
n.push(i)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
func (n *Node) prettyPrint(depth, width int) {
|
||||
nodes := []*Node{}
|
||||
n.getLine(depth, &nodes)
|
||||
fmt.Printf("%*s", (width-depth)*2, "")
|
||||
toggle := true
|
||||
if len(nodes) > 1 {
|
||||
for _, i := range nodes {
|
||||
if i != nil {
|
||||
if toggle {
|
||||
fmt.Print("/ ")
|
||||
} else {
|
||||
fmt.Print("\\ ")
|
||||
}
|
||||
}
|
||||
toggle = !toggle
|
||||
}
|
||||
fmt.Println()
|
||||
fmt.Printf("%*s", (width-depth)*2, "")
|
||||
}
|
||||
for _, i := range nodes {
|
||||
if i != nil {
|
||||
fmt.Print(i.Val.Val, " ")
|
||||
}
|
||||
}
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
func (n *Node) getLine(depth int, ret *[]*Node) {
|
||||
if depth <= 0 && n != nil {
|
||||
*ret = append(*ret, n)
|
||||
return
|
||||
}
|
||||
if n.Left != nil {
|
||||
n.Left.getLine(depth-1, ret)
|
||||
} else if depth-1 <= 0 {
|
||||
*ret = append(*ret, nil)
|
||||
}
|
||||
if n.Right != nil {
|
||||
n.Right.getLine(depth-1, ret)
|
||||
} else if depth-1 <= 0 {
|
||||
*ret = append(*ret, nil)
|
||||
}
|
||||
}
|
||||
*/
|
||||
200
vendor/github.com/ChrisTrenkamp/goxpath/parser/parser.go
generated
vendored
Normal file
200
vendor/github.com/ChrisTrenkamp/goxpath/parser/parser.go
generated
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/ChrisTrenkamp/goxpath/lexer"
|
||||
)
|
||||
|
||||
type stateType int
|
||||
|
||||
const (
|
||||
defState stateType = iota
|
||||
xpathState
|
||||
funcState
|
||||
paramState
|
||||
predState
|
||||
parenState
|
||||
)
|
||||
|
||||
type parseStack struct {
|
||||
stack []*Node
|
||||
stateTypes []stateType
|
||||
cur *Node
|
||||
}
|
||||
|
||||
func (p *parseStack) push(t stateType) {
|
||||
p.stack = append(p.stack, p.cur)
|
||||
p.stateTypes = append(p.stateTypes, t)
|
||||
}
|
||||
|
||||
func (p *parseStack) pop() {
|
||||
stackPos := len(p.stack) - 1
|
||||
|
||||
p.cur = p.stack[stackPos]
|
||||
p.stack = p.stack[:stackPos]
|
||||
p.stateTypes = p.stateTypes[:stackPos]
|
||||
}
|
||||
|
||||
func (p *parseStack) curState() stateType {
|
||||
if len(p.stateTypes) == 0 {
|
||||
return defState
|
||||
}
|
||||
return p.stateTypes[len(p.stateTypes)-1]
|
||||
}
|
||||
|
||||
type lexFn func(*parseStack, lexer.XItem)
|
||||
|
||||
var parseMap = map[lexer.XItemType]lexFn{
|
||||
lexer.XItemAbsLocPath: xiXPath,
|
||||
lexer.XItemAbbrAbsLocPath: xiXPath,
|
||||
lexer.XItemAbbrRelLocPath: xiXPath,
|
||||
lexer.XItemRelLocPath: xiXPath,
|
||||
lexer.XItemEndPath: xiEndPath,
|
||||
lexer.XItemAxis: xiXPath,
|
||||
lexer.XItemAbbrAxis: xiXPath,
|
||||
lexer.XItemNCName: xiXPath,
|
||||
lexer.XItemQName: xiXPath,
|
||||
lexer.XItemNodeType: xiXPath,
|
||||
lexer.XItemProcLit: xiXPath,
|
||||
lexer.XItemFunction: xiFunc,
|
||||
lexer.XItemArgument: xiFuncArg,
|
||||
lexer.XItemEndFunction: xiEndFunc,
|
||||
lexer.XItemPredicate: xiPred,
|
||||
lexer.XItemEndPredicate: xiEndPred,
|
||||
lexer.XItemStrLit: xiValue,
|
||||
lexer.XItemNumLit: xiValue,
|
||||
lexer.XItemOperator: xiOp,
|
||||
lexer.XItemVariable: xiValue,
|
||||
}
|
||||
|
||||
var opPrecedence = map[string]int{
|
||||
"|": 1,
|
||||
"*": 2,
|
||||
"div": 2,
|
||||
"mod": 2,
|
||||
"+": 3,
|
||||
"-": 3,
|
||||
"=": 4,
|
||||
"!=": 4,
|
||||
"<": 4,
|
||||
"<=": 4,
|
||||
">": 4,
|
||||
">=": 4,
|
||||
"and": 5,
|
||||
"or": 6,
|
||||
}
|
||||
|
||||
//Parse creates an AST tree for XPath expressions.
|
||||
func Parse(xp string) (*Node, error) {
|
||||
var err error
|
||||
c := lexer.Lex(xp)
|
||||
n := &Node{}
|
||||
p := &parseStack{cur: n}
|
||||
|
||||
for next := range c {
|
||||
if next.Typ != lexer.XItemError {
|
||||
parseMap[next.Typ](p, next)
|
||||
} else if err == nil {
|
||||
err = fmt.Errorf(next.Val)
|
||||
}
|
||||
}
|
||||
|
||||
return n, err
|
||||
}
|
||||
|
||||
func xiXPath(p *parseStack, i lexer.XItem) {
|
||||
if p.curState() == xpathState {
|
||||
p.cur.push(i)
|
||||
p.cur = p.cur.next
|
||||
return
|
||||
}
|
||||
|
||||
if p.cur.Val.Typ == lexer.XItemFunction {
|
||||
p.cur.Right = &Node{Val: i, Parent: p.cur}
|
||||
p.cur.next = p.cur.Right
|
||||
p.push(xpathState)
|
||||
p.cur = p.cur.next
|
||||
return
|
||||
}
|
||||
|
||||
p.cur.pushNotEmpty(i)
|
||||
p.push(xpathState)
|
||||
p.cur = p.cur.next
|
||||
}
|
||||
|
||||
func xiEndPath(p *parseStack, i lexer.XItem) {
|
||||
p.pop()
|
||||
}
|
||||
|
||||
func xiFunc(p *parseStack, i lexer.XItem) {
|
||||
if p.cur.Val.Typ == Empty {
|
||||
p.cur.pushNotEmpty(i)
|
||||
p.push(funcState)
|
||||
p.cur = p.cur.next
|
||||
return
|
||||
}
|
||||
p.cur.push(i)
|
||||
p.cur = p.cur.next
|
||||
p.push(funcState)
|
||||
}
|
||||
|
||||
func xiFuncArg(p *parseStack, i lexer.XItem) {
|
||||
if p.curState() != funcState {
|
||||
p.pop()
|
||||
}
|
||||
|
||||
p.cur.push(i)
|
||||
p.cur = p.cur.next
|
||||
p.push(paramState)
|
||||
p.cur.push(lexer.XItem{Typ: Empty, Val: ""})
|
||||
p.cur = p.cur.next
|
||||
}
|
||||
|
||||
func xiEndFunc(p *parseStack, i lexer.XItem) {
|
||||
if p.curState() == paramState {
|
||||
p.pop()
|
||||
}
|
||||
p.pop()
|
||||
}
|
||||
|
||||
func xiPred(p *parseStack, i lexer.XItem) {
|
||||
p.cur.push(i)
|
||||
p.cur = p.cur.next
|
||||
p.push(predState)
|
||||
p.cur.push(lexer.XItem{Typ: Empty, Val: ""})
|
||||
p.cur = p.cur.next
|
||||
}
|
||||
|
||||
func xiEndPred(p *parseStack, i lexer.XItem) {
|
||||
p.pop()
|
||||
}
|
||||
|
||||
func xiValue(p *parseStack, i lexer.XItem) {
|
||||
p.cur.add(i)
|
||||
}
|
||||
|
||||
func xiOp(p *parseStack, i lexer.XItem) {
|
||||
if i.Val == "(" {
|
||||
p.cur.push(lexer.XItem{Typ: Empty, Val: ""})
|
||||
p.push(parenState)
|
||||
p.cur = p.cur.next
|
||||
return
|
||||
}
|
||||
|
||||
if i.Val == ")" {
|
||||
p.pop()
|
||||
return
|
||||
}
|
||||
|
||||
if p.cur.Val.Typ == lexer.XItemOperator {
|
||||
if opPrecedence[p.cur.Val.Val] <= opPrecedence[i.Val] {
|
||||
p.cur.add(i)
|
||||
} else {
|
||||
p.cur.push(i)
|
||||
}
|
||||
} else {
|
||||
p.cur.add(i)
|
||||
}
|
||||
p.cur = p.cur.next
|
||||
}
|
||||
11
vendor/github.com/ChrisTrenkamp/goxpath/parser/pathexpr/pathexpr.go
generated
vendored
Normal file
11
vendor/github.com/ChrisTrenkamp/goxpath/parser/pathexpr/pathexpr.go
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
package pathexpr
|
||||
|
||||
import "encoding/xml"
|
||||
|
||||
//PathExpr represents XPath step's. xmltree.XMLTree uses it to find nodes.
|
||||
type PathExpr struct {
|
||||
Name xml.Name
|
||||
Axis string
|
||||
NodeType string
|
||||
NS map[string]string
|
||||
}
|
||||
18
vendor/github.com/ChrisTrenkamp/goxpath/tree/interfaces.go
generated
vendored
Normal file
18
vendor/github.com/ChrisTrenkamp/goxpath/tree/interfaces.go
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
package tree
|
||||
|
||||
import "fmt"
|
||||
|
||||
//Result is used for all data types.
|
||||
type Result interface {
|
||||
fmt.Stringer
|
||||
}
|
||||
|
||||
//IsBool is used for the XPath boolean function. It turns the data type to a bool.
|
||||
type IsBool interface {
|
||||
Bool() Bool
|
||||
}
|
||||
|
||||
//IsNum is used for the XPath number function. It turns the data type to a number.
|
||||
type IsNum interface {
|
||||
Num() Num
|
||||
}
|
||||
221
vendor/github.com/ChrisTrenkamp/goxpath/tree/tree.go
generated
vendored
Normal file
221
vendor/github.com/ChrisTrenkamp/goxpath/tree/tree.go
generated
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
package tree
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"sort"
|
||||
)
|
||||
|
||||
//XMLSpace is the W3C XML namespace
|
||||
const XMLSpace = "http://www.w3.org/XML/1998/namespace"
|
||||
|
||||
//NodePos is a helper for representing the node's document order
|
||||
type NodePos int
|
||||
|
||||
//Pos returns the node's document order position
|
||||
func (n NodePos) Pos() int {
|
||||
return int(n)
|
||||
}
|
||||
|
||||
//NodeType is a safer way to determine a node's type than type assertions.
|
||||
type NodeType int
|
||||
|
||||
//GetNodeType returns the node's type.
|
||||
func (t NodeType) GetNodeType() NodeType {
|
||||
return t
|
||||
}
|
||||
|
||||
//These are all the possible node types
|
||||
const (
|
||||
NtAttr NodeType = iota
|
||||
NtChd
|
||||
NtComm
|
||||
NtElem
|
||||
NtNs
|
||||
NtRoot
|
||||
NtPi
|
||||
)
|
||||
|
||||
//Node is a XPath result that is a node except elements
|
||||
type Node interface {
|
||||
//ResValue prints the node's string value
|
||||
ResValue() string
|
||||
//Pos returns the node's position in the document order
|
||||
Pos() int
|
||||
//GetToken returns the xml.Token representation of the node
|
||||
GetToken() xml.Token
|
||||
//GetParent returns the parent node, which will always be an XML element
|
||||
GetParent() Elem
|
||||
//GetNodeType returns the node's type
|
||||
GetNodeType() NodeType
|
||||
}
|
||||
|
||||
//Elem is a XPath result that is an element node
|
||||
type Elem interface {
|
||||
Node
|
||||
//GetChildren returns the elements children.
|
||||
GetChildren() []Node
|
||||
//GetAttrs returns the attributes of the element
|
||||
GetAttrs() []Node
|
||||
}
|
||||
|
||||
//NSElem is a node that keeps track of namespaces.
|
||||
type NSElem interface {
|
||||
Elem
|
||||
GetNS() map[xml.Name]string
|
||||
}
|
||||
|
||||
//NSBuilder is a helper-struct for satisfying the NSElem interface
|
||||
type NSBuilder struct {
|
||||
NS map[xml.Name]string
|
||||
}
|
||||
|
||||
//GetNS returns the namespaces found on the current element. It should not be
|
||||
//confused with BuildNS, which actually resolves the namespace nodes.
|
||||
func (ns NSBuilder) GetNS() map[xml.Name]string {
|
||||
return ns.NS
|
||||
}
|
||||
|
||||
type nsValueSort []NS
|
||||
|
||||
func (ns nsValueSort) Len() int { return len(ns) }
|
||||
func (ns nsValueSort) Swap(i, j int) {
|
||||
ns[i], ns[j] = ns[j], ns[i]
|
||||
}
|
||||
func (ns nsValueSort) Less(i, j int) bool {
|
||||
return ns[i].Value < ns[j].Value
|
||||
}
|
||||
|
||||
//BuildNS resolves all the namespace nodes of the element and returns them
|
||||
func BuildNS(t Elem) (ret []NS) {
|
||||
vals := make(map[xml.Name]string)
|
||||
|
||||
if nselem, ok := t.(NSElem); ok {
|
||||
buildNS(nselem, vals)
|
||||
|
||||
ret = make([]NS, 0, len(vals))
|
||||
i := 1
|
||||
|
||||
for k, v := range vals {
|
||||
if !(k.Local == "xmlns" && k.Space == "" && v == "") {
|
||||
ret = append(ret, NS{
|
||||
Attr: xml.Attr{Name: k, Value: v},
|
||||
Parent: t,
|
||||
NodeType: NtNs,
|
||||
})
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(nsValueSort(ret))
|
||||
for i := range ret {
|
||||
ret[i].NodePos = NodePos(t.Pos() + i + 1)
|
||||
}
|
||||
}
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
func buildNS(x NSElem, ret map[xml.Name]string) {
|
||||
if x.GetNodeType() == NtRoot {
|
||||
return
|
||||
}
|
||||
|
||||
if nselem, ok := x.GetParent().(NSElem); ok {
|
||||
buildNS(nselem, ret)
|
||||
}
|
||||
|
||||
for k, v := range x.GetNS() {
|
||||
ret[k] = v
|
||||
}
|
||||
}
|
||||
|
||||
//NS is a namespace node.
|
||||
type NS struct {
|
||||
xml.Attr
|
||||
Parent Elem
|
||||
NodePos
|
||||
NodeType
|
||||
}
|
||||
|
||||
//GetToken returns the xml.Token representation of the namespace.
|
||||
func (ns NS) GetToken() xml.Token {
|
||||
return ns.Attr
|
||||
}
|
||||
|
||||
//GetParent returns the parent node of the namespace.
|
||||
func (ns NS) GetParent() Elem {
|
||||
return ns.Parent
|
||||
}
|
||||
|
||||
//ResValue returns the string value of the namespace
|
||||
func (ns NS) ResValue() string {
|
||||
return ns.Attr.Value
|
||||
}
|
||||
|
||||
//GetAttribute is a convenience function for getting the specified attribute from an element.
|
||||
//false is returned if the attribute is not found.
|
||||
func GetAttribute(n Elem, local, space string) (xml.Attr, bool) {
|
||||
attrs := n.GetAttrs()
|
||||
for _, i := range attrs {
|
||||
attr := i.GetToken().(xml.Attr)
|
||||
if local == attr.Name.Local && space == attr.Name.Space {
|
||||
return attr, true
|
||||
}
|
||||
}
|
||||
return xml.Attr{}, false
|
||||
}
|
||||
|
||||
//GetAttributeVal is like GetAttribute, except it returns the attribute's value.
|
||||
func GetAttributeVal(n Elem, local, space string) (string, bool) {
|
||||
attr, ok := GetAttribute(n, local, space)
|
||||
return attr.Value, ok
|
||||
}
|
||||
|
||||
//GetAttrValOrEmpty is like GetAttributeVal, except it returns an empty string if
|
||||
//the attribute is not found instead of false.
|
||||
func GetAttrValOrEmpty(n Elem, local, space string) string {
|
||||
val, ok := GetAttributeVal(n, local, space)
|
||||
if !ok {
|
||||
return ""
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
//FindNodeByPos finds a node from the given position. Returns nil if the node
|
||||
//is not found.
|
||||
func FindNodeByPos(n Node, pos int) Node {
|
||||
if n.Pos() == pos {
|
||||
return n
|
||||
}
|
||||
|
||||
if elem, ok := n.(Elem); ok {
|
||||
chldrn := elem.GetChildren()
|
||||
for i := 1; i < len(chldrn); i++ {
|
||||
if chldrn[i-1].Pos() <= pos && chldrn[i].Pos() > pos {
|
||||
return FindNodeByPos(chldrn[i-1], pos)
|
||||
}
|
||||
}
|
||||
|
||||
if len(chldrn) > 0 {
|
||||
if chldrn[len(chldrn)-1].Pos() <= pos {
|
||||
return FindNodeByPos(chldrn[len(chldrn)-1], pos)
|
||||
}
|
||||
}
|
||||
|
||||
attrs := elem.GetAttrs()
|
||||
for _, i := range attrs {
|
||||
if i.Pos() == pos {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
ns := BuildNS(elem)
|
||||
for _, i := range ns {
|
||||
if i.Pos() == pos {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
52
vendor/github.com/ChrisTrenkamp/goxpath/tree/xfn.go
generated
vendored
Normal file
52
vendor/github.com/ChrisTrenkamp/goxpath/tree/xfn.go
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
package tree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
//Ctx represents the current context position, size, node, and the current filtered result
|
||||
type Ctx struct {
|
||||
NodeSet
|
||||
Pos int
|
||||
Size int
|
||||
}
|
||||
|
||||
//Fn is a XPath function, written in Go
|
||||
type Fn func(c Ctx, args ...Result) (Result, error)
|
||||
|
||||
//LastArgOpt sets whether the last argument in a function is optional, variadic, or neither
|
||||
type LastArgOpt int
|
||||
|
||||
//LastArgOpt options
|
||||
const (
|
||||
None LastArgOpt = iota
|
||||
Optional
|
||||
Variadic
|
||||
)
|
||||
|
||||
//Wrap interfaces XPath function calls with Go
|
||||
type Wrap struct {
|
||||
Fn Fn
|
||||
//NArgs represents the number of arguments to the XPath function. -1 represents a single optional argument
|
||||
NArgs int
|
||||
LastArgOpt LastArgOpt
|
||||
}
|
||||
|
||||
//Call checks the arguments and calls Fn if they are valid
|
||||
func (w Wrap) Call(c Ctx, args ...Result) (Result, error) {
|
||||
switch w.LastArgOpt {
|
||||
case Optional:
|
||||
if len(args) == w.NArgs || len(args) == w.NArgs-1 {
|
||||
return w.Fn(c, args...)
|
||||
}
|
||||
case Variadic:
|
||||
if len(args) >= w.NArgs-1 {
|
||||
return w.Fn(c, args...)
|
||||
}
|
||||
default:
|
||||
if len(args) == w.NArgs {
|
||||
return w.Fn(c, args...)
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("Invalid number of arguments")
|
||||
}
|
||||
113
vendor/github.com/ChrisTrenkamp/goxpath/tree/xtypes.go
generated
vendored
Normal file
113
vendor/github.com/ChrisTrenkamp/goxpath/tree/xtypes.go
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
package tree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
//Boolean strings
|
||||
const (
|
||||
True = "true"
|
||||
False = "false"
|
||||
)
|
||||
|
||||
//Bool is a boolean XPath type
|
||||
type Bool bool
|
||||
|
||||
//ResValue satisfies the Res interface for Bool
|
||||
func (b Bool) String() string {
|
||||
if b {
|
||||
return True
|
||||
}
|
||||
|
||||
return False
|
||||
}
|
||||
|
||||
//Bool satisfies the HasBool interface for Bool's
|
||||
func (b Bool) Bool() Bool {
|
||||
return b
|
||||
}
|
||||
|
||||
//Num satisfies the HasNum interface for Bool's
|
||||
func (b Bool) Num() Num {
|
||||
if b {
|
||||
return Num(1)
|
||||
}
|
||||
|
||||
return Num(0)
|
||||
}
|
||||
|
||||
//Num is a number XPath type
|
||||
type Num float64
|
||||
|
||||
//ResValue satisfies the Res interface for Num
|
||||
func (n Num) String() string {
|
||||
if math.IsInf(float64(n), 0) {
|
||||
if math.IsInf(float64(n), 1) {
|
||||
return "Infinity"
|
||||
}
|
||||
return "-Infinity"
|
||||
}
|
||||
return fmt.Sprintf("%g", float64(n))
|
||||
}
|
||||
|
||||
//Bool satisfies the HasBool interface for Num's
|
||||
func (n Num) Bool() Bool {
|
||||
return n != 0
|
||||
}
|
||||
|
||||
//Num satisfies the HasNum interface for Num's
|
||||
func (n Num) Num() Num {
|
||||
return n
|
||||
}
|
||||
|
||||
//String is string XPath type
|
||||
type String string
|
||||
|
||||
//ResValue satisfies the Res interface for String
|
||||
func (s String) String() string {
|
||||
return string(s)
|
||||
}
|
||||
|
||||
//Bool satisfies the HasBool interface for String's
|
||||
func (s String) Bool() Bool {
|
||||
return Bool(len(s) > 0)
|
||||
}
|
||||
|
||||
//Num satisfies the HasNum interface for String's
|
||||
func (s String) Num() Num {
|
||||
num, err := strconv.ParseFloat(strings.TrimSpace(string(s)), 64)
|
||||
if err != nil {
|
||||
return Num(math.NaN())
|
||||
}
|
||||
return Num(num)
|
||||
}
|
||||
|
||||
//NodeSet is a node-set XPath type
|
||||
type NodeSet []Node
|
||||
|
||||
//GetNodeNum converts the node to a string-value and to a number
|
||||
func GetNodeNum(n Node) Num {
|
||||
return String(n.ResValue()).Num()
|
||||
}
|
||||
|
||||
//String satisfies the Res interface for NodeSet
|
||||
func (n NodeSet) String() string {
|
||||
if len(n) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return n[0].ResValue()
|
||||
}
|
||||
|
||||
//Bool satisfies the HasBool interface for node-set's
|
||||
func (n NodeSet) Bool() Bool {
|
||||
return Bool(len(n) > 0)
|
||||
}
|
||||
|
||||
//Num satisfies the HasNum interface for NodeSet's
|
||||
func (n NodeSet) Num() Num {
|
||||
return String(n.String()).Num()
|
||||
}
|
||||
66
vendor/github.com/ChrisTrenkamp/goxpath/xconst/xconst.go
generated
vendored
Normal file
66
vendor/github.com/ChrisTrenkamp/goxpath/xconst/xconst.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package xconst
|
||||
|
||||
const (
|
||||
//AxisAncestor represents the "ancestor" axis
|
||||
AxisAncestor = "ancestor"
|
||||
//AxisAncestorOrSelf represents the "ancestor-or-self" axis
|
||||
AxisAncestorOrSelf = "ancestor-or-self"
|
||||
//AxisAttribute represents the "attribute" axis
|
||||
AxisAttribute = "attribute"
|
||||
//AxisChild represents the "child" axis
|
||||
AxisChild = "child"
|
||||
//AxisDescendent represents the "descendant" axis
|
||||
AxisDescendent = "descendant"
|
||||
//AxisDescendentOrSelf represents the "descendant-or-self" axis
|
||||
AxisDescendentOrSelf = "descendant-or-self"
|
||||
//AxisFollowing represents the "following" axis
|
||||
AxisFollowing = "following"
|
||||
//AxisFollowingSibling represents the "following-sibling" axis
|
||||
AxisFollowingSibling = "following-sibling"
|
||||
//AxisNamespace represents the "namespace" axis
|
||||
AxisNamespace = "namespace"
|
||||
//AxisParent represents the "parent" axis
|
||||
AxisParent = "parent"
|
||||
//AxisPreceding represents the "preceding" axis
|
||||
AxisPreceding = "preceding"
|
||||
//AxisPrecedingSibling represents the "preceding-sibling" axis
|
||||
AxisPrecedingSibling = "preceding-sibling"
|
||||
//AxisSelf represents the "self" axis
|
||||
AxisSelf = "self"
|
||||
)
|
||||
|
||||
//AxisNames is all the possible Axis identifiers wrapped in an array for convenience
|
||||
var AxisNames = []string{
|
||||
AxisAncestor,
|
||||
AxisAncestorOrSelf,
|
||||
AxisAttribute,
|
||||
AxisChild,
|
||||
AxisDescendent,
|
||||
AxisDescendentOrSelf,
|
||||
AxisFollowing,
|
||||
AxisFollowingSibling,
|
||||
AxisNamespace,
|
||||
AxisParent,
|
||||
AxisPreceding,
|
||||
AxisPrecedingSibling,
|
||||
AxisSelf,
|
||||
}
|
||||
|
||||
const (
|
||||
//NodeTypeComment represents the "comment" node test
|
||||
NodeTypeComment = "comment"
|
||||
//NodeTypeText represents the "text" node test
|
||||
NodeTypeText = "text"
|
||||
//NodeTypeProcInst represents the "processing-instruction" node test
|
||||
NodeTypeProcInst = "processing-instruction"
|
||||
//NodeTypeNode represents the "node" node test
|
||||
NodeTypeNode = "node"
|
||||
)
|
||||
|
||||
//NodeTypes is all the possible node tests wrapped in an array for convenience
|
||||
var NodeTypes = []string{
|
||||
NodeTypeComment,
|
||||
NodeTypeText,
|
||||
NodeTypeProcInst,
|
||||
NodeTypeNode,
|
||||
}
|
||||
1
vendor/github.com/Masterminds/squirrel/.gitignore
generated
vendored
Normal file
1
vendor/github.com/Masterminds/squirrel/.gitignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
squirrel.test
|
||||
30
vendor/github.com/Masterminds/squirrel/.travis.yml
generated
vendored
Normal file
30
vendor/github.com/Masterminds/squirrel/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.11.x
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
|
||||
services:
|
||||
- mysql
|
||||
- postgresql
|
||||
|
||||
# Setting sudo access to false will let Travis CI use containers rather than
|
||||
# VMs to run the tests. For more details see:
|
||||
# - http://docs.travis-ci.com/user/workers/container-based-infrastructure/
|
||||
# - http://docs.travis-ci.com/user/workers/standard-infrastructure/
|
||||
sudo: false
|
||||
|
||||
before_script:
|
||||
- mysql -e 'CREATE DATABASE squirrel;'
|
||||
- psql -c 'CREATE DATABASE squirrel;' -U postgres
|
||||
|
||||
script:
|
||||
- go test
|
||||
- cd integration
|
||||
- go test -args -driver sqlite3
|
||||
- go test -args -driver mysql -dataSource travis@/squirrel
|
||||
- go test -args -driver postgres -dataSource 'postgres://postgres@localhost/squirrel?sslmode=disable'
|
||||
|
||||
notifications:
|
||||
irc: "irc.freenode.net#masterminds"
|
||||
23
vendor/github.com/Masterminds/squirrel/LICENSE.txt
generated
vendored
Normal file
23
vendor/github.com/Masterminds/squirrel/LICENSE.txt
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
Squirrel
|
||||
The Masterminds
|
||||
Copyright (C) 2014-2015, Lann Martin
|
||||
Copyright (C) 2015-2016, Google
|
||||
Copyright (C) 2015, Matt Farina and Matt Butcher
|
||||
|
||||
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.
|
||||
142
vendor/github.com/Masterminds/squirrel/README.md
generated
vendored
Normal file
142
vendor/github.com/Masterminds/squirrel/README.md
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
[](https://www.repostatus.org/#inactive)
|
||||
### Squirrel is "complete".
|
||||
Bug fixes will still be merged (slowly). Bug reports are welcome, but I will not necessarily respond to them. If another fork (or substantially similar project) actively improves on what Squirrel does, let me know and I may link to it here.
|
||||
|
||||
|
||||
# Squirrel - fluent SQL generator for Go
|
||||
|
||||
```go
|
||||
import "github.com/Masterminds/squirrel"
|
||||
```
|
||||
|
||||
|
||||
[](https://godoc.org/github.com/Masterminds/squirrel)
|
||||
[](https://travis-ci.org/Masterminds/squirrel)
|
||||
|
||||
**Squirrel is not an ORM.** For an application of Squirrel, check out
|
||||
[structable, a table-struct mapper](https://github.com/Masterminds/structable)
|
||||
|
||||
|
||||
Squirrel helps you build SQL queries from composable parts:
|
||||
|
||||
```go
|
||||
import sq "github.com/Masterminds/squirrel"
|
||||
|
||||
users := sq.Select("*").From("users").Join("emails USING (email_id)")
|
||||
|
||||
active := users.Where(sq.Eq{"deleted_at": nil})
|
||||
|
||||
sql, args, err := active.ToSql()
|
||||
|
||||
sql == "SELECT * FROM users JOIN emails USING (email_id) WHERE deleted_at IS NULL"
|
||||
```
|
||||
|
||||
```go
|
||||
sql, args, err := sq.
|
||||
Insert("users").Columns("name", "age").
|
||||
Values("moe", 13).Values("larry", sq.Expr("? + 5", 12)).
|
||||
ToSql()
|
||||
|
||||
sql == "INSERT INTO users (name,age) VALUES (?,?),(?,? + 5)"
|
||||
```
|
||||
|
||||
Squirrel can also execute queries directly:
|
||||
|
||||
```go
|
||||
stooges := users.Where(sq.Eq{"username": []string{"moe", "larry", "curly", "shemp"}})
|
||||
three_stooges := stooges.Limit(3)
|
||||
rows, err := three_stooges.RunWith(db).Query()
|
||||
|
||||
// Behaves like:
|
||||
rows, err := db.Query("SELECT * FROM users WHERE username IN (?,?,?,?) LIMIT 3",
|
||||
"moe", "larry", "curly", "shemp")
|
||||
```
|
||||
|
||||
Squirrel makes conditional query building a breeze:
|
||||
|
||||
```go
|
||||
if len(q) > 0 {
|
||||
users = users.Where("name LIKE ?", fmt.Sprint("%", q, "%"))
|
||||
}
|
||||
```
|
||||
|
||||
Squirrel wants to make your life easier:
|
||||
|
||||
```go
|
||||
// StmtCache caches Prepared Stmts for you
|
||||
dbCache := sq.NewStmtCacher(db)
|
||||
|
||||
// StatementBuilder keeps your syntax neat
|
||||
mydb := sq.StatementBuilder.RunWith(dbCache)
|
||||
select_users := mydb.Select("*").From("users")
|
||||
```
|
||||
|
||||
Squirrel loves PostgreSQL:
|
||||
|
||||
```go
|
||||
psql := sq.StatementBuilder.PlaceholderFormat(sq.Dollar)
|
||||
|
||||
// You use question marks for placeholders...
|
||||
sql, _, _ := psql.Select("*").From("elephants").Where("name IN (?,?)", "Dumbo", "Verna").ToSql()
|
||||
|
||||
/// ...squirrel replaces them using PlaceholderFormat.
|
||||
sql == "SELECT * FROM elephants WHERE name IN ($1,$2)"
|
||||
|
||||
|
||||
/// You can retrieve id ...
|
||||
query := sq.Insert("nodes").
|
||||
Columns("uuid", "type", "data").
|
||||
Values(node.Uuid, node.Type, node.Data).
|
||||
Suffix("RETURNING \"id\"").
|
||||
RunWith(m.db).
|
||||
PlaceholderFormat(sq.Dollar)
|
||||
|
||||
query.QueryRow().Scan(&node.id)
|
||||
```
|
||||
|
||||
You can escape question marks by inserting two question marks:
|
||||
|
||||
```sql
|
||||
SELECT * FROM nodes WHERE meta->'format' ??| array[?,?]
|
||||
```
|
||||
|
||||
will generate with the Dollar Placeholder:
|
||||
|
||||
```sql
|
||||
SELECT * FROM nodes WHERE meta->'format' ?| array[$1,$2]
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
* **How can I build an IN query on composite keys / tuples, e.g. `WHERE (col1, col2) IN ((1,2),(3,4))`? ([#104](https://github.com/Masterminds/squirrel/issues/104))**
|
||||
|
||||
Squirrel does not explicitly support tuples, but you can get the same effect with e.g.:
|
||||
|
||||
```go
|
||||
sq.Or{
|
||||
sq.Eq{"col1": 1, "col2": 2},
|
||||
sq.Eq{"col1": 3, "col2": 4}}
|
||||
```
|
||||
|
||||
```sql
|
||||
WHERE (col1 = 1 AND col2 = 2) OR (col1 = 3 AND col2 = 4)
|
||||
```
|
||||
|
||||
(which should produce the same query plan as the tuple version)
|
||||
|
||||
* **Why doesn't `Eq{"mynumber": []uint8{1,2,3}}` turn into an `IN` query? ([#114](https://github.com/Masterminds/squirrel/issues/114))**
|
||||
|
||||
Values of type `[]byte` are handled specially by `database/sql`. In Go, [`byte` is just an alias of `uint8`](https://golang.org/pkg/builtin/#byte), so there is no way to distinguish `[]uint8` from `[]byte`.
|
||||
|
||||
* **Some features are poorly documented!**
|
||||
|
||||
This isn't a frequent complaints section!
|
||||
|
||||
* **Some features are poorly documented?**
|
||||
|
||||
Yes. The tests should be considered a part of the documentation; take a look at those for ideas on how to express more complex queries.
|
||||
|
||||
## License
|
||||
|
||||
Squirrel is released under the
|
||||
[MIT License](http://www.opensource.org/licenses/MIT).
|
||||
118
vendor/github.com/Masterminds/squirrel/case.go
generated
vendored
Normal file
118
vendor/github.com/Masterminds/squirrel/case.go
generated
vendored
Normal file
@@ -0,0 +1,118 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
func init() {
|
||||
builder.Register(CaseBuilder{}, caseData{})
|
||||
}
|
||||
|
||||
// sqlizerBuffer is a helper that allows to write many Sqlizers one by one
|
||||
// without constant checks for errors that may come from Sqlizer
|
||||
type sqlizerBuffer struct {
|
||||
bytes.Buffer
|
||||
args []interface{}
|
||||
err error
|
||||
}
|
||||
|
||||
// WriteSql converts Sqlizer to SQL strings and writes it to buffer
|
||||
func (b *sqlizerBuffer) WriteSql(item Sqlizer) {
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var str string
|
||||
var args []interface{}
|
||||
str, args, b.err = item.ToSql()
|
||||
|
||||
if b.err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
b.WriteString(str)
|
||||
b.WriteByte(' ')
|
||||
b.args = append(b.args, args...)
|
||||
}
|
||||
|
||||
func (b *sqlizerBuffer) ToSql() (string, []interface{}, error) {
|
||||
return b.String(), b.args, b.err
|
||||
}
|
||||
|
||||
// whenPart is a helper structure to describe SQLs "WHEN ... THEN ..." expression
|
||||
type whenPart struct {
|
||||
when Sqlizer
|
||||
then Sqlizer
|
||||
}
|
||||
|
||||
func newWhenPart(when interface{}, then interface{}) whenPart {
|
||||
return whenPart{newPart(when), newPart(then)}
|
||||
}
|
||||
|
||||
// caseData holds all the data required to build a CASE SQL construct
|
||||
type caseData struct {
|
||||
What Sqlizer
|
||||
WhenParts []whenPart
|
||||
Else Sqlizer
|
||||
}
|
||||
|
||||
// ToSql implements Sqlizer
|
||||
func (d *caseData) ToSql() (sqlStr string, args []interface{}, err error) {
|
||||
if len(d.WhenParts) == 0 {
|
||||
err = errors.New("case expression must contain at lease one WHEN clause")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
sql := sqlizerBuffer{}
|
||||
|
||||
sql.WriteString("CASE ")
|
||||
if d.What != nil {
|
||||
sql.WriteSql(d.What)
|
||||
}
|
||||
|
||||
for _, p := range d.WhenParts {
|
||||
sql.WriteString("WHEN ")
|
||||
sql.WriteSql(p.when)
|
||||
sql.WriteString("THEN ")
|
||||
sql.WriteSql(p.then)
|
||||
}
|
||||
|
||||
if d.Else != nil {
|
||||
sql.WriteString("ELSE ")
|
||||
sql.WriteSql(d.Else)
|
||||
}
|
||||
|
||||
sql.WriteString("END")
|
||||
|
||||
return sql.ToSql()
|
||||
}
|
||||
|
||||
// CaseBuilder builds SQL CASE construct which could be used as parts of queries.
|
||||
type CaseBuilder builder.Builder
|
||||
|
||||
// ToSql builds the query into a SQL string and bound args.
|
||||
func (b CaseBuilder) ToSql() (string, []interface{}, error) {
|
||||
data := builder.GetStruct(b).(caseData)
|
||||
return data.ToSql()
|
||||
}
|
||||
|
||||
// what sets optional value for CASE construct "CASE [value] ..."
|
||||
func (b CaseBuilder) what(expr interface{}) CaseBuilder {
|
||||
return builder.Set(b, "What", newPart(expr)).(CaseBuilder)
|
||||
}
|
||||
|
||||
// When adds "WHEN ... THEN ..." part to CASE construct
|
||||
func (b CaseBuilder) When(when interface{}, then interface{}) CaseBuilder {
|
||||
// TODO: performance hint: replace slice of WhenPart with just slice of parts
|
||||
// where even indices of the slice belong to "when"s and odd indices belong to "then"s
|
||||
return builder.Append(b, "WhenParts", newWhenPart(when, then)).(CaseBuilder)
|
||||
}
|
||||
|
||||
// What sets optional "ELSE ..." part for CASE construct
|
||||
func (b CaseBuilder) Else(expr interface{}) CaseBuilder {
|
||||
return builder.Set(b, "Else", newPart(expr)).(CaseBuilder)
|
||||
}
|
||||
181
vendor/github.com/Masterminds/squirrel/delete.go
generated
vendored
Normal file
181
vendor/github.com/Masterminds/squirrel/delete.go
generated
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
type deleteData struct {
|
||||
PlaceholderFormat PlaceholderFormat
|
||||
RunWith BaseRunner
|
||||
Prefixes []Sqlizer
|
||||
From string
|
||||
WhereParts []Sqlizer
|
||||
OrderBys []string
|
||||
Limit string
|
||||
Offset string
|
||||
Suffixes []Sqlizer
|
||||
}
|
||||
|
||||
func (d *deleteData) Exec() (sql.Result, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return ExecWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *deleteData) ToSql() (sqlStr string, args []interface{}, err error) {
|
||||
if len(d.From) == 0 {
|
||||
err = fmt.Errorf("delete statements must specify a From table")
|
||||
return
|
||||
}
|
||||
|
||||
sql := &bytes.Buffer{}
|
||||
|
||||
if len(d.Prefixes) > 0 {
|
||||
args, err = appendToSql(d.Prefixes, sql, " ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
sql.WriteString("DELETE FROM ")
|
||||
sql.WriteString(d.From)
|
||||
|
||||
if len(d.WhereParts) > 0 {
|
||||
sql.WriteString(" WHERE ")
|
||||
args, err = appendToSql(d.WhereParts, sql, " AND ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.OrderBys) > 0 {
|
||||
sql.WriteString(" ORDER BY ")
|
||||
sql.WriteString(strings.Join(d.OrderBys, ", "))
|
||||
}
|
||||
|
||||
if len(d.Limit) > 0 {
|
||||
sql.WriteString(" LIMIT ")
|
||||
sql.WriteString(d.Limit)
|
||||
}
|
||||
|
||||
if len(d.Offset) > 0 {
|
||||
sql.WriteString(" OFFSET ")
|
||||
sql.WriteString(d.Offset)
|
||||
}
|
||||
|
||||
if len(d.Suffixes) > 0 {
|
||||
sql.WriteString(" ")
|
||||
args, err = appendToSql(d.Suffixes, sql, " ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
|
||||
return
|
||||
}
|
||||
|
||||
// Builder
|
||||
|
||||
// DeleteBuilder builds SQL DELETE statements.
|
||||
type DeleteBuilder builder.Builder
|
||||
|
||||
func init() {
|
||||
builder.Register(DeleteBuilder{}, deleteData{})
|
||||
}
|
||||
|
||||
// Format methods
|
||||
|
||||
// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
|
||||
// query.
|
||||
func (b DeleteBuilder) PlaceholderFormat(f PlaceholderFormat) DeleteBuilder {
|
||||
return builder.Set(b, "PlaceholderFormat", f).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// Runner methods
|
||||
|
||||
// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
|
||||
func (b DeleteBuilder) RunWith(runner BaseRunner) DeleteBuilder {
|
||||
return setRunWith(b, runner).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// Exec builds and Execs the query with the Runner set by RunWith.
|
||||
func (b DeleteBuilder) Exec() (sql.Result, error) {
|
||||
data := builder.GetStruct(b).(deleteData)
|
||||
return data.Exec()
|
||||
}
|
||||
|
||||
// SQL methods
|
||||
|
||||
// ToSql builds the query into a SQL string and bound args.
|
||||
func (b DeleteBuilder) ToSql() (string, []interface{}, error) {
|
||||
data := builder.GetStruct(b).(deleteData)
|
||||
return data.ToSql()
|
||||
}
|
||||
|
||||
// Prefix adds an expression to the beginning of the query
|
||||
func (b DeleteBuilder) Prefix(sql string, args ...interface{}) DeleteBuilder {
|
||||
return b.PrefixExpr(Expr(sql, args...))
|
||||
}
|
||||
|
||||
// PrefixExpr adds an expression to the very beginning of the query
|
||||
func (b DeleteBuilder) PrefixExpr(expr Sqlizer) DeleteBuilder {
|
||||
return builder.Append(b, "Prefixes", expr).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// From sets the table to be deleted from.
|
||||
func (b DeleteBuilder) From(from string) DeleteBuilder {
|
||||
return builder.Set(b, "From", from).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// Where adds WHERE expressions to the query.
|
||||
//
|
||||
// See SelectBuilder.Where for more information.
|
||||
func (b DeleteBuilder) Where(pred interface{}, args ...interface{}) DeleteBuilder {
|
||||
return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// OrderBy adds ORDER BY expressions to the query.
|
||||
func (b DeleteBuilder) OrderBy(orderBys ...string) DeleteBuilder {
|
||||
return builder.Extend(b, "OrderBys", orderBys).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// Limit sets a LIMIT clause on the query.
|
||||
func (b DeleteBuilder) Limit(limit uint64) DeleteBuilder {
|
||||
return builder.Set(b, "Limit", fmt.Sprintf("%d", limit)).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// Offset sets a OFFSET clause on the query.
|
||||
func (b DeleteBuilder) Offset(offset uint64) DeleteBuilder {
|
||||
return builder.Set(b, "Offset", fmt.Sprintf("%d", offset)).(DeleteBuilder)
|
||||
}
|
||||
|
||||
// Suffix adds an expression to the end of the query
|
||||
func (b DeleteBuilder) Suffix(sql string, args ...interface{}) DeleteBuilder {
|
||||
return b.SuffixExpr(Expr(sql, args...))
|
||||
}
|
||||
|
||||
// SuffixExpr adds an expression to the end of the query
|
||||
func (b DeleteBuilder) SuffixExpr(expr Sqlizer) DeleteBuilder {
|
||||
return builder.Append(b, "Suffixes", expr).(DeleteBuilder)
|
||||
}
|
||||
|
||||
func (b DeleteBuilder) Query() (*sql.Rows, error) {
|
||||
data := builder.GetStruct(b).(deleteData)
|
||||
return data.Query()
|
||||
}
|
||||
|
||||
func (d *deleteData) Query() (*sql.Rows, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return QueryWith(d.RunWith, d)
|
||||
}
|
||||
69
vendor/github.com/Masterminds/squirrel/delete_ctx.go
generated
vendored
Normal file
69
vendor/github.com/Masterminds/squirrel/delete_ctx.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
// +build go1.8
|
||||
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
func (d *deleteData) ExecContext(ctx context.Context) (sql.Result, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
ctxRunner, ok := d.RunWith.(ExecerContext)
|
||||
if !ok {
|
||||
return nil, NoContextSupport
|
||||
}
|
||||
return ExecContextWith(ctx, ctxRunner, d)
|
||||
}
|
||||
|
||||
func (d *deleteData) QueryContext(ctx context.Context) (*sql.Rows, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
ctxRunner, ok := d.RunWith.(QueryerContext)
|
||||
if !ok {
|
||||
return nil, NoContextSupport
|
||||
}
|
||||
return QueryContextWith(ctx, ctxRunner, d)
|
||||
}
|
||||
|
||||
func (d *deleteData) QueryRowContext(ctx context.Context) RowScanner {
|
||||
if d.RunWith == nil {
|
||||
return &Row{err: RunnerNotSet}
|
||||
}
|
||||
queryRower, ok := d.RunWith.(QueryRowerContext)
|
||||
if !ok {
|
||||
if _, ok := d.RunWith.(QueryerContext); !ok {
|
||||
return &Row{err: RunnerNotQueryRunner}
|
||||
}
|
||||
return &Row{err: NoContextSupport}
|
||||
}
|
||||
return QueryRowContextWith(ctx, queryRower, d)
|
||||
}
|
||||
|
||||
// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
|
||||
func (b DeleteBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
|
||||
data := builder.GetStruct(b).(deleteData)
|
||||
return data.ExecContext(ctx)
|
||||
}
|
||||
|
||||
// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
|
||||
func (b DeleteBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
|
||||
data := builder.GetStruct(b).(deleteData)
|
||||
return data.QueryContext(ctx)
|
||||
}
|
||||
|
||||
// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
|
||||
func (b DeleteBuilder) QueryRowContext(ctx context.Context) RowScanner {
|
||||
data := builder.GetStruct(b).(deleteData)
|
||||
return data.QueryRowContext(ctx)
|
||||
}
|
||||
|
||||
// ScanContext is a shortcut for QueryRowContext().Scan.
|
||||
func (b DeleteBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
|
||||
return b.QueryRowContext(ctx).Scan(dest...)
|
||||
}
|
||||
419
vendor/github.com/Masterminds/squirrel/expr.go
generated
vendored
Normal file
419
vendor/github.com/Masterminds/squirrel/expr.go
generated
vendored
Normal file
@@ -0,0 +1,419 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql/driver"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// Portable true/false literals.
|
||||
sqlTrue = "(1=1)"
|
||||
sqlFalse = "(1=0)"
|
||||
)
|
||||
|
||||
type expr struct {
|
||||
sql string
|
||||
args []interface{}
|
||||
}
|
||||
|
||||
// Expr builds an expression from a SQL fragment and arguments.
|
||||
//
|
||||
// Ex:
|
||||
// Expr("FROM_UNIXTIME(?)", t)
|
||||
func Expr(sql string, args ...interface{}) Sqlizer {
|
||||
return expr{sql: sql, args: args}
|
||||
}
|
||||
|
||||
func (e expr) ToSql() (sql string, args []interface{}, err error) {
|
||||
simple := true
|
||||
for _, arg := range e.args {
|
||||
if _, ok := arg.(Sqlizer); ok {
|
||||
simple = false
|
||||
}
|
||||
}
|
||||
if simple {
|
||||
return e.sql, e.args, nil
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
ap := e.args
|
||||
sp := e.sql
|
||||
|
||||
var isql string
|
||||
var iargs []interface{}
|
||||
|
||||
for err == nil && len(ap) > 0 && len(sp) > 0 {
|
||||
i := strings.Index(sp, "?")
|
||||
if i < 0 {
|
||||
// no more placeholders
|
||||
break
|
||||
}
|
||||
if len(sp) > i+1 && sp[i+1:i+2] == "?" {
|
||||
// escaped "??"; append it and step past
|
||||
buf.WriteString(sp[:i+2])
|
||||
sp = sp[i+2:]
|
||||
continue
|
||||
}
|
||||
|
||||
if as, ok := ap[0].(Sqlizer); ok {
|
||||
// sqlizer argument; expand it and append the result
|
||||
isql, iargs, err = as.ToSql()
|
||||
buf.WriteString(sp[:i])
|
||||
buf.WriteString(isql)
|
||||
args = append(args, iargs...)
|
||||
} else {
|
||||
// normal argument; append it and the placeholder
|
||||
buf.WriteString(sp[:i+1])
|
||||
args = append(args, ap[0])
|
||||
}
|
||||
|
||||
// step past the argument and placeholder
|
||||
ap = ap[1:]
|
||||
sp = sp[i+1:]
|
||||
}
|
||||
|
||||
// append the remaining sql and arguments
|
||||
buf.WriteString(sp)
|
||||
return buf.String(), append(args, ap...), err
|
||||
}
|
||||
|
||||
type concatExpr []interface{}
|
||||
|
||||
func (ce concatExpr) ToSql() (sql string, args []interface{}, err error) {
|
||||
for _, part := range ce {
|
||||
switch p := part.(type) {
|
||||
case string:
|
||||
sql += p
|
||||
case Sqlizer:
|
||||
pSql, pArgs, err := p.ToSql()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
sql += pSql
|
||||
args = append(args, pArgs...)
|
||||
default:
|
||||
return "", nil, fmt.Errorf("%#v is not a string or Sqlizer", part)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// ConcatExpr builds an expression by concatenating strings and other expressions.
|
||||
//
|
||||
// Ex:
|
||||
// name_expr := Expr("CONCAT(?, ' ', ?)", firstName, lastName)
|
||||
// ConcatExpr("COALESCE(full_name,", name_expr, ")")
|
||||
func ConcatExpr(parts ...interface{}) concatExpr {
|
||||
return concatExpr(parts)
|
||||
}
|
||||
|
||||
// aliasExpr helps to alias part of SQL query generated with underlying "expr"
|
||||
type aliasExpr struct {
|
||||
expr Sqlizer
|
||||
alias string
|
||||
}
|
||||
|
||||
// Alias allows to define alias for column in SelectBuilder. Useful when column is
|
||||
// defined as complex expression like IF or CASE
|
||||
// Ex:
|
||||
// .Column(Alias(caseStmt, "case_column"))
|
||||
func Alias(expr Sqlizer, alias string) aliasExpr {
|
||||
return aliasExpr{expr, alias}
|
||||
}
|
||||
|
||||
func (e aliasExpr) ToSql() (sql string, args []interface{}, err error) {
|
||||
sql, args, err = e.expr.ToSql()
|
||||
if err == nil {
|
||||
sql = fmt.Sprintf("(%s) AS %s", sql, e.alias)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Eq is syntactic sugar for use with Where/Having/Set methods.
|
||||
type Eq map[string]interface{}
|
||||
|
||||
func (eq Eq) toSQL(useNotOpr bool) (sql string, args []interface{}, err error) {
|
||||
if len(eq) == 0 {
|
||||
// Empty Sql{} evaluates to true.
|
||||
sql = sqlTrue
|
||||
return
|
||||
}
|
||||
|
||||
var (
|
||||
exprs []string
|
||||
equalOpr = "="
|
||||
inOpr = "IN"
|
||||
nullOpr = "IS"
|
||||
inEmptyExpr = sqlFalse
|
||||
)
|
||||
|
||||
if useNotOpr {
|
||||
equalOpr = "<>"
|
||||
inOpr = "NOT IN"
|
||||
nullOpr = "IS NOT"
|
||||
inEmptyExpr = sqlTrue
|
||||
}
|
||||
|
||||
sortedKeys := getSortedKeys(eq)
|
||||
for _, key := range sortedKeys {
|
||||
var expr string
|
||||
val := eq[key]
|
||||
|
||||
switch v := val.(type) {
|
||||
case driver.Valuer:
|
||||
if val, err = v.Value(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
r := reflect.ValueOf(val)
|
||||
if r.Kind() == reflect.Ptr {
|
||||
if r.IsNil() {
|
||||
val = nil
|
||||
} else {
|
||||
val = r.Elem().Interface()
|
||||
}
|
||||
}
|
||||
|
||||
if val == nil {
|
||||
expr = fmt.Sprintf("%s %s NULL", key, nullOpr)
|
||||
} else {
|
||||
if isListType(val) {
|
||||
valVal := reflect.ValueOf(val)
|
||||
if valVal.Len() == 0 {
|
||||
expr = inEmptyExpr
|
||||
if args == nil {
|
||||
args = []interface{}{}
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < valVal.Len(); i++ {
|
||||
args = append(args, valVal.Index(i).Interface())
|
||||
}
|
||||
expr = fmt.Sprintf("%s %s (%s)", key, inOpr, Placeholders(valVal.Len()))
|
||||
}
|
||||
} else {
|
||||
expr = fmt.Sprintf("%s %s ?", key, equalOpr)
|
||||
args = append(args, val)
|
||||
}
|
||||
}
|
||||
exprs = append(exprs, expr)
|
||||
}
|
||||
sql = strings.Join(exprs, " AND ")
|
||||
return
|
||||
}
|
||||
|
||||
func (eq Eq) ToSql() (sql string, args []interface{}, err error) {
|
||||
return eq.toSQL(false)
|
||||
}
|
||||
|
||||
// NotEq is syntactic sugar for use with Where/Having/Set methods.
|
||||
// Ex:
|
||||
// .Where(NotEq{"id": 1}) == "id <> 1"
|
||||
type NotEq Eq
|
||||
|
||||
func (neq NotEq) ToSql() (sql string, args []interface{}, err error) {
|
||||
return Eq(neq).toSQL(true)
|
||||
}
|
||||
|
||||
// Like is syntactic sugar for use with LIKE conditions.
|
||||
// Ex:
|
||||
// .Where(Like{"name": "%irrel"})
|
||||
type Like map[string]interface{}
|
||||
|
||||
func (lk Like) toSql(opr string) (sql string, args []interface{}, err error) {
|
||||
var exprs []string
|
||||
for key, val := range lk {
|
||||
expr := ""
|
||||
|
||||
switch v := val.(type) {
|
||||
case driver.Valuer:
|
||||
if val, err = v.Value(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if val == nil {
|
||||
err = fmt.Errorf("cannot use null with like operators")
|
||||
return
|
||||
} else {
|
||||
if isListType(val) {
|
||||
err = fmt.Errorf("cannot use array or slice with like operators")
|
||||
return
|
||||
} else {
|
||||
expr = fmt.Sprintf("%s %s ?", key, opr)
|
||||
args = append(args, val)
|
||||
}
|
||||
}
|
||||
exprs = append(exprs, expr)
|
||||
}
|
||||
sql = strings.Join(exprs, " AND ")
|
||||
return
|
||||
}
|
||||
|
||||
func (lk Like) ToSql() (sql string, args []interface{}, err error) {
|
||||
return lk.toSql("LIKE")
|
||||
}
|
||||
|
||||
// NotLike is syntactic sugar for use with LIKE conditions.
|
||||
// Ex:
|
||||
// .Where(NotLike{"name": "%irrel"})
|
||||
type NotLike Like
|
||||
|
||||
func (nlk NotLike) ToSql() (sql string, args []interface{}, err error) {
|
||||
return Like(nlk).toSql("NOT LIKE")
|
||||
}
|
||||
|
||||
// ILike is syntactic sugar for use with ILIKE conditions.
|
||||
// Ex:
|
||||
// .Where(ILike{"name": "sq%"})
|
||||
type ILike Like
|
||||
|
||||
func (ilk ILike) ToSql() (sql string, args []interface{}, err error) {
|
||||
return Like(ilk).toSql("ILIKE")
|
||||
}
|
||||
|
||||
// NotILike is syntactic sugar for use with ILIKE conditions.
|
||||
// Ex:
|
||||
// .Where(NotILike{"name": "sq%"})
|
||||
type NotILike Like
|
||||
|
||||
func (nilk NotILike) ToSql() (sql string, args []interface{}, err error) {
|
||||
return Like(nilk).toSql("NOT ILIKE")
|
||||
}
|
||||
|
||||
// Lt is syntactic sugar for use with Where/Having/Set methods.
|
||||
// Ex:
|
||||
// .Where(Lt{"id": 1})
|
||||
type Lt map[string]interface{}
|
||||
|
||||
func (lt Lt) toSql(opposite, orEq bool) (sql string, args []interface{}, err error) {
|
||||
var (
|
||||
exprs []string
|
||||
opr = "<"
|
||||
)
|
||||
|
||||
if opposite {
|
||||
opr = ">"
|
||||
}
|
||||
|
||||
if orEq {
|
||||
opr = fmt.Sprintf("%s%s", opr, "=")
|
||||
}
|
||||
|
||||
sortedKeys := getSortedKeys(lt)
|
||||
for _, key := range sortedKeys {
|
||||
var expr string
|
||||
val := lt[key]
|
||||
|
||||
switch v := val.(type) {
|
||||
case driver.Valuer:
|
||||
if val, err = v.Value(); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if val == nil {
|
||||
err = fmt.Errorf("cannot use null with less than or greater than operators")
|
||||
return
|
||||
}
|
||||
if isListType(val) {
|
||||
err = fmt.Errorf("cannot use array or slice with less than or greater than operators")
|
||||
return
|
||||
}
|
||||
expr = fmt.Sprintf("%s %s ?", key, opr)
|
||||
args = append(args, val)
|
||||
|
||||
exprs = append(exprs, expr)
|
||||
}
|
||||
sql = strings.Join(exprs, " AND ")
|
||||
return
|
||||
}
|
||||
|
||||
func (lt Lt) ToSql() (sql string, args []interface{}, err error) {
|
||||
return lt.toSql(false, false)
|
||||
}
|
||||
|
||||
// LtOrEq is syntactic sugar for use with Where/Having/Set methods.
|
||||
// Ex:
|
||||
// .Where(LtOrEq{"id": 1}) == "id <= 1"
|
||||
type LtOrEq Lt
|
||||
|
||||
func (ltOrEq LtOrEq) ToSql() (sql string, args []interface{}, err error) {
|
||||
return Lt(ltOrEq).toSql(false, true)
|
||||
}
|
||||
|
||||
// Gt is syntactic sugar for use with Where/Having/Set methods.
|
||||
// Ex:
|
||||
// .Where(Gt{"id": 1}) == "id > 1"
|
||||
type Gt Lt
|
||||
|
||||
func (gt Gt) ToSql() (sql string, args []interface{}, err error) {
|
||||
return Lt(gt).toSql(true, false)
|
||||
}
|
||||
|
||||
// GtOrEq is syntactic sugar for use with Where/Having/Set methods.
|
||||
// Ex:
|
||||
// .Where(GtOrEq{"id": 1}) == "id >= 1"
|
||||
type GtOrEq Lt
|
||||
|
||||
func (gtOrEq GtOrEq) ToSql() (sql string, args []interface{}, err error) {
|
||||
return Lt(gtOrEq).toSql(true, true)
|
||||
}
|
||||
|
||||
type conj []Sqlizer
|
||||
|
||||
func (c conj) join(sep, defaultExpr string) (sql string, args []interface{}, err error) {
|
||||
if len(c) == 0 {
|
||||
return defaultExpr, []interface{}{}, nil
|
||||
}
|
||||
var sqlParts []string
|
||||
for _, sqlizer := range c {
|
||||
partSQL, partArgs, err := sqlizer.ToSql()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
if partSQL != "" {
|
||||
sqlParts = append(sqlParts, partSQL)
|
||||
args = append(args, partArgs...)
|
||||
}
|
||||
}
|
||||
if len(sqlParts) > 0 {
|
||||
sql = fmt.Sprintf("(%s)", strings.Join(sqlParts, sep))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// And conjunction Sqlizers
|
||||
type And conj
|
||||
|
||||
func (a And) ToSql() (string, []interface{}, error) {
|
||||
return conj(a).join(" AND ", sqlTrue)
|
||||
}
|
||||
|
||||
// Or conjunction Sqlizers
|
||||
type Or conj
|
||||
|
||||
func (o Or) ToSql() (string, []interface{}, error) {
|
||||
return conj(o).join(" OR ", sqlFalse)
|
||||
}
|
||||
|
||||
func getSortedKeys(exp map[string]interface{}) []string {
|
||||
sortedKeys := make([]string, 0, len(exp))
|
||||
for k := range exp {
|
||||
sortedKeys = append(sortedKeys, k)
|
||||
}
|
||||
sort.Strings(sortedKeys)
|
||||
return sortedKeys
|
||||
}
|
||||
|
||||
func isListType(val interface{}) bool {
|
||||
if driver.IsValue(val) {
|
||||
return false
|
||||
}
|
||||
valVal := reflect.ValueOf(val)
|
||||
return valVal.Kind() == reflect.Array || valVal.Kind() == reflect.Slice
|
||||
}
|
||||
9
vendor/github.com/Masterminds/squirrel/go.mod
generated
vendored
Normal file
9
vendor/github.com/Masterminds/squirrel/go.mod
generated
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
module github.com/Masterminds/squirrel
|
||||
|
||||
require (
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/stretchr/testify v1.2.2
|
||||
)
|
||||
10
vendor/github.com/Masterminds/squirrel/go.sum
generated
vendored
Normal file
10
vendor/github.com/Masterminds/squirrel/go.sum
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
|
||||
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
|
||||
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
288
vendor/github.com/Masterminds/squirrel/insert.go
generated
vendored
Normal file
288
vendor/github.com/Masterminds/squirrel/insert.go
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
type insertData struct {
|
||||
PlaceholderFormat PlaceholderFormat
|
||||
RunWith BaseRunner
|
||||
Prefixes []Sqlizer
|
||||
StatementKeyword string
|
||||
Options []string
|
||||
Into string
|
||||
Columns []string
|
||||
Values [][]interface{}
|
||||
Suffixes []Sqlizer
|
||||
Select *SelectBuilder
|
||||
}
|
||||
|
||||
func (d *insertData) Exec() (sql.Result, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return ExecWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *insertData) Query() (*sql.Rows, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return QueryWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *insertData) QueryRow() RowScanner {
|
||||
if d.RunWith == nil {
|
||||
return &Row{err: RunnerNotSet}
|
||||
}
|
||||
queryRower, ok := d.RunWith.(QueryRower)
|
||||
if !ok {
|
||||
return &Row{err: RunnerNotQueryRunner}
|
||||
}
|
||||
return QueryRowWith(queryRower, d)
|
||||
}
|
||||
|
||||
func (d *insertData) ToSql() (sqlStr string, args []interface{}, err error) {
|
||||
if len(d.Into) == 0 {
|
||||
err = errors.New("insert statements must specify a table")
|
||||
return
|
||||
}
|
||||
if len(d.Values) == 0 && d.Select == nil {
|
||||
err = errors.New("insert statements must have at least one set of values or select clause")
|
||||
return
|
||||
}
|
||||
|
||||
sql := &bytes.Buffer{}
|
||||
|
||||
if len(d.Prefixes) > 0 {
|
||||
args, err = appendToSql(d.Prefixes, sql, " ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
if d.StatementKeyword == "" {
|
||||
sql.WriteString("INSERT ")
|
||||
} else {
|
||||
sql.WriteString(d.StatementKeyword)
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
if len(d.Options) > 0 {
|
||||
sql.WriteString(strings.Join(d.Options, " "))
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
sql.WriteString("INTO ")
|
||||
sql.WriteString(d.Into)
|
||||
sql.WriteString(" ")
|
||||
|
||||
if len(d.Columns) > 0 {
|
||||
sql.WriteString("(")
|
||||
sql.WriteString(strings.Join(d.Columns, ","))
|
||||
sql.WriteString(") ")
|
||||
}
|
||||
|
||||
if d.Select != nil {
|
||||
args, err = d.appendSelectToSQL(sql, args)
|
||||
} else {
|
||||
args, err = d.appendValuesToSQL(sql, args)
|
||||
}
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if len(d.Suffixes) > 0 {
|
||||
sql.WriteString(" ")
|
||||
args, err = appendToSql(d.Suffixes, sql, " ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
|
||||
return
|
||||
}
|
||||
|
||||
func (d *insertData) appendValuesToSQL(w io.Writer, args []interface{}) ([]interface{}, error) {
|
||||
if len(d.Values) == 0 {
|
||||
return args, errors.New("values for insert statements are not set")
|
||||
}
|
||||
|
||||
io.WriteString(w, "VALUES ")
|
||||
|
||||
valuesStrings := make([]string, len(d.Values))
|
||||
for r, row := range d.Values {
|
||||
valueStrings := make([]string, len(row))
|
||||
for v, val := range row {
|
||||
if vs, ok := val.(Sqlizer); ok {
|
||||
vsql, vargs, err := vs.ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
valueStrings[v] = vsql
|
||||
args = append(args, vargs...)
|
||||
} else {
|
||||
valueStrings[v] = "?"
|
||||
args = append(args, val)
|
||||
}
|
||||
}
|
||||
valuesStrings[r] = fmt.Sprintf("(%s)", strings.Join(valueStrings, ","))
|
||||
}
|
||||
|
||||
io.WriteString(w, strings.Join(valuesStrings, ","))
|
||||
|
||||
return args, nil
|
||||
}
|
||||
|
||||
func (d *insertData) appendSelectToSQL(w io.Writer, args []interface{}) ([]interface{}, error) {
|
||||
if d.Select == nil {
|
||||
return args, errors.New("select clause for insert statements are not set")
|
||||
}
|
||||
|
||||
selectClause, sArgs, err := d.Select.ToSql()
|
||||
if err != nil {
|
||||
return args, err
|
||||
}
|
||||
|
||||
io.WriteString(w, selectClause)
|
||||
args = append(args, sArgs...)
|
||||
|
||||
return args, nil
|
||||
}
|
||||
|
||||
// Builder
|
||||
|
||||
// InsertBuilder builds SQL INSERT statements.
|
||||
type InsertBuilder builder.Builder
|
||||
|
||||
func init() {
|
||||
builder.Register(InsertBuilder{}, insertData{})
|
||||
}
|
||||
|
||||
// Format methods
|
||||
|
||||
// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
|
||||
// query.
|
||||
func (b InsertBuilder) PlaceholderFormat(f PlaceholderFormat) InsertBuilder {
|
||||
return builder.Set(b, "PlaceholderFormat", f).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Runner methods
|
||||
|
||||
// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
|
||||
func (b InsertBuilder) RunWith(runner BaseRunner) InsertBuilder {
|
||||
return setRunWith(b, runner).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Exec builds and Execs the query with the Runner set by RunWith.
|
||||
func (b InsertBuilder) Exec() (sql.Result, error) {
|
||||
data := builder.GetStruct(b).(insertData)
|
||||
return data.Exec()
|
||||
}
|
||||
|
||||
// Query builds and Querys the query with the Runner set by RunWith.
|
||||
func (b InsertBuilder) Query() (*sql.Rows, error) {
|
||||
data := builder.GetStruct(b).(insertData)
|
||||
return data.Query()
|
||||
}
|
||||
|
||||
// QueryRow builds and QueryRows the query with the Runner set by RunWith.
|
||||
func (b InsertBuilder) QueryRow() RowScanner {
|
||||
data := builder.GetStruct(b).(insertData)
|
||||
return data.QueryRow()
|
||||
}
|
||||
|
||||
// Scan is a shortcut for QueryRow().Scan.
|
||||
func (b InsertBuilder) Scan(dest ...interface{}) error {
|
||||
return b.QueryRow().Scan(dest...)
|
||||
}
|
||||
|
||||
// SQL methods
|
||||
|
||||
// ToSql builds the query into a SQL string and bound args.
|
||||
func (b InsertBuilder) ToSql() (string, []interface{}, error) {
|
||||
data := builder.GetStruct(b).(insertData)
|
||||
return data.ToSql()
|
||||
}
|
||||
|
||||
// Prefix adds an expression to the beginning of the query
|
||||
func (b InsertBuilder) Prefix(sql string, args ...interface{}) InsertBuilder {
|
||||
return b.PrefixExpr(Expr(sql, args...))
|
||||
}
|
||||
|
||||
// PrefixExpr adds an expression to the very beginning of the query
|
||||
func (b InsertBuilder) PrefixExpr(expr Sqlizer) InsertBuilder {
|
||||
return builder.Append(b, "Prefixes", expr).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Options adds keyword options before the INTO clause of the query.
|
||||
func (b InsertBuilder) Options(options ...string) InsertBuilder {
|
||||
return builder.Extend(b, "Options", options).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Into sets the INTO clause of the query.
|
||||
func (b InsertBuilder) Into(from string) InsertBuilder {
|
||||
return builder.Set(b, "Into", from).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Columns adds insert columns to the query.
|
||||
func (b InsertBuilder) Columns(columns ...string) InsertBuilder {
|
||||
return builder.Extend(b, "Columns", columns).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Values adds a single row's values to the query.
|
||||
func (b InsertBuilder) Values(values ...interface{}) InsertBuilder {
|
||||
return builder.Append(b, "Values", values).(InsertBuilder)
|
||||
}
|
||||
|
||||
// Suffix adds an expression to the end of the query
|
||||
func (b InsertBuilder) Suffix(sql string, args ...interface{}) InsertBuilder {
|
||||
return b.SuffixExpr(Expr(sql, args...))
|
||||
}
|
||||
|
||||
// SuffixExpr adds an expression to the end of the query
|
||||
func (b InsertBuilder) SuffixExpr(expr Sqlizer) InsertBuilder {
|
||||
return builder.Append(b, "Suffixes", expr).(InsertBuilder)
|
||||
}
|
||||
|
||||
// SetMap set columns and values for insert builder from a map of column name and value
|
||||
// note that it will reset all previous columns and values was set if any
|
||||
func (b InsertBuilder) SetMap(clauses map[string]interface{}) InsertBuilder {
|
||||
// Keep the columns in a consistent order by sorting the column key string.
|
||||
cols := make([]string, 0, len(clauses))
|
||||
for col := range clauses {
|
||||
cols = append(cols, col)
|
||||
}
|
||||
sort.Strings(cols)
|
||||
|
||||
vals := make([]interface{}, 0, len(clauses))
|
||||
for _, col := range cols {
|
||||
vals = append(vals, clauses[col])
|
||||
}
|
||||
|
||||
b = builder.Set(b, "Columns", cols).(InsertBuilder)
|
||||
b = builder.Set(b, "Values", [][]interface{}{vals}).(InsertBuilder)
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Select set Select clause for insert query
|
||||
// If Values and Select are used, then Select has higher priority
|
||||
func (b InsertBuilder) Select(sb SelectBuilder) InsertBuilder {
|
||||
return builder.Set(b, "Select", &sb).(InsertBuilder)
|
||||
}
|
||||
|
||||
func (b InsertBuilder) statementKeyword(keyword string) InsertBuilder {
|
||||
return builder.Set(b, "StatementKeyword", keyword).(InsertBuilder)
|
||||
}
|
||||
69
vendor/github.com/Masterminds/squirrel/insert_ctx.go
generated
vendored
Normal file
69
vendor/github.com/Masterminds/squirrel/insert_ctx.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
// +build go1.8
|
||||
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
func (d *insertData) ExecContext(ctx context.Context) (sql.Result, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
ctxRunner, ok := d.RunWith.(ExecerContext)
|
||||
if !ok {
|
||||
return nil, NoContextSupport
|
||||
}
|
||||
return ExecContextWith(ctx, ctxRunner, d)
|
||||
}
|
||||
|
||||
func (d *insertData) QueryContext(ctx context.Context) (*sql.Rows, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
ctxRunner, ok := d.RunWith.(QueryerContext)
|
||||
if !ok {
|
||||
return nil, NoContextSupport
|
||||
}
|
||||
return QueryContextWith(ctx, ctxRunner, d)
|
||||
}
|
||||
|
||||
func (d *insertData) QueryRowContext(ctx context.Context) RowScanner {
|
||||
if d.RunWith == nil {
|
||||
return &Row{err: RunnerNotSet}
|
||||
}
|
||||
queryRower, ok := d.RunWith.(QueryRowerContext)
|
||||
if !ok {
|
||||
if _, ok := d.RunWith.(QueryerContext); !ok {
|
||||
return &Row{err: RunnerNotQueryRunner}
|
||||
}
|
||||
return &Row{err: NoContextSupport}
|
||||
}
|
||||
return QueryRowContextWith(ctx, queryRower, d)
|
||||
}
|
||||
|
||||
// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
|
||||
func (b InsertBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
|
||||
data := builder.GetStruct(b).(insertData)
|
||||
return data.ExecContext(ctx)
|
||||
}
|
||||
|
||||
// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
|
||||
func (b InsertBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
|
||||
data := builder.GetStruct(b).(insertData)
|
||||
return data.QueryContext(ctx)
|
||||
}
|
||||
|
||||
// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
|
||||
func (b InsertBuilder) QueryRowContext(ctx context.Context) RowScanner {
|
||||
data := builder.GetStruct(b).(insertData)
|
||||
return data.QueryRowContext(ctx)
|
||||
}
|
||||
|
||||
// ScanContext is a shortcut for QueryRowContext().Scan.
|
||||
func (b InsertBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
|
||||
return b.QueryRowContext(ctx).Scan(dest...)
|
||||
}
|
||||
55
vendor/github.com/Masterminds/squirrel/part.go
generated
vendored
Normal file
55
vendor/github.com/Masterminds/squirrel/part.go
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
)
|
||||
|
||||
type part struct {
|
||||
pred interface{}
|
||||
args []interface{}
|
||||
}
|
||||
|
||||
func newPart(pred interface{}, args ...interface{}) Sqlizer {
|
||||
return &part{pred, args}
|
||||
}
|
||||
|
||||
func (p part) ToSql() (sql string, args []interface{}, err error) {
|
||||
switch pred := p.pred.(type) {
|
||||
case nil:
|
||||
// no-op
|
||||
case Sqlizer:
|
||||
sql, args, err = pred.ToSql()
|
||||
case string:
|
||||
sql = pred
|
||||
args = p.args
|
||||
default:
|
||||
err = fmt.Errorf("expected string or Sqlizer, not %T", pred)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func appendToSql(parts []Sqlizer, w io.Writer, sep string, args []interface{}) ([]interface{}, error) {
|
||||
for i, p := range parts {
|
||||
partSql, partArgs, err := p.ToSql()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if len(partSql) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if i > 0 {
|
||||
_, err := io.WriteString(w, sep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
_, err = io.WriteString(w, partSql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
args = append(args, partArgs...)
|
||||
}
|
||||
return args, nil
|
||||
}
|
||||
114
vendor/github.com/Masterminds/squirrel/placeholder.go
generated
vendored
Normal file
114
vendor/github.com/Masterminds/squirrel/placeholder.go
generated
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// PlaceholderFormat is the interface that wraps the ReplacePlaceholders method.
|
||||
//
|
||||
// ReplacePlaceholders takes a SQL statement and replaces each question mark
|
||||
// placeholder with a (possibly different) SQL placeholder.
|
||||
type PlaceholderFormat interface {
|
||||
ReplacePlaceholders(sql string) (string, error)
|
||||
}
|
||||
|
||||
type placeholderDebugger interface {
|
||||
debugPlaceholder() string
|
||||
}
|
||||
|
||||
var (
|
||||
// Question is a PlaceholderFormat instance that leaves placeholders as
|
||||
// question marks.
|
||||
Question = questionFormat{}
|
||||
|
||||
// Dollar is a PlaceholderFormat instance that replaces placeholders with
|
||||
// dollar-prefixed positional placeholders (e.g. $1, $2, $3).
|
||||
Dollar = dollarFormat{}
|
||||
|
||||
// Colon is a PlaceholderFormat instance that replaces placeholders with
|
||||
// colon-prefixed positional placeholders (e.g. :1, :2, :3).
|
||||
Colon = colonFormat{}
|
||||
|
||||
// AtP is a PlaceholderFormat instance that replaces placeholders with
|
||||
// "@p"-prefixed positional placeholders (e.g. @p1, @p2, @p3).
|
||||
AtP = atpFormat{}
|
||||
)
|
||||
|
||||
type questionFormat struct{}
|
||||
|
||||
func (questionFormat) ReplacePlaceholders(sql string) (string, error) {
|
||||
return sql, nil
|
||||
}
|
||||
|
||||
func (questionFormat) debugPlaceholder() string {
|
||||
return "?"
|
||||
}
|
||||
|
||||
type dollarFormat struct{}
|
||||
|
||||
func (dollarFormat) ReplacePlaceholders(sql string) (string, error) {
|
||||
return replacePositionalPlaceholders(sql, "$")
|
||||
}
|
||||
|
||||
func (dollarFormat) debugPlaceholder() string {
|
||||
return "$"
|
||||
}
|
||||
|
||||
type colonFormat struct{}
|
||||
|
||||
func (colonFormat) ReplacePlaceholders(sql string) (string, error) {
|
||||
return replacePositionalPlaceholders(sql, ":")
|
||||
}
|
||||
|
||||
func (colonFormat) debugPlaceholder() string {
|
||||
return ":"
|
||||
}
|
||||
|
||||
type atpFormat struct{}
|
||||
|
||||
func (atpFormat) ReplacePlaceholders(sql string) (string, error) {
|
||||
return replacePositionalPlaceholders(sql, "@p")
|
||||
}
|
||||
|
||||
func (atpFormat) debugPlaceholder() string {
|
||||
return "@p"
|
||||
}
|
||||
|
||||
// Placeholders returns a string with count ? placeholders joined with commas.
|
||||
func Placeholders(count int) string {
|
||||
if count < 1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return strings.Repeat(",?", count)[1:]
|
||||
}
|
||||
|
||||
func replacePositionalPlaceholders(sql, prefix string) (string, error) {
|
||||
buf := &bytes.Buffer{}
|
||||
i := 0
|
||||
for {
|
||||
p := strings.Index(sql, "?")
|
||||
if p == -1 {
|
||||
break
|
||||
}
|
||||
|
||||
if len(sql[p:]) > 1 && sql[p:p+2] == "??" { // escape ?? => ?
|
||||
buf.WriteString(sql[:p])
|
||||
buf.WriteString("?")
|
||||
if len(sql[p:]) == 1 {
|
||||
break
|
||||
}
|
||||
sql = sql[p+2:]
|
||||
} else {
|
||||
i++
|
||||
buf.WriteString(sql[:p])
|
||||
fmt.Fprintf(buf, "%s%d", prefix, i)
|
||||
sql = sql[p+1:]
|
||||
}
|
||||
}
|
||||
|
||||
buf.WriteString(sql)
|
||||
return buf.String(), nil
|
||||
}
|
||||
22
vendor/github.com/Masterminds/squirrel/row.go
generated
vendored
Normal file
22
vendor/github.com/Masterminds/squirrel/row.go
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
package squirrel
|
||||
|
||||
// RowScanner is the interface that wraps the Scan method.
|
||||
//
|
||||
// Scan behaves like database/sql.Row.Scan.
|
||||
type RowScanner interface {
|
||||
Scan(...interface{}) error
|
||||
}
|
||||
|
||||
// Row wraps database/sql.Row to let squirrel return new errors on Scan.
|
||||
type Row struct {
|
||||
RowScanner
|
||||
err error
|
||||
}
|
||||
|
||||
// Scan returns Row.err or calls RowScanner.Scan.
|
||||
func (r *Row) Scan(dest ...interface{}) error {
|
||||
if r.err != nil {
|
||||
return r.err
|
||||
}
|
||||
return r.RowScanner.Scan(dest...)
|
||||
}
|
||||
388
vendor/github.com/Masterminds/squirrel/select.go
generated
vendored
Normal file
388
vendor/github.com/Masterminds/squirrel/select.go
generated
vendored
Normal file
@@ -0,0 +1,388 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
type selectData struct {
|
||||
PlaceholderFormat PlaceholderFormat
|
||||
RunWith BaseRunner
|
||||
Prefixes []Sqlizer
|
||||
Options []string
|
||||
Columns []Sqlizer
|
||||
From Sqlizer
|
||||
Joins []Sqlizer
|
||||
WhereParts []Sqlizer
|
||||
GroupBys []string
|
||||
HavingParts []Sqlizer
|
||||
OrderByParts []Sqlizer
|
||||
Limit string
|
||||
Offset string
|
||||
Suffixes []Sqlizer
|
||||
}
|
||||
|
||||
func (d *selectData) Exec() (sql.Result, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return ExecWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *selectData) Query() (*sql.Rows, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return QueryWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *selectData) QueryRow() RowScanner {
|
||||
if d.RunWith == nil {
|
||||
return &Row{err: RunnerNotSet}
|
||||
}
|
||||
queryRower, ok := d.RunWith.(QueryRower)
|
||||
if !ok {
|
||||
return &Row{err: RunnerNotQueryRunner}
|
||||
}
|
||||
return QueryRowWith(queryRower, d)
|
||||
}
|
||||
|
||||
func (d *selectData) ToSql() (sqlStr string, args []interface{}, err error) {
|
||||
sqlStr, args, err = d.toSql()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sqlStr)
|
||||
return
|
||||
}
|
||||
|
||||
func (d *selectData) toSqlRaw() (sqlStr string, args []interface{}, err error) {
|
||||
return d.toSql()
|
||||
}
|
||||
|
||||
func (d *selectData) toSql() (sqlStr string, args []interface{}, err error) {
|
||||
if len(d.Columns) == 0 {
|
||||
err = fmt.Errorf("select statements must have at least one result column")
|
||||
return
|
||||
}
|
||||
|
||||
sql := &bytes.Buffer{}
|
||||
|
||||
if len(d.Prefixes) > 0 {
|
||||
args, err = appendToSql(d.Prefixes, sql, " ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
sql.WriteString("SELECT ")
|
||||
|
||||
if len(d.Options) > 0 {
|
||||
sql.WriteString(strings.Join(d.Options, " "))
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
if len(d.Columns) > 0 {
|
||||
args, err = appendToSql(d.Columns, sql, ", ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if d.From != nil {
|
||||
sql.WriteString(" FROM ")
|
||||
args, err = appendToSql([]Sqlizer{d.From}, sql, "", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.Joins) > 0 {
|
||||
sql.WriteString(" ")
|
||||
args, err = appendToSql(d.Joins, sql, " ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.WhereParts) > 0 {
|
||||
sql.WriteString(" WHERE ")
|
||||
args, err = appendToSql(d.WhereParts, sql, " AND ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.GroupBys) > 0 {
|
||||
sql.WriteString(" GROUP BY ")
|
||||
sql.WriteString(strings.Join(d.GroupBys, ", "))
|
||||
}
|
||||
|
||||
if len(d.HavingParts) > 0 {
|
||||
sql.WriteString(" HAVING ")
|
||||
args, err = appendToSql(d.HavingParts, sql, " AND ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.OrderByParts) > 0 {
|
||||
sql.WriteString(" ORDER BY ")
|
||||
args, err = appendToSql(d.OrderByParts, sql, ", ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.Limit) > 0 {
|
||||
sql.WriteString(" LIMIT ")
|
||||
sql.WriteString(d.Limit)
|
||||
}
|
||||
|
||||
if len(d.Offset) > 0 {
|
||||
sql.WriteString(" OFFSET ")
|
||||
sql.WriteString(d.Offset)
|
||||
}
|
||||
|
||||
if len(d.Suffixes) > 0 {
|
||||
sql.WriteString(" ")
|
||||
|
||||
args, err = appendToSql(d.Suffixes, sql, " ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
sqlStr = sql.String()
|
||||
return
|
||||
}
|
||||
|
||||
// Builder
|
||||
|
||||
// SelectBuilder builds SQL SELECT statements.
|
||||
type SelectBuilder builder.Builder
|
||||
|
||||
func init() {
|
||||
builder.Register(SelectBuilder{}, selectData{})
|
||||
}
|
||||
|
||||
// Format methods
|
||||
|
||||
// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
|
||||
// query.
|
||||
func (b SelectBuilder) PlaceholderFormat(f PlaceholderFormat) SelectBuilder {
|
||||
return builder.Set(b, "PlaceholderFormat", f).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Runner methods
|
||||
|
||||
// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
|
||||
// For most cases runner will be a database connection.
|
||||
//
|
||||
// Internally we use this to mock out the database connection for testing.
|
||||
func (b SelectBuilder) RunWith(runner BaseRunner) SelectBuilder {
|
||||
return setRunWith(b, runner).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Exec builds and Execs the query with the Runner set by RunWith.
|
||||
func (b SelectBuilder) Exec() (sql.Result, error) {
|
||||
data := builder.GetStruct(b).(selectData)
|
||||
return data.Exec()
|
||||
}
|
||||
|
||||
// Query builds and Querys the query with the Runner set by RunWith.
|
||||
func (b SelectBuilder) Query() (*sql.Rows, error) {
|
||||
data := builder.GetStruct(b).(selectData)
|
||||
return data.Query()
|
||||
}
|
||||
|
||||
// QueryRow builds and QueryRows the query with the Runner set by RunWith.
|
||||
func (b SelectBuilder) QueryRow() RowScanner {
|
||||
data := builder.GetStruct(b).(selectData)
|
||||
return data.QueryRow()
|
||||
}
|
||||
|
||||
// Scan is a shortcut for QueryRow().Scan.
|
||||
func (b SelectBuilder) Scan(dest ...interface{}) error {
|
||||
return b.QueryRow().Scan(dest...)
|
||||
}
|
||||
|
||||
// SQL methods
|
||||
|
||||
// ToSql builds the query into a SQL string and bound args.
|
||||
func (b SelectBuilder) ToSql() (string, []interface{}, error) {
|
||||
data := builder.GetStruct(b).(selectData)
|
||||
return data.ToSql()
|
||||
}
|
||||
|
||||
func (b SelectBuilder) MustSql() (string, []interface{}) {
|
||||
sql, args, err := b.ToSql()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return sql, args
|
||||
}
|
||||
|
||||
func (b SelectBuilder) toSqlRaw() (string, []interface{}, error) {
|
||||
data := builder.GetStruct(b).(selectData)
|
||||
return data.toSqlRaw()
|
||||
}
|
||||
|
||||
// Prefix adds an expression to the beginning of the query
|
||||
func (b SelectBuilder) Prefix(sql string, args ...interface{}) SelectBuilder {
|
||||
return b.PrefixExpr(Expr(sql, args...))
|
||||
}
|
||||
|
||||
// PrefixExpr adds an expression to the very beginning of the query
|
||||
func (b SelectBuilder) PrefixExpr(expr Sqlizer) SelectBuilder {
|
||||
return builder.Append(b, "Prefixes", expr).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Distinct adds a DISTINCT clause to the query.
|
||||
func (b SelectBuilder) Distinct() SelectBuilder {
|
||||
return b.Options("DISTINCT")
|
||||
}
|
||||
|
||||
// Options adds select option to the query
|
||||
func (b SelectBuilder) Options(options ...string) SelectBuilder {
|
||||
return builder.Extend(b, "Options", options).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Columns adds result columns to the query.
|
||||
func (b SelectBuilder) Columns(columns ...string) SelectBuilder {
|
||||
parts := make([]interface{}, 0, len(columns))
|
||||
for _, str := range columns {
|
||||
parts = append(parts, newPart(str))
|
||||
}
|
||||
return builder.Extend(b, "Columns", parts).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Column adds a result column to the query.
|
||||
// Unlike Columns, Column accepts args which will be bound to placeholders in
|
||||
// the columns string, for example:
|
||||
// Column("IF(col IN ("+squirrel.Placeholders(3)+"), 1, 0) as col", 1, 2, 3)
|
||||
func (b SelectBuilder) Column(column interface{}, args ...interface{}) SelectBuilder {
|
||||
return builder.Append(b, "Columns", newPart(column, args...)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// From sets the FROM clause of the query.
|
||||
func (b SelectBuilder) From(from string) SelectBuilder {
|
||||
return builder.Set(b, "From", newPart(from)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// FromSelect sets a subquery into the FROM clause of the query.
|
||||
func (b SelectBuilder) FromSelect(from SelectBuilder, alias string) SelectBuilder {
|
||||
// Prevent misnumbered parameters in nested selects (#183).
|
||||
from = from.PlaceholderFormat(Question)
|
||||
return builder.Set(b, "From", Alias(from, alias)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// JoinClause adds a join clause to the query.
|
||||
func (b SelectBuilder) JoinClause(pred interface{}, args ...interface{}) SelectBuilder {
|
||||
return builder.Append(b, "Joins", newPart(pred, args...)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Join adds a JOIN clause to the query.
|
||||
func (b SelectBuilder) Join(join string, rest ...interface{}) SelectBuilder {
|
||||
return b.JoinClause("JOIN "+join, rest...)
|
||||
}
|
||||
|
||||
// LeftJoin adds a LEFT JOIN clause to the query.
|
||||
func (b SelectBuilder) LeftJoin(join string, rest ...interface{}) SelectBuilder {
|
||||
return b.JoinClause("LEFT JOIN "+join, rest...)
|
||||
}
|
||||
|
||||
// RightJoin adds a RIGHT JOIN clause to the query.
|
||||
func (b SelectBuilder) RightJoin(join string, rest ...interface{}) SelectBuilder {
|
||||
return b.JoinClause("RIGHT JOIN "+join, rest...)
|
||||
}
|
||||
|
||||
// Where adds an expression to the WHERE clause of the query.
|
||||
//
|
||||
// Expressions are ANDed together in the generated SQL.
|
||||
//
|
||||
// Where accepts several types for its pred argument:
|
||||
//
|
||||
// nil OR "" - ignored.
|
||||
//
|
||||
// string - SQL expression.
|
||||
// If the expression has SQL placeholders then a set of arguments must be passed
|
||||
// as well, one for each placeholder.
|
||||
//
|
||||
// map[string]interface{} OR Eq - map of SQL expressions to values. Each key is
|
||||
// transformed into an expression like "<key> = ?", with the corresponding value
|
||||
// bound to the placeholder. If the value is nil, the expression will be "<key>
|
||||
// IS NULL". If the value is an array or slice, the expression will be "<key> IN
|
||||
// (?,?,...)", with one placeholder for each item in the value. These expressions
|
||||
// are ANDed together.
|
||||
//
|
||||
// Where will panic if pred isn't any of the above types.
|
||||
func (b SelectBuilder) Where(pred interface{}, args ...interface{}) SelectBuilder {
|
||||
if pred == nil || pred == "" {
|
||||
return b
|
||||
}
|
||||
return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// GroupBy adds GROUP BY expressions to the query.
|
||||
func (b SelectBuilder) GroupBy(groupBys ...string) SelectBuilder {
|
||||
return builder.Extend(b, "GroupBys", groupBys).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Having adds an expression to the HAVING clause of the query.
|
||||
//
|
||||
// See Where.
|
||||
func (b SelectBuilder) Having(pred interface{}, rest ...interface{}) SelectBuilder {
|
||||
return builder.Append(b, "HavingParts", newWherePart(pred, rest...)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// OrderByClause adds ORDER BY clause to the query.
|
||||
func (b SelectBuilder) OrderByClause(pred interface{}, args ...interface{}) SelectBuilder {
|
||||
return builder.Append(b, "OrderByParts", newPart(pred, args...)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// OrderBy adds ORDER BY expressions to the query.
|
||||
func (b SelectBuilder) OrderBy(orderBys ...string) SelectBuilder {
|
||||
for _, orderBy := range orderBys {
|
||||
b = b.OrderByClause(orderBy)
|
||||
}
|
||||
|
||||
return b
|
||||
}
|
||||
|
||||
// Limit sets a LIMIT clause on the query.
|
||||
func (b SelectBuilder) Limit(limit uint64) SelectBuilder {
|
||||
return builder.Set(b, "Limit", fmt.Sprintf("%d", limit)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// Limit ALL allows to access all records with limit
|
||||
func (b SelectBuilder) RemoveLimit() SelectBuilder {
|
||||
return builder.Delete(b, "Limit").(SelectBuilder)
|
||||
}
|
||||
|
||||
// Offset sets a OFFSET clause on the query.
|
||||
func (b SelectBuilder) Offset(offset uint64) SelectBuilder {
|
||||
return builder.Set(b, "Offset", fmt.Sprintf("%d", offset)).(SelectBuilder)
|
||||
}
|
||||
|
||||
// RemoveOffset removes OFFSET clause.
|
||||
func (b SelectBuilder) RemoveOffset() SelectBuilder {
|
||||
return builder.Delete(b, "Offset").(SelectBuilder)
|
||||
}
|
||||
|
||||
// Suffix adds an expression to the end of the query
|
||||
func (b SelectBuilder) Suffix(sql string, args ...interface{}) SelectBuilder {
|
||||
return b.SuffixExpr(Expr(sql, args...))
|
||||
}
|
||||
|
||||
// SuffixExpr adds an expression to the end of the query
|
||||
func (b SelectBuilder) SuffixExpr(expr Sqlizer) SelectBuilder {
|
||||
return builder.Append(b, "Suffixes", expr).(SelectBuilder)
|
||||
}
|
||||
69
vendor/github.com/Masterminds/squirrel/select_ctx.go
generated
vendored
Normal file
69
vendor/github.com/Masterminds/squirrel/select_ctx.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
// +build go1.8
|
||||
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
func (d *selectData) ExecContext(ctx context.Context) (sql.Result, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
ctxRunner, ok := d.RunWith.(ExecerContext)
|
||||
if !ok {
|
||||
return nil, NoContextSupport
|
||||
}
|
||||
return ExecContextWith(ctx, ctxRunner, d)
|
||||
}
|
||||
|
||||
func (d *selectData) QueryContext(ctx context.Context) (*sql.Rows, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
ctxRunner, ok := d.RunWith.(QueryerContext)
|
||||
if !ok {
|
||||
return nil, NoContextSupport
|
||||
}
|
||||
return QueryContextWith(ctx, ctxRunner, d)
|
||||
}
|
||||
|
||||
func (d *selectData) QueryRowContext(ctx context.Context) RowScanner {
|
||||
if d.RunWith == nil {
|
||||
return &Row{err: RunnerNotSet}
|
||||
}
|
||||
queryRower, ok := d.RunWith.(QueryRowerContext)
|
||||
if !ok {
|
||||
if _, ok := d.RunWith.(QueryerContext); !ok {
|
||||
return &Row{err: RunnerNotQueryRunner}
|
||||
}
|
||||
return &Row{err: NoContextSupport}
|
||||
}
|
||||
return QueryRowContextWith(ctx, queryRower, d)
|
||||
}
|
||||
|
||||
// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
|
||||
func (b SelectBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
|
||||
data := builder.GetStruct(b).(selectData)
|
||||
return data.ExecContext(ctx)
|
||||
}
|
||||
|
||||
// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
|
||||
func (b SelectBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
|
||||
data := builder.GetStruct(b).(selectData)
|
||||
return data.QueryContext(ctx)
|
||||
}
|
||||
|
||||
// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
|
||||
func (b SelectBuilder) QueryRowContext(ctx context.Context) RowScanner {
|
||||
data := builder.GetStruct(b).(selectData)
|
||||
return data.QueryRowContext(ctx)
|
||||
}
|
||||
|
||||
// ScanContext is a shortcut for QueryRowContext().Scan.
|
||||
func (b SelectBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
|
||||
return b.QueryRowContext(ctx).Scan(dest...)
|
||||
}
|
||||
183
vendor/github.com/Masterminds/squirrel/squirrel.go
generated
vendored
Normal file
183
vendor/github.com/Masterminds/squirrel/squirrel.go
generated
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
// Package squirrel provides a fluent SQL generator.
|
||||
//
|
||||
// See https://github.com/Masterminds/squirrel for examples.
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
// Sqlizer is the interface that wraps the ToSql method.
|
||||
//
|
||||
// ToSql returns a SQL representation of the Sqlizer, along with a slice of args
|
||||
// as passed to e.g. database/sql.Exec. It can also return an error.
|
||||
type Sqlizer interface {
|
||||
ToSql() (string, []interface{}, error)
|
||||
}
|
||||
|
||||
// rawSqlizer is expected to do what Sqlizer does, but without finalizing placeholders.
|
||||
// This is useful for nested queries.
|
||||
type rawSqlizer interface {
|
||||
toSqlRaw() (string, []interface{}, error)
|
||||
}
|
||||
|
||||
// Execer is the interface that wraps the Exec method.
|
||||
//
|
||||
// Exec executes the given query as implemented by database/sql.Exec.
|
||||
type Execer interface {
|
||||
Exec(query string, args ...interface{}) (sql.Result, error)
|
||||
}
|
||||
|
||||
// Queryer is the interface that wraps the Query method.
|
||||
//
|
||||
// Query executes the given query as implemented by database/sql.Query.
|
||||
type Queryer interface {
|
||||
Query(query string, args ...interface{}) (*sql.Rows, error)
|
||||
}
|
||||
|
||||
// QueryRower is the interface that wraps the QueryRow method.
|
||||
//
|
||||
// QueryRow executes the given query as implemented by database/sql.QueryRow.
|
||||
type QueryRower interface {
|
||||
QueryRow(query string, args ...interface{}) RowScanner
|
||||
}
|
||||
|
||||
// BaseRunner groups the Execer and Queryer interfaces.
|
||||
type BaseRunner interface {
|
||||
Execer
|
||||
Queryer
|
||||
}
|
||||
|
||||
// Runner groups the Execer, Queryer, and QueryRower interfaces.
|
||||
type Runner interface {
|
||||
Execer
|
||||
Queryer
|
||||
QueryRower
|
||||
}
|
||||
|
||||
// WrapStdSql wraps a type implementing the standard SQL interface with methods that
|
||||
// squirrel expects.
|
||||
func WrapStdSql(stdSql StdSql) Runner {
|
||||
return &stdsqlRunner{stdSql}
|
||||
}
|
||||
|
||||
// StdSql encompasses the standard methods of the *sql.DB type, and other types that
|
||||
// wrap these methods.
|
||||
type StdSql interface {
|
||||
Query(string, ...interface{}) (*sql.Rows, error)
|
||||
QueryRow(string, ...interface{}) *sql.Row
|
||||
Exec(string, ...interface{}) (sql.Result, error)
|
||||
}
|
||||
|
||||
type stdsqlRunner struct {
|
||||
StdSql
|
||||
}
|
||||
|
||||
func (r *stdsqlRunner) QueryRow(query string, args ...interface{}) RowScanner {
|
||||
return r.StdSql.QueryRow(query, args...)
|
||||
}
|
||||
|
||||
func setRunWith(b interface{}, runner BaseRunner) interface{} {
|
||||
switch r := runner.(type) {
|
||||
case StdSqlCtx:
|
||||
runner = WrapStdSqlCtx(r)
|
||||
case StdSql:
|
||||
runner = WrapStdSql(r)
|
||||
}
|
||||
return builder.Set(b, "RunWith", runner)
|
||||
}
|
||||
|
||||
// RunnerNotSet is returned by methods that need a Runner if it isn't set.
|
||||
var RunnerNotSet = fmt.Errorf("cannot run; no Runner set (RunWith)")
|
||||
|
||||
// RunnerNotQueryRunner is returned by QueryRow if the RunWith value doesn't implement QueryRower.
|
||||
var RunnerNotQueryRunner = fmt.Errorf("cannot QueryRow; Runner is not a QueryRower")
|
||||
|
||||
// ExecWith Execs the SQL returned by s with db.
|
||||
func ExecWith(db Execer, s Sqlizer) (res sql.Result, err error) {
|
||||
query, args, err := s.ToSql()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return db.Exec(query, args...)
|
||||
}
|
||||
|
||||
// QueryWith Querys the SQL returned by s with db.
|
||||
func QueryWith(db Queryer, s Sqlizer) (rows *sql.Rows, err error) {
|
||||
query, args, err := s.ToSql()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return db.Query(query, args...)
|
||||
}
|
||||
|
||||
// QueryRowWith QueryRows the SQL returned by s with db.
|
||||
func QueryRowWith(db QueryRower, s Sqlizer) RowScanner {
|
||||
query, args, err := s.ToSql()
|
||||
return &Row{RowScanner: db.QueryRow(query, args...), err: err}
|
||||
}
|
||||
|
||||
// DebugSqlizer calls ToSql on s and shows the approximate SQL to be executed
|
||||
//
|
||||
// If ToSql returns an error, the result of this method will look like:
|
||||
// "[ToSql error: %s]" or "[DebugSqlizer error: %s]"
|
||||
//
|
||||
// IMPORTANT: As its name suggests, this function should only be used for
|
||||
// debugging. While the string result *might* be valid SQL, this function does
|
||||
// not try very hard to ensure it. Additionally, executing the output of this
|
||||
// function with any untrusted user input is certainly insecure.
|
||||
func DebugSqlizer(s Sqlizer) string {
|
||||
sql, args, err := s.ToSql()
|
||||
if err != nil {
|
||||
return fmt.Sprintf("[ToSql error: %s]", err)
|
||||
}
|
||||
|
||||
var placeholder string
|
||||
downCast, ok := s.(placeholderDebugger)
|
||||
if !ok {
|
||||
placeholder = "?"
|
||||
} else {
|
||||
placeholder = downCast.debugPlaceholder()
|
||||
}
|
||||
// TODO: dedupe this with placeholder.go
|
||||
buf := &bytes.Buffer{}
|
||||
i := 0
|
||||
for {
|
||||
p := strings.Index(sql, placeholder)
|
||||
if p == -1 {
|
||||
break
|
||||
}
|
||||
if len(sql[p:]) > 1 && sql[p:p+2] == "??" { // escape ?? => ?
|
||||
buf.WriteString(sql[:p])
|
||||
buf.WriteString("?")
|
||||
if len(sql[p:]) == 1 {
|
||||
break
|
||||
}
|
||||
sql = sql[p+2:]
|
||||
} else {
|
||||
if i+1 > len(args) {
|
||||
return fmt.Sprintf(
|
||||
"[DebugSqlizer error: too many placeholders in %#v for %d args]",
|
||||
sql, len(args))
|
||||
}
|
||||
buf.WriteString(sql[:p])
|
||||
fmt.Fprintf(buf, "'%v'", args[i])
|
||||
// advance our sql string "cursor" beyond the arg we placed
|
||||
sql = sql[p+1:]
|
||||
i++
|
||||
}
|
||||
}
|
||||
if i < len(args) {
|
||||
return fmt.Sprintf(
|
||||
"[DebugSqlizer error: not enough placeholders in %#v for %d args]",
|
||||
sql, len(args))
|
||||
}
|
||||
// "append" any remaning sql that won't need interpolating
|
||||
buf.WriteString(sql)
|
||||
return buf.String()
|
||||
}
|
||||
93
vendor/github.com/Masterminds/squirrel/squirrel_ctx.go
generated
vendored
Normal file
93
vendor/github.com/Masterminds/squirrel/squirrel_ctx.go
generated
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
// +build go1.8
|
||||
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// NoContextSupport is returned if a db doesn't support Context.
|
||||
var NoContextSupport = errors.New("DB does not support Context")
|
||||
|
||||
// ExecerContext is the interface that wraps the ExecContext method.
|
||||
//
|
||||
// Exec executes the given query as implemented by database/sql.ExecContext.
|
||||
type ExecerContext interface {
|
||||
ExecContext(ctx context.Context, query string, args ...interface{}) (sql.Result, error)
|
||||
}
|
||||
|
||||
// QueryerContext is the interface that wraps the QueryContext method.
|
||||
//
|
||||
// QueryContext executes the given query as implemented by database/sql.QueryContext.
|
||||
type QueryerContext interface {
|
||||
QueryContext(ctx context.Context, query string, args ...interface{}) (*sql.Rows, error)
|
||||
}
|
||||
|
||||
// QueryRowerContext is the interface that wraps the QueryRowContext method.
|
||||
//
|
||||
// QueryRowContext executes the given query as implemented by database/sql.QueryRowContext.
|
||||
type QueryRowerContext interface {
|
||||
QueryRowContext(ctx context.Context, query string, args ...interface{}) RowScanner
|
||||
}
|
||||
|
||||
// RunnerContext groups the Runner interface, along with the Contect versions of each of
|
||||
// its methods
|
||||
type RunnerContext interface {
|
||||
Runner
|
||||
QueryerContext
|
||||
QueryRowerContext
|
||||
ExecerContext
|
||||
}
|
||||
|
||||
// WrapStdSqlCtx wraps a type implementing the standard SQL interface plus the context
|
||||
// versions of the methods with methods that squirrel expects.
|
||||
func WrapStdSqlCtx(stdSqlCtx StdSqlCtx) RunnerContext {
|
||||
return &stdsqlCtxRunner{stdSqlCtx}
|
||||
}
|
||||
|
||||
// StdSqlCtx encompasses the standard methods of the *sql.DB type, along with the Context
|
||||
// versions of those methods, and other types that wrap these methods.
|
||||
type StdSqlCtx interface {
|
||||
StdSql
|
||||
QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
|
||||
QueryRowContext(context.Context, string, ...interface{}) *sql.Row
|
||||
ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
|
||||
}
|
||||
|
||||
type stdsqlCtxRunner struct {
|
||||
StdSqlCtx
|
||||
}
|
||||
|
||||
func (r *stdsqlCtxRunner) QueryRow(query string, args ...interface{}) RowScanner {
|
||||
return r.StdSqlCtx.QueryRow(query, args...)
|
||||
}
|
||||
|
||||
func (r *stdsqlCtxRunner) QueryRowContext(ctx context.Context, query string, args ...interface{}) RowScanner {
|
||||
return r.StdSqlCtx.QueryRowContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
// ExecContextWith ExecContexts the SQL returned by s with db.
|
||||
func ExecContextWith(ctx context.Context, db ExecerContext, s Sqlizer) (res sql.Result, err error) {
|
||||
query, args, err := s.ToSql()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return db.ExecContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
// QueryContextWith QueryContexts the SQL returned by s with db.
|
||||
func QueryContextWith(ctx context.Context, db QueryerContext, s Sqlizer) (rows *sql.Rows, err error) {
|
||||
query, args, err := s.ToSql()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return db.QueryContext(ctx, query, args...)
|
||||
}
|
||||
|
||||
// QueryRowContextWith QueryRowContexts the SQL returned by s with db.
|
||||
func QueryRowContextWith(ctx context.Context, db QueryRowerContext, s Sqlizer) RowScanner {
|
||||
query, args, err := s.ToSql()
|
||||
return &Row{RowScanner: db.QueryRowContext(ctx, query, args...), err: err}
|
||||
}
|
||||
104
vendor/github.com/Masterminds/squirrel/statement.go
generated
vendored
Normal file
104
vendor/github.com/Masterminds/squirrel/statement.go
generated
vendored
Normal file
@@ -0,0 +1,104 @@
|
||||
package squirrel
|
||||
|
||||
import "github.com/lann/builder"
|
||||
|
||||
// StatementBuilderType is the type of StatementBuilder.
|
||||
type StatementBuilderType builder.Builder
|
||||
|
||||
// Select returns a SelectBuilder for this StatementBuilderType.
|
||||
func (b StatementBuilderType) Select(columns ...string) SelectBuilder {
|
||||
return SelectBuilder(b).Columns(columns...)
|
||||
}
|
||||
|
||||
// Insert returns a InsertBuilder for this StatementBuilderType.
|
||||
func (b StatementBuilderType) Insert(into string) InsertBuilder {
|
||||
return InsertBuilder(b).Into(into)
|
||||
}
|
||||
|
||||
// Replace returns a InsertBuilder for this StatementBuilderType with the
|
||||
// statement keyword set to "REPLACE".
|
||||
func (b StatementBuilderType) Replace(into string) InsertBuilder {
|
||||
return InsertBuilder(b).statementKeyword("REPLACE").Into(into)
|
||||
}
|
||||
|
||||
// Update returns a UpdateBuilder for this StatementBuilderType.
|
||||
func (b StatementBuilderType) Update(table string) UpdateBuilder {
|
||||
return UpdateBuilder(b).Table(table)
|
||||
}
|
||||
|
||||
// Delete returns a DeleteBuilder for this StatementBuilderType.
|
||||
func (b StatementBuilderType) Delete(from string) DeleteBuilder {
|
||||
return DeleteBuilder(b).From(from)
|
||||
}
|
||||
|
||||
// PlaceholderFormat sets the PlaceholderFormat field for any child builders.
|
||||
func (b StatementBuilderType) PlaceholderFormat(f PlaceholderFormat) StatementBuilderType {
|
||||
return builder.Set(b, "PlaceholderFormat", f).(StatementBuilderType)
|
||||
}
|
||||
|
||||
// RunWith sets the RunWith field for any child builders.
|
||||
func (b StatementBuilderType) RunWith(runner BaseRunner) StatementBuilderType {
|
||||
return setRunWith(b, runner).(StatementBuilderType)
|
||||
}
|
||||
|
||||
// Where adds WHERE expressions to the query.
|
||||
//
|
||||
// See SelectBuilder.Where for more information.
|
||||
func (b StatementBuilderType) Where(pred interface{}, args ...interface{}) StatementBuilderType {
|
||||
return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(StatementBuilderType)
|
||||
}
|
||||
|
||||
// StatementBuilder is a parent builder for other builders, e.g. SelectBuilder.
|
||||
var StatementBuilder = StatementBuilderType(builder.EmptyBuilder).PlaceholderFormat(Question)
|
||||
|
||||
// Select returns a new SelectBuilder, optionally setting some result columns.
|
||||
//
|
||||
// See SelectBuilder.Columns.
|
||||
func Select(columns ...string) SelectBuilder {
|
||||
return StatementBuilder.Select(columns...)
|
||||
}
|
||||
|
||||
// Insert returns a new InsertBuilder with the given table name.
|
||||
//
|
||||
// See InsertBuilder.Into.
|
||||
func Insert(into string) InsertBuilder {
|
||||
return StatementBuilder.Insert(into)
|
||||
}
|
||||
|
||||
// Replace returns a new InsertBuilder with the statement keyword set to
|
||||
// "REPLACE" and with the given table name.
|
||||
//
|
||||
// See InsertBuilder.Into.
|
||||
func Replace(into string) InsertBuilder {
|
||||
return StatementBuilder.Replace(into)
|
||||
}
|
||||
|
||||
// Update returns a new UpdateBuilder with the given table name.
|
||||
//
|
||||
// See UpdateBuilder.Table.
|
||||
func Update(table string) UpdateBuilder {
|
||||
return StatementBuilder.Update(table)
|
||||
}
|
||||
|
||||
// Delete returns a new DeleteBuilder with the given table name.
|
||||
//
|
||||
// See DeleteBuilder.Table.
|
||||
func Delete(from string) DeleteBuilder {
|
||||
return StatementBuilder.Delete(from)
|
||||
}
|
||||
|
||||
// Case returns a new CaseBuilder
|
||||
// "what" represents case value
|
||||
func Case(what ...interface{}) CaseBuilder {
|
||||
b := CaseBuilder(builder.EmptyBuilder)
|
||||
|
||||
switch len(what) {
|
||||
case 0:
|
||||
case 1:
|
||||
b = b.what(what[0])
|
||||
default:
|
||||
b = b.what(newPart(what[0], what[1:]...))
|
||||
|
||||
}
|
||||
return b
|
||||
}
|
||||
121
vendor/github.com/Masterminds/squirrel/stmtcacher.go
generated
vendored
Normal file
121
vendor/github.com/Masterminds/squirrel/stmtcacher.go
generated
vendored
Normal file
@@ -0,0 +1,121 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Prepareer is the interface that wraps the Prepare method.
|
||||
//
|
||||
// Prepare executes the given query as implemented by database/sql.Prepare.
|
||||
type Preparer interface {
|
||||
Prepare(query string) (*sql.Stmt, error)
|
||||
}
|
||||
|
||||
// DBProxy groups the Execer, Queryer, QueryRower, and Preparer interfaces.
|
||||
type DBProxy interface {
|
||||
Execer
|
||||
Queryer
|
||||
QueryRower
|
||||
Preparer
|
||||
}
|
||||
|
||||
// NOTE: NewStmtCache is defined in stmtcacher_ctx.go (Go >= 1.8) or stmtcacher_noctx.go (Go < 1.8).
|
||||
|
||||
// StmtCache wraps and delegates down to a Preparer type
|
||||
//
|
||||
// It also automatically prepares all statements sent to the underlying Preparer calls
|
||||
// for Exec, Query and QueryRow and caches the returns *sql.Stmt using the provided
|
||||
// query as the key. So that it can be automatically re-used.
|
||||
type StmtCache struct {
|
||||
prep Preparer
|
||||
cache map[string]*sql.Stmt
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// Prepare delegates down to the underlying Preparer and caches the result
|
||||
// using the provided query as a key
|
||||
func (sc *StmtCache) Prepare(query string) (*sql.Stmt, error) {
|
||||
sc.mu.Lock()
|
||||
defer sc.mu.Unlock()
|
||||
|
||||
stmt, ok := sc.cache[query]
|
||||
if ok {
|
||||
return stmt, nil
|
||||
}
|
||||
stmt, err := sc.prep.Prepare(query)
|
||||
if err == nil {
|
||||
sc.cache[query] = stmt
|
||||
}
|
||||
return stmt, err
|
||||
}
|
||||
|
||||
// Exec delegates down to the underlying Preparer using a prepared statement
|
||||
func (sc *StmtCache) Exec(query string, args ...interface{}) (res sql.Result, err error) {
|
||||
stmt, err := sc.Prepare(query)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return stmt.Exec(args...)
|
||||
}
|
||||
|
||||
// Query delegates down to the underlying Preparer using a prepared statement
|
||||
func (sc *StmtCache) Query(query string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
stmt, err := sc.Prepare(query)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return stmt.Query(args...)
|
||||
}
|
||||
|
||||
// QueryRow delegates down to the underlying Preparer using a prepared statement
|
||||
func (sc *StmtCache) QueryRow(query string, args ...interface{}) RowScanner {
|
||||
stmt, err := sc.Prepare(query)
|
||||
if err != nil {
|
||||
return &Row{err: err}
|
||||
}
|
||||
return stmt.QueryRow(args...)
|
||||
}
|
||||
|
||||
// Clear removes and closes all the currently cached prepared statements
|
||||
func (sc *StmtCache) Clear() (err error) {
|
||||
sc.mu.Lock()
|
||||
defer sc.mu.Unlock()
|
||||
|
||||
for key, stmt := range sc.cache {
|
||||
delete(sc.cache, key)
|
||||
|
||||
if stmt == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if cerr := stmt.Close(); cerr != nil {
|
||||
err = cerr
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("one or more Stmt.Close failed; last error: %v", err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
type DBProxyBeginner interface {
|
||||
DBProxy
|
||||
Begin() (*sql.Tx, error)
|
||||
}
|
||||
|
||||
type stmtCacheProxy struct {
|
||||
DBProxy
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func NewStmtCacheProxy(db *sql.DB) DBProxyBeginner {
|
||||
return &stmtCacheProxy{DBProxy: NewStmtCache(db), db: db}
|
||||
}
|
||||
|
||||
func (sp *stmtCacheProxy) Begin() (*sql.Tx, error) {
|
||||
return sp.db.Begin()
|
||||
}
|
||||
86
vendor/github.com/Masterminds/squirrel/stmtcacher_ctx.go
generated
vendored
Normal file
86
vendor/github.com/Masterminds/squirrel/stmtcacher_ctx.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
// +build go1.8
|
||||
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
// PrepareerContext is the interface that wraps the Prepare and PrepareContext methods.
|
||||
//
|
||||
// Prepare executes the given query as implemented by database/sql.Prepare.
|
||||
// PrepareContext executes the given query as implemented by database/sql.PrepareContext.
|
||||
type PreparerContext interface {
|
||||
Preparer
|
||||
PrepareContext(ctx context.Context, query string) (*sql.Stmt, error)
|
||||
}
|
||||
|
||||
// DBProxyContext groups the Execer, Queryer, QueryRower and PreparerContext interfaces.
|
||||
type DBProxyContext interface {
|
||||
Execer
|
||||
Queryer
|
||||
QueryRower
|
||||
PreparerContext
|
||||
}
|
||||
|
||||
// NewStmtCache returns a *StmtCache wrapping a PreparerContext that caches Prepared Stmts.
|
||||
//
|
||||
// Stmts are cached based on the string value of their queries.
|
||||
func NewStmtCache(prep PreparerContext) *StmtCache {
|
||||
return &StmtCache{prep: prep, cache: make(map[string]*sql.Stmt)}
|
||||
}
|
||||
|
||||
// NewStmtCacher is deprecated
|
||||
//
|
||||
// Use NewStmtCache instead
|
||||
func NewStmtCacher(prep PreparerContext) DBProxyContext {
|
||||
return NewStmtCache(prep)
|
||||
}
|
||||
|
||||
// PrepareContext delegates down to the underlying PreparerContext and caches the result
|
||||
// using the provided query as a key
|
||||
func (sc *StmtCache) PrepareContext(ctx context.Context, query string) (*sql.Stmt, error) {
|
||||
ctxPrep, ok := sc.prep.(PreparerContext)
|
||||
if !ok {
|
||||
return nil, NoContextSupport
|
||||
}
|
||||
sc.mu.Lock()
|
||||
defer sc.mu.Unlock()
|
||||
stmt, ok := sc.cache[query]
|
||||
if ok {
|
||||
return stmt, nil
|
||||
}
|
||||
stmt, err := ctxPrep.PrepareContext(ctx, query)
|
||||
if err == nil {
|
||||
sc.cache[query] = stmt
|
||||
}
|
||||
return stmt, err
|
||||
}
|
||||
|
||||
// ExecContext delegates down to the underlying PreparerContext using a prepared statement
|
||||
func (sc *StmtCache) ExecContext(ctx context.Context, query string, args ...interface{}) (res sql.Result, err error) {
|
||||
stmt, err := sc.PrepareContext(ctx, query)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return stmt.ExecContext(ctx, args...)
|
||||
}
|
||||
|
||||
// QueryContext delegates down to the underlying PreparerContext using a prepared statement
|
||||
func (sc *StmtCache) QueryContext(ctx context.Context, query string, args ...interface{}) (rows *sql.Rows, err error) {
|
||||
stmt, err := sc.PrepareContext(ctx, query)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return stmt.QueryContext(ctx, args...)
|
||||
}
|
||||
|
||||
// QueryRowContext delegates down to the underlying PreparerContext using a prepared statement
|
||||
func (sc *StmtCache) QueryRowContext(ctx context.Context, query string, args ...interface{}) RowScanner {
|
||||
stmt, err := sc.PrepareContext(ctx, query)
|
||||
if err != nil {
|
||||
return &Row{err: err}
|
||||
}
|
||||
return stmt.QueryRowContext(ctx, args...)
|
||||
}
|
||||
21
vendor/github.com/Masterminds/squirrel/stmtcacher_noctx.go
generated
vendored
Normal file
21
vendor/github.com/Masterminds/squirrel/stmtcacher_noctx.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// +build !go1.8
|
||||
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
// NewStmtCacher returns a DBProxy wrapping prep that caches Prepared Stmts.
|
||||
//
|
||||
// Stmts are cached based on the string value of their queries.
|
||||
func NewStmtCache(prep Preparer) *StmtCache {
|
||||
return &StmtCacher{prep: prep, cache: make(map[string]*sql.Stmt)}
|
||||
}
|
||||
|
||||
// NewStmtCacher is deprecated
|
||||
//
|
||||
// Use NewStmtCache instead
|
||||
func NewStmtCacher(prep Preparer) DBProxy {
|
||||
return NewStmtCache(prep)
|
||||
}
|
||||
252
vendor/github.com/Masterminds/squirrel/update.go
generated
vendored
Normal file
252
vendor/github.com/Masterminds/squirrel/update.go
generated
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
type updateData struct {
|
||||
PlaceholderFormat PlaceholderFormat
|
||||
RunWith BaseRunner
|
||||
Prefixes []Sqlizer
|
||||
Table string
|
||||
SetClauses []setClause
|
||||
WhereParts []Sqlizer
|
||||
OrderBys []string
|
||||
Limit string
|
||||
Offset string
|
||||
Suffixes []Sqlizer
|
||||
}
|
||||
|
||||
type setClause struct {
|
||||
column string
|
||||
value interface{}
|
||||
}
|
||||
|
||||
func (d *updateData) Exec() (sql.Result, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return ExecWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *updateData) Query() (*sql.Rows, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
return QueryWith(d.RunWith, d)
|
||||
}
|
||||
|
||||
func (d *updateData) QueryRow() RowScanner {
|
||||
if d.RunWith == nil {
|
||||
return &Row{err: RunnerNotSet}
|
||||
}
|
||||
queryRower, ok := d.RunWith.(QueryRower)
|
||||
if !ok {
|
||||
return &Row{err: RunnerNotQueryRunner}
|
||||
}
|
||||
return QueryRowWith(queryRower, d)
|
||||
}
|
||||
|
||||
func (d *updateData) ToSql() (sqlStr string, args []interface{}, err error) {
|
||||
if len(d.Table) == 0 {
|
||||
err = fmt.Errorf("update statements must specify a table")
|
||||
return
|
||||
}
|
||||
if len(d.SetClauses) == 0 {
|
||||
err = fmt.Errorf("update statements must have at least one Set clause")
|
||||
return
|
||||
}
|
||||
|
||||
sql := &bytes.Buffer{}
|
||||
|
||||
if len(d.Prefixes) > 0 {
|
||||
args, err = appendToSql(d.Prefixes, sql, " ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
sql.WriteString(" ")
|
||||
}
|
||||
|
||||
sql.WriteString("UPDATE ")
|
||||
sql.WriteString(d.Table)
|
||||
|
||||
sql.WriteString(" SET ")
|
||||
setSqls := make([]string, len(d.SetClauses))
|
||||
for i, setClause := range d.SetClauses {
|
||||
var valSql string
|
||||
if vs, ok := setClause.value.(Sqlizer); ok {
|
||||
vsql, vargs, err := vs.ToSql()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
valSql = vsql
|
||||
args = append(args, vargs...)
|
||||
} else {
|
||||
valSql = "?"
|
||||
args = append(args, setClause.value)
|
||||
}
|
||||
setSqls[i] = fmt.Sprintf("%s = %s", setClause.column, valSql)
|
||||
}
|
||||
sql.WriteString(strings.Join(setSqls, ", "))
|
||||
|
||||
if len(d.WhereParts) > 0 {
|
||||
sql.WriteString(" WHERE ")
|
||||
args, err = appendToSql(d.WhereParts, sql, " AND ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(d.OrderBys) > 0 {
|
||||
sql.WriteString(" ORDER BY ")
|
||||
sql.WriteString(strings.Join(d.OrderBys, ", "))
|
||||
}
|
||||
|
||||
if len(d.Limit) > 0 {
|
||||
sql.WriteString(" LIMIT ")
|
||||
sql.WriteString(d.Limit)
|
||||
}
|
||||
|
||||
if len(d.Offset) > 0 {
|
||||
sql.WriteString(" OFFSET ")
|
||||
sql.WriteString(d.Offset)
|
||||
}
|
||||
|
||||
if len(d.Suffixes) > 0 {
|
||||
sql.WriteString(" ")
|
||||
args, err = appendToSql(d.Suffixes, sql, " ", args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
sqlStr, err = d.PlaceholderFormat.ReplacePlaceholders(sql.String())
|
||||
return
|
||||
}
|
||||
|
||||
// Builder
|
||||
|
||||
// UpdateBuilder builds SQL UPDATE statements.
|
||||
type UpdateBuilder builder.Builder
|
||||
|
||||
func init() {
|
||||
builder.Register(UpdateBuilder{}, updateData{})
|
||||
}
|
||||
|
||||
// Format methods
|
||||
|
||||
// PlaceholderFormat sets PlaceholderFormat (e.g. Question or Dollar) for the
|
||||
// query.
|
||||
func (b UpdateBuilder) PlaceholderFormat(f PlaceholderFormat) UpdateBuilder {
|
||||
return builder.Set(b, "PlaceholderFormat", f).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Runner methods
|
||||
|
||||
// RunWith sets a Runner (like database/sql.DB) to be used with e.g. Exec.
|
||||
func (b UpdateBuilder) RunWith(runner BaseRunner) UpdateBuilder {
|
||||
return setRunWith(b, runner).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Exec builds and Execs the query with the Runner set by RunWith.
|
||||
func (b UpdateBuilder) Exec() (sql.Result, error) {
|
||||
data := builder.GetStruct(b).(updateData)
|
||||
return data.Exec()
|
||||
}
|
||||
|
||||
func (b UpdateBuilder) Query() (*sql.Rows, error) {
|
||||
data := builder.GetStruct(b).(updateData)
|
||||
return data.Query()
|
||||
}
|
||||
|
||||
func (b UpdateBuilder) QueryRow() RowScanner {
|
||||
data := builder.GetStruct(b).(updateData)
|
||||
return data.QueryRow()
|
||||
}
|
||||
|
||||
func (b UpdateBuilder) Scan(dest ...interface{}) error {
|
||||
return b.QueryRow().Scan(dest...)
|
||||
}
|
||||
|
||||
// SQL methods
|
||||
|
||||
// ToSql builds the query into a SQL string and bound args.
|
||||
func (b UpdateBuilder) ToSql() (string, []interface{}, error) {
|
||||
data := builder.GetStruct(b).(updateData)
|
||||
return data.ToSql()
|
||||
}
|
||||
|
||||
// Prefix adds an expression to the beginning of the query
|
||||
func (b UpdateBuilder) Prefix(sql string, args ...interface{}) UpdateBuilder {
|
||||
return b.PrefixExpr(Expr(sql, args...))
|
||||
}
|
||||
|
||||
// PrefixExpr adds an expression to the very beginning of the query
|
||||
func (b UpdateBuilder) PrefixExpr(expr Sqlizer) UpdateBuilder {
|
||||
return builder.Append(b, "Prefixes", expr).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Table sets the table to be updated.
|
||||
func (b UpdateBuilder) Table(table string) UpdateBuilder {
|
||||
return builder.Set(b, "Table", table).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Set adds SET clauses to the query.
|
||||
func (b UpdateBuilder) Set(column string, value interface{}) UpdateBuilder {
|
||||
return builder.Append(b, "SetClauses", setClause{column: column, value: value}).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// SetMap is a convenience method which calls .Set for each key/value pair in clauses.
|
||||
func (b UpdateBuilder) SetMap(clauses map[string]interface{}) UpdateBuilder {
|
||||
keys := make([]string, len(clauses))
|
||||
i := 0
|
||||
for key := range clauses {
|
||||
keys[i] = key
|
||||
i++
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, key := range keys {
|
||||
val, _ := clauses[key]
|
||||
b = b.Set(key, val)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Where adds WHERE expressions to the query.
|
||||
//
|
||||
// See SelectBuilder.Where for more information.
|
||||
func (b UpdateBuilder) Where(pred interface{}, args ...interface{}) UpdateBuilder {
|
||||
return builder.Append(b, "WhereParts", newWherePart(pred, args...)).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// OrderBy adds ORDER BY expressions to the query.
|
||||
func (b UpdateBuilder) OrderBy(orderBys ...string) UpdateBuilder {
|
||||
return builder.Extend(b, "OrderBys", orderBys).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Limit sets a LIMIT clause on the query.
|
||||
func (b UpdateBuilder) Limit(limit uint64) UpdateBuilder {
|
||||
return builder.Set(b, "Limit", fmt.Sprintf("%d", limit)).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Offset sets a OFFSET clause on the query.
|
||||
func (b UpdateBuilder) Offset(offset uint64) UpdateBuilder {
|
||||
return builder.Set(b, "Offset", fmt.Sprintf("%d", offset)).(UpdateBuilder)
|
||||
}
|
||||
|
||||
// Suffix adds an expression to the end of the query
|
||||
func (b UpdateBuilder) Suffix(sql string, args ...interface{}) UpdateBuilder {
|
||||
return b.SuffixExpr(Expr(sql, args...))
|
||||
}
|
||||
|
||||
// SuffixExpr adds an expression to the end of the query
|
||||
func (b UpdateBuilder) SuffixExpr(expr Sqlizer) UpdateBuilder {
|
||||
return builder.Append(b, "Suffixes", expr).(UpdateBuilder)
|
||||
}
|
||||
69
vendor/github.com/Masterminds/squirrel/update_ctx.go
generated
vendored
Normal file
69
vendor/github.com/Masterminds/squirrel/update_ctx.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
// +build go1.8
|
||||
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/lann/builder"
|
||||
)
|
||||
|
||||
func (d *updateData) ExecContext(ctx context.Context) (sql.Result, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
ctxRunner, ok := d.RunWith.(ExecerContext)
|
||||
if !ok {
|
||||
return nil, NoContextSupport
|
||||
}
|
||||
return ExecContextWith(ctx, ctxRunner, d)
|
||||
}
|
||||
|
||||
func (d *updateData) QueryContext(ctx context.Context) (*sql.Rows, error) {
|
||||
if d.RunWith == nil {
|
||||
return nil, RunnerNotSet
|
||||
}
|
||||
ctxRunner, ok := d.RunWith.(QueryerContext)
|
||||
if !ok {
|
||||
return nil, NoContextSupport
|
||||
}
|
||||
return QueryContextWith(ctx, ctxRunner, d)
|
||||
}
|
||||
|
||||
func (d *updateData) QueryRowContext(ctx context.Context) RowScanner {
|
||||
if d.RunWith == nil {
|
||||
return &Row{err: RunnerNotSet}
|
||||
}
|
||||
queryRower, ok := d.RunWith.(QueryRowerContext)
|
||||
if !ok {
|
||||
if _, ok := d.RunWith.(QueryerContext); !ok {
|
||||
return &Row{err: RunnerNotQueryRunner}
|
||||
}
|
||||
return &Row{err: NoContextSupport}
|
||||
}
|
||||
return QueryRowContextWith(ctx, queryRower, d)
|
||||
}
|
||||
|
||||
// ExecContext builds and ExecContexts the query with the Runner set by RunWith.
|
||||
func (b UpdateBuilder) ExecContext(ctx context.Context) (sql.Result, error) {
|
||||
data := builder.GetStruct(b).(updateData)
|
||||
return data.ExecContext(ctx)
|
||||
}
|
||||
|
||||
// QueryContext builds and QueryContexts the query with the Runner set by RunWith.
|
||||
func (b UpdateBuilder) QueryContext(ctx context.Context) (*sql.Rows, error) {
|
||||
data := builder.GetStruct(b).(updateData)
|
||||
return data.QueryContext(ctx)
|
||||
}
|
||||
|
||||
// QueryRowContext builds and QueryRowContexts the query with the Runner set by RunWith.
|
||||
func (b UpdateBuilder) QueryRowContext(ctx context.Context) RowScanner {
|
||||
data := builder.GetStruct(b).(updateData)
|
||||
return data.QueryRowContext(ctx)
|
||||
}
|
||||
|
||||
// ScanContext is a shortcut for QueryRowContext().Scan.
|
||||
func (b UpdateBuilder) ScanContext(ctx context.Context, dest ...interface{}) error {
|
||||
return b.QueryRowContext(ctx).Scan(dest...)
|
||||
}
|
||||
30
vendor/github.com/Masterminds/squirrel/where.go
generated
vendored
Normal file
30
vendor/github.com/Masterminds/squirrel/where.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package squirrel
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type wherePart part
|
||||
|
||||
func newWherePart(pred interface{}, args ...interface{}) Sqlizer {
|
||||
return &wherePart{pred: pred, args: args}
|
||||
}
|
||||
|
||||
func (p wherePart) ToSql() (sql string, args []interface{}, err error) {
|
||||
switch pred := p.pred.(type) {
|
||||
case nil:
|
||||
// no-op
|
||||
case rawSqlizer:
|
||||
return pred.toSqlRaw()
|
||||
case Sqlizer:
|
||||
return pred.ToSql()
|
||||
case map[string]interface{}:
|
||||
return Eq(pred).ToSql()
|
||||
case string:
|
||||
sql = pred
|
||||
args = p.args
|
||||
default:
|
||||
err = fmt.Errorf("expected string-keyed map or string, not %T", pred)
|
||||
}
|
||||
return
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user