github.com/gogf/gf/v2@v2.7.4/database/gdb/gdb_core_ctx.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gdb
     8  
     9  import (
    10  	"context"
    11  	"sync"
    12  
    13  	"github.com/gogf/gf/v2/errors/gcode"
    14  	"github.com/gogf/gf/v2/errors/gerror"
    15  	"github.com/gogf/gf/v2/os/gctx"
    16  )
    17  
    18  // internalCtxData stores data in ctx for internal usage purpose.
    19  type internalCtxData struct {
    20  	sync.Mutex
    21  	// Used configuration node in current operation.
    22  	ConfigNode *ConfigNode
    23  }
    24  
    25  // column stores column data in ctx for internal usage purpose.
    26  type internalColumnData struct {
    27  	// The first column in result response from database server.
    28  	// This attribute is used for Value/Count selection statement purpose,
    29  	// which is to avoid HOOK handler that might modify the result columns
    30  	// that can confuse the Value/Count selection statement logic.
    31  	FirstResultColumn string
    32  }
    33  
    34  const (
    35  	internalCtxDataKeyInCtx    gctx.StrKey = "InternalCtxData"
    36  	internalColumnDataKeyInCtx gctx.StrKey = "InternalColumnData"
    37  
    38  	// `ignoreResultKeyInCtx` is a mark for some db drivers that do not support `RowsAffected` function,
    39  	// for example: `clickhouse`. The `clickhouse` does not support fetching insert/update results,
    40  	// but returns errors when execute `RowsAffected`. It here ignores the calling of `RowsAffected`
    41  	// to avoid triggering errors, rather than ignoring errors after they are triggered.
    42  	ignoreResultKeyInCtx gctx.StrKey = "IgnoreResult"
    43  )
    44  
    45  func (c *Core) injectInternalCtxData(ctx context.Context) context.Context {
    46  	// If the internal data is already injected, it does nothing.
    47  	if ctx.Value(internalCtxDataKeyInCtx) != nil {
    48  		return ctx
    49  	}
    50  	return context.WithValue(ctx, internalCtxDataKeyInCtx, &internalCtxData{
    51  		ConfigNode: c.config,
    52  	})
    53  }
    54  
    55  func (c *Core) setConfigNodeToCtx(ctx context.Context, node *ConfigNode) error {
    56  	value := ctx.Value(internalCtxDataKeyInCtx)
    57  	if value == nil {
    58  		return gerror.NewCode(gcode.CodeInternalError, `no internal data found in context`)
    59  	}
    60  
    61  	data := value.(*internalCtxData)
    62  	data.Lock()
    63  	defer data.Unlock()
    64  	data.ConfigNode = node
    65  	return nil
    66  }
    67  
    68  func (c *Core) getConfigNodeFromCtx(ctx context.Context) *ConfigNode {
    69  	if value := ctx.Value(internalCtxDataKeyInCtx); value != nil {
    70  		data := value.(*internalCtxData)
    71  		data.Lock()
    72  		defer data.Unlock()
    73  		return data.ConfigNode
    74  	}
    75  	return nil
    76  }
    77  
    78  func (c *Core) injectInternalColumn(ctx context.Context) context.Context {
    79  	return context.WithValue(ctx, internalColumnDataKeyInCtx, &internalColumnData{})
    80  }
    81  
    82  func (c *Core) getInternalColumnFromCtx(ctx context.Context) *internalColumnData {
    83  	if v := ctx.Value(internalColumnDataKeyInCtx); v != nil {
    84  		return v.(*internalColumnData)
    85  	}
    86  	return nil
    87  }
    88  
    89  func (c *Core) InjectIgnoreResult(ctx context.Context) context.Context {
    90  	if ctx.Value(ignoreResultKeyInCtx) != nil {
    91  		return ctx
    92  	}
    93  	return context.WithValue(ctx, ignoreResultKeyInCtx, true)
    94  }
    95  
    96  func (c *Core) GetIgnoreResultFromCtx(ctx context.Context) bool {
    97  	return ctx.Value(ignoreResultKeyInCtx) != nil
    98  }