提交 7313a762 authored 作者: sylvain-ilm's avatar sylvain-ilm

added SIGNAL function

上级 7365ba5c
......@@ -4013,6 +4013,14 @@ This function may be expensive since it has to load every page in the table.
CALL DISK_SPACE_USED('my_table');
"
"Functions (System)","SIGNAL","
SIGNAL(sqlState, message)
","
Throw an SQLException with the passed SQLState and reason.
","
CALL SIGNAL('23505', 'Duplicate user ID: ' || user_id);
"
"Functions (System)","FILE_READ","
FILE_READ(fileNameString [,encodingString])
","
......
......@@ -22,6 +22,7 @@ import java.util.Locale;
import java.util.TimeZone;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import org.h2.api.ErrorCode;
import org.h2.command.Command;
import org.h2.command.Parser;
......@@ -109,7 +110,9 @@ public class Function extends Expression implements FunctionCall {
public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152,
IDENTITY = 153, SCOPE_IDENTITY = 154, AUTOCOMMIT = 155,
READONLY = 156, DATABASE_PATH = 157, LOCK_TIMEOUT = 158,
DISK_SPACE_USED = 159;
DISK_SPACE_USED = 159, SIGNAL = 160;
private static final Pattern SIGNAL_PATTERN = Pattern.compile("[0-9A-Z]{5}");
public static final int IFNULL = 200, CASEWHEN = 201, CONVERT = 202,
CAST = 203, COALESCE = 204, NULLIF = 205, CASE = 206,
......@@ -480,6 +483,7 @@ public class Function extends Expression implements FunctionCall {
VAR_ARGS, Value.NULL);
addFunctionNotDeterministic("DISK_SPACE_USED", DISK_SPACE_USED,
1, Value.LONG);
addFunctionWithNull("SIGNAL", SIGNAL, 2, Value.NULL);
addFunction("H2VERSION", H2VERSION, 0, Value.STRING);
// TableFunction
......@@ -1705,6 +1709,13 @@ public class Function extends Expression implements FunctionCall {
result = session.getVariable(args[0].getSchemaName() + "." +
args[0].getTableName() + "." + args[0].getColumnName());
break;
case SIGNAL: {
String sqlState = v0.getString();
if (sqlState.startsWith("00") || !SIGNAL_PATTERN.matcher(sqlState).matches())
throw DbException.getInvalidValueException("SQLSTATE", sqlState);
String msgText = v1.getString();
throw DbException.fromUser(sqlState, msgText);
}
default:
throw DbException.throwInternalError("type=" + info.type);
}
......
......@@ -179,6 +179,17 @@ public class DbException extends RuntimeException {
return new DbException(getJdbcSQLException(errorCode, null, params));
}
/**
* Create a database exception for an arbitrary SQLState.
*
* @param sqlstate the state to use
* @param message the message to use
* @return the exception
*/
public static DbException fromUser(String sqlstate, String message) {
return new DbException(getJdbcSQLException(sqlstate, message));
}
/**
* Create a syntax error exception.
*
......@@ -345,6 +356,11 @@ public class DbException extends RuntimeException {
return new JdbcSQLException(message, null, sqlstate, errorCode, cause, null);
}
private static JdbcSQLException getJdbcSQLException(String sqlstate, String message) {
// do not translate as sqlstate is arbitrary : avoid "message not found"
return new JdbcSQLException(message, null, sqlstate, 0, null, null);
}
/**
* Convert an exception to an IO exception.
*
......
......@@ -38,6 +38,7 @@ import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;
import java.util.UUID;
import org.h2.api.Aggregate;
import org.h2.api.AggregateFunction;
import org.h2.api.ErrorCode;
......@@ -119,6 +120,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
testThatCurrentTimestampUpdatesOutsideATransaction();
testAnnotationProcessorsOutput();
testRound();
testSignal();
deleteDb("functions");
}
......@@ -2037,6 +2039,26 @@ public class TestFunctions extends TestBase implements AggregateFunction {
conn.close();
}
private void testSignal() throws SQLException {
deleteDb("functions");
Connection conn = getConnection("functions");
Statement stat = conn.createStatement();
assertThrows(ErrorCode.INVALID_VALUE_2, stat).execute("select signal('00145', 'success class is invalid')");
assertThrows(ErrorCode.INVALID_VALUE_2, stat).execute("select signal('foo', 'SQLSTATE has 5 chars')");
assertThrows(ErrorCode.INVALID_VALUE_2, stat).execute("select signal('Ab123', 'SQLSTATE has only digits or upper-case letters')");
try {
stat.execute("select signal('AB123', 'some custom error')");
fail("Should have thrown");
} catch (SQLException e) {
assertEquals("AB123", e.getSQLState());
assertContains(e.getMessage(), "some custom error");
}
conn.close();
}
private void testThatCurrentTimestampIsSane() throws SQLException,
ParseException {
deleteDb("functions");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论