Не запустить процедуру с параметрами, заданную в базе

259
14 ноября 2021, 05:30

не получается запустить процедуру бд из 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)
Answer 1

Первая ошибка:

У вас пять входных параметров и три выходных. В запросе перечислено только 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();
Answer 2

Решил вопрос сам, просто сделав класс, который смотрит запрос, а потом парсит название столбца, которое я добавляю, в индекс этого столбца.

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();
}

}

READ ALSO
Парсинг string в int

Парсинг string в int

Есть код, который читает строку и парсит в intКак заставить видеть переменную s как int?

176
при работе с RecyclerView возникает ошибка java.lang.RuntimeException: Unable to start activity ComponentInfo

при работе с RecyclerView возникает ошибка java.lang.RuntimeException: Unable to start activity ComponentInfo

Пишу что-то вроде текстового редактора, текст в котором добавляется в элементе:

229
Как нарисовать векторное изображение canvas

Как нарисовать векторное изображение canvas

Как используя canvas нарисовать VectorDrawableОбычный Drawable у меня получается нарисовать конвертацией в Bitmap, но как нарисовать VectorDrawable, возможно ли это?

115
Как выстроить структуру классов?

Как выстроить структуру классов?

Дорый день! У меня есть тестовое заданиеКейс сбора данных:

277