Skip to content

Instantly share code, notes, and snippets.

@forstie
Last active July 22, 2021 16:15
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save forstie/1bdf4ee3662c17e916025ff45bd5f2d0 to your computer and use it in GitHub Desktop.
Save forstie/1bdf4ee3662c17e916025ff45bd5f2d0 to your computer and use it in GitHub Desktop.
I was asked how ifs_read and ifs_write could be combined to build a new IFS stream file, where certain character strings are replaced.
--
-- Subject: IFS stream file transformation
-- Author: Scott Forstie (thanks to Sue Romano for helping with this Gist)
-- Date : June 28, 2021
-- Features Used : This Gist uses ifs_read, ifs_write, regexp_replace, and the previously unknown fx designation for a unicode literal.
--
-- Function - Point is routine at an existing IFS steam file, which contains some character data that you want to globally replace.
-- The function extracts (reads) the contents, replaces the search string occurrences with the replacement string, and then
-- writes everything to the target IFS stream file.
--
cl: crtlib coolstuff;
create or replace procedure coolstuff.IFS_search_replace_and_create(
Source_IFS_file DBCLOB(16M) ccsid 1200,
Target_IFS_file DBCLOB(16M) ccsid 1200,
search_string CLOB(100) ccsid 1208,
replace_string CLOB(100) ccsid 1208
)
begin
declare a_line CLOB(2G) ccsid 1208;
declare not_found condition for '02000';
declare at_end integer default 0;
declare local_sqlcode integer;
declare local_sqlstate char(5);
declare v_message_text varchar(70) for sbcs data;
declare ifs_cursor_stmt_text clob(10k) ccsid 37;
declare ifs_cursor cursor with hold for ifs_cursor_stmt;
declare continue handler for sqlexception
begin
get diagnostics condition 1
local_sqlcode = db2_returned_sqlcode, local_sqlstate = returned_sqlstate;
set v_message_text = 'coolstuff.IFS_search_replace_and_create() failed with: ' concat local_sqlcode concat
' AND ' concat local_sqlstate;
signal sqlstate 'QZZ01'
set message_text = v_message_text;
set at_end = 1;
end;
declare continue handler for not_found set at_end = 1;
set ifs_cursor_stmt_text = 'select regexp_replace(line, fx''' concat hex(search_string)
concat ''', fx''' concat hex(replace_string) concat ''') from
table(QSYS2.IFS_READ_UTF8(?, END_OF_LINE => ''NONE'')
)' ;
-- In case debug is needed...
-- call systools.lprintf('ifs_cursor_stmt_text: ' concat ifs_cursor_stmt_text);
--
-- Remove the target IFS stream file, should it exist
--
begin
declare ignore_error integer default 0;
declare continue handler for sqlexception set ignore_error = 1;
call qsys2.qcmdexc('RMVLNK OBJLNK(''' concat Target_IFS_file concat ''')');
end;
prepare ifs_cursor_stmt from ifs_cursor_stmt_text;
open ifs_cursor using Source_IFS_file;
--
-- Each fetch will bring back up to 2GB of data
-- An IFS stream file could be as large as 1TB, so we need to loop until all the data is processed
--
fetch from ifs_cursor into a_line;
while (at_end = 0) do
CALL QSYS2.IFS_WRITE_UTF8(Target_IFS_file, a_line, END_OF_LINE => 'NONE');
fetch from ifs_cursor into a_line;
end while;
close ifs_cursor;
end;
stop;
--
-- Example usage:
--
call coolstuff.IFS_search_replace_and_create(Source_IFS_file => '/home/coolstuff/ainput.txt',
Target_IFS_file => '/home/coolstuff/aoutput.txt',
search_string => 'blah',
replace_string => '客');
stop;
select *
from table (
QSYS2.IFS_READ_UTF8('/home/coolstuff/aoutput.txt')
);
@forstie
Copy link
Author

forstie commented Jun 29, 2021

Updated a_line to use clob(2G)

@MarinaSchwenk
Copy link

Ok, this one is my new favorite thank you Scott and Sue!!!!

@coramaetaclas
Copy link

coramaetaclas commented Jul 6, 2021

Hi,

I tried this and upon running

call coolstuff.IFS_search_replace_and_create(Source_IFS_file => '/home/coolstuff/ainput.txt',
Target_IFS_file => '/home/coolstuff/aoutput.txt',
search_string => 'blah',
replace_string => '客');

I received this error. Can you please help me to resolve this?

Message ID . . . . . . : SQL0438 Severity . . . . . . . : 30
Message type . . . . . : Diagnostic

Message . . . . : Message IFS_search_replace_and_create() failed
with: -418 AND 4261 returned from SIGNAL, RESIGNAL, or RAISE_ERROR.
Cause . . . . . : An application has executed a SIGNAL or RESIGNAL
statement, the RAISE_ERROR function has been invoked, or an error was
signalled within a MERGE statement. If the application is an SQL procedure,
function, trigger, or a compound (dynamic) statement, the SQLSTATE was not
handled in the SQL routine. The message returned is
IFS_search_replace_and_create() failed with: -418 AND 4261.
Recovery . . . : See the documentation for the application that issued the
SIGNAL or RESIGNAL statement or invoked the RAISE_ERROR function.

Thank you

@forstie
Copy link
Author

forstie commented Jul 6, 2021

Hi, I need more details to go on, like the joblog and/or STRDBMON output.
Also, what interface were you using when you executed it?
Also, what are these set to in the job being used to execute the CALL?
(Coded character set identifier
Default coded character set identifier)

@coramaetaclas
Copy link

Hi fortsie,

• Hi, I need more details to go on, like the joblog and/or STRDBMON output.
4>> strsql
Object not found. Object is
/admsapps/notifications/WORKORDERCOMPLETION.TEMPLATE.
Trigger program or external routine detected an error.
Trigger program or external routine detected an error.
Use of parameter marker or NULL not valid.
Substitution characters may be used for field.
Message acndbs6lib.IFS_search_replace_and_create() failed with: -418 AND
4261 returned from SIGNAL, RESIGNAL, or RAISE_ERROR.
Cursor IFS_CURSOR not open.
Message acndbs6lib.IFS_search_replace_and_create() failed with: -418 AND
4261 returned from SIGNAL, RESIGNAL, or RAISE_ERROR.

• Also, what interface were you using when you executed it?
I run this in my black screen and changed the Chinese character into test.
Sample:
call acndbs6lib.IFS_search_replace_and_create(Source_IFS_file =>
'/admsapps/notifications/templates/WORKORDERCOMPLETION.TEMPLATE',
Target_IFS_file =>
'/admsapps/notifications/WORKORDERCOMPLETION.TEMPLATE',
search_string => '&CONTACTNAME',
replace_string => 'TEST')

• Also, what are these set to in the job being used to execute the CALL?
(Coded character set identifier
Default coded character set identifier)

Language identifier . . . . . . . . . . . . . . . : CHS
Country or region identifier . . . . . . . . . . : CN
Coded character set identifier . . . . . . . . . : 935
Default coded character set identifier . . . . . : 935

Thank you

@forstie
Copy link
Author

forstie commented Jul 7, 2021

I would try changing line 27 from CCSID 37 to 935.
I would also try using this from ACS's Run SQL Scripts and not in STRSQL.
For the case that failed, it looks like the source path did not exist.
Lets see what the joblog looks like in Run SQL Scripts, with CCSID 935, and being passed a good source path.

@coramaetaclas
Copy link

Hi,

I changed the line 27 to 935 and used the RUN SQL Script.

call acndbs6lib.IFS_search_replace_and_create(Source_IFS_file =>
'/admsapps/notifications/templates/WORKORDERCOMPLETION.TEMPLATE',
Target_IFS_file =>
'/admsapps/notifications/WORKORDERCOMPLETION.TEMPLATE',
search_string => '&CONTACTNAME',
replace_string => '客') ;

And here's the error message.
SQL State: QZZ01 Vendor Code: -438 Message:
[SQL0438] ACNDBS6LIB.IFS_search_replace_and_create() failed with: -418  AND 4261.

'/admsapps/notifications/templates/WORKORDERCOMPLETION.TEMPLATE' exists in my IFS Directory
'/admsapps/notifications/WORKORDERCOMPLETION.TEMPLATE' this one does not exist, since it should be created once the script runs successfully.

Thank you

@forstie
Copy link
Author

forstie commented Jul 9, 2021

Can you wrapper the CALL with:
STRDBMON / ENDDBMON and query the output for QQRID = 1000 order by QQETIM?
Or... open a service ticket and it might be easier to resolve what's happening.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment