Prevent infinite loops with nested subqueries
This commit is contained in:
parent
d2a451345a
commit
fb256df42b
9 changed files with 67 additions and 0 deletions
48
db/context.go
Normal file
48
db/context.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
// Copyright © 2016 Abcum Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
func vers(ctx context.Context) int {
|
||||
|
||||
v := ctx.Value(ctxKeyDive)
|
||||
|
||||
switch v {
|
||||
case nil:
|
||||
return 0
|
||||
default:
|
||||
return v.(int)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func dive(ctx context.Context) context.Context {
|
||||
|
||||
v := ctx.Value(ctxKeyDive)
|
||||
|
||||
switch v {
|
||||
case nil:
|
||||
return context.WithValue(ctx, ctxKeyDive, 1)
|
||||
default:
|
||||
if v.(int) > maxRecursiveQueries {
|
||||
panic(errRecursiveOverload)
|
||||
}
|
||||
return context.WithValue(ctx, ctxKeyDive, v.(int)+1)
|
||||
}
|
||||
|
||||
}
|
|
@ -76,6 +76,8 @@ func (e *executor) executeCreate(ctx context.Context, stm *sql.CreateStatement)
|
|||
|
||||
func (e *executor) fetchCreate(ctx context.Context, stm *sql.CreateStatement, doc *data.Doc) (interface{}, error) {
|
||||
|
||||
ctx = dive(ctx)
|
||||
|
||||
if doc != nil {
|
||||
vars := data.New()
|
||||
vars.Set(doc.Data(), varKeyParent)
|
||||
|
|
|
@ -75,6 +75,8 @@ func (e *executor) executeDelete(ctx context.Context, stm *sql.DeleteStatement)
|
|||
|
||||
func (e *executor) fetchDelete(ctx context.Context, stm *sql.DeleteStatement, doc *data.Doc) (interface{}, error) {
|
||||
|
||||
ctx = dive(ctx)
|
||||
|
||||
if doc != nil {
|
||||
vars := data.New()
|
||||
vars.Set(doc.Data(), varKeyParent)
|
||||
|
|
|
@ -54,6 +54,8 @@ func (e *executor) executeInsert(ctx context.Context, stm *sql.InsertStatement)
|
|||
|
||||
func (e *executor) fetchInsert(ctx context.Context, stm *sql.InsertStatement, doc *data.Doc) (interface{}, error) {
|
||||
|
||||
ctx = dive(ctx)
|
||||
|
||||
if doc != nil {
|
||||
vars := data.New()
|
||||
vars.Set(doc.Data(), varKeyParent)
|
||||
|
|
|
@ -68,6 +68,8 @@ func (e *executor) executeRelate(ctx context.Context, stm *sql.RelateStatement)
|
|||
|
||||
func (e *executor) fetchRelate(ctx context.Context, stm *sql.RelateStatement, doc *data.Doc) (interface{}, error) {
|
||||
|
||||
ctx = dive(ctx)
|
||||
|
||||
if doc != nil {
|
||||
vars := data.New()
|
||||
vars.Set(doc.Data(), varKeyParent)
|
||||
|
|
|
@ -84,6 +84,8 @@ func (e *executor) executeSelect(ctx context.Context, stm *sql.SelectStatement)
|
|||
|
||||
func (e *executor) fetchSelect(ctx context.Context, stm *sql.SelectStatement, doc *data.Doc) (interface{}, error) {
|
||||
|
||||
ctx = dive(ctx)
|
||||
|
||||
if doc != nil {
|
||||
vars := data.New()
|
||||
vars.Set(doc.Data(), varKeyParent)
|
||||
|
|
|
@ -75,6 +75,8 @@ func (e *executor) executeUpdate(ctx context.Context, stm *sql.UpdateStatement)
|
|||
|
||||
func (e *executor) fetchUpdate(ctx context.Context, stm *sql.UpdateStatement, doc *data.Doc) (interface{}, error) {
|
||||
|
||||
ctx = dive(ctx)
|
||||
|
||||
if doc != nil {
|
||||
vars := data.New()
|
||||
vars.Set(doc.Data(), varKeyParent)
|
||||
|
|
|
@ -54,6 +54,8 @@ func (e *executor) executeUpsert(ctx context.Context, stm *sql.UpsertStatement)
|
|||
|
||||
func (e *executor) fetchUpsert(ctx context.Context, stm *sql.UpsertStatement, doc *data.Doc) (interface{}, error) {
|
||||
|
||||
ctx = dive(ctx)
|
||||
|
||||
if doc != nil {
|
||||
vars := data.New()
|
||||
vars.Set(doc.Data(), varKeyParent)
|
||||
|
|
|
@ -38,6 +38,7 @@ const (
|
|||
ctxKeyId = "id"
|
||||
ctxKeyNs = "ns"
|
||||
ctxKeyDb = "db"
|
||||
ctxKeyDive = "dive"
|
||||
ctxKeyVars = "vars"
|
||||
ctxKeySubs = "subs"
|
||||
ctxKeySpec = "spec"
|
||||
|
@ -71,6 +72,10 @@ var (
|
|||
// to process each query statement concurrently.
|
||||
workerCount = runtime.NumCPU() * 2
|
||||
|
||||
// maxRecursiveQueries specifies how many queries will be
|
||||
// processed recursively before the query is cancelled.
|
||||
maxRecursiveQueries = 50
|
||||
|
||||
// queryIdentFailed occurs when a permission query asks
|
||||
// for a field, meaning a document has to be fetched.
|
||||
queryIdentFailed = errors.New("Found ident but no doc available")
|
||||
|
|
Loading…
Reference in a new issue