I'm calling an Oracle array bound stored procedure from C#
I can add output parameters of type NUMBER, and the return values are correctly populated.
If I try to use output values of type VARCHAR2, I'm getting "OracleParameter.ArrayBindSize is invalid" Exception.
This works:
CREATE OR REPLACE PROCEDURE CLOUDDBA.INSERTTEST (
P_VALUE NUMBER,
P_CODE OUT NUMBER--,
-- P_MESSAGE OUT VARCHAR
)
AS
BEGIN
P_CODE := P_Value ;
--P_MESSAGE := '';
IF P_Value = 1 THEN
P_CODE := 1;
--P_MESSAGE := 'ONE';
END IF;
END INSERTTEST;
C# code:
var values = new int[] { 1, 2, 3 };
ocmd.CommandText = "INSERTTEST";
ocmd.CommandType = CommandType;
ocmd.BindByName = true;
ocmd.ArrayBindCount = 3;
ocmd.Transaction = transaction;
ocmd.Parameters.Clear();
var pValue = new OracleParameter("P_VALUE", OracleDbType.Int32, 255, ParameterDirection.Output) { Value = values };
ocmd.Parameters.Add(pValue);
var pVCode= new OracleParameter("P_CODE", OracleDbType.Int32, 255, ParameterDirection.Output);
ocmd.Parameters.Add(pVCode);
This blows up:
CREATE OR REPLACE PROCEDURE CLOUDDBA.INSERTTEST (
P_VALUE NUMBER,
P_CODE OUT NUMBER,
P_MESSAGE OUT VARCHAR
)
AS
BEGIN
P_CODE := P_Value ;
P_MESSAGE := '';
IF P_Value = 1 THEN
P_CODE := 1;
P_MESSAGE := 'ONE';
END IF;
END INSERTTEST;
C# code:
var values = new int[] { 1, 2, 3 };
ocmd.CommandText = "INSERTTEST";
ocmd.CommandType = CommandType;
ocmd.BindByName = true;
ocmd.ArrayBindCount = 3;
ocmd.Transaction = transaction;
ocmd.Parameters.Clear();
var pValue = new OracleParameter("P_VALUE", OracleDbType.Int32, 255, ParameterDirection.Output) { Value = values };
ocmd.Parameters.Add(pValue);
var pVCode= new OracleParameter("P_CODE", OracleDbType.Int32, 255, ParameterDirection.Output);
ocmd.Parameters.Add(pVCode);
var pVMessage= new OracleParameter("P_MESSAGE", OracleDbType.Varchar2, 255, ParameterDirection.Output);
ocmd.Parameters.Add(pVMessage);
Found the solution.
Use SQL Server.
Need to specify ArrayBindSize.
replace
var pVMessage = new OracleParameter("P_MESSAGE", OracleDbType.Varchar2, 255, ParameterDirection.Output);
with
var pVMessage = new OracleParameter("P_MESSAGE", OracleDbType.Varchar2, 255, ParameterDirection.Output) {ArrayBindSize = new int[]{255, 255, 255}};
Related
I have an xml file stored in the DB. this xml file is converted to a zipped byte[] and then stored in the db as shown below:
ByteArrayOutputStream byteOut = null;
ZipOutputStream out = null;
try {
byteOut = new ByteArrayOutputStream();
out = new ZipOutputStream(byteOut);
out.setLevel(level);
ZipInput entry = new ZipStringInput("string", xmlString));
out.putNextEntry(getZipEntry(encrypt, entry.getEntryName()));
InputStream in = entry.getInputStream();
byte[] buffer = new byte[BUFFER];
for (int length; (length = in.read(buffer)) != -1; ) {
out.write(buffer, 0, length);
}
out.finish();
saveToDB(byteOut.toByteArray()
In java I can easily fetch it like shown below (simplified wihtout catch, close etc.,):
byte[] xmlBytes = (byte[])blob;
ByteArrayOutputStream out = new ByteArrayOutputStream();
try (ByteArrayInputStream byteIn = new ByteArrayInputStream(xmlBytes );) {
try (ZipInputStream zipIn = new ZipInputStream(byteIn);) {
for (ZipEntry entry; (entry = zipIn.getNextEntry()) != null;) {
byte[] buffer = new byte[32768];
for (int length; (length = zipIn.read(buffer, 0, buffer.length)) != -1;) {
out.write(buffer, 0, length);
}
}
return out.toString("UTF-8"));
}
Oracle DB: Now I have to task to do the same in a SQL stored procedure. how do I do it. I have tried combinations of lz_uncompress, lob.substr etc., I can see the bytes, but not sure how to convert it to the XML file.
CREATE OR REPLACE PROCEDURE print_clob AS
v_clob CLOB;
v_varchar VARCHAR2(32767);
v_start PLS_INTEGER := 1;
v_buffer PLS_INTEGER := 32767;
blob_in BLOB;
x XMLTYPE;
BEGIN
dbms_lob.createtemporary(v_clob, true);
FOR i IN (
SELECT
blobdata AS blob_in
FROM
myTable
WHERE
id = 123
) LOOP
FOR j IN 1..ceil(dbms_lob.getlength(i.blob_in) / v_buffer) LOOP
v_varchar := dbms_lob.substr(i.blob_in, v_buffer, v_start);
dbms_lob.writeappend(v_clob, length(v_varchar), v_varchar);
v_start := v_start + v_buffer;
END LOOP;
dbms_output.put_line(v_clob ); prints some binary stirng looking like '504B0304140008000800E0843E4200000000000000000.....'
-- dbms_output.put_line(UTL_RAW.CAST_TO_NVARCHAR2(v_clob )); -> throws error
-- dbms_output.put_line(utl_compress.lz_uncompress(v_clob )); -> throws error
--x := xmltype.createxml(v_clob); -> Throws error that the input it not an XML <, but some randoms tring
-- dbms_output.put_line(x.getclobval());
END LOOP;
END;
You are trying to substring a BLOB and stick it into a CLOB without any conversion. If the BLOB is compressed, you'll need to uncompress it first with utl_compress.lz_uncompress. Then once uncompressed, you need to convert it to a CLOB using dbms_lob.converttoclob.
Below procedure to get the value from the metadata table and pass
its value into another procedure.
create or replace procedure get_results()
RETURNS VARIANT
LANGUAGE javascript
as
$$
var return_value = [];
var SQL_STMT = "select * from metad" ;
var stmt = snowflake.createStatement(
{
sqlText: SQL_STMT
}
);
/* Creates result set */
var res = stmt.execute();
while (res.next()) {
//return_value += "\n";
var srctbl=res.getColumnValue('SRC_TBL');
var tgttbl=res.getColumnValue('TGT_TBL');
var prc_stmt = 'CALL sync_table('+ srctbl + ',' + tgttbl+')';
var pstmt = snowflake.createStatement({sqlText: prc_stmt});
/* Creates result set */
var spResult = pstmt.execute();
if(spResult !='Success'){
return_value=spResult;
break;
}
}
return return_value;
$$
;
CALL get_results()
Give the error message:
Execution error in store procedure GET_RESULTS: SQL compilation error: error line 1 at position 16 invalid indetifier 'STBL1' At Statement.execute, line 18 position 26
I am going to guess that both the values you are passing to the Stored Procedure sync_table are strings, and you sql command prc_stmt will look like:
CALL sync_table( soruce_table_name, target_table_name );
but that is not valid SQL, it should be
CALL sync_table( 'soruce_table_name', 'target_table_name' );
which means you should add some quotes, given this is javascript the string can use double quotes and allow simple insertion of the needed single quotes:
create or replace procedure get_results()
RETURNS VARIANT
LANGUAGE javascript
as
$$
var return_value = [];
var SQL_STMT = "select * from metad" ;
var stmt = snowflake.createStatement(
{
sqlText: SQL_STMT
}
);
/* Creates result set */
var res = stmt.execute();
while (res.next()) {
//return_value += "\n";
var srctbl=res.getColumnValue('SRC_TBL');
var tgttbl=res.getColumnValue('TGT_TBL');
var prc_stmt = "CALL sync_table('"+ srctbl + "','" + tgttbl+"')";
var pstmt = snowflake.createStatement({sqlText: prc_stmt});
/* Creates result set */
var spResult = pstmt.execute();
if(spResult !='Success'){
return_value=spResult;
break;
}
}
return return_value;
$$
;
I am trying to verify server certificate. I use Indy 10 and OpenSSL. I specify Root RootCertFile and VerifyDepth to MaxInt. OnVerifyPeer works fine - AOk is true. I wonder how to load certificates from Windows Trusted Root Certification Authorities. There is my stripped code of a client:
uses
{Delphi}
IdSSLOpenSSL
, IdHTTP
, IdHeaderList
, System.Classes
{Project}
;
type
TUnicodeHTTPPoster = class
strict private
FidHTTP: TIdHTTP;
FLastError: string;
FCertPassword: string;
procedure OnGetPassword(var Password: string);
function OnVerifySSLPeer(Certificate: TIdX509;AOk: Boolean; ADepth, AError: Integer): Boolean;
public
constructor Create(const ASSLVersion: TIdSSLVersion; const AAccept: string = 'application/xml';
const ACharSet: string = 'utf-8'; const ACertFile: string = ''; const AKeyFile: string = '';
const ACertPassword: string = ''); reintroduce;
destructor Destroy; override;
function Post(const ACustomHeaders: TIdHeaderList; const ARawBody: TStream;
const AURL: string; out AResponse: string): integer;
end;
implementation
uses
{Delphi}
System.SysUtils
, IdURI
, IdGlobal
{Project}
;
constructor TUnicodeHTTPPoster.Create(const ASSLVersion: TIdSSLVersion; const AAccept: string = 'application/xml';
const ACharSet: string = 'utf-8'; const ACertFile: string = ''; const AKeyFile: string = '';
const ACertPassword: string = '');
var
_IdSSLIOHandlerSocketOpenSSL: TIdSSLIOHandlerSocketOpenSSL;
begin
inherited Create;
FidHTTP := TIdHTTP.Create(nil);
FidHTTP.Request.Accept := 'application/xml';
if AAccept <> '' then
FidHTTP.Request.Accept := AAccept;
FidHTTP.Request.Charset := 'utf-8';
if ACharSet <> '' then
FidHTTP.Request.Charset := ACharSet;
_IdSSLIOHandlerSocketOpenSSL := TIdSSLIOHandlerSocketOpenSSL.Create(FidHTTP);
if FileExists(ACertFile) then
_IdSSLIOHandlerSocketOpenSSL.SSLOptions.CertFile := ACertFile;
if FileExists(AKeyFile) then
_IdSSLIOHandlerSocketOpenSSL.SSLOptions.KeyFile := AKeyFile;
FCertPassword := ACertPassword;
FidHTTP.Request.BasicAuthentication := False;
_IdSSLIOHandlerSocketOpenSSL.SSLOptions.Mode := sslmClient;
_IdSSLIOHandlerSocketOpenSSL.SSLOptions.Method := ASSLVersion;
_IdSSLIOHandlerSocketOpenSSL.OnGetPassword := OnGetPassword;
_IdSSLIOHandlerSocketOpenSSL.SSLOptions.VerifyMode := [sslvrfPeer];
_IdSSLIOHandlerSocketOpenSSL.SSLOptions.VerifyDepth := MaxInt;
_IdSSLIOHandlerSocketOpenSSL.OnVerifyPeer := OnVerifySSLPeer;
_IdSSLIOHandlerSocketOpenSSL.SSLOptions.RootCertFile := 'C:\Users\ekolesnikovics\Desktop\Projects\nDentity\ndentify\Build\dc_ofisas.nsoft.lt.pem';
FidHTTP.IOHandler := _IdSSLIOHandlerSocketOpenSSL;
end;
function TUnicodeHTTPPoster.OnVerifySSLPeer(Certificate: TIdX509;AOk: Boolean; ADepth, AError: Integer): Boolean;
begin
Result := AOk;
end;
procedure TUnicodeHTTPPoster.OnGetPassword(var Password: string);
begin
Password := FCertPassword;
end;
function TUnicodeHTTPPoster.Post(const ACustomHeaders: TIdHeaderList; const ARawBody: TStream;
const AURL: string; out AResponse: string): integer;
var
_URL: string;
_ResponseStream: TStringStream;
begin
Result := 500;
FLastError := '';
try
if Trim(AURL) = '' then
raise EArgumentException.Create('URL is not provided.');
_URL := TIdURI.URLEncode(AURL, IndyTextEncoding_UTF8);
_ResponseStream := TStringStream.Create('', TEncoding.UTF8);
try
if Assigned(FidHTTP.Request.CustomHeaders) then
FidHTTP.Request.CustomHeaders.Clear;
if Assigned(ACustomHeaders) then
FidHTTP.Request.CustomHeaders := ACustomHeaders;
FidHTTP.Post(_URL, ARawBody, _ResponseStream);
_ResponseStream.Position := 0;
AResponse := _ResponseStream.DataString;
finally
FreeAndNil(_ResponseStream);
end;
Result := 200;
except
on E: EIdHTTPProtocolException do
begin
Result := E.ErrorCode;
FLastError := E.ErrorMessage;
FidHTTP.Disconnect;
end;
on E: Exception do
begin
FLastError := E.Message;
FidHTTP.Disconnect;
end;
end;
end;
I ended up using free https://github.com/magicxor/WinCryptographyAPIs
procedure TUnicodeHTTPPoster.ExportWindowsCertificateStoreToFile(const ACertFile: string);
var
_hStore: HCERTSTORE;
_CertContext: PCertContext;
_pchString: Cardinal;
_szString: string;
_CertList: TStringList;
begin
_hStore := CertOpenSystemStore(0, PChar('ROOT'));
if (_hStore = nil) then
RaiseLastOSError;
_CertList := TStringList.Create;
try
_CertContext := CertEnumCertificatesInStore(_hStore, nil);
if (_CertContext = nil) then
RaiseLastOSError;
while _CertContext <> nil do
begin
_pchString := 0;
if not CryptBinaryToString(_CertContext.pbCertEncoded,
_CertContext.cbCertEncoded, CRYPT_STRING_BASE64, nil, _pchString) then
RaiseLastOSError;
SetLength(_szString, 0);
SetLength(_szString, _pchString - 1);
if not CryptBinaryToString(_CertContext.pbCertEncoded,
_CertContext.cbCertEncoded, CRYPT_STRING_BASE64, PWideChar(_szString),
_pchString) then
RaiseLastOSError;
_CertList.Add('-----BEGIN CERTIFICATE-----');
_CertList.Add(Trim(StrPas(PWideChar(_szString))));
_CertList.Add('-----END CERTIFICATE-----');
_CertContext := CertEnumCertificatesInStore(_hStore, _CertContext);
end;
_CertList.SaveToFile(ACertFile);
finally
FreeAndNil(_CertList);
CertCloseStore(_hStore, 0);
end;
end;
_RootCertFileName := TPath.Combine(ExtractFilePath(ParamStr(0)), 'windows_cert.pem');
ExportWindowsCertificateStoreToFile(_RootCertFileName);
_IdSSLIOHandlerSocketOpenSSL.SSLOptions.RootCertFile := _RootCertFileName;
Here My C# Code
public DailyLossElements DeleteDailyLossElements(DailyLossElements _DOmodel)
{
decimal res = 0;
try
{
var DOC = new SqlParameter("#DOC", _DOmodel.Daily_Opt_Code);
var LossCategory = new SqlParameter("#LossCategory", _DOmodel.LossCategory);
var Loss_Sub_Category = new SqlParameter("#Loss_Sub_Category", _DOmodel.Loss_Sub_Category);
var Loss_Element = new SqlParameter("#Loss_Element", _DOmodel.Loss_Element);
//var Result = new SqlParameter("#Result", _DOmodel.Loss_Element);
OEEDBEntities oeedbEntities = new OEEDBEntities();
res = oeedbEntities.Database.SqlQuery<decimal>("DeleteDailyLossElements #DOC,#LossCategory,#Loss_Sub_Category,#Loss_Element", DOC, LossCategory, Loss_Sub_Category, Loss_Element).FirstOrDefault();
if (res != -999)
{
_DOmodel.IsActive = true;
DeductFromDailyInput(_DOmodel.Daily_Opt_Code,res, _DOmodel.LossCategory, _DOmodel.Loss_Sub_Category);
}
}
catch (Exception ex)
{
var excep = ex.Message;
}
return _DOmodel;
}
Here My Stored Procedure
ALTER PROCEDURE [dbo].[DeleteDailyLossElements]
(#DOC int,#LossCategory nvarchar(50),#Loss_Sub_Category nvarchar(50),#Loss_Element nvarchar(50),#Result Decimal = -999 Output)
AS
Begin
DECLARE #LossElement_value as decimal
if exists(SELECT LossElement_value from DailyLossElement where Daily_Opt_Code = #DOC AND LossCategory = #LossCategory AND Loss_Sub_Category = #Loss_Sub_Category AND Loss_Element = #Loss_Element )
Begin
SELECT #LossElement_value = LossElement_value from DailyLossElement where Daily_Opt_Code = #DOC AND LossCategory = #LossCategory AND Loss_Sub_Category = #Loss_Sub_Category AND Loss_Element = #Loss_Element
Delete from DailyLossElement where Daily_Opt_Code = #DOC AND LossCategory = #LossCategory AND Loss_Sub_Category = #Loss_Sub_Category AND Loss_Element = #Loss_Element
Set #Result= #LossElement_value;
End
else
Begin
Set #Result=-999;
end
SELECT #Result
End
When I Try to Retrieve Return Result from stored procedure And Check it in c# Code It doesn't Work.and also i want to Returned value to send another function named DeductFromDailyInput() as a parameter.
Change your code to the following:
public DailyLossElements DeleteDailyLossElements(DailyLossElements _DOmodel)
{
decimal res = 0;
try
{
var DOC = new SqlParameter("#DOC", _DOmodel.Daily_Opt_Code);
var LossCategory = new SqlParameter("#LossCategory", _DOmodel.LossCategory);
var Loss_Sub_Category = new SqlParameter("#Loss_Sub_Category", _DOmodel.Loss_Sub_Category);
var Loss_Element = new SqlParameter("#Loss_Element", _DOmodel.Loss_Element);
var Result = new SqlParameter("#Result", _DOmodel.Loss_Element) { Direction = ParameterDirection.Output };
OEEDBEntities oeedbEntities = new OEEDBEntities();
oeedbEntities.Database.SqlQuery<decimal>("DeleteDailyLossElements #DOC,#LossCategory,#Loss_Sub_Category,#Loss_Element", DOC, LossCategory, Loss_Sub_Category, Loss_Element, Result).FirstOrDefault();
res = decimal.Parse(Result.Value.ToString());
if (res != -999)
{
_DOmodel.IsActive = true;
DeductFromDailyInput(_DOmodel.Daily_Opt_Code,res, _DOmodel.LossCategory, _DOmodel.Loss_Sub_Category);
}
}
catch (Exception ex)
{
var excep = ex.Message;
}
return _DOmodel;
}
So, I've updated your code from the top of my mind. Probably I missed something but it should give you are pretty good idea where to go from here.
In your procedure you are setting the variable #Result as output parameter. So in code,you must have sql parameter #Result and used as ParameterDirection.Output
This is my function:
create function fn_Inventory(#qty int, #item_ID int)
returns int
as begin
declare #result int
set #result = (SELECT Quantity - #qty from Items where #item_ID = item_ID)
return #result
end
And I want to execute this function from my asp.net code; how to do it?
public int TotalCupom(int qty,int item_ID)
{
int result;
SqlDataAdapter da2 = new SqlDataAdapter();
if (conex1.State == ConnectionState.Closed)
{ conex1.Open();}
SqlCommand Totalf = new SqlCommand("SELECT dbo.fn_Inventory(#qty,#item_ID)", qty,item_ID);
SqlParameter _qty= new SqlParameter("#qty", SqlDbType.Int);
SqlParameter _item_ID= new SqlParameter("#item_ID", SqlDbType.Int);
_qty.Value = qty;
_item_ID.Value = item_ID;
result= Totalf.ExecuteScalar();
return result;
}