не получается запустить процедуру бд из java приложения, когда задаю параметры не по номерам столбцов, а по имени столбца.
Часть кода, которая вызывает процедуру:
CallableStatement cstmt;
cstmt = connection.prepareCall("{call SET_CLIENT_ADD (?, ?, ?, ?, ?)}");
cstmt.setString("FIRSTNAME", client.getFirstName());
cstmt.setString("LASTNAME", client.getLastName());
cstmt.setString("MIDNAME", client.getMidName());
cstmt.setString("PHONE", client.getPhone());
cstmt.setDate("BDATE", new Date(client.getBirthDate().getTime()));
cstmt.registerOutParameter(1, Types.INTEGER);
cstmt.registerOutParameter(2, Types.INTEGER);
cstmt.registerOutParameter(3, Types.VARCHAR);
cstmt.execute();
cstmt.close();
Ошибка (возникает на 3ей строке):
Exception in thread "main" org.firebirdsql.jdbc.FBDriverNotCapableException: Setting parameters by name is not supported
at org.firebirdsql.jdbc.AbstractCallableStatement.setString(AbstractCallableStatement.java:1146)
at JDBCStuff.Services.ClientService.saveClient(ClientService.java:37)
at Main.Main.main(Main.java:23)
Первая ошибка:
У вас пять входных параметров и три выходных. В запросе перечислено только 5.
Вторая ошибка:
Если к параметрам обращаетесь по именам, то эти имена должны быть указаны в запросе:
CallableStatement cstmt;
cstmt = connection.prepareCall("{call SET_CLIENT_ADD (:FIRSTNAME, :LASTNAME, :MIDNAME, :PHONE, :BDATE, :out1, :out2, :out3)}");
cstmt.setString("FIRSTNAME", client.getFirstName());
cstmt.setString("LASTNAME", client.getLastName());
cstmt.setString("MIDNAME", client.getMidName());
cstmt.setString("PHONE", client.getPhone());
cstmt.setDate("BDATE", new Date(client.getBirthDate().getTime()));
cstmt.registerOutParameter("out1", Types.INTEGER);
cstmt.registerOutParameter("out2", Types.INTEGER);
cstmt.registerOutParameter("out3", Types.VARCHAR);
cstmt.execute();
cstmt.close();
Если именованные параметры не поддерживаются то придется писать так:
CallableStatement cstmt;
cstmt = connection.prepareCall("{call SET_CLIENT_ADD (?, ?, ?, ?, ?, ?, ?, ?)}");
cstmt.setString(1, client.getFirstName());
cstmt.setString(2, client.getLastName());
cstmt.setString(3, client.getMidName());
cstmt.setString(4, client.getPhone());
cstmt.setDate(5, new Date(client.getBirthDate().getTime()));
cstmt.registerOutParameter(6, Types.INTEGER);
cstmt.registerOutParameter(7, Types.INTEGER);
cstmt.registerOutParameter(8, Types.VARCHAR);
cstmt.execute();
cstmt.close();
Решил вопрос сам, просто сделав класс, который смотрит запрос, а потом парсит название столбца, которое я добавляю, в индекс этого столбца.
NamedParamStatement statement = new NamedParamStatement(connection, "{call SET_CLIENT_ADD (:LASTNAME, :FIRSTNAME, :MIDNAME, :PHONE, :BDATE)}");
statement.setString("FIRSTNAME", client.getFirstName());
statement.setString("LASTNAME", client.getLastName());
statement.setString("MIDNAME", client.getMidName());
statement.setString("PHONE", client.getPhone());
statement.setDate("BDATE", new Date(client.getBirthDate().getTime()));
statement.execute();
.
public class NamedParamStatement {
private final PreparedStatement statement;
private Map<String, int[]> indexMap;
public NamedParamStatement(Connection connection, String query) throws SQLException {
String parsedQuery = parse(query);
statement = connection.prepareStatement(parsedQuery);
}
final String parse(String query) {
// I was originally using regular expressions, but they didn't work well for ignoring
// parameter-like strings inside quotes.
int length = query.length();
StringBuffer parsedQuery = new StringBuffer(length);
boolean inSingleQuote = false;
boolean inDoubleQuote = false;
int index = 1;
HashMap<String, List<Integer>> indexes = new HashMap<String, List<Integer>>(10);
for (int i = 0; i < length; i++) {
char c = query.charAt(i);
if (inSingleQuote) {
if (c == '\'') {
inSingleQuote = false;
}
} else if (inDoubleQuote) {
if (c == '"') {
inDoubleQuote = false;
}
} else {
if (c == '\'') {
inSingleQuote = true;
} else if (c == '"') {
inDoubleQuote = true;
} else if (c == ':' && i + 1 < length && Character.isJavaIdentifierStart(query.charAt(i + 1))) {
int j = i + 2;
while (j < length && Character.isJavaIdentifierPart(query.charAt(j))) {
j++;
}
String name = query.substring(i + 1, j);
c = '?'; // replace the parameter with a question mark
i += name.length(); // skip past the end if the parameter
List<Integer> indexList = indexes.get(name);
if (indexList == null) {
indexList = new LinkedList<Integer>();
indexes.put(name, indexList);
}
indexList.add(Integer.valueOf(index));
index++;
}
}
parsedQuery.append(c);
}
indexMap = new HashMap<String, int[]>(indexes.size());
// replace the lists of Integer objects with arrays of ints
for (Map.Entry<String, List<Integer>> entry : indexes.entrySet()) {
List<Integer> list = entry.getValue();
int[] intIndexes = new int[list.size()];
int i = 0;
for (Integer x : list) {
intIndexes[i++] = x.intValue();
}
indexMap.put(entry.getKey(), intIndexes);
}
return parsedQuery.toString();
}
private int[] getIndexes(String name) {
int[] indexes = indexMap.get(name);
if (indexes == null) {
throw new IllegalArgumentException("Parameter not found: " + name);
}
return indexes;
}
public void setObject(String name, Object value) throws SQLException {
int[] indexes = getIndexes(name);
for (int i = 0; i < indexes.length; i++) {
statement.setObject(indexes[i], value);
}
}
public void setString(String name, String value) throws SQLException {
int[] indexes = getIndexes(name);
for (int i = 0; i < indexes.length; i++) {
statement.setString(indexes[i], value);
}
}
public void setInt(String name, int value) throws SQLException {
int[] indexes = getIndexes(name);
for (int i = 0; i < indexes.length; i++) {
statement.setInt(indexes[i], value);
}
}
public void setLong(String name, long value) throws SQLException {
int[] indexes = getIndexes(name);
for (int i = 0; i < indexes.length; i++) {
statement.setLong(indexes[i], value);
}
}
public void setTimestamp(String name, Timestamp value) throws SQLException {
int[] indexes = getIndexes(name);
for (int i = 0; i < indexes.length; i++) {
statement.setTimestamp(indexes[i], value);
}
}
public void setDate(String name, java.sql.Date value) throws SQLException {
int[] indexes = getIndexes(name);
for (int i = 0; i < indexes.length; i++) {
statement.setDate(indexes[i], value);
}
}
public void setDate(String name, java.sql.Date value, Calendar cal) throws SQLException {
int[] indexes = getIndexes(name);
for (int i = 0; i < indexes.length; i++) {
statement.setDate(indexes[i], value, cal);
}
}
public PreparedStatement getStatement() {
return statement;
}
public boolean execute() throws SQLException {
return statement.execute();
}
public ResultSet executeQuery() throws SQLException {
return statement.executeQuery();
}
public int executeUpdate() throws SQLException {
return statement.executeUpdate();
}
public void close() throws SQLException {
statement.close();
}
public void addBatch() throws SQLException {
statement.addBatch();
}
public int[] executeBatch() throws SQLException {
return statement.executeBatch();
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Есть код, который читает строку и парсит в intКак заставить видеть переменную s как int?
Пишу что-то вроде текстового редактора, текст в котором добавляется в элементе:
Как используя canvas нарисовать VectorDrawableОбычный Drawable у меня получается нарисовать конвертацией в Bitmap, но как нарисовать VectorDrawable, возможно ли это?