вопрос по API - execute_immediate//

IBX, FIBPlus, UIB, ADO, .Net и прочее-прочее-прочее, в общем все, что относится к созданию приложений, работающих с InterBase, Firebird и Yaffil - клиент-серверных, трехзвенных, консольных и т.п.

Модератор: kdv

Ответить
debug
Сообщения: 10
Зарегистрирован: 17 май 2006, 12:46

вопрос по API - execute_immediate//

Сообщение debug » 23 май 2006, 07:00

Следующий код работает неверно на мой взгляд.
Кодга работаю через isc_dsql_execute - т.е. рабтает тот код - который в данном случае закоментарен, всё работает правильно. В таблицу БД всё записывается верно как и ожидается.
Когда работаю через isc_dsql_execute_immediate - то программа отрабатывает без ошибок - но в таблицу БД в три первых поля (они все SQL_LONG) записываются только нули. Одни нули, а поле SQL_TEXT типа записываются теже значения - т.е. верные.
Тип пр этом первых трёх параметров и размер клинт "видит", а значения почему-то нет :(. Как только "возвращаю" программу в исходное (коментарю immediate и раскоментариваю предыдущее) всё работает правильно. В чём может быть причина?

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

	XSQLDA *xsqlda=NULL;
	XSQLVAR *sqlvar=NULL;

	xsqlda=(XSQLDA*)malloc(XSQLDA_LENGTH(4));
	xsqlda->version=SQLDA_VERSION1;
	xsqlda->sqln=4;
	xsqlda->sqld=4;
	char *str_sql_stmt="insert into fire_info (id, value_, type_, rem) values(?, ?, ?, ?)";

	// declare SQL statement
	/*
	isc_stmt_handle stmt=NULL;
	isc_dsql_allocate_statement(status, &h_db_agroprom, &stmt);
	if (status[0]==1 && status[1]) {
		isc_print_status(status);
	}

	isc_dsql_prepare(status, &h_tr_agroprom, &stmt, 0, str_sql_stmt, 1, xsqlda);
	if (status[0]==1 && status[1]) {
		isc_print_status(status);
	}

	isc_dsql_describe_bind(status, &stmt, 1, xsqlda);
	if (status[0]==1 && status[1]) {
		isc_print_status(status);
	}
	*/
	int id=1, value_=id+10, type_=2;
	static char remark[255], num[3];

	int i;
	for (i=0; i<10; i++) {
		sqlvar=xsqlda->sqlvar;
		itoa(i, num, 10);
		strcpy(remark, "remark string: 1");
		strcat(remark, num);
		
		sqlvar->sqltype=SQL_LONG;
		sqlvar->sqldata=(char*)&id;
		sqlvar->sqllen=sizeof(id);
		sqlvar++;

		sqlvar->sqltype=SQL_LONG;
		sqlvar->sqldata=(char*)&value_;
		sqlvar->sqllen=sizeof(value_);
		sqlvar++;

		sqlvar->sqltype=SQL_LONG;
		sqlvar->sqldata=(char*)&type_;
		sqlvar->sqllen=sizeof(type_);
		sqlvar++;

		sqlvar->sqltype=SQL_TEXT;
		sqlvar->sqldata=remark;
		sqlvar->sqllen=strlen(remark);

//		isc_dsql_execute(status, &h_tr_agroprom, &stmt, 1, xsqlda); 
		isc_dsql_execute_immediate(status, &h_db_agroprom, &h_tr_agroprom, 0, str_sql_stmt, 1, xsqlda); 
		if (status[0]==1 && status[1]) {
			isc_print_status(status);
		}
		id++;
		value_++;
	}
	

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 23 май 2006, 08:50

Симптомы типичны для неполного/неправильного заполнения sqlvar. Ну так и есть: не указал sqlscale.
Кстати, запихивать одну и ту же sqlda и в prepare и в describe как минимум странно...

debug
Сообщения: 10
Зарегистрирован: 17 май 2006, 12:46

Сообщение debug » 23 май 2006, 11:22

Спасибо, я так и предполагал - что неполностью заполнил sqlvar, но
что, конкретно не знал потому, что смотрел в пример - api4.c кажется так. И там параметр scale не заполнялся, хотя там тип SQL_DOUBLE. Вот это и смутило.
Dimitry Sibiryakov писал(а): Кстати, запихивать одну и ту же sqlda и в prepare и в describe как минимум странно...
А как нужно? Создавать его копию для describe? А зачем это нужно?
Я вот только недавно решил разобраться - день назад - необходимость появилась.

debug
Сообщения: 10
Зарегистрирован: 17 май 2006, 12:46

Сообщение debug » 23 май 2006, 12:11

Dimitry Sibiryakov писал(а):Симптомы типичны для неполного/неправильного заполнения sqlvar. Ну так и есть: не указал sqlscale.
Забыл спросить - а почему в первом случае - когда работает isc_dsql_prepare...ну и вся цепочка до isc_dsql_execute - без заполнения sqlscale работает правильно - пишет ожидаемые данные в БД? Или в данном случае describe заполняет sqlscale как то по умолчанию? Где можно по этому вопросу и по многим другим поподробнее прочитать? - а то в API-стандартном доки - очень мало описано.

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 23 май 2006, 16:07

Для SQL_DOUBLE scale не используется.
prepare заполняет sqlda для возвращаемых значений, describe_bind - для параметров. Это разные sqlda.
Читать все тот же ApiGuide исходники примеров и разных компонент доступа (ibpp, например). Ну еще можно исходники FB, но это не для слабонервных.

debug
Сообщения: 10
Зарегистрирован: 17 май 2006, 12:46

Сообщение debug » 23 май 2006, 21:12

Dimitry Sibiryakov писал(а): prepare заполняет sqlda для возвращаемых значений, describe_bind - для параметров. Это разные sqlda.
Читать все тот же ApiGuide исходники примеров и разных компонент доступа (ibpp, например).
В APIguide в главе DSQL programming methods есть Method 2.
Вот в нём сказано и показано - как используються для этого и prepare и describe_bind совместно - с одним и тем же xdsql. prepare - не обязательно как я понял только для возвращаемых значений. И в примерах они совместно используются, видимо prepare и заполняет scale. А когда без prepare - тут видимо уже ручками нужно. Ну по крайней мере я так понял :-)

debug
Сообщения: 10
Зарегистрирован: 17 май 2006, 12:46

Сообщение debug » 23 май 2006, 21:32

Разобрался - действительно prepare - для результатного xsqlda. Вот что значит некорректные примеры - просто напросто с толку сбивают.
Корректнее в таких примерах вместо xsqlda ставить NULL - по крайней мере не запутается никто.

Dimitry Sibiryakov
Заслуженный разработчик
Сообщения: 1436
Зарегистрирован: 15 сен 2005, 09:05

Сообщение Dimitry Sibiryakov » 24 май 2006, 09:31

Действительно, какой-то придурок в АПИгаде запихнул in_sqlda в вызов prepare()... Ну да потому этот набор документации и называется "бета". А нормальную доку Б. отдает только за деньги.
Если ты в prepare поставишь null, придется либо заполнять sqlda самому либо звать дополнительный describe (не describe_bind, заметь). Первое обычно делать лениво, а второе - дополнительный round-trip.

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

Сообщение hvlad » 24 май 2006, 11:05

Dimitry Sibiryakov писал(а):Действительно, какой-то придурок в АПИгаде запихнул in_sqlda в вызов prepare()... Ну да потому этот набор документации и называется "бета". А нормальную доку Б. отдает только за деньги.
Оптимист - в доке по IB 7.5 та же лажа :lol:
Правда в описании isc_dsql_prepare всё таки указывается, что это "XSQLDA used for results of statement execution"

Ответить