Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1] 2 3 4 5   Вниз
  Печать  
Автор Тема: Firebird+ODBC  (Прочитано 142750 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« : 24-09-2007 05:10 » 

подключаюсь к базе *.fdb при помощи связки Firebird(1.5) + ODBC
Имеется тип поля BIGINT.

Читаю при помощи класса MFC:


CString sql="SELECT fff FROM mytable";
CRecordset rs(pbase);
rs.Open(CRecordset::snapshot,sql,CRecordset::readOnly);

//var.m_dwType==DBVT_STRING

//var.m_pstring - значение поля в ТЕКСТОВОМ ВИДЕ!!!

почему именно в текстовом ? Это ж тормоза при преобразовании... Как можно иначе прочитать значение?

---------------
а может как-нибудь при чтении разбить в запросе значение этого поля на два значения типа INTEGER, а потом в программе соединить обратно ?
« Последнее редактирование: 11-07-2008 04:30 от Алексей1153++ » Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #1 : 06-04-2008 13:15 » 

с той проблемой, кстати, давно разобрался - именно в текстовом виде тольк ои можно.
Теперь ещё вопрос.

данные об объекте разнесены по нескольким таблицам, хочется сделать встроенную процедуру, которая сама бцдет раскидывать данные, а я только куча параметров буду передавать. И тут возникает вопрос. Процедура выглядит примерно так

Код:
create procedure MyProc
(
 param1 SMALLINT
,param2 SMALLINT
,param3 VARCHAR(10)
,param4 VARCHAR(20)
....
....
,param113 INTEGER
,param114 INTEGER

)
as
BEGIN
END

вопрос в том, нельзя ли как-то упростить использование этого списка, с учётом того, что он может ведь и в другой процедуре повториться ? Как тут с защищённостью от ошибок, если набор полей у таблиц придётся менять (а особенно - типы полей) ?
Посоветуйте, как обычно тут поступают
Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #2 : 06-04-2008 13:45 » 

Алексей1153++, надо наперед планировать потребности и механизмы расширения возможностей. Если тебе понадобится расширить возможности процедуры, то обязательно проверь на совместимость с существующим ПО, где она используется. Может оказаться, что лучше написать вторую процедуру. При этом можно переписать первую, превратив ее в затычку: она будет вызывать вторую процедуру, сама добавляя недостающие параметры.

Чем-то жизнь могут облегчить:
1. Дефолтные значения у параметров. Позволит не писать их все без необходимости.
2. Использовать "лишние" параметры. По наличию того или иного параметра выполнять разные действия.
3. Параметры-списки. Реализация целиком зависит от возможностей языка БД. Сам пока пробовал, но хочу как-нибудь рассмотреть в рамках Oracle.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #3 : 06-04-2008 13:57 » 

Ром,

1) писать мне надо ВСЕ параметры. По умолчанию нет смысла оставлять.
2) в смысле ?
3) типа структур, наверное ? ) Может есть что то такое
Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 07-04-2008 19:50 » 

2. Скажем, использовать значение NULL как условие "параметер не назначен" или "не используется" и строить логику с ветвлением.

3. В Оракле есть NESTED TABLE - типа таблицы в одном значении: можно в переменной держать, можно в поле таблицы.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #5 : 08-04-2008 03:21 » 

2 - не выйдет так у меня. В новой версии могут поля добавиться, а в процедуре я хоп - и забыл. Охота что то вроде сишной структуры в качестве параметра поиметь Улыбаюсь Понимаю - сказки. Придётся внимательно перебирать вручную

3- тут я такого не нашёл...
Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #6 : 08-04-2008 05:53 » new

Алексей1153++, при изменении таблицы тебе все равно надо наводить ревизию в зависимых ф-иях.

Есть такая идея: сделать ф-ию, которая бы разбирала строку параметров - это самый простой способ расширения, с сохранением обратной совместимости.

(name VARCHAR, params VARCHAR, default_value VARCHAR) RETURN VARCHAR
Первый аргумент - имя параметра, второй - строка с параметрами список, третьим - дефолтное значение, если параметра нет в строке.

Не знаю - может будет полезно...
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #7 : 08-04-2008 06:15 » 

вот тут поподробнее )
Цитата
(name VARCHAR, params VARCHAR, default_value VARCHAR) RETURN VARCHAR
Первый аргумент - имя параметра, второй - строка с параметрами список, третьим - дефолтное значение, если параметра нет в строке.

Первый аргумент - то есть имя процедуры ?
paramsIn  - список входных переменных
paramsOut  - список выходных переменных
default_value - затычки

а как это в процедуру отправить ?

Код:
/*парсим на предмет необходимости вставки затычек*/
...
...

/*запуск*/
execute procedure :name (paramsIn)

или

select * from :name(paramsIn)


так ?
« Последнее редактирование: 08-04-2008 06:17 от Алексей1153++ » Записан

RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #8 : 08-04-2008 06:34 » 

Грубо говоря, примерно так:

Код: (SQL)
CREATE FUNCTION getParameter(name VARCHAR, params VARCHAR, default_value VARCHAR) RETURN VARCHAR
BEGIN
  ...
END;

DECLARE
  params VARCHAR(255) := 'id=10;name=текст;create_date=08.04.2008;';
  param1 INT;
  param2 VARCHAR(255);
  param3 DATE;

BEGIN

  param1 = getParameter('id', params, 0);
  param2 = getParameter('name', params, ' ');
  param3 = getParameter('create_date', params, SYSDATE());

  ...

END;

Алгоритм вычленения уж придумай сам Улыбаюсь
« Последнее редактирование: 08-04-2008 06:36 от RXL » Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #9 : 08-04-2008 07:15 » 

а, понял. Мне такое скорее всего не подойдёт (
Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #10 : 22-04-2008 04:17 » 

ещё парочка вопросов:

1) теоретический. Можно ли из встроенной процедуры создать (и наполнить) файл произвольного формата ?

2) хотелось бы использовать в селекте оператор IN, например

select * from T1 where F in (3,4,5,6)

но только вот так -

select * from T1 where F in (:my_list) ,

где my_list - это переменная VARCHAR(1000) , которую я передаю как параметр во встроенную процедуру.
Насколько я понял из экспериментов, напрямую так сделать не получается, есть ли способ сделать подобное ?
Записан

Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #11 : 22-04-2008 06:01 » 

а если так
select * from T1 where F in (select :my_list)
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #12 : 22-04-2008 06:05 » 

Слав , не , ты не понял, в переменной передаётся строка вида
'1,2,3,7,10'

а в любом случае, вложенные запросы тут не катят
Записан

Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #13 : 22-04-2008 06:13 » 

Алексей1153++, я все понял Улыбаюсь
я не виноват, что не поддерживаются вложенные запросы, а FB я не знаю
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #14 : 22-04-2008 06:37 » 

а как бы спасло
select * from T1 where F in (select :my_list)

?
Не могу въехать
Записан

Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #15 : 22-04-2008 07:02 » 

select :my_list тебе возвратит список, а не текстовую переменную
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #16 : 22-04-2008 09:38 » 

мдя. Мысль понял, но не канает из-за этих подзапросов (
Может какой то оператор есть специальный, только я об этом не знаю...
Записан

Sla
Команда клуба

ua
Offline Offline
Пол: Мужской

WWW
« Ответ #17 : 22-04-2008 12:50 » 

Алексей1153++, дарю код, все равно я его украл
'~12~23~267~675~'

и запрос пишу

Select тыры-пыры
From Table T
Where :ParamStr Containing '~'||T.ID||'~'

украдено здесь http://ibase.ru/ibfaq.htm#inparam
Записан

Мы все учились понемногу... Чему-нибудь и как-нибудь.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #18 : 22-04-2008 14:11 » 

А динамический запрос собрать?

типа
Код:
sqlCommand.Text = "select * from t where f in (" + myList.toString() + ")";
ну, садаптировав под FB и C++.

Или внутри хранимки
Код:
exec('select * from t where f in (' + myList + ')')

гарантировав, что внутри строчки только числа через запятую.

P.S. Сразу предупреждаю, что когда список достигает размера порядка 100 Кб, исполняться будет очень долго.
« Последнее редактирование: 22-04-2008 14:14 от dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #19 : 22-04-2008 14:29 » 

Sla, это решение, но использование индексов автоматом исключается. Жаль

dimka, поддерживаю. Только тут все будет зависеть от возможности СУБД.
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #20 : 22-04-2008 18:24 » 

А динамический запрос собрать?

- это легко, но долго работает. В том и дело, что хочется в хранимую передать список

exec - такой команды тут не наблюдается...

Sla,
Where :ParamStr Containing '~'||T.ID||'~'

это канает, я ещё не понял, как, но работает ))) . Завтра вчитаюсь , щас сплю
« Последнее редактирование: 23-04-2008 15:32 от Алексей1153++ » Записан

HandKot
Молодой специалист

ru
Offline Offline

« Ответ #21 : 24-04-2008 04:44 » 

еще такой вариант (для MSSQL)
пусть передали в ХП параметр ParamStr = '1,2,3,7,10'

Код:
--создаем временную таблицу
create table #t(f int)
--заносим туда данные условий
exec('insert into #t select ' + replace(ParamStr , ',',  ' as f union select'))

--делаем выборку
select * from MyTable mt
inner join #t t on t.f = mt.f

Цитата
Цитата: dimka от 22-04-2008 19:11
А динамический запрос собрать?

- это легко, но долго работает. В том и дело, что хочется в хранимую передать список


никогда не думал, что динамический запрос работает дольше чем нединамический
единственное конечно оптимизатор будет дольше думать, но ...
Записан

I Have Nine Lives You Have One Only
THINK!
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #22 : 24-04-2008 05:00 » 

HandKot,

Цитата
Код:
--создаем временную таблицу
create table #t(f int)
--заносим туда данные условий
exec('insert into #t select ' + replace(ParamStr , ',',  ' as f union select'))

--делаем выборку
select * from MyTable mt
inner join #t t on t.f = mt.f

мне кажется, это ещё дольше работать станет Улыбаюсь

Цитата
никогда не думал, что динамический запрос работает дольше чем нединамический
разница, может и не большая, но встроенная процедура работает всё же быстрее. Именно в этом случае запрос не большой, может разницы и не почувствуется, а на длинных запросах заметно. Но всё же охота встроенную сделать изза удобства, чтобы в программе не городить , а один раз в базе Улыбаюсь Я совсем недавно перешёл на хранимые, до этого в коде бацал , гибкости в коде программы при работе с базой иногда маловато
Записан

Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #23 : 24-04-2008 05:14 » 

Цитата: Алексей1153++
мне кажется, это ещё дольше работать станет
Если каким-либо образом передать список во временную таблицу, сам запрос будет работать быстрее с ней, нежели с конструкцией IN. Особенно заметно на больших списках. Так что при разных объёмах данных разные подходы могут получать и терять преимущества.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #24 : 24-04-2008 05:52 » 

попробую при случае по всякому Улыбаюсь
Записан

Oldy
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #25 : 24-04-2008 17:53 » 

Алексей, при случае, попробуй посмотреть в сторону Execute Statement, вдруг увидишь нечто полезное.
Записан

С уважением, Oldy.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #26 : 24-04-2008 18:13 » 

Oldy, а что за зверь, что делает ?
Записан

Oldy
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #27 : 24-04-2008 18:37 » 

Цитата
SQL Language Extension: EXECUTE STATEMENT

   Implements capability to take a string which is a valid dynamic SQL
   statement and execute it as if it had been submitted to DSQL. 
   Available in triggers and stored procedures.

Author:
   Alex Peshkoff <pes@insi.yaroslavl.ru>

Syntax may have three forms.

Syntax 1
========

EXECUTE STATEMENT <string>;

Description

Executes <string> as SQL operation. It should not return any data rows.
Following types of SQL operators may be executed:

   * Insert, Delete and Update.
   * Execute Procedure.
   * Any DDL (except Create/Drop Database).

Sample:

CREATE PROCEDURE DynamicSampleOne (Pname VARCHAR(100))
AS
DECLARE VARIABLE Sql VARCHAR(1024);
DECLARE VARIABLE Par INT;

BEGIN
SELECT MIN(SomeField) FROM SomeTable INTO :Par;
Sql = 'EXECUTE PROCEDURE ' || Pname || '(';
Sql = Sql || CAST(Par AS VARCHAR(20)) || ')';
EXECUTE STATEMENT Sql;
END


Syntax 2
=========

EXECUTE STATEMENT <string> INTO :var1, ., :varn;

Description

Executes <string> as SQL operation, returning single data row. Only
singleton SELECT operators may be executed with this form of EXECUTE
STATEMENT.

Sample:

CREATE PROCEDURE DynamicSampleTwo (TableName VARCHAR(100))
AS
DECLARE VARIABLE Par INT;

BEGIN
EXECUTE STATEMENT 'SELECT MAX(CheckField) FROM ' || TableName INTO :Par;
IF (Par > 100) THEN
  EXCEPTION Ex_Overflow 'Overflow in ' || TableName;
END


Syntax 3
========

FOR EXECUTE STATEMENT <string> INTO :var1, ., :varn DO
<compound-statement>;

Description

Executes <string> as SQL operation, returning multiple data rows. Any SELECT
operator may be executed with this form of EXECUTE STATEMENT.

Sample:

CREATE PROCEDURE DynamicSampleThree (TextField VARCHAR(100), TableName VARCHAR(100))
   RETURNING_VALUES (Line VARCHAR(32000))
AS
DECLARE VARIABLE OneLine VARCHAR(100);

BEGIN
Line = '';
FOR EXECUTE STATEMENT 'SELECT ' || TextField || ' FROM ' || TableName
   INTO :OneLine
DO
  IF (OneLine IS NOT NULL) THEN
    Line = Line || OneLine || ' ';
SUSPEND;
END


N O T E S
=========

I. For all forms of EXECUTE STATEMENT SQL, the DSQL string can not contain
any parameters. All variable substitution into the static part of the SQL
statement should be performed before EXECUTE STATEMENT.

EXECUTE STATEMENT is potentially dangerous, because:

  1. At compile time there is no checking for the correctness of the SQL
     statement.  No checking of returned values (in syntax forms 2 & 3 )
     can be done.
  2. There can be no dependency checks to ensure that objects referred to in
     the SQL statement string are not dropped from the database or modified
     in a manner that would break your statement. For example, a DROP TABLE
     request for the table used in the compiled EXECUTE PROCEDURE statement
     will be granted.
  3. In general, EXECUTE STATEMENT operations are rather slow, because the
     statement to be executed has to be prepared each time it is executed
     by this method.

These don't mean that you should never use this feature.  But, please,
take into account the given facts and apply a rule of thumb to use
EXECUTE STATEMENT only when other methods are impossible, or perform even
worse than EXECUTE STATEMENT.

To help (a little) with bugfixing, returned values are strictly checked for
correct datatype. This helps to avoid some errors where unpredictable
type-casting would otherwise cause exceptions in some conditions but not
in others.  For example, the string '1234' would convert to an int 1234,
but 'abc' would give a conversion error.

II. If the stored procedure has special privileges on some objects, the
dynamic statement submitted in the EXECUTE STATEMENT string does not
inherit them. Privileges are restricted to those granted to the user who
is executing the procedure.

Записан

С уважением, Oldy.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #28 : 25-04-2008 03:14 » 

Oldy, хорошая штучка Улыбаюсь  Буду иметь в виду, спасибо
« Последнее редактирование: 25-04-2008 03:16 от Алексей1153++ » Записан

Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #29 : 10-07-2008 08:07 » 

интересная фигня на меня напала, хочется понять...

подключаюсь при помощи строки
Код:
"DBNAME=...;"
"READONL=Y;"
"CHARSET=WIN1251;"
"DIALECT=3;"
"DRIVER=Firebird/InterBase(r) driver;"
"NOWAIT=N;"
"QUOTED=Y;"
"SENSITIVE=N;"
"AUTOQUOTED=N;"
"USER=SYSDBA;"
"PASSWORD=masterkey;"
"ROLE=operator;"
всё ок, тут вопросов нет. Но выясняется, что в пароле важны только первые 8 символов, остальные по барабану - почему ?

и ещё: подсмотрел, как IBExpert DSN создаёт в реестре, пароль masterkey там хранится шифрованный.
Я подставил эту строку заместо пароля:

"PASSWORD=DKEBFJENHFCOBHGHLAIMNAAFICELEAEGDNMFNOGALAMHBBGCHFADNKCBPPGMANOGIEKENIOPHDIPBIECPLLLCBIKEJKMJLPLIB;"

прокатывает на ура , при чём изменение любого символа приводит к невозможности подключения (оно и правильно)

отсюда хотелось бы узнать -  что за алгоритм шифрования ?
Записан

Страниц: [1] 2 3 4 5   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines