.Net calling Oracle Array bound stored procedure output VarChar2 - sql

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

SQL stored procedure to convert a blob field to XML

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.

Trying to create procedure in snowflake and getting error while passing value to another procedure

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;
$$
;

Indy 10 SSL root certificate

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;

Deleting Record using stored procedure and get a return result to C#

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

how do i call a sql function from my asp.net project?

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;
}