[English version]  [Главная страница]  [Книга жалоб]  [Зеркало на i72.by.ru]  [Зеркало на i72.narod.ru]
Другое на сайте: [Perl]  [PowerBuilder]  [Multiedit]  [IBSO]  [Clarion]  [Far]  [Юмор]  [Фотки]

Вызов хранимых процедур MS SQL из программ на PowerBuilder.

Приведенная здесь информация собрана из документации PB, конференций и форумов и проверена с PowerBuilder 6.0 и MS SQL Server 6.5.

Внимание! Использование оператора print в sp воспринимается как ошибка! При этом:

sqlcode=-1
sqldbcode=999
sqlerrtext=текст в print.

Возможны два варианта вызова:

Вызов через declare/execute

Как описать

DECLARE ProcedureName PROCEDURE FOR [@Return_Var=]StoredProcedureName @Param1=Value1 [output], @Param2=Value2 [output],... {USING TransactionObject};
    

Как вызвать

EXECUTE ProcedureName;

Как узнать, что была ошибка

В случае ошибки:

sqlca.sqlcode=-1
sqlca.sqldbcode=код ошибки sql server
sqlca.sqlerrtext=текст сообщения sql server

Если ошибок было несколько, в sqlca информация о первой ошибке. При возникновении ошибки с severity>=16 (кроме raiserror) выполнение sp прерывается, ошибки меньшего уровня можно перехватывать в sp проверяя @@error.

Как получить результат

Можно обрабатывать resultset-ы, возвращаемые sp:

EXECUTE ProcedureName ;
<проверка ошибки>
do while true
	FETCH ProcedureName INTO HostVariableList ;
	<проверка конца resultset>
	<проверка ошибки>
	...
loop
<обработка других resultset и (или) output-параметров>
...
CLOSE ProcedureName;

Если есть параметры типа output, то их выходные значения возвращается как дополнительный resultset из одной строки, содержащий выходные значения переменных в порядке описания. Если при описании процедуры указана Return_Var (это указывает, что SP возвращает код завершения), в resultset с output переменными первой колонкой включается код возврата. Resultset не возвращается, если были ошибки (в т.ч. raiserror) или print.

Вызов через RPC

Как описать

Необходимо создать свой класс  наследованием от transaction. В Local External Functions этого объекта описать хранимые процедуры как external-функции. Описать используемые transaction objects приложения как объекты этого класса (тип sqlca можно изменить в properties application object). Синтаксис описаний:

FUNCTION rtndatatype functionname ( { { REF } datatype1 arg1,..., { REF } datatypen argn } ) RPCFUNC { ALIAS FOR "spname" }
    
SUBROUTINE functionname ( { { REF } datatype1 arg1 , ..., { REF } datatypen argn } ) RPCFUNC { ALIAS FOR " spname" }

Этот синтаксис действует только в local external functions для объектов transaction. Если sp описана в программе, но не создана в базе при запуске будет ошибка:

sqlcode=-1
sqldbcode=2812
sqlerrtext=Stored procedure 'spname' not found.

Как запустить

long ll_rc

ll_rc=sqlca.functionname(params...)

Как узнать, что была ошибка

Если при выполнении sp были ошибки (в том числе raiserror, независимо от уровня ошибки, или print), код возврата и значения параметров типа output в script не возращаются (bug pb?).

При ошибках:

sqlca.sqlcode=-1
sqlca.sqldbcode=код ошибки sql server
sqlca.sqlerrtext=текст сообщения sql server

Если ошибок было несколько, в sqlca информация о первой ошибке.

Как получить результат

Если sp описана как function, возвращается код завершения sp (оператор return xx в sp)

Работа с параметрами типа output прозрачная, результат возвращается в переменные.

Resultset не обработать.

Примеры:

Пример 1. Процедура, возвращающая параметры

Процедура:

create proc sp_test1 (@al_1 int,@al_2 int OUTPUT,@as_1 varchar(20) OUTPUT)
as
	select @al_2=@al_1*4,@as_1=convert(varchar,@al_2)

Script:

long ll_1,ll_2
string ls_1

ll_1=111
ll_2=222
ls_1="abcdf"

declare sp_test1 procedure for sp_test1 @al_1=:ll_1 ,@al_2=:ll_2 output,@as_1=:ls_1 output;

execute sp_test1;
  
if sqlca.sqlcode<>0 then
  	//обработка ошибок типа: неверное имя процедуры, нет
	//прав на запуск процедуры,
    неверные имена параметров и.т.д.
end if

fetch sp_test1 into :ll_2,:ls_1;


//в ll_2 - 444, в ls_1 - "222"


close sp_test1;

Ушло на SQL сервер (Т.Е., что можно увидеть в SQL Trace):

DECLARE @P002 int, @P003 varchar(20)
SELECT @P002 = 222, @P003 = 'abcdf'
execute sp_test1 @ai = 111, @ai2 = @P002 output , @as_1 = @P003 output
SELECT @P002, @P003
go

Пример 2. Процедура, возвращающая 1 resultset

Таблица:

create table t (
	t_id int,
  t_data varchar(20)
)

Данные:

insert into t values(1,'row1')
insert into t values(2,'row2')

Процедура:

create proc sp_test2
as
	select * from t

Script:

long ll_1,ll_2
string ls_1
declare sp_test2 procedure for sp_test2;

execute sp_test2;

if sqlca.sqlcode<>0 then
    //обработка ошибок типа: неверное имя процедуры, нет
    //прав на запуск процедуры, неверные имена параметров и.т.д.
end if

do while true
	fetch sp_test2 into :ll_2,:ls_1;
  	if sqlca.sqlcode=100 then exit
  	
  	//на первой итерации в ll_2 - 1, в ls_1 - "row1"
	//на второй итерации в ll_2 - 2, в ls_1 - "row2"
  	//на третьей итерации в ll_2 - 2, в ls_1 - "row2", sqlca.sqlcode=100
  	
  	if sqlca.sqlcode<0 then
  		//обработка ошибок типа несоответствия типа и (или) количества
  		//host-переменных resultset-у
		...
  	end if
loop

close sp_test2;
  

Ушло на SQL-сервер:

  execute sp_test2
  go
  

Пример 3. Процедура, возвращающая несколько resultset, параметры и код возврата

Таблица/данные - как в предыдущем примере

Процедура:

create proc sp_test3 (@al_1 int,@al_2 int OUTPUT,@as_1 varchar(20) OUTPUT)
as
  	select @al_2=@al_1*4,@as_1=convert(varchar,@al_2)
  	select * from t
  	select t_id from t

Script:

long ll_1,ll_2,ll_rc
string ls_1
declare sp_test3 procedure for @ll_sp_rc=sp_test3 @al_1=:ll_1 ,@al_2=:ll_2 output,@as_1=:ls_1 output;
  
ll_1=111
ll_2=222
ls_1="abcdf"
  
execute sp_test3;
if sqlca.sqlcode<>0 then
	//обработка ошибок типа: неверное имя процедуры, нет
   //прав на запуск процедуры, неверные имена параметров и.т.д.
  	...
end if

do while true
	fetch sp_test3 into :ll_2,:ls_1;
  	//на первой итерации в ll_2 - 1, в ls_1 - "row1"
  	//на второй итерации в ll_2 - 2, в ls_1 - "row2"
  	//на третьей итерации в ll_2 - 2, в ls_1 - "row2", sqlca.sqlcode=100

  	if sqlca.sqlcode=100 then exit
  	if sqlca.sqlcode<0 then
  		//обработка ошибок типа несоответствия типа и (или) количества
  		//host-переменных resultset-у
  		...
	end if
loop

do while true
  	fetch sp_test3 into :ll_2;
  	//на первой итерации в ll_2 - 1
  	//на второй итерации в ll_2 - 2
  	//на третьей итерации в ll_2 - 2
  	sqlca.sqlcode=100
  	if sqlca.sqlcode=100 then exit
  	if sqlca.sqlcode<0 then
  		//обработка ошибок типа несоответствия типа и (или) количества
  		//host-переменных resultset-у
		...
  	end if
loop

fetch sp_test3 into :ll_rc,:ll_2,:ls_1;
	//в ll_rc - 99,ll_2 - 444, в ls_1 - "222"
	
close sp_test3;

Ушло на SQL-сервер:

DECLARE @ll_sp_rc int, @P003 int, @P004 varchar(20)
SELECT @P003 = 222, @P004 = 'abcdf'
execute @ll_sp_rc = sp_test3 @al_1 = 111, @al_2 = @P003 output , @as_1 = @P004 output
SELECT @ll_sp_rc, @P003, @P004
go

[English version]  [Главная страница]  [Книга жалоб]  [Зеркало на i72.by.ru]  [Зеркало на i72.narod.ru]
Другое на сайте: [Perl]  [PowerBuilder]  [Multiedit]  [IBSO]  [Clarion]  [Far]  [Юмор]  [Фотки]


$Date: 18/05/07 8:32 $