package ocsql

import (
	
	
	
	
	
	
	
	
	

	
)

type conn interface {
	driver.Pinger
	driver.Execer
	driver.ExecerContext
	driver.Queryer
	driver.QueryerContext
	driver.Conn
	driver.ConnPrepareContext
	driver.ConnBeginTx
}

var (
	regMu              sync.Mutex
	attrMissingContext = trace.StringAttribute("ocsql.warning", "missing upstream context")
	attrDeprecated     = trace.StringAttribute("ocsql.warning", "database driver uses deprecated features")
Register initializes and registers our ocsql wrapped database driver identified by its driverName and using provided TraceOptions. On success it returns the generated driverName to use when calling sql.Open. It is possible to register multiple wrappers for the same database driver if needing different TraceOptions for different connections.
retrieve the driver implementation we need to wrap with instrumentation
	,  := sql.Open(, "")
	if  != nil {
		return "", 
	}
	 := .Driver()
	if  = .Close();  != nil {
		return "", 
	}

	regMu.Lock()
	defer regMu.Unlock()
Since we might want to register multiple ocsql drivers to have different TraceOptions, but potentially the same underlying database driver, we cycle through to find available driver names.
	 =  + "-ocsql-"
	for  := int64(0);  < 100; ++ {
		var (
			   = false
			 =  + strconv.FormatInt(, 10)
		)
		for ,  := range sql.Drivers() {
			if  ==  {
				 = true
			}
		}
		if ! {
			sql.Register(, Wrap(, ...))
			return , nil
		}
	}
	return "", errors.New("unable to register driver, all slots have been taken")
}
Wrap takes a SQL driver and wraps it with OpenCensus instrumentation.
func ( driver.Driver,  ...TraceOption) driver.Driver {
	 := TraceOptions{}
	for ,  := range  {
		(&)
	}
	if .QueryParams && !.Query {
		.QueryParams = false
	}
	return wrapDriver(, )
}
Open implements driver.Driver
func ( ocDriver) ( string) (driver.Conn, error) {
	,  := .parent.Open()
	if  != nil {
		return nil, 
	}
	return wrapConn(, .options), nil
}
WrapConn allows an existing driver.Conn to be wrapped by ocsql.
func ( driver.Conn,  ...TraceOption) driver.Conn {
	 := TraceOptions{}
	for ,  := range  {
		(&)
	}
	return wrapConn(, )
}
ocConn implements driver.Conn
type ocConn struct {
	parent  driver.Conn
	options TraceOptions
}

func ( ocConn) ( context.Context) ( error) {
	defer recordCallStats(, "go.sql.ping")()

	if .options.Ping && (.options.AllowRoot || trace.FromContext() != nil) {
		var  *trace.Span
		,  = trace.StartSpan(, "sql:ping", trace.WithSpanKind(trace.SpanKindClient))
		if len(.options.DefaultAttributes) > 0 {
			.AddAttributes(.options.DefaultAttributes...)
		}
		defer func() {
			if  != nil {
				.SetStatus(trace.Status{
					Code:    trace.StatusCodeUnavailable,
					Message: .Error(),
				})
			} else {
				.SetStatus(trace.Status{Code: trace.StatusCodeOK})
			}
			.End()
		}()
	}

	if ,  := .parent.(driver.Pinger);  {
		 = .Ping()
	}
	return
}

func ( ocConn) ( string,  []driver.Value) ( driver.Result,  error) {
	defer recordCallStats(context.Background(), "go.sql.exec")()

	if ,  := .parent.(driver.Execer);  {
		if !.options.AllowRoot {
			return .Exec(, )
		}

		,  := trace.StartSpan(context.Background(), "sql:exec", trace.WithSpanKind(trace.SpanKindClient))
		 := make([]trace.Attribute, 0, len(.options.DefaultAttributes)+2)
		 = append(, .options.DefaultAttributes...)
		 = append(
			,
			attrDeprecated,
			trace.StringAttribute(
				"ocsql.deprecated", "driver does not support ExecerContext",
			),
		)
		if .options.Query {
			 = append(, trace.StringAttribute("sql.query", ))
			if .options.QueryParams {
				 = append(, paramsAttr()...)
			}
		}
		.AddAttributes(...)

		defer func() {
			setSpanStatus(, )
			.End()
		}()

		if ,  = .Exec(, );  != nil {
			return nil, 
		}

		return ocResult{parent: , ctx: , options: .options}, nil
	}

	return nil, driver.ErrSkip
}

func ( ocConn) ( context.Context,  string,  []driver.NamedValue) ( driver.Result,  error) {
	defer recordCallStats(, "go.sql.exec")()

	if ,  := .parent.(driver.ExecerContext);  {
		 := trace.FromContext()
		if !.options.AllowRoot &&  == nil {
			return .ExecContext(, , )
		}

		var  *trace.Span
		if  == nil {
			,  = trace.StartSpan(, "sql:exec", trace.WithSpanKind(trace.SpanKindClient))
		} else {
			_,  = trace.StartSpan(, "sql:exec", trace.WithSpanKind(trace.SpanKindClient))
		}
		 := append([]trace.Attribute(nil), .options.DefaultAttributes...)
		if .options.Query {
			 = append(, trace.StringAttribute("sql.query", ))
			if .options.QueryParams {
				 = append(, namedParamsAttr()...)
			}
		}
		.AddAttributes(...)

		defer func() {
			setSpanStatus(, )
			.End()
		}()

		if ,  = .ExecContext(, , );  != nil {
			return nil, 
		}

		return ocResult{parent: , ctx: , options: .options}, nil
	}

	return nil, driver.ErrSkip
}

func ( ocConn) ( string,  []driver.Value) ( driver.Rows,  error) {
	defer recordCallStats(context.Background(), "go.sql.query")()

	if ,  := .parent.(driver.Queryer);  {
		if !.options.AllowRoot {
			return .Query(, )
		}

		,  := trace.StartSpan(context.Background(), "sql:query", trace.WithSpanKind(trace.SpanKindClient))
		 := make([]trace.Attribute, 0, len(.options.DefaultAttributes)+2)
		 = append(, .options.DefaultAttributes...)
		 = append(
			,
			attrDeprecated,
			trace.StringAttribute(
				"ocsql.deprecated", "driver does not support QueryerContext",
			),
		)
		if .options.Query {
			 = append(, trace.StringAttribute("sql.query", ))
			if .options.QueryParams {
				 = append(, paramsAttr()...)
			}
		}
		.AddAttributes(...)

		defer func() {
			setSpanStatus(, )
			.End()
		}()

		,  = .Query(, )
		if  != nil {
			return nil, 
		}

		return wrapRows(, , .options), nil
	}

	return nil, driver.ErrSkip
}

func ( ocConn) ( context.Context,  string,  []driver.NamedValue) ( driver.Rows,  error) {
	defer recordCallStats(, "go.sql.query")()

	if ,  := .parent.(driver.QueryerContext);  {
		 := trace.FromContext()
		if !.options.AllowRoot &&  == nil {
			return .QueryContext(, , )
		}

		var  *trace.Span
		if  == nil {
			,  = trace.StartSpan(, "sql:query", trace.WithSpanKind(trace.SpanKindClient))
		} else {
			_,  = trace.StartSpan(, "sql:query", trace.WithSpanKind(trace.SpanKindClient))
		}
		 := append([]trace.Attribute(nil), .options.DefaultAttributes...)
		if .options.Query {
			 = append(, trace.StringAttribute("sql.query", ))
			if .options.QueryParams {
				 = append(, namedParamsAttr()...)
			}
		}
		.AddAttributes(...)

		defer func() {
			setSpanStatus(, )
			.End()
		}()

		,  = .QueryContext(, , )
		if  != nil {
			return nil, 
		}

		return wrapRows(, , .options), nil
	}

	return nil, driver.ErrSkip
}

func ( ocConn) ( string) ( driver.Stmt,  error) {
	defer recordCallStats(context.Background(), "go.sql.prepare")()

	if .options.AllowRoot {
		,  := trace.StartSpan(context.Background(), "sql:prepare", trace.WithSpanKind(trace.SpanKindClient))
		 := make([]trace.Attribute, 0, len(.options.DefaultAttributes)+1)
		 = append(, .options.DefaultAttributes...)
		 = append(, attrMissingContext)
		if .options.Query {
			 = append(, trace.StringAttribute("sql.query", ))
		}
		.AddAttributes(...)

		defer func() {
			setSpanStatus(, )
			.End()
		}()
	}

	,  = .parent.Prepare()
	if  != nil {
		return nil, 
	}

	 = wrapStmt(, , .options)
	return
}

func ( *ocConn) () error {
	return .parent.Close()
}

func ( *ocConn) () (driver.Tx, error) {
	return .BeginTx(context.TODO(), driver.TxOptions{})
}

func ( *ocConn) ( context.Context,  string) ( driver.Stmt,  error) {
	defer recordCallStats(, "go.sql.prepare")()

	var  *trace.Span
	 := append([]trace.Attribute(nil), .options.DefaultAttributes...)
	if .options.AllowRoot || trace.FromContext() != nil {
		,  = trace.StartSpan(, "sql:prepare", trace.WithSpanKind(trace.SpanKindClient))
		if .options.Query {
			 = append(, trace.StringAttribute("sql.query", ))
		}
		defer func() {
			setSpanStatus(, )
			.End()
		}()
	}

	if ,  := .parent.(driver.ConnPrepareContext);  {
		,  = .PrepareContext(, )
	} else {
		if  != nil {
			 = append(, attrMissingContext)
		}
		,  = .parent.Prepare()
	}
	.AddAttributes(...)
	if  != nil {
		return nil, 
	}

	 = wrapStmt(, , .options)
	return
}

func ( *ocConn) ( context.Context,  driver.TxOptions) ( driver.Tx,  error) {
	defer recordCallStats(, "go.sql.begin")()

	if !.options.AllowRoot && trace.FromContext() == nil {
		if ,  := .parent.(driver.ConnBeginTx);  {
			return .BeginTx(, )
		}
		return .parent.Begin()
	}

	var  *trace.Span
	 := append([]trace.Attribute(nil), .options.DefaultAttributes...)

	if  == nil ||  == context.TODO() {
		 = context.Background()
		_,  = trace.StartSpan(, "sql:begin_transaction", trace.WithSpanKind(trace.SpanKindClient))
		 = append(, attrMissingContext)
	} else {
		_,  = trace.StartSpan(, "sql:begin_transaction", trace.WithSpanKind(trace.SpanKindClient))
	}
	defer func() {
		if len() > 0 {
			.AddAttributes(...)
		}
		.End()
	}()

	if ,  := .parent.(driver.ConnBeginTx);  {
		,  = .BeginTx(, )
		setSpanStatus(, )
		if  != nil {
			return nil, 
		}
		return ocTx{parent: , ctx: , options: .options}, nil
	}

	 = append(
		,
		attrDeprecated,
		trace.StringAttribute(
			"ocsql.deprecated", "driver does not support ConnBeginTx",
		),
	)
	,  = .parent.Begin()
	setSpanStatus(, )
	if  != nil {
		return nil, 
	}
	return ocTx{parent: , ctx: , options: .options}, nil
}
ocResult implements driver.Result
type ocResult struct {
	parent  driver.Result
	ctx     context.Context
	options TraceOptions
}

func ( ocResult) () ( int64,  error) {
	if .options.LastInsertID {
		,  := trace.StartSpan(.ctx, "sql:last_insert_id", trace.WithSpanKind(trace.SpanKindClient))
		if len(.options.DefaultAttributes) > 0 {
			.AddAttributes(.options.DefaultAttributes...)
		}
		defer func() {
			setSpanStatus(, )
			.End()
		}()
	}

	,  = .parent.LastInsertId()
	return
}

func ( ocResult) () ( int64,  error) {
	if .options.RowsAffected {
		,  := trace.StartSpan(.ctx, "sql:rows_affected", trace.WithSpanKind(trace.SpanKindClient))
		if len(.options.DefaultAttributes) > 0 {
			.AddAttributes(.options.DefaultAttributes...)
		}
		defer func() {
			setSpanStatus(, )
			.End()
		}()
	}

	,  = .parent.RowsAffected()
	return
}
ocStmt implements driver.Stmt
type ocStmt struct {
	parent  driver.Stmt
	query   string
	options TraceOptions
}

func ( ocStmt) ( []driver.Value) ( driver.Result,  error) {
	defer recordCallStats(context.Background(), "go.sql.stmt.exec")()

	if !.options.AllowRoot {
		return .parent.Exec()
	}

	,  := trace.StartSpan(context.Background(), "sql:exec", trace.WithSpanKind(trace.SpanKindClient))
	 := make([]trace.Attribute, 0, len(.options.DefaultAttributes)+2)
	 = append(, .options.DefaultAttributes...)
	 = append(
		,
		attrDeprecated,
		trace.StringAttribute(
			"ocsql.deprecated", "driver does not support StmtExecContext",
		),
	)
	if .options.Query {
		 = append(, trace.StringAttribute("sql.query", .query))
		if .options.QueryParams {
			 = append(, paramsAttr()...)
		}
	}
	.AddAttributes(...)

	defer func() {
		setSpanStatus(, )
		.End()
	}()

	,  = .parent.Exec()
	if  != nil {
		return nil, 
	}

	,  = ocResult{parent: , ctx: , options: .options}, nil
	return
}

func ( ocStmt) () error {
	return .parent.Close()
}

func ( ocStmt) () int {
	return .parent.NumInput()
}

func ( ocStmt) ( []driver.Value) ( driver.Rows,  error) {
	defer recordCallStats(context.Background(), "go.sql.stmt.query")()

	if !.options.AllowRoot {
		return .parent.Query()
	}

	,  := trace.StartSpan(context.Background(), "sql:query", trace.WithSpanKind(trace.SpanKindClient))
	 := make([]trace.Attribute, 0, len(.options.DefaultAttributes)+2)
	 = append(, .options.DefaultAttributes...)
	 = append(
		,
		attrDeprecated,
		trace.StringAttribute(
			"ocsql.deprecated", "driver does not support StmtQueryContext",
		),
	)
	if .options.Query {
		 = append(, trace.StringAttribute("sql.query", .query))
		if .options.QueryParams {
			 = append(, paramsAttr()...)
		}
	}
	.AddAttributes(...)

	defer func() {
		setSpanStatus(, )
		.End()
	}()

	,  = .parent.Query()
	if  != nil {
		return nil, 
	}
	,  = wrapRows(, , .options), nil
	return
}

func ( ocStmt) ( context.Context,  []driver.NamedValue) ( driver.Result,  error) {
	defer recordCallStats(, "go.sql.stmt.exec")()

	 := trace.FromContext()
we already tested driver to implement StmtExecContext
		return .parent.(driver.StmtExecContext).ExecContext(, )
	}

	var  *trace.Span
	if  == nil {
		,  = trace.StartSpan(, "sql:exec", trace.WithSpanKind(trace.SpanKindClient))
	} else {
		_,  = trace.StartSpan(, "sql:exec", trace.WithSpanKind(trace.SpanKindClient))
	}
	 := append([]trace.Attribute(nil), .options.DefaultAttributes...)
	if .options.Query {
		 = append(, trace.StringAttribute("sql.query", .query))
		if .options.QueryParams {
			 = append(, namedParamsAttr()...)
		}
	}
	.AddAttributes(...)

	defer func() {
		setSpanStatus(, )
		.End()
	}()
we already tested driver to implement StmtExecContext
	 := .parent.(driver.StmtExecContext)
	,  = .ExecContext(, )
	if  != nil {
		return nil, 
	}
	,  = ocResult{parent: , ctx: , options: .options}, nil
	return
}

func ( ocStmt) ( context.Context,  []driver.NamedValue) ( driver.Rows,  error) {
	defer recordCallStats(, "go.sql.stmt.query")()

	 := trace.FromContext()
we already tested driver to implement StmtQueryContext
		return .parent.(driver.StmtQueryContext).QueryContext(, )
	}

	var  *trace.Span
	if  == nil {
		,  = trace.StartSpan(, "sql:query", trace.WithSpanKind(trace.SpanKindClient))
	} else {
		_,  = trace.StartSpan(, "sql:query", trace.WithSpanKind(trace.SpanKindClient))
	}
	 := append([]trace.Attribute(nil), .options.DefaultAttributes...)
	if .options.Query {
		 = append(, trace.StringAttribute("sql.query", .query))
		if .options.QueryParams {
			 = append(, namedParamsAttr()...)
		}
	}
	.AddAttributes(...)

	defer func() {
		setSpanStatus(, )
		.End()
	}()
we already tested driver to implement StmtQueryContext
	 := .parent.(driver.StmtQueryContext)
	,  = .QueryContext(, )
	if  != nil {
		return nil, 
	}
	,  = wrapRows(, , .options), nil
	return
}
withRowsColumnTypeScanType is the same as the driver.RowsColumnTypeScanType interface except it omits the driver.Rows embedded interface. If the original driver.Rows implementation wrapped by ocsql supports RowsColumnTypeScanType we enable the original method implementation in the returned driver.Rows from wrapRows by doing a composition with ocRows.
type withRowsColumnTypeScanType interface {
	ColumnTypeScanType(index int) reflect.Type
}
ocRows implements driver.Rows and all enhancement interfaces except driver.RowsColumnTypeScanType.
HasNextResultSet calls the implements the driver.RowsNextResultSet for ocRows. It returns the the underlying result of HasNextResultSet from the ocRows.parent if the parent implements driver.RowsNextResultSet.
func ( ocRows) () bool {
	if ,  := .parent.(driver.RowsNextResultSet);  {
		return .HasNextResultSet()
	}

	return false
}
NextResultsSet calls the implements the driver.RowsNextResultSet for ocRows. It returns the the underlying result of NextResultSet from the ocRows.parent if the parent implements driver.RowsNextResultSet.
func ( ocRows) () error {
	if ,  := .parent.(driver.RowsNextResultSet);  {
		return .NextResultSet()
	}

	return io.EOF
}
ColumnTypeDatabaseTypeName calls the implements the driver.RowsColumnTypeDatabaseTypeName for ocRows. It returns the the underlying result of ColumnTypeDatabaseTypeName from the ocRows.parent if the parent implements driver.RowsColumnTypeDatabaseTypeName.
func ( ocRows) ( int) string {
	if ,  := .parent.(driver.RowsColumnTypeDatabaseTypeName);  {
		return .ColumnTypeDatabaseTypeName()
	}

	return ""
}
ColumnTypeLength calls the implements the driver.RowsColumnTypeLength for ocRows. It returns the the underlying result of ColumnTypeLength from the ocRows.parent if the parent implements driver.RowsColumnTypeLength.
func ( ocRows) ( int) ( int64,  bool) {
	if ,  := .parent.(driver.RowsColumnTypeLength);  {
		return .ColumnTypeLength()
	}

	return 0, false
}
ColumnTypeNullable calls the implements the driver.RowsColumnTypeNullable for ocRows. It returns the the underlying result of ColumnTypeNullable from the ocRows.parent if the parent implements driver.RowsColumnTypeNullable.
func ( ocRows) ( int) (,  bool) {
	if ,  := .parent.(driver.RowsColumnTypeNullable);  {
		return .ColumnTypeNullable()
	}

	return false, false
}
ColumnTypePrecisionScale calls the implements the driver.RowsColumnTypePrecisionScale for ocRows. It returns the the underlying result of ColumnTypePrecisionScale from the ocRows.parent if the parent implements driver.RowsColumnTypePrecisionScale.
func ( ocRows) ( int) (,  int64,  bool) {
	if ,  := .parent.(driver.RowsColumnTypePrecisionScale);  {
		return .ColumnTypePrecisionScale()
	}

	return 0, 0, false
}

func ( ocRows) () []string {
	return .parent.Columns()
}

func ( ocRows) () ( error) {
	if .options.RowsClose {
		,  := trace.StartSpan(.ctx, "sql:rows_close", trace.WithSpanKind(trace.SpanKindClient))
		if len(.options.DefaultAttributes) > 0 {
			.AddAttributes(.options.DefaultAttributes...)
		}
		defer func() {
			setSpanStatus(, )
			.End()
		}()
	}

	 = .parent.Close()
	return
}

func ( ocRows) ( []driver.Value) ( error) {
	if .options.RowsNext {
		,  := trace.StartSpan(.ctx, "sql:rows_next", trace.WithSpanKind(trace.SpanKindClient))
		if len(.options.DefaultAttributes) > 0 {
			.AddAttributes(.options.DefaultAttributes...)
		}
		defer func() {
not an error; expected to happen during iteration
				setSpanStatus(, nil)
			} else {
				setSpanStatus(, )
			}
			.End()
		}()
	}

	 = .parent.Next()
	return
}
wrapRows returns a struct which conforms to the driver.Rows interface. ocRows implements all enhancement interfaces that have no effect on sql/database logic in case the underlying parent implementation lacks them. Currently the one exception is RowsColumnTypeScanType which does not have a valid zero value. This interface is tested for and only enabled in case the parent implementation supports it.
func ( context.Context,  driver.Rows,  TraceOptions) driver.Rows {
	var (
		,  = .(driver.RowsColumnTypeScanType)
	)

	 := ocRows{
		parent:  ,
		ctx:     ,
		options: ,
	}

	if  {
		return struct {
			ocRows
			withRowsColumnTypeScanType
		}{, }
	}

	return 
}
ocTx implemens driver.Tx
type ocTx struct {
	parent  driver.Tx
	ctx     context.Context
	options TraceOptions
}

func ( ocTx) () ( error) {
	defer recordCallStats(context.Background(), "go.sql.commit")()

	,  := trace.StartSpan(.ctx, "sql:commit", trace.WithSpanKind(trace.SpanKindClient))
	if len(.options.DefaultAttributes) > 0 {
		.AddAttributes(.options.DefaultAttributes...)
	}
	defer func() {
		setSpanStatus(, )
		.End()
	}()

	 = .parent.Commit()
	return
}

func ( ocTx) () ( error) {
	defer recordCallStats(context.Background(), "go.sql.rollback")()

	,  := trace.StartSpan(.ctx, "sql:rollback", trace.WithSpanKind(trace.SpanKindClient))
	if len(.options.DefaultAttributes) > 0 {
		.AddAttributes(.options.DefaultAttributes...)
	}
	defer func() {
		setSpanStatus(, )
		.End()
	}()

	 = .parent.Rollback()
	return
}

func ( []driver.Value) []trace.Attribute {
	 := make([]trace.Attribute, 0, len())
	for ,  := range  {
		 := "sql.arg" + strconv.Itoa()
		 = append(, argToAttr(, ))
	}
	return 
}

func ( []driver.NamedValue) []trace.Attribute {
	 := make([]trace.Attribute, 0, len())
	for ,  := range  {
		var  string
		if .Name != "" {
			 = .Name
		} else {
			 = "sql.arg." + strconv.Itoa(.Ordinal)
		}
		 = append(, argToAttr(, .Value))
	}
	return 
}

func ( string,  interface{}) trace.Attribute {
	switch v := .(type) {
	case nil:
		return trace.StringAttribute(, "")
	case int64:
		return trace.Int64Attribute(, )
	case float64:
		return trace.StringAttribute(, fmt.Sprintf("%f", ))
	case bool:
		return trace.BoolAttribute(, )
	case []byte:
		if len() > 256 {
			 = [0:256]
		}
		return trace.StringAttribute(, fmt.Sprintf("%s", ))
	default:
		 := fmt.Sprintf("%v", )
		if len() > 256 {
			 = [0:256]
		}
		return trace.StringAttribute(, )
	}
}

func ( *trace.Span,  error) {
	var  trace.Status
	switch  {
	case nil:
		.Code = trace.StatusCodeOK
		.SetStatus()
		return
	case context.Canceled:
		.Code = trace.StatusCodeCancelled
	case context.DeadlineExceeded:
		.Code = trace.StatusCodeDeadlineExceeded
	case sql.ErrNoRows:
		.Code = trace.StatusCodeNotFound
	case sql.ErrTxDone, errConnDone:
		.Code = trace.StatusCodeFailedPrecondition
	default:
		.Code = trace.StatusCodeUnknown
	}
	.Message = .Error()
	.SetStatus()