提交 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. ...@@ -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'); 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"," "Functions (System)","FILE_READ","
FILE_READ(fileNameString [,encodingString]) FILE_READ(fileNameString [,encodingString])
"," ","
......
...@@ -22,6 +22,7 @@ import java.util.Locale; ...@@ -22,6 +22,7 @@ import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException; import java.util.regex.PatternSyntaxException;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
import org.h2.command.Command; import org.h2.command.Command;
import org.h2.command.Parser; import org.h2.command.Parser;
...@@ -109,7 +110,9 @@ public class Function extends Expression implements FunctionCall { ...@@ -109,7 +110,9 @@ public class Function extends Expression implements FunctionCall {
public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152, public static final int DATABASE = 150, USER = 151, CURRENT_USER = 152,
IDENTITY = 153, SCOPE_IDENTITY = 154, AUTOCOMMIT = 155, IDENTITY = 153, SCOPE_IDENTITY = 154, AUTOCOMMIT = 155,
READONLY = 156, DATABASE_PATH = 157, LOCK_TIMEOUT = 158, 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, public static final int IFNULL = 200, CASEWHEN = 201, CONVERT = 202,
CAST = 203, COALESCE = 204, NULLIF = 205, CASE = 206, CAST = 203, COALESCE = 204, NULLIF = 205, CASE = 206,
...@@ -480,6 +483,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -480,6 +483,7 @@ public class Function extends Expression implements FunctionCall {
VAR_ARGS, Value.NULL); VAR_ARGS, Value.NULL);
addFunctionNotDeterministic("DISK_SPACE_USED", DISK_SPACE_USED, addFunctionNotDeterministic("DISK_SPACE_USED", DISK_SPACE_USED,
1, Value.LONG); 1, Value.LONG);
addFunctionWithNull("SIGNAL", SIGNAL, 2, Value.NULL);
addFunction("H2VERSION", H2VERSION, 0, Value.STRING); addFunction("H2VERSION", H2VERSION, 0, Value.STRING);
// TableFunction // TableFunction
...@@ -1705,6 +1709,13 @@ public class Function extends Expression implements FunctionCall { ...@@ -1705,6 +1709,13 @@ public class Function extends Expression implements FunctionCall {
result = session.getVariable(args[0].getSchemaName() + "." + result = session.getVariable(args[0].getSchemaName() + "." +
args[0].getTableName() + "." + args[0].getColumnName()); args[0].getTableName() + "." + args[0].getColumnName());
break; 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: default:
throw DbException.throwInternalError("type=" + info.type); throw DbException.throwInternalError("type=" + info.type);
} }
......
...@@ -179,6 +179,17 @@ public class DbException extends RuntimeException { ...@@ -179,6 +179,17 @@ public class DbException extends RuntimeException {
return new DbException(getJdbcSQLException(errorCode, null, params)); 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. * Create a syntax error exception.
* *
...@@ -345,6 +356,11 @@ public class DbException extends RuntimeException { ...@@ -345,6 +356,11 @@ public class DbException extends RuntimeException {
return new JdbcSQLException(message, null, sqlstate, errorCode, cause, null); 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. * Convert an exception to an IO exception.
* *
......
...@@ -38,6 +38,7 @@ import java.util.Locale; ...@@ -38,6 +38,7 @@ import java.util.Locale;
import java.util.Properties; import java.util.Properties;
import java.util.TimeZone; import java.util.TimeZone;
import java.util.UUID; import java.util.UUID;
import org.h2.api.Aggregate; import org.h2.api.Aggregate;
import org.h2.api.AggregateFunction; import org.h2.api.AggregateFunction;
import org.h2.api.ErrorCode; import org.h2.api.ErrorCode;
...@@ -119,6 +120,7 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -119,6 +120,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
testThatCurrentTimestampUpdatesOutsideATransaction(); testThatCurrentTimestampUpdatesOutsideATransaction();
testAnnotationProcessorsOutput(); testAnnotationProcessorsOutput();
testRound(); testRound();
testSignal();
deleteDb("functions"); deleteDb("functions");
} }
...@@ -2037,6 +2039,26 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -2037,6 +2039,26 @@ public class TestFunctions extends TestBase implements AggregateFunction {
conn.close(); 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, private void testThatCurrentTimestampIsSane() throws SQLException,
ParseException { ParseException {
deleteDb("functions"); deleteDb("functions");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论