#stored-procedures #jdbc #sqlanywhere #out-parameters #jconnect
#хранимые процедуры #jdbc #sqlanywhere #выходные параметры #jconnect
Вопрос:
Я схожу с ума от того, как драйвер Sybase JDBC обрабатывает хранимые процедуры со смешанными IN
и OUT
параметрами. Ознакомьтесь с этой простой хранимой процедурой:
CREATE OR REPLACE PROCEDURE p (IN i1 INT, OUT o1 INT, IN i2 INT, OUT o2 INT)
BEGIN
set o1 = i1;
set o2 = i2;
END
И вот как я бы назвал это с помощью JDBC:
CallableStatement c = connection.prepareCall("{ call dba.p(?, ?, ?, ?) }");
c.setInt(1, 1);
c.setInt(3, 2);
c.registerOutParameter(2, Types.INTEGER);
c.registerOutParameter(4, Types.INTEGER);
c.execute();
System.out.println(c.getObject(2));
System.out.println(c.getObject(4));
Но это приводит к
1
null
Что происходит?? Это действительно серьезная ошибка в драйвере JDBC или я что-то полностью упускаю? Методом проб и ошибок я обнаружил, что это способ, которым это работает:
c.setInt(1, 1);
c.setInt(2, 2);
c.registerOutParameter(3, Types.INTEGER);
c.registerOutParameter(4, Types.INTEGER);
c.execute();
System.out.println(c.getObject(3));
System.out.println(c.getObject(4));
Теперь результат
1
2
Изменяет ли драйвер JDBC тайно порядок IN
и OUT
параметры??
Я использую SQL Anywhere 12 и jconn3.jar
Ответ №1:
Похоже на ошибку в драйвере.
Я подозреваю, что ошибочный драйвер ожидает, что параметры будут переданы / зарегистрированы в порядке (т. е. 1,2,3,4). Когда вы выполняете registerOut(2), оператор, по-видимому, забывает, что вы установили (3) 🙂
Или, может быть, все должно быть сделано после ввода. Опять же, это ошибка в драйвере.
Обновить
Подождите, вы не изменили процедуру для второго варианта? Этот результат не имеет никакого смысла. Если, как вы сказали, драйвер не выполняет переупорядочение. Что, мягко говоря, необычно.
ОБНОВЛЕНИЕ 2
Я декомпилировал драйвер. Он выполняет несколько довольно забавных игр с исходящими параметрами, и со всей этой суматохой я чувствую, что у них есть достаточный потенциал для ошибки там, но пока я ее явно не вижу.
Единственная забавная вещь, которую я заметил, это то, что, по-видимому, если параметр в позиции n не отсутствует, драйвер будет сканировать параметры вперед, пока не найдет значение; если значение не найдено, оно переходит к следующей строке:
s.registerOutParameter(5,Types.INT);
...
// no out value at position 4, it will go to 5 and get the value
rs.getInteger(4);
ОБНОВЛЕНИЕ 3
Может быть интересно посмотреть выходные данные всех 4 параметров в примере 1, т.е.:
CallableStatement c = connection.prepareCall("{ call dba.p(?, ?, ?, ?) }");
c.setInt(1, 1);
c.setInt(3, 2);
c.registerOutParameter(2, Types.INTEGER);
c.registerOutParameter(4, Types.INTEGER);
c.execute();
System.out.println(c.getObject(1));
System.out.println(c.getObject(2));
System.out.println(c.getObject(3));
System.out.println(c.getObject(4));
Комментарии:
1. ДА. Это одна и та же процедура, просто вызов отличается. Я также подозреваю, что этот драйвер выполняет переупорядочивание параметров. Но поскольку я не мог представить такой ужасный недостаток в драйвере крупной СУБД, я подумал, что, возможно, я что-то не так понял…
2. Я хотел декомпилировать драйвер, но не смог найти его с помощью Google, только новые версии. У вас есть ссылка, указывающая на этот глючный драйвер?
3. Вы можете найти это здесь: sybase.com/detail?id=1041013 . jconn3.jar содержится в пакете jconnect 6
4. Я предполагаю, что вы были недостаточно быстры для получения награды … Извините. Я ничего не знаю об этом бизнесе с вознаграждением. Теперь я поднял проблему и в meta: meta.stackexchange.com/questions/84785 /…
5. не заботьтесь о вознаграждении 😀 рассматриваемая проблема — это то, что является захватывающим!
Ответ №2:
Я попробовал это с Oracle 9.2, и это работает так, как ожидалось.. Я думаю, что эта проблема связана с вашим драйвером JDBC, а не с самим JDBC.
public static void main(String[] args) throws Exception {
Connection connection = getConnection();
CallableStatement c = connection.prepareCall("{ call p(?, ?, ?, ?) }");
c.setInt(1, 1);
c.setInt(3, 2);
c.registerOutParameter(2, Types.INTEGER);
c.registerOutParameter(4, Types.INTEGER);
c.execute();
System.out.println(c.getObject(2));
System.out.println(c.getObject(4));
}
Вывод:
Connected to database
1
2
Комментарии:
1. Второй вариант, который вы упомянули в своем вопросе, приводит к нулю, null с моим драйвером Oracle 9.2 JDBC.
2. Вы написали в вопросе: «Это действительно серьезная ошибка в драйвере JDBC или я что-то полностью упускаю?» Вот почему я попробовал это с Oracle, чтобы убедиться, что это только в вашем драйвере JDBC. Основываясь на этом, я мог бы написать: да, Лукас, возможно, это ошибка в вашем драйвере sybase jdbc, который хорошо работает с Oracle. В любом случае: спасибо, что проголосовали против единственного, кто потратил время на изучение этой проблемы .. 🙁
3. Ах, смотрите. Вы автоматически получили половину вознаграждения … 😉
4. спасибо 🙂 забавно, как эти бесполезные очки репутации могут мотивировать скучающих людей
Ответ №3:
Below sybase stored procedure works for me
public String IDGEN(String tableName, Connection con , LOG _log)
{
String strReturnValue = "-1";
try
{
CallableStatement cs = con.prepareCall("{call usp_NEWPK_string_v6(?,?)}");
cs.registerOutParameter(2,java.sql.Types.NUMERIC);
cs.setString(1,tableName);
cs.setInt(2,0);
cs.execute();
strReturnValue = cs.getLong(2) "";
} catch (Exception ex) {
_log.logInstance(" ERROR: [IDGEN] " ex.getMessage());
}
return strReturnValue;
}
// abobjects.com
create proc usp_NEWPK_string_v6 (@tablename varchar(32) , @ID numeric output
)
as
declare @newValue numeric
declare @oldValue numeric
select @oldValue=IDGEN_ID from DB_IDGEN where IDGEN_TableName = @tablename
select @newValue=@oldValue 1 from DB
_IDGEN where IDGEN_TableName = @tablename
update DB_IDGEN set IDGEN_ID = @newValue where IDGEN_TableName = @tablename
select @ID = @oldValue
return