Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sentry: comparison ops with suboperators don't handle NULLs #37547

Closed
cockroach-teamcity opened this issue May 16, 2019 · 5 comments · Fixed by #37775
Closed

sentry: comparison ops with suboperators don't handle NULLs #37547

cockroach-teamcity opened this issue May 16, 2019 · 5 comments · Fixed by #37775
Assignees
Labels
C-bug Code not up to spec/doc, specs & docs deemed correct. Solution expected to change code/behavior. E-easy Easy issue to tackle, requires little or no CockroachDB experience E-starter Might be suitable for a starter project for new employees or team members. O-sentry Originated from an in-the-wild panic report.

Comments

@cockroach-teamcity
Copy link
Member

This issue was autofiled by Sentry. It represents a crash or reported error on a live cluster with telemetry enabled.

Sentry link: https://sentry.io/organizations/cockroach-labs/issues/1029811314/?referrer=webhooks_plugin

Panic message:

(0) eval.go:3600: unhandled right expression %s | tree.dNull
(see stack traces in additional data)

Stacktrace (expand for inline code snippets):

} else {
return nil, pgerror.NewAssertionErrorf("unhandled right expression %s", right)
}
in pkg/sql/sem/tree.(*ComparisonExpr).Eval
}
right, err := expr.Right.(TypedExpr).Eval(ctx)
if err != nil {
in pkg/sql/sem/tree.(*AndExpr).Eval
d, err := filter.Eval(evalCtx)
if err != nil {
in pkg/sql/sqlbase.RunFilter
eh.evalCtx.PushIVarContainer(eh)
pass, err := sqlbase.RunFilter(eh.expr, eh.evalCtx)
eh.evalCtx.PopIVarContainer()
in pkg/sql/distsqlrun.(*exprHelper).evalFilter
// Filtering.
passes, err := h.filter.evalFilter(row)
if err != nil {
in pkg/sql/distsqlrun.(*ProcOutputHelper).ProcessRow
func (pb *ProcessorBase) ProcessRowHelper(row sqlbase.EncDatumRow) sqlbase.EncDatumRow {
outRow, ok, err := pb.out.ProcessRow(pb.Ctx, row)
if err != nil {
in pkg/sql/distsqlrun.(*ProcessorBase).ProcessRowHelper
if outRow := tr.ProcessRowHelper(row); outRow != nil {
return outRow, nil
in pkg/sql/distsqlrun.(*tableReader).Next
for {
row, meta := ag.input.Next()
if meta != nil {
in pkg/sql/distsqlrun.(*orderedAggregator).accumulateRows
case aggAccumulating:
ag.runningState, row, meta = ag.accumulateRows()
case aggEmittingRows:
in pkg/sql/distsqlrun.(*orderedAggregator).Next
for {
row, meta := src.Next()
// Emit the row; stop if no more rows are needed.
in pkg/sql/distsqlrun.Run
ctx = pb.self.Start(ctx)
Run(ctx, pb.self, pb.out.output)
}
in pkg/sql/distsqlrun.(*ProcessorBase).Run
}
headProc.Run(ctx)
return nil
in pkg/sql/distsqlrun.(*Flow).Run
// TODO(radu): this should go through the flow scheduler.
if err := flow.Run(ctx, func() {}); err != nil {
log.Fatalf(ctx, "unexpected error from syncFlow.Start(): %s "+
in pkg/sql.(*DistSQLPlanner).Run
dsp.FinalizePlan(planCtx, &physPlan)
dsp.Run(planCtx, txn, &physPlan, recv, evalCtx, nil /* finishedSetupFn */)
}
in pkg/sql.(*DistSQLPlanner).PlanAndRun
// the planner whether or not to plan remote table readers.
ex.server.cfg.DistSQLPlanner.PlanAndRun(
ctx, evalCtx, planCtx, planner.txn, planner.curPlan.plan, recv)
in pkg/sql.(*connExecutor).execWithDistSQLEngine
ex.sessionTracing.TraceExecStart(ctx, "distributed")
err = ex.execWithDistSQLEngine(ctx, planner, stmt.AST.StatementType(), res, distributePlan)
ex.sessionTracing.TraceExecEnd(ctx, res.Err(), res.RowsAffected())
in pkg/sql.(*connExecutor).dispatchToExecutionEngine
p.autoCommit = os.ImplicitTxn.Get() && !ex.server.cfg.TestingKnobs.DisableAutoCommit
if err := ex.dispatchToExecutionEngine(ctx, p, res); err != nil {
return nil, nil, err
in pkg/sql.(*connExecutor).execStmtInOpenState
} else {
ev, payload, err = ex.execStmtInOpenState(ctx, stmt, pinfo, res)
}
in pkg/sql.(*connExecutor).execStmt
ctx := withStatement(ex.Ctx(), ex.curStmt)
ev, payload, err = ex.execStmt(ctx, curStmt, stmtRes, pinfo)
if err != nil {
in pkg/sql.(*connExecutor).run
}()
return h.ex.run(ctx, s.pool, reserved, cancel)
}
in pkg/sql.(*Server).ServeConn
}()
writerErr = sqlServer.ServeConn(ctx, connHandler, reserved, cancelConn)
// TODO(andrei): Should we sometimes transmit the writerErr's to the
in pkg/sql/pgwire.(*conn).serveImpl.func4

pkg/sql/sem/tree/eval.go in pkg/sql/sem/tree.(*ComparisonExpr).Eval at line 3600
pkg/sql/sem/tree/eval.go in pkg/sql/sem/tree.(*AndExpr).Eval at line 2781
pkg/sql/sqlbase/expr_filter.go in pkg/sql/sqlbase.RunFilter at line 26
pkg/sql/distsqlrun/expr.go in pkg/sql/distsqlrun.(*exprHelper).evalFilter at line 179
pkg/sql/distsqlrun/processors.go in pkg/sql/distsqlrun.(*ProcOutputHelper).ProcessRow at line 355
pkg/sql/distsqlrun/processors.go in pkg/sql/distsqlrun.(*ProcessorBase).ProcessRowHelper at line 778
pkg/sql/distsqlrun/tablereader.go in pkg/sql/distsqlrun.(*tableReader).Next at line 290
pkg/sql/distsqlrun/aggregator.go in pkg/sql/distsqlrun.(*orderedAggregator).accumulateRows at line 533
pkg/sql/distsqlrun/aggregator.go in pkg/sql/distsqlrun.(*orderedAggregator).Next at line 721
pkg/sql/distsqlrun/base.go in pkg/sql/distsqlrun.Run at line 174
pkg/sql/distsqlrun/processors.go in pkg/sql/distsqlrun.(*ProcessorBase).Run at line 801
pkg/sql/distsqlrun/flow.go in pkg/sql/distsqlrun.(*Flow).Run at line 626
pkg/sql/distsql_running.go in pkg/sql.(*DistSQLPlanner).Run at line 252
pkg/sql/distsql_running.go in pkg/sql.(*DistSQLPlanner).PlanAndRun at line 839
pkg/sql/conn_executor_exec.go in pkg/sql.(*connExecutor).execWithDistSQLEngine at line 1112
pkg/sql/conn_executor_exec.go in pkg/sql.(*connExecutor).dispatchToExecutionEngine at line 948
pkg/sql/conn_executor_exec.go in pkg/sql.(*connExecutor).execStmtInOpenState at line 456
pkg/sql/conn_executor_exec.go in pkg/sql.(*connExecutor).execStmt at line 102
pkg/sql/conn_executor.go in pkg/sql.(*connExecutor).run at line 1241
pkg/sql/conn_executor.go in pkg/sql.(*Server).ServeConn at line 433
pkg/sql/pgwire/conn.go in pkg/sql/pgwire.(*conn).serveImpl.func4 at line 337
Tag Value
Cockroach Release v19.1.0
Cockroach SHA: 25dd36f
Platform linux amd64
Distribution CCL
Environment v19.1.0
Command server
Go Version go1.11.6
# of CPUs 6
# of Goroutines 181
@cockroach-teamcity cockroach-teamcity added C-bug Code not up to spec/doc, specs & docs deemed correct. Solution expected to change code/behavior. O-sentry Originated from an in-the-wild panic report. labels May 16, 2019
@jordanlewis
Copy link
Member

op := expr.Operator
	if op.hasSubOperator() {
		var datums Datums
		// Right is either a tuple or an array of Datums.
		if tuple, ok := AsDTuple(right); ok {
			datums = tuple.D
		} else if array, ok := AsDArray(right); ok {
			datums = array.Array
		} else {
			return nil, pgerror.NewAssertionErrorf("unhandled right expression %s", right)
		}
		return evalDatumsCmp(ctx, op, expr.SubOperator, expr.fn, left, datums)
	}

Looks like a comparison operator with a subop assumes that the right side is either an array or a tuple, and in this case, there was a different reality. What could that reality be?

@jordanlewis
Copy link
Member

Oh, I think the message says - it's a DNull literal?

@justinj
Copy link
Contributor

justinj commented May 16, 2019

repro:

select x = any string_to_array(null, ' ') from (values ('foo')) v(x);

I think this might be caused by constant-folding an array-typed value to NULL? I think that sounds valid though, so I think the bug here seems to be in the code block you pasted.

@justinj
Copy link
Contributor

justinj commented May 16, 2019

repro that doesn't involve constant folding:

select x = any string_to_array(x, ' ') from (values (null::string)) v(x);

@jordanlewis
Copy link
Member

I think the fix here is to make sure that comparison exprs with sub operators explicitly look for NULL, just like all other builtins.

Here's a repro without builtins:

select 1 = any null::int[];

@jordanlewis jordanlewis added E-easy Easy issue to tackle, requires little or no CockroachDB experience E-starter Might be suitable for a starter project for new employees or team members. labels May 16, 2019
@asubiotto asubiotto changed the title sentry: (0) eval.go:3600: unhandled right expression %s | tree.dNull (see stack traces in additional data) sentry: comparison ops with suboperators don't handle NULLs May 20, 2019
craig bot pushed a commit that referenced this issue May 24, 2019
37775: tree: handle null in suboperator expressions r=rafiss a=rafiss

Before this change, a null right operand in a suboperator would cause an
unhandled error. We were receiving stack trace reports from the wild.
Add a test and fix it.

fixes #37547 
Release note (bug fix): a null right operand now causes the suboperator
expression to return null

Co-authored-by: Rafi Shamim <[email protected]>
@craig craig bot closed this as completed in #37775 May 24, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Code not up to spec/doc, specs & docs deemed correct. Solution expected to change code/behavior. E-easy Easy issue to tackle, requires little or no CockroachDB experience E-starter Might be suitable for a starter project for new employees or team members. O-sentry Originated from an in-the-wild panic report.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants