Получить NREC после вставки записи (ADO)

Программирование на Атлантисе (VIP, FCOM, ARD), FastReport

Модераторы: m0p3e, edward_K, Модераторы

ilshat
Местный житель
Сообщения: 222
Зарегистрирован: 04 июн 2008, 14:35
Откуда: Стерлитамак
Контактная информация:

Сообщение ilshat »

Это вы пока не наткнулись на такую таблицу :)
Den
Местный житель
Сообщения: 1844
Зарегистрирован: 29 мар 2005, 17:49
Откуда: Ярославская область ОАО "Часовой завод Чайка" г. Углич
Контактная информация:

Сообщение Den »

хм..специально выставлял в функции этой

set @needmax=1 перед блоком необходимости поиска max значение в конретной табле.
Vik
Местный житель
Сообщения: 370
Зарегистрирован: 28 сен 2006, 15:43
Откуда: Санкт-Петербург
Контактная информация:

Сообщение Vik »

даже когда needmax = 1? Интересно, почему тогда у меня ругается ( Вообще, не понимаю механизм формирования нового нрека
Den
Местный житель
Сообщения: 1844
Зарегистрирован: 29 мар 2005, 17:49
Откуда: Ярославская область ОАО "Часовой завод Чайка" г. Углич
Контактная информация:

Сообщение Den »

Vik писал(а):Ну это все понятно) Я ее написал, все хорошо работало, пока однажды не получил @needmax = 1. Сразу же в этом месте :

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

.....
set @cparam=N'@max#F$NREC binary(8) OUT, @OriginOffice int'
  exec sp_executesql @csql, @cparam, @max#F$NREC OUT, @OriginOffice
  if @@error<>0 
......
ругань на то, что exec sp_executesql не может быть выполнен внутри функции..
Все же удалось реализовать этот кусок с помощью расширенной хранимки ради интереса и не только ...) Правда мне филиальность побоку, но не думаю что сереьзная проблема будет ее приделать. Теперь можно юзать все же конструкцию
Insert into table (f$nrec,...) values (function,....), получая приращенный нрек
ilshat
Местный житель
Сообщения: 222
Зарегистрирован: 04 июн 2008, 14:35
Откуда: Стерлитамак
Контактная информация:

Сообщение ilshat »

Выложите пожалуйста код :)
Den
Местный житель
Сообщения: 1844
Зарегистрирован: 29 мар 2005, 17:49
Откуда: Ярославская область ОАО "Часовой завод Чайка" г. Углич
Контактная информация:

Сообщение Den »

Сделано под 2000скуль(sp4, авторизация у меня смешанная) , так что не знаю как это дело будет фунциклировать под 2005. Реализовано через интерфейс ODS, который вроде как обещано, не будет поддерживаться вскоре ))

library Project1;

uses
StrUtils,
SysUtils,
Classes,
srv in 'srv.pas',
sqldb_h in 'sqldb_h.pas',
sqlfront_h in 'sqlfront_h.pas';

//Для совместимости
Function __GetXpVersion():Longint; cdecl;
begin
Result:= ODS_VERSION;
end;

procedure printUsage(srvproc: pSRV_PROC; errMassage:AnsiString=''); forward;
function msg_handler(dbproc:PDBPROCESS; msgno:DBINT; msgstate:INT; severity: INT;
const msgtext:LPSTR; const srvname:PAnsiChar = nil; const procname:PAnsiChar = nil;
line:DBUSMALLINT = 0):RETCODE; cdecl; forward;

const
MAX_BINDTOKEN=255;
XP_ERROR = SRV_MAXERROR+1;

{В этой функции коннектимся к экземпляру скуля и выгребаем
max значение нрек-а из заданной таблицы в качестве входного параметра функции
}
// GetNrecSomeTable
function GetNrecSomeTable(srvproc: pSRV_PROC): RETCODE; cdecl;
var
msgError:AnsiString;
bType: byte;
fNull: BOOL;
cbMaxLen, cbActualLen: ULONG;
TableNameLen:integer;
TableName, myKey, serverName:array[0..255] of char;
i:integer;
//для подключения к базе
loginrec:PLOGINREC;
bImpersonated:LongBool;
dbproc:PDBPROCESS;
//
szBindToken:array[0..MAX_BINDTOKEN] of char;
bufLength:integer;
bufQuery:AnsiString;
rc:RETCODE;
nCol, nCols:integer;
valBuffer, pHost, pServer:Pchar;

begin
//проверка правильности (в т.ч. порядка и типов) переданных параметров
Result:=0;

FillChar(TableName, sizeOf(TableName), 0);

if srv_rpcparams(srvproc) = 3 then // Check if input parameters are present...
begin
cbMaxLen:=sizeof(myKey);
srv_paraminfo(srvproc, 1, @bType, // Let's use 1st input parameter!
@cbMaxLen, @cbActualLen, // NOTE: We assume here what only 2 parameters
@TableName[0], @fNull); //of type String can be passed!!!

cbMaxLen:=sizeof(myKey);
FillChar(myKey, sizeof(myKey), 0);
srv_paraminfo(srvproc, 2, @bType,
@cbMaxLen, @cbActualLen,
@myKey[0], @fNull);

bufQuery:=DupeString(#0,8000);
cbMaxLen:=Length(bufQuery)-1;
srv_paraminfo(srvproc, 3, @bType,
@cbMaxLen, @cbActualLen,
pchar(bufQuery), @fNull);
end
else
begin
//НЕПРАВИЛЬНЫЕ параметры
Result:=1;
exit;
end;

srv_paramsetoutput(srvproc, 2, nil, 0, System.True);

//подключение ОБРАТНО к базе данных
// Get a loginrec and register our error and message handlers.
loginrec := dblogin();
if loginrec=nil then begin
bufQuery:='DBLOGIN - is failed';
srv_paramsetoutput(srvproc, 3, pchar(bufQuery), Length(bufQuery), System.False);
bufQuery:='';
Result:=1;
exit;
end;
// dbprocerrhandle(loginrec, (DBERRHANDLE_PROC) err_handler);
// dbprocmsghandle(loginrec, msg_handler);
(* dbprocerrhandle(loginrec, nil);
dbprocmsghandle(loginrec, nil);
*)

// Check for integrated security.
if (StrComp(srv_pfield(srvproc, SRV_LSECURE, nil), 'TRUE') = 0) then
begin
// Client has accessed using some form of integrated security
// Impersonate client and set DBSETLSECURE flag
bImpersonated := (srv_impersonate_client(srvproc) <> 0);
DBSETLSECURE(loginrec);
end
else
begin
// Set the user name, password, and application name for the remote
DBSETLUSER( loginrec, srv_pfield(srvproc, SRV_USER, nil) );
DBSETLPWD( loginrec, srv_pfield(srvproc, SRV_PWD, nil) );
end;

DBSETLAPP (loginrec, 'Project2.GetNrecSomeTable');
srv_rpcdb(srvproc, nil);

(*
i:=0;
valBuffer:=srv_pfield(srvproc, SRV_SPID, @i);
valBuffer:=srv_pfield(srvproc, SRV_NETSPID, @i);
valBuffer:=srv_pfield(srvproc, SRV_TYPE, @i);
valBuffer:=srv_pfield(srvproc, SRV_STATUS, @i);
valBuffer:=srv_pfield(srvproc, SRV_RMTSERVER, @i);
valBuffer:=srv_pfield(srvproc, SRV_HOST, @i);
valBuffer:=srv_pfield(srvproc, SRV_USER, @i);
valBuffer:=srv_pfield(srvproc, SRV_PWD, @i);
valBuffer:=srv_pfield(srvproc, SRV_CPID, @i);
valBuffer:=srv_pfield(srvproc, SRV_APPLNAME, @i);
valBuffer:=srv_pfield(srvproc, SRV_TDS, @i);
valBuffer:=srv_pfield(srvproc, SRV_CLIB, @i);
valBuffer:=srv_pfield(srvproc, SRV_LIBVERS, @i);
valBuffer:=srv_pfield(srvproc, SRV_ROWSENT, @i);
valBuffer:=srv_pfield(srvproc, SRV_BCPFLAG, @i);
valBuffer:=srv_pfield(srvproc, SRV_NATLANG, @i);
valBuffer:=srv_pfield(srvproc, SRV_PIPEHANDLE, @i);
valBuffer:=srv_pfield(srvproc, SRV_NETWORK_MODULE, @i);
valBuffer:=srv_pfield(srvproc, SRV_NETWORK_VERSION, @i);
valBuffer:=srv_pfield(srvproc, SRV_NETWORK_CONNECTION, @i);
valBuffer:=srv_pfield(srvproc, SRV_LSECURE, @i);
valBuffer:=srv_pfield(srvproc, SRV_SAXP, @i);
valBuffer:=srv_pfield(srvproc, SRV_UNICODE_USER, @i);
valBuffer:=srv_pfield(srvproc, SRV_UNICODE_PWD, @i);
valBuffer:=srv_pfield(srvproc, SRV_SPROC_CODEPAGE, @i);
valBuffer:=srv_pfield(srvproc, SRV_MSGLCID, @i);
valBuffer:=srv_pfield(srvproc, SRV_INSTANCENAME, @i);
valBuffer:=srv_pfield(srvproc, SRV_HASHPWD, @i);
*)

valBuffer:=srv_pfield(srvproc, SRV_RMTSERVER, nil);
srv_paramsetoutput(srvproc, 3, valBuffer, StrLen(valBuffer), System.False);

// Since the servername parameter is set to NULL, the connection will be
// opened to the local DBMS.
dbproc := dbopen(loginrec, valBuffer);
if(dbproc=nil)then begin
StrCat(valBuffer, ' - invalid DBOPEN');
srv_paramsetoutput(srvproc, 3, valBuffer, StrLen(valBuffer), System.False);
srv_senddone (srvproc, SRV_DONE_MORE, 0, 0);
dbfreelogin(loginrec);
Result:=1;
exit;
end

// dbsetuserdata (dbproc, pointer(pSrvProc));

FillChar(szBindToken, sizeof(szBindToken), 0);
// for i:=0 to MAX_BINDTOKEN do szBindToken:=#0;

bufQuery:='Select max(f$nrec) from '+StrPas(@TableName[0]);
// Bind to the clients connection for shared transaction space.
// srv_getbindtoken (srvproc, szBindToken);

// Execute the SELECT * FROM table.
dbcmd(dbproc, PAnsiChar(bufQuery));
rc := dbsqlexec(dbproc);
if rc=FAIL then begin
valBuffer:='DBSQLEXEC - is failed';
srv_paramsetoutput(srvproc, 3, valBuffer, StrLen(valBuffer), System.False);
srv_senddone (srvproc, SRV_DONE_MORE, 0, 0);
dbclose( dbproc );
dbfreelogin(loginrec);
Result:=1;
exit;
end;

bufQuery:='';

//получение результата запроса
//bufQuery:='нет данных';
//srv_paramsetoutput(srvproc, 3, pchar(bufQuery), Length(bufQuery), System.False);
Repeat
rc := dbresults (dbproc);
case rc of
FAIL:begin //какая-то ошибка, ХЗ
bufQuery:='dbresults - FAIL';
srv_paramsetoutput(srvproc, 3, pchar(bufQuery), Length(bufQuery), System.False);
bufQuery:='';
Result:=1;
break;
end;
SUCCEED:begin
end;
NO_MORE_RESULTS:begin //возможно, неверное имя таблицы
bufQuery:='dbresults - NO_MORE_RESULTS';
srv_paramsetoutput(srvproc, 3, pchar(bufQuery), Length(bufQuery), System.False);
bufQuery:='';
Result:=1;
break;
end;
NO_MORE_RPC_RESULTS:begin
bufQuery:='dbresults - NO_MORE_RPC_RESULTS';
srv_paramsetoutput(srvproc, 3, pchar(bufQuery), Length(bufQuery), System.False);
bufQuery:='';
Result:=1;
break;
end;
end;

// How many data columns are in the row?
nCols := dbnumcols (dbproc);
nCol:=1;

bufQuery:=format('cols=%d coltype=%d collen=%d '
, [nCols, DBINT(dbcoltype(dbproc,nCol)), dbcollen(dbproc, nCol)]);
srv_paramsetoutput(srvproc, 3, pchar(bufQuery), Length(bufQuery), System.false);

if (SRV_TDS_BINARY = DBINT(dbcoltype(dbproc,nCol)))
and (8=dbcollen(dbproc, nCol)) then
begin
srv_paramsetoutput(srvproc, 2, nil, 0, System.True);
while (dbnextrow(dbproc) <> NO_MORE_ROWS) do begin
BufLength:=dbdatlen (dbproc, nCol);
valBuffer:=pointer(dbdata(dbproc, 1));

srv_paramsetoutput(srvproc, 2, valBuffer, BufLength, System.False);
valBuffer:=nil;
break;
end;
end else begin
bufQuery:='F$NREC - non BINARY( 8 )';
srv_paramsetoutput(srvproc, 3, pchar(bufQuery), Length(bufQuery), System.False);
end;

Until (0=0);

srv_senddone (srvproc, SRV_DONE_MORE, 0, 0);

// Close the connection to SQL Server.
dbclose( dbproc );
dbfreelogin(loginrec);

end;

(*int err_handler(dbproc, severity, dberr, oserr, dberrstr, oserrstr)
DBPROCESS *dbproc;
int severity;
int dberr;
int oserr;
char *dberrstr;
char *oserrstr;
{
SRV_PROC* srvproc = ( SRV_PROC* ) dbgetuserdata(dbproc);

if (srvproc == NULL)
return 0;

srv_sendmsg(srvproc, SRV_MSG_ERROR, (DBINT) GETTABLE_MSG,
(DBTINYINT)severity, (DBTINYINT)0, NULL, 0, 0, dberrstr,
SRV_NULLTERM);

if ((dbproc == NULL) || (DBDEAD(dbproc)))
return(INT_EXIT);

return(INT_CANCEL);
}
*)

function msg_handler;//(dbproc:PDBPROCESS; msgno:DBINT; msgstate:INT; severity: INT; const msgtext:LPSTR):RETCODE; cdecl;
var
srvproc:pSRV_PROC;
begin
Result:=0;
srvproc := pSRV_PROC(dbgetuserdata(dbproc));
if (srvproc = nil) then exit;

if (severity < 10) then begin
// If informational message....
srv_sendmsg(srvproc, SRV_MSG_INFO, msgno, DBTINYINT(severity),
DBTINYINT(msgstate), nil, 0, 0, msgtext, SRV_NULLTERM);
exit;
end;

// Trap login fail message
if (msgno = REMOTE_FAIL) then begin
// Send a message to the client that
// the remote connection failed.
srv_sendmsg(srvproc, SRV_MSG_ERROR, DBINT(msgno), DBTINYINT(severity),
DBTINYINT(msgstate), nil, 0, 0,
'Login to remote DBMS failed (dbopen).', SRV_NULLTERM);
exit;
end;

// Must be an error message....
srv_sendmsg(srvproc, SRV_MSG_ERROR, msgno, DBTINYINT(severity),
DBTINYINT(msgstate), nil, 0, 0, msgtext, SRV_NULLTERM);
end;

// send XP usage info to client
Procedure printUsage;
begin
// usage: exec xp_hello <@param1 output>
// Example:
// declare @txt varchar(33)
// exec xp_hello @txt OUTPUT
(* if(errMassage<>'')and(srv_rpcparams(srvproc)>=3)and(srv_paraminfo(srvproc, 3, @pbType, 8000, cbActualLen, ))then
begin
srv_paramsetoutput(srvproc, 3, msgError, Length(bufQuery), System.False);
end;
srv_sendmsg(pSrvProc, SRV_MSG_ERROR, XP_ERROR, SRV_INFO, 1,
NULL, 0, 0,
'Usage: exec @rc=GetNrecSomeTable <@TableName varchar(100)>, <@retMaxNrec binary( 8 ) OUTPUT>' +
'[, <@ErrorMessage varchar(8000) OUTPUT>]',
SRV_NULLTERM);
srv_senddone(pSrvProc, (SRV_DONE_ERROR | SRV_DONE_MORE), 0, 0);
*)
end;

exports
__GetXpVersion,
// ProjecT2,
GetNrecSomeTable;
begin
end.



И еще отдавать в качестве параметра приходиться в виде dbname.dbo.имя таблицы. Так и не удалось победить пока шоб он все время автоматом выгребал нужное значение из конкретной таблицы БД, из которой собственно дерагается функция (огребаешь в этом случае почему то по поводу 'DBSQLEXEC - is failed' :???: ):

declare @max#F$NREC binary( 8 ), @table_name varchar(200), @retCode int, @rc int, @msg varchar(256)
select @table_name = 'test.dbo.t$katorg'
exec @rc = master..GetNrecSomeTable @table_name, @max#F$NREC OUTPUT, @msg OUTPUT
select @rc, @table_name, @max#F$NREC, @msg
SNET
Посетитель
Сообщения: 32
Зарегистрирован: 06 июл 2009, 19:01

Сообщение SNET »

Тоже подошли к необходимости работы напрямую с MS SQL при миграции данных. Попробовали использовать ХП уважаемого WiRuc. Все прекрасно работае, однако непонятно что за функция up_sys_raisefatalerror вызывается для обработки ошибок. У нас используется "Галактика" версии 8.10 и подобной функции нет.
WiRuc
Местный житель
Сообщения: 414
Зарегистрирован: 29 мар 2005, 17:49
Откуда: Воронеж

Сообщение WiRuc »

Самописная. Можете просто заменить ее на вызов функции RAISERROR
SNET
Посетитель
Сообщения: 32
Зарегистрирован: 06 июл 2009, 19:01

Сообщение SNET »

WiRuc
Спасибо, с RAISERROR разобрался, все получилось. А еще какой функционал несла в себе up_sys_raiseinvalidcall? :-?
Friendlyman
Постоянный гость
Сообщения: 74
Зарегистрирован: 23 июн 2007, 23:07
Откуда: ТопСофт, Минск

Re:

Сообщение Friendlyman »

Vik писал(а):... Дублирование уникального ключа таблицы и так далее) Насчет вьюхи - попробую! А не подскажете, почему, когда делаю инсерт без присваивания нрека одной новой записи, запись вставляется, то есть триггер отрабатывает, а когда несколько - дублирование уникального ключа? Имею ввиду из MSSQL вставка производится.
Ветка достаточно старая. Может уже найдены какие-то более простые и оптимальные методы групповой вставки записей с БД Галактики сторонними средствами (в частности решение проблемы "Дублирование уникального ключа")?
Friendlyman
Постоянный гость
Сообщения: 74
Зарегистрирован: 23 июн 2007, 23:07
Откуда: ТопСофт, Минск

Re: Re:

Сообщение Friendlyman »

Friendlyman писал(а):
Vik писал(а):... Дублирование уникального ключа таблицы и так далее) Насчет вьюхи - попробую! А не подскажете, почему, когда делаю инсерт без присваивания нрека одной новой записи, запись вставляется, то есть триггер отрабатывает, а когда несколько - дублирование уникального ключа? Имею ввиду из MSSQL вставка производится.
Ветка достаточно старая. Может уже найдены какие-то более простые и оптимальные методы групповой вставки записей с БД Галактики сторонними средствами (в частности решение проблемы "Дублирование уникального ключа")?

Рассказали страшную тайну, что избежать дублирования ключа можно, если вставлять не в таблицу t$..., а во вьюху v$...

РАБОТАЕТ!!!


Надеюсь, кому-то еще это поможет!
Friendlyman
Постоянный гость
Сообщения: 74
Зарегистрирован: 23 июн 2007, 23:07
Откуда: ТопСофт, Минск

Re: Получить NREC после вставки записи (ADO)

Сообщение Friendlyman »

Опять немножко оффтопик, но краем-боком касалось все таки темы обсуждения.
Чтобы не выкидывало ошибок при групповом update нужно его таким образом делать.

Create table #xx$locks (TableNRec binary(8));

здесь кусок на update

drop Table #xx$locks;
Den
Местный житель
Сообщения: 1844
Зарегистрирован: 29 мар 2005, 17:49
Откуда: Ярославская область ОАО "Часовой завод Чайка" г. Углич
Контактная информация:

Re: Re:

Сообщение Den »

Friendlyman писал(а): Ветка достаточно старая. Может уже найдены какие-то более простые и оптимальные методы групповой вставки записей с БД Галактики сторонними средствами (в частности решение проблемы "Дублирование уникального ключа")?
интересует намного быстрее происходит групповая вставка ?(должна стопц быть быстрее)) ) тестили ради интереса на приличных объемах данных ?
Friendlyman
Постоянный гость
Сообщения: 74
Зарегистрирован: 23 июн 2007, 23:07
Откуда: ТопСофт, Минск

Re: Re:

Сообщение Friendlyman »

Den писал(а):интересует намного быстрее происходит групповая вставка ?(должна стопц быть быстрее)) ) тестили ради интереса на приличных объемах данных ?
Friendlyman писал(а):чтобы избежать дублирования ключа можно, если вставлять не в таблицу t$..., а во вьюху v$...
А в этом варианте получается групповая вставка? Или все равно в конечном итоге выливается в множество единичных вставок?
Den
Местный житель
Сообщения: 1844
Зарегистрирован: 29 мар 2005, 17:49
Откуда: Ярославская область ОАО "Часовой завод Чайка" г. Углич
Контактная информация:

Re: Получить NREC после вставки записи (ADO)

Сообщение Den »

Вы же сами озадачились проблемой и написали что, мол :
"
Рассказали страшную тайну, что избежать дублирования ключа можно, если вставлять не в таблицу t$..., а во вьюху v$...

РАБОТАЕТ!!!"

раз работает..значит пробовали ? )
Я групповую не пинал...
Ответить