Skip to content

Commit

Permalink
sql: make SQL_TARANTOOL_ERROR the only errcode of OP_Halt
Browse files Browse the repository at this point in the history
Currently, in OP_Halt, you can get a SQL error other than
SQL_TARANTOOL_ERROR, for example, the SQL_CONSTRAINT error. After
this patch, all errors going through OP_Halt will have SQL error
code SQL_TARANTOOL_ERROR and have diag set.

Part of #4074
  • Loading branch information
ImeevMA committed May 5, 2019
1 parent 83d98f0 commit 330e71f
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 62 deletions.
20 changes: 0 additions & 20 deletions src/box/sql/build.c
Expand Up @@ -2972,26 +2972,6 @@ sql_set_multi_write(struct Parse *parse_context, bool is_set)
pToplevel->isMultiWrite |= is_set;
}

/*
* Code an OP_Halt that causes the vdbe to return an SQL_CONSTRAINT
* error. The onError parameter determines which (if any) of the statement
* and/or current transaction is rolled back.
*/
void
sqlHaltConstraint(Parse * pParse, /* Parsing context */
int errCode, /* extended error code */
int onError, /* Constraint type */
char *p4, /* Error message */
i8 p4type, /* P4_STATIC or P4_TRANSIENT */
u8 p5Errmsg /* P5_ErrMsg type */
)
{
Vdbe *v = sqlGetVdbe(pParse);
assert((errCode & 0xff) == SQL_CONSTRAINT);
sqlVdbeAddOp4(v, OP_Halt, errCode, onError, 0, p4, p4type);
sqlVdbeChangeP5(v, p5Errmsg);
}

#ifndef SQL_OMIT_CTE
/*
* This routine is invoked once per CTE by the parser while parsing a
Expand Down
7 changes: 4 additions & 3 deletions src/box/sql/expr.c
Expand Up @@ -4386,9 +4386,10 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
ON_CONFLICT_ACTION_IGNORE, 0,
pExpr->u.zToken, 0);
} else {
sqlHaltConstraint(pParse, SQL_CONSTRAINT_TRIGGER,
pExpr->on_conflict_action,
pExpr->u.zToken, 0, 0);
sqlVdbeAddOp4(v, OP_Halt, SQL_TARANTOOL_ERROR,
pExpr->on_conflict_action, 0,
pExpr->u.zToken, 0);
sqlVdbeChangeP5(v, ER_SQL_EXECUTE);
}
break;
}
Expand Down
7 changes: 3 additions & 4 deletions src/box/sql/fk_constraint.c
Expand Up @@ -287,10 +287,9 @@ fk_constraint_lookup_parent(struct Parse *parse_context, struct space *parent,
* transaction.
*/
assert(incr_count == 1);
sqlHaltConstraint(parse_context,
SQL_CONSTRAINT_FOREIGNKEY,
ON_CONFLICT_ACTION_ABORT, 0, P4_STATIC,
P5_ConstraintFK);
sqlVdbeAddOp4(v, OP_Halt, SQL_TARANTOOL_ERROR, 0, 0, "FOREIGN "\
"KEY constraint failed", P4_STATIC);
sqlVdbeChangeP5(v, ER_SQL_EXECUTE);
} else {
sqlVdbeAddOp2(v, OP_FkCounter, fk_def->is_deferred,
incr_count);
Expand Down
29 changes: 14 additions & 15 deletions src/box/sql/insert.c
Expand Up @@ -865,7 +865,6 @@ vdbe_emit_constraint_checks(struct Parse *parse_context, struct space *space,
enum on_conflict_action on_conflict,
int ignore_label, int *upd_cols)
{
struct sql *db = parse_context->db;
struct Vdbe *v = sqlGetVdbe(parse_context);
assert(v != NULL);
bool is_update = upd_cols != NULL;
Expand Down Expand Up @@ -895,20 +894,18 @@ vdbe_emit_constraint_checks(struct Parse *parse_context, struct space *space,
if (on_conflict_nullable == ON_CONFLICT_ACTION_REPLACE &&
dflt == NULL)
on_conflict_nullable = ON_CONFLICT_ACTION_ABORT;
char *err_msg;
const char *err;
int addr;
switch (on_conflict_nullable) {
case ON_CONFLICT_ACTION_ABORT:
case ON_CONFLICT_ACTION_ROLLBACK:
case ON_CONFLICT_ACTION_FAIL:
err_msg = sqlMPrintf(db, "%s.%s", def->name,
def->fields[i].name);
sqlVdbeAddOp3(v, OP_HaltIfNull,
SQL_CONSTRAINT_NOTNULL,
on_conflict_nullable,
new_tuple_reg + i);
sqlVdbeAppendP4(v, err_msg, P4_DYNAMIC);
sqlVdbeChangeP5(v, P5_ConstraintNotNull);
err = tt_sprintf("NOT NULL constraint failed: %s.%s",
def->name, def->fields[i].name);
sqlVdbeAddOp4(v, OP_HaltIfNull, SQL_TARANTOOL_ERROR,
on_conflict_nullable, new_tuple_reg + i,
err, P4_STATIC);
sqlVdbeChangeP5(v, ER_SQL_EXECUTE);
break;
case ON_CONFLICT_ACTION_IGNORE:
sqlVdbeAddOp2(v, OP_IsNull, new_tuple_reg + i,
Expand Down Expand Up @@ -951,11 +948,13 @@ vdbe_emit_constraint_checks(struct Parse *parse_context, struct space *space,
char *name = checks->a[i].zName;
if (name == NULL)
name = def->name;
sqlHaltConstraint(parse_context,
SQL_CONSTRAINT_CHECK,
on_conflict_check, name,
P4_TRANSIENT,
P5_ConstraintCheck);
const char *err =
tt_sprintf("CHECK constraint failed: "\
"%s", name);
sqlVdbeAddOp4(v, OP_Halt, SQL_TARANTOOL_ERROR,
on_conflict_check, 0, err,
P4_STATIC);
sqlVdbeChangeP5(v, ER_SQL_EXECUTE);
}
sqlVdbeResolveLabel(v, all_ok);
}
Expand Down
1 change: 0 additions & 1 deletion src/box/sql/sqlInt.h
Expand Up @@ -3912,7 +3912,6 @@ vdbe_emit_insertion_completion(struct Vdbe *v, struct space *space,

void
sql_set_multi_write(Parse *, bool);
void sqlHaltConstraint(Parse *, int, int, char *, i8, u8);

Expr *sqlExprDup(sql *, Expr *, int);
SrcList *sqlSrcListDup(sql *, SrcList *, int);
Expand Down
23 changes: 4 additions & 19 deletions src/box/sql/vdbe.c
Expand Up @@ -1031,25 +1031,10 @@ case OP_Halt: {
p->errorAction = (u8)pOp->p2;
p->pc = pcx;
if (p->rc) {
if (p->rc == SQL_TARANTOOL_ERROR) {
if (pOp->p4.z != NULL)
diag_set(ClientError, pOp->p5, pOp->p4.z);
assert(! diag_is_empty(diag_get()));
} else if (pOp->p5 != 0) {
static const char * const azType[] = { "NOT NULL", "UNIQUE", "CHECK",
"FOREIGN KEY" };
testcase( pOp->p5==1);
testcase( pOp->p5==2);
testcase( pOp->p5==3);
testcase( pOp->p5==4);
sqlVdbeError(p, "%s constraint failed", azType[pOp->p5-1]);
if (pOp->p4.z) {
p->zErrMsg = sqlMPrintf(db, "%z: %s", p->zErrMsg, pOp->p4.z);
}
} else {
sqlVdbeError(p, "%s", pOp->p4.z);
}
sql_log(pOp->p1, "abort at %d in [%s]: %s", pcx, p->zSql, p->zErrMsg);
assert(p->rc == SQL_TARANTOOL_ERROR);
if (pOp->p4.z != NULL)
diag_set(ClientError, pOp->p5, pOp->p4.z);
assert(! diag_is_empty(diag_get()));
}
rc = sqlVdbeHalt(p);
assert(rc==SQL_BUSY || rc==SQL_OK || rc==SQL_ERROR);
Expand Down

0 comments on commit 330e71f

Please sign in to comment.