SQL stored procedure to convert a blob field to XML - sql

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.

Related

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;

question about out_msg.Destination in MOESI_CMP_directory response message

In MOESI_CMP_directory-L2cache.sm--the action of j_forwardGlobalRequestToLocalOwner, the "out_msg.Requestor" of the request message is filled in the machineID of that L2 cache, so it is the correct requestor.
While, to response that message in "MOESI_CMP_directory-L1cache.sm"--the action of "ee_sendDataExclusive" ,when in_msg.RequestorMachine == MachineType:L2Cache, why is the out_msg.Destination filled in "mapAddressToRange", instead of "in_msg.Requestor"? (I think it is the "out_msg.Requestor" value of the request message.)
L2 cache:
action(j_forwardGlobalRequestToLocalOwner, "j", desc="Forward external request to local owner") {
peek(requestNetwork_in, RequestMsg) {
enqueue( localRequestNetwork_out, RequestMsg, response_latency ) {
out_msg.addr := in_msg.addr;
out_msg.Type := in_msg.Type;
out_msg.Requestor := machineID;// the machineID of the request L2
out_msg.RequestorMachine := MachineType:L2Cache;
out_msg.Destination.add(getLocalOwner(cache_entry, in_msg.addr));
out_msg.Type := in_msg.Type;
out_msg.MessageSize := MessageSizeType:Forwarded_Control;
out_msg.Acks := 0 - 1;
}
}
}
L1 cacheļ¼š
action(ee_sendDataExclusive, "\e", desc="Send data from cache to requestor, don't keep a shared copy") {
peek(requestNetwork_in, RequestMsg) {
assert(is_valid(cache_entry));
if (in_msg.RequestorMachine == MachineType:L2Cache) {
enqueue(responseNetwork_out, ResponseMsg, request_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L1Cache;
out_msg.Destination.add(mapAddressToRange(address, MachineType:L2Cache,
l2_select_low_bit, l2_select_num_bits, intToID(0)));//why do not filled in "in_msg.Requestor"?
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := cache_entry.Dirty;
out_msg.Acks := in_msg.Acks;
out_msg.MessageSize := MessageSizeType:Response_Data;
}
DPRINTF(RubySlicc, "Sending exclusive data to L2\n");
}
else {
enqueue(responseNetwork_out, ResponseMsg, request_latency) {
out_msg.addr := address;
out_msg.Type := CoherenceResponseType:DATA_EXCLUSIVE;
out_msg.Sender := machineID;
out_msg.SenderMachine := MachineType:L1Cache;
out_msg.Destination.add(in_msg.Requestor);
out_msg.DataBlk := cache_entry.DataBlk;
out_msg.Dirty := cache_entry.Dirty;
out_msg.Acks := in_msg.Acks;
out_msg.MessageSize := MessageSizeType:ResponseLocal_Data;
}
DPRINTF(RubySlicc, "Sending exclusive data to L1\n");
}
}
}

Pl Sql Decode and Unzip

I have the below Java script which works but runs into issues at times. I need to try and write it as Pl Sql which I can then work with inside the application. I can get to the point of base64_decode but I can not get UTL_COMPRESS.LZ_UNCOMPRESS to work. Any ideas, suggestions, please?
Bellow is the working(ish) java code i need to emulate in Pl SQL
import java.util.*;
import java.util.zip.*;
import java.io.*;
import java.util.Arrays;
import org.apache.commons.codec.binary.Base64;
//import org.apache.bob;
public class decompress {
public static void main(String[] args) {
//String zpl = "rVrbbhw5kn33V+hlgV1sWg7mjVk9wADMqmRnVkmyWlK37cGiAE2PVnb3WDbc02uMH/phsT8x
this is a very long string staored as a clob in the data base .
6kwF4z6vyGzQYdMKVlUUj1lsWrJJlABbPLdfYvz7xzZVbzZv/7DPwE=";
try{
String zpl = args[0];
if (zpl.length()<2) {
System.out.println("ERROR");
} else {
//System.out.println(zpl);
//byte[] res = decompress(zpl.getBytes("UTF-8"));
Base64 b64 = new Base64();
byte[] res=Base64.decodeBase64(zpl);
//System.out.println(new String(res, "UTF-8"));
byte[] decom=decompress(res);
System.out.println(new String(decom,"UTF-8"));
}
//System.out.println("THIS " + res.toString());
} catch (Exception e) {
//System.out.println(e.getMessage());
//e.printStackTrace();
System.out.println("ERROR");
}
}
public static byte[] decompress(byte[] data) throws IOException, DataFormatException {
Inflater inflater = new Inflater(true);
inflater.setInput(data);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
while (!inflater.finished()) {
int count = inflater.inflate(buffer);
outputStream.write(buffer, 0, count);
}
outputStream.close();
byte[] output = outputStream.toByteArray();
inflater.end();
return output;
}
}
SQL Function attempt which seam to do teh base 64 bit but falls apart when trying to decompress.
CREATE OR REPLACE
FUNCTION decode_base64_x(
p_clob_in IN CLOB)
RETURN BLOB
IS
v_blob BLOB ;
v_result BLOB ;
v_offset INTEGER;
v_buffer_size binary_integer := 48;
v_buffer_varchar VARCHAR2(48);
v_buffer_raw raw(48);
l_uncompressed_blob BLOB ;
l_in_blob BLOB;
BEGIN
IF p_clob_in IS NULL THEN
RETURN NULL;
END IF;
dbms_lob.createtemporary(v_blob, true);
v_offset := 1;
FOR i IN 1 .. ceil(dbms_lob.getlength(p_clob_in) / v_buffer_size)
LOOP
dbms_lob.read(p_clob_in, v_buffer_size, v_offset, v_buffer_varchar);
v_buffer_raw := utl_raw.cast_to_raw(v_buffer_varchar);
v_buffer_raw := utl_encode.base64_decode(v_buffer_raw);
dbms_lob.writeappend(v_blob, utl_raw.length(v_buffer_raw), v_buffer_raw);
v_offset := v_offset + v_buffer_size;
END LOOP;
v_result := v_blob;
--
--
-- l_in_blob := (UTL_RAW.CAST_TO_RAW (v_blob) );
--
UTL_COMPRESS.LZ_UNCOMPRESS( src => v_blob, dst => l_uncompressed_blob);
--
dbms_lob.freetemporary(v_blob);
-- l_uncompressed_blob := UTL_COMPRESS.LZ_UNCOMPRESS( src => v_blob ) ;
-- UTL_COMPRESS.lz_uncompress (src => v_blob , dst => l_uncompressed_blob);
-- RETURN l_uncompressed_blob;
RETURN v_result;
END decode_base64_x;
i think that its just the UTL_COMPRESS.LZ_UNCOMPRESS bit i am getting wrong !

.Net calling Oracle Array bound stored procedure output VarChar2

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