execute statement и чарсет подключения

Access Violation, некорректное выполнение запросов или вызовов API, ошибки утилит командной строки, в общем все, что вам мешает работать

Модераторы: kdv, dimitr

mustafa
Сообщения: 67
Зарегистрирован: 07 мар 2006, 17:53

execute statement и чарсет подключения

Сообщение mustafa » 17 фев 2009, 10:00

Server FB2.1.1 win, база WIN1251
----------------------------------------

Код: Выделить всё

create procedure TEST (NAME varchar(10))
returns (ID integer)
as
declare variable LSQL varchar(100);
begin
  LSQL =
    'select rdb$relation_id from rdb$database where rdb$character_set_name = '''
    || :NAME || '''';
  for execute statement :LSQL into :ID
  do
    suspend;
end
Подключаемся с UTF8, выполняем: select * from TEST('проверка');
получаем ошибку:
SQL error code = -104.
Malformed string.

т.е. execute statement для строки запроса берёт чарсет подключения к базе игнорируя чарсет базы/переменной?

И ещё. встроенные функции bin_and, bin_or, bin_xor позволяют задавать всего один аргумент. что не есть хорошо.

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: execute statement и чарсет подключения

Сообщение hvlad » 17 фев 2009, 11:39

mustafa писал(а):Server FB2.1.1 win, база WIN1251
----------------------------------------

Код: Выделить всё

create procedure TEST (NAME varchar(10))
returns (ID integer)
as
declare variable LSQL varchar(100);
begin
  LSQL =
    'select rdb$relation_id from rdb$database where rdb$character_set_name = '''
    || :NAME || '''';
  for execute statement :LSQL into :ID
  do
    suspend;
end
Подключаемся с UTF8, выполняем: select * from TEST('проверка');
получаем ошибку:
SQL error code = -104.
Malformed string.
И запрос, конечно же, тоже формируем в UTF8 ?
mustafa писал(а):т.е. execute statement для строки запроса берёт чарсет подключения к базе игнорируя чарсет базы/переменной?
А то без execute statement этот пример будет себя вести не так ?
mustafa писал(а):И ещё. встроенные функции bin_and, bin_or, bin_xor позволяют задавать всего один аргумент. что не есть хорошо.
Не хорошо писать глупости, не проверив их сначала :wink:

mustafa
Сообщения: 67
Зарегистрирован: 07 мар 2006, 17:53

Re: execute statement и чарсет подключения

Сообщение mustafa » 17 фев 2009, 12:31

hvlad писал(а):И запрос, конечно же, тоже формируем в UTF8 ?
строка(параметр) в fbclient передаётся в UTF-8.
hvlad писал(а):
mustafa писал(а):т.е. execute statement для строки запроса берёт чарсет подключения к базе игнорируя чарсет базы/переменной?
А то без execute statement этот пример будет себя вести не так ?
не понял.
на этот же запрос в процедуре, только без execute statement, сервер ошибок не выдаёт.
т.е. если там написать так: select rdb$relation_id from rdb$database where rdb$character_set_name = :NAME into :ID;
hvlad писал(а):
mustafa писал(а):И ещё. встроенные функции bin_and, bin_or, bin_xor позволяют задавать всего один аргумент. что не есть хорошо.
Не хорошо писать глупости, не проверив их сначала :wink:
проверил прямо сейчас: select bin_and(0) from rdb$database; вернул 0. а надо бы чтоб ругался

mustafa
Сообщения: 67
Зарегистрирован: 07 мар 2006, 17:53

Re: execute statement и чарсет подключения

Сообщение mustafa » 17 фев 2009, 12:44

Вдогонку: если переменную объявить как UTF8(т.е. с чарсетом отличным от чарсета базы), то при подключении с UTF8 всё будет работать, но если подключиться с WIN1251(чарсетом базы), то ругани не будет, но и найти ничего не найдёт, даже если значение(ессно в WIN1251) будет иметься в таблице.

MadLizard
Сообщения: 2
Зарегистрирован: 17 фев 2009, 11:09

Re: execute statement и чарсет подключения

Сообщение MadLizard » 17 фев 2009, 12:58

mustafa писал(а):строка(параметр) в fbclient передаётся в UTF-8.
Каким образом? А если попробовать "select * from TEST(_win1251 'проверка')"?
mustafa писал(а):проверил прямо сейчас: select bin_and(0) from rdb$database; вернул 0. а надо бы чтоб ругался
На что ругался? Единственное, на что ему следует ругаться, это нечитание документации пользователями
Аргументов у этой функции может быть от одного и до... N. Нет, N - много. До M. :)

С уважением,
Денис Редозубов.

mustafa
Сообщения: 67
Зарегистрирован: 07 мар 2006, 17:53

Re: execute statement и чарсет подключения

Сообщение mustafa » 17 фев 2009, 13:17

MadLizard писал(а):На что ругался? Единственное, на что ему следует ругаться, это нечитание документации пользователями
Аргументов у этой функции может быть от одного и до... N. Нет, N - много. До M. :)
я о том что по логике должно быть не от 1-го, а от 2-х и до много. это же не унарные типа abs.

MadLizard
Сообщения: 2
Зарегистрирован: 17 фев 2009, 11:09

Re: execute statement и чарсет подключения

Сообщение MadLizard » 17 фев 2009, 13:27

mustafa писал(а):я о том что по логике должно быть не от 1-го, а от 2-х и до много. это же не унарные типа abs.
Это функции над непустым множеством. А в непустом множестве бывает и всего один элемент.

С уважением,
Денис Редозубов.

mustafa
Сообщения: 67
Зарегистрирован: 07 мар 2006, 17:53

Re: execute statement и чарсет подключения

Сообщение mustafa » 17 фев 2009, 13:48

MadLizard писал(а):Это функции над непустым множеством. А в непустом множестве бывает и всего один элемент.
Если б это были агрегатные функции, так и не спрашивал бы (кстати от агрегатных bin_xxx я б не отказался :) ).

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: execute statement и чарсет подключения

Сообщение hvlad » 17 фев 2009, 14:11

mustafa писал(а):
hvlad писал(а):И запрос, конечно же, тоже формируем в UTF8 ?
строка(параметр) в fbclient передаётся в UTF-8.
И где в вышепреведенном примере параметр ?
mustafa писал(а):
hvlad писал(а):
mustafa писал(а):т.е. execute statement для строки запроса берёт чарсет подключения к базе игнорируя чарсет базы/переменной?
А то без execute statement этот пример будет себя вести не так ?
не понял.
Сделай то, что сам же написал выше - станет понятно :)
mustafa писал(а):
hvlad писал(а):
mustafa писал(а):И ещё. встроенные функции bin_and, bin_or, bin_xor позволяют задавать всего один аргумент. что не есть хорошо.
Не хорошо писать глупости, не проверив их сначала :wink:
проверил прямо сейчас: select bin_and(0) from rdb$database; вернул 0. а надо бы чтоб ругался
Я прочитал так, как написано. А написано, что они позволяют задавать всего один аргумент, т.е. не позволяют задавать больше одного.
Впрочем, не вижу почему возможность задать один аргумент - это плохо

mustafa
Сообщения: 67
Зарегистрирован: 07 мар 2006, 17:53

Re: execute statement и чарсет подключения

Сообщение mustafa » 17 фев 2009, 18:01

hvlad писал(а):И где в вышепреведенном примере параметр ?
запускал и из isql и из IBExpert и из своей проги как есть, а уточнил про параметр т.к. проверил ещё и в своей проге где параметр передавался собственно как параметр.
результат всегда один и тот же.
hvlad писал(а):
mustafa писал(а):не понял.
Сделай то, что сам же написал выше - станет понятно :)
Прости, ну скажи плиз что я должен понять? что второй вариант работает прекрасно? но мне то нужен execute statement.
а сейчас я понимаю, что если мне необходимо использовать execute statement, то я обязан подключаться _только_ с чарсетом базы! :(
hvlad писал(а):Я прочитал так, как написано. А написано, что они позволяют задавать всего один аргумент, т.е. не позволяют задавать больше одного.
Впрочем, не вижу почему возможность задать один аргумент - это плохо
Эт моё косноязычие - без наводящих вопросов никак. :(
может и неплохо, только бессмысленно. и при разработке ошибки (были уже как с udf-функций перебрались).

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: execute statement и чарсет подключения

Сообщение kdv » 17 фев 2009, 18:31

IBExpert и из своей проги как есть
http://www.ibase.ru/unicode_faq.html
faq не дописан, могут быть косяки. но ibexpert проверен.

mustafa
Сообщения: 67
Зарегистрирован: 07 мар 2006, 17:53

Re: execute statement и чарсет подключения

Сообщение mustafa » 17 фев 2009, 20:16

kdv писал(а):http://www.ibase.ru/unicode_faq.html
faq не дописан, могут быть косяки. но ibexpert проверен.
У меня свой маленький класс-оболочка над api FB.
при подключении с UTF8 транслирую юникод(UTF-16) в UTF-8. ну или в текущую кодовую страницу, если в чарсете указано что-то отличное от "UTF8". соответственно и обратно из UTF-8 в UTF-16 при получении.
и всё прекрасно работает.
кроме процедур, содержащих execute statement.

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: execute statement и чарсет подключения

Сообщение kdv » 18 фев 2009, 09:03

ок. тогда
1 почему база в win1251?
2 у процедуры входной параметр какой чарсет имеет?
3 что если явно пересоздать процедуру, указав у всех переменных процедуры (входных и локальных) чарсет юникода?

mustafa
Сообщения: 67
Зарегистрирован: 07 мар 2006, 17:53

Re: execute statement и чарсет подключения

Сообщение mustafa » 18 фев 2009, 11:24

kdv писал(а):1 почему база в win1251?
потому что до того все подключались с WIN1251 и в дальнейшем так будет, но в данный момент в одном из модулей программы я вынужден подключаться по UTF8.
kdv писал(а):2 у процедуры входной параметр какой чарсет имеет?
по умолчанию. т.е. чарсет базы WIN1251.
kdv писал(а):3 что если явно пересоздать процедуру, указав у всех переменных процедуры (входных и локальных) чарсет юникода?
в этом случае при подключении с UTF8 процедура работает.
но, при этом, если подключиться из другого модуля уже с WIN1251, то нет ни ругани "Malformed string", ни результата процедуры.
Чарсет(подключение) | ЧарсетSQL(сделал две переменные для текста запроса в процедуре)
-------------- | ------------
1. WIN1251 | WIN1251 - ok (нет трансляции - чарсет базы и подключения совпадают)
2. WIN1251 | UTF8 - нет результата (нет трансляции - чарсет базы и подключения совпадают)
3. UTF8 | UTF8 - ok (трансляция в чарсет базы)
4. UTF8 | WIN1251 - ошибка "Malformed string" (трансляция в чарсет базы)
т.е. execute statement считает что переданная ему строка запроса всегда в чарсете подключения и в случае несоответствия приводит к чарсету базы.
отсюда и проблема - попытка преобразования WIN1251(якобы из UTF8) в WIN1251 для (4) и отсутствие необходимого преобразования в случае (2).
получается что в процедуре необходимо анализировать с каким чарсетом подключился клиент и приводить к нему текст запроса перед передачей его execute statement. :(

kdv
Forum Admin
Сообщения: 6595
Зарегистрирован: 25 окт 2004, 18:07

Re: execute statement и чарсет подключения

Сообщение kdv » 18 фев 2009, 13:47

(трансляция в чарсет базы)
просто замечу - нет никакого "чарсета базы", и никогда не было. Это банальный default charset для создаваемых строковых объектов DDL, если у них чарсет не указан. Я понятно выражаюсь?
Поэтому "трансляция" возникает только тогда, когда чарсет объекта или данных НЕ совпадает с чарсетом коннекта (кроме none), и существует таблица трансляции.

Кроме этого - я могу быть неправ, но еще вопрос в том, в каком виде сохраняется строка execute statement. Мне кажется, что у Вас возникает ошибка, когда Вы склеиваете в процедуре строку текста с неизвестным мне чарсетом с куском текста известного чарсета.
Например, строка_в_юникоде + строка_в_win1251.

mustafa
Сообщения: 67
Зарегистрирован: 07 мар 2006, 17:53

Re: execute statement и чарсет подключения

Сообщение mustafa » 18 фев 2009, 15:04

говоря о чарсете базы, я и имел ввиду DEFAULT CHARACTER SET задаваемый при создании базы.
нет у меня никаких других чарсетов кроме дефолтного(т.е. без явного указания) для параметров и переменных процедур/триггеров/udf
и его-же, но явно указанного с коллейтом PXW_CYRL в доменах для полей таблиц.

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: execute statement и чарсет подключения

Сообщение hvlad » 18 фев 2009, 15:19

Попробуй что-то вроде

Код: Выделить всё

create procedure TEST (NAME varchar(10))
returns (ID integer)
as
declare variable LSQL varchar(100);
begin
  LSQL =
    _utf8 'select rdb$relation_id from rdb$database where rdb$character_set_name = '''
    || CAST(:NAME as varchar(10) character set UTF8) || _utf8 '''';
  for execute statement :LSQL into :ID
  do
    suspend;
end

mustafa
Сообщения: 67
Зарегистрирован: 07 мар 2006, 17:53

Re: execute statement и чарсет подключения

Сообщение mustafa » 18 фев 2009, 15:53

тоже самое

hvlad
Разработчик Firebird
Сообщения: 1244
Зарегистрирован: 21 мар 2005, 10:48

Re: execute statement и чарсет подключения

Сообщение hvlad » 18 фев 2009, 17:13

А вот так ?

Код: Выделить всё

create or alter procedure TEST (NAME varchar(10))
returns (ID integer)
as
declare variable LSQL varchar(100) character set win1251;
begin
  LSQL = 'select id from t_test where name = _win1251''' ||
         CAST (:NAME as varchar(32) character set WIN1251) || '''';
  for execute statement :LSQL into :ID
  do
    suspend;
end

mustafa
Сообщения: 67
Зарегистрирован: 07 мар 2006, 17:53

Re: execute statement и чарсет подключения

Сообщение mustafa » 18 фев 2009, 20:43

дело-то не в смешении чарсетов.
вообще убрал входной параметр:

Код: Выделить всё

create procedure TEST
returns (ID integer)
as
declare variable LSQL varchar(500);
begin
  LSQL = 'select rdb$relation_id from rdb$database where rdb$character_set_name = ''проверка''';
  for execute statement :LSQL into :ID
  do
    suspend;
end
и даже вообще без переменной:

Код: Выделить всё

create procedure TEST
returns (ID integer)
as
begin
  for execute statement 'select rdb$relation_id from rdb$database where rdb$character_set_name = ''проверка''' into :ID
  do
    suspend;
end
результат тот же самый. :(

Ответить