**free/TITLE PMTSTATE Search and return a USA State Code//==============================================================*// This is a "load all" subfile, where the system takes care or// paging up and down. All selected data is loaded into the// subfile. STATES table has only 58 rows, so selecting all// is approptiate.// For larger numbers of rows, a "page at at time" approach// may make more sense.//==============================================================*// Displays USA state names and their 2-char codes in a window.// Can sort the display by name or code.// Optionally can select and return a 2-char code.//// Parameters// ----------// Out CL2 Selected 2-Char State Code (optional)////===============================================================// Program is essentially without indicators. (Indicators are// stil lneeded to control the display file, but all have names.)//// Naming Conventions// ==================// - Lower case is the default for opcodes.// - TitleCase is used for program variables, subroutines and procedure// names, e.g. MaxOrderQty, BldFkeyText, etc.// - Temporary variables are prefixed with "wk", e.g., wkDate. Such// variables contain valid data for only a short time and are never// carried across subroutines.// - UPPERCASE is used for external names, i.e., files, fields, formats// and anything else not directly coded in the program.//// - In the display file, this field naming convention is used:// Screen Header: Fields begin with SH_// Subfile: Fields begin with SF_// Subfile Control: Fields begin with SC_// Screen footer: Fields begin with SFT_//===============================================================// Compilation// Use CRTSQLRPGI command.// Note that /INCLUDEs expects to find code in Copy_Mbrs file,// not the default of QRPGLESRC. Change as needed.//=============================================================// 12/2023 Converted to totally **FREE// Use SQLPROBLEM service program//=============================================================ctl-opt dftactgrp(*no) actgrp(*caller) option(*nodebugio: *srcstmt)bnddir('UTIL_BND': 'SQL_BND');// === Program parameters =======================================dcl-pi *n; pState like(FetchData.state);end-pi;//=== Display File ==============================================dcl-f PMTSTATED workstn infds(dfInfDS) indds(dfIndDS) sfile(SFL:SflRRN)usropn;//=== Service Program Prototypes ================================/INCLUDE ../Copy_Mbrs/SRV_MSG_P.RPGLE/INCLUDE ../Copy_Mbrs/SRV_SQL_P.RPGLE//=== Named hexadecimal constants for function keys =============/INCLUDE ../Copy_Mbrs/AIDBYTES.RPGLE//=== Fields read by SQL ========================================// NOTE: Only the fields in fetchData which are fetched by the// SQL Cursor are populated.dcl-ds STATESds extname('STATES') qualified template end-ds;dcl-ds FetchData likeds(STATESds);//=== SQL State Constants =======================================dcl-c SQLSUCCESS '00000';dcl-c SQLNODATA '02000';dcl-c SQLNOMOREDATA '02000';dcl-c SQLDUPRECD '23505';dcl-c SQLROWLOCKED '57033';//=== Display File Information Data Structure ===================// Allows us to determine which function key was presseddcl-ds dfInfDS; Key char(1) pos(369);end-ds;//=== Display File Indicator Data Structure =====================// This is a "private" indicator area for the display file.//--- 01-20 are not automatically cleared after EXFMT ----------dcl-ds dfIndDS len(99); scCodeHi char(1) pos(1);//--- 21-99 automatically cleared after EXFMT ------------------ scNameHi char(1) pos(2);//--- Subfile indicators (prefix "sf") ------------------------- dfIndClr char(79) pos(21); sfSflNxtChg ind pos(80); sfOPT_RI ind pos(81);//--- Subfile Control indicators (prefix "sc") ---------------- sfOPT_PC ind pos(82); scMDT ind pos(95); scNoDta ind pos(96); scSflEnd ind pos(97); scSflDsp ind pos(98); scSflClr ind pos(99);end-ds;//=== Fields to control the subfile screen ======================dcl-s SflRRN int(5);dcl-s RcdsInSfl int(5);dcl-c SFLPAGESIZE 6;dcl-s SflMaxRecd int(5) inz(9999);// SC_CSR_RCD is defined in the display file and is set with a// RRN which determines which subfile page is displayed and on// which record the cursor is positioned.//=== Program Status Data Structure =============================dcl-ds ProgStatus PSDS; PgmName *PROC;end-ds;dcl-s MainProc char(10);//=== Text for function keys ====================================dcl-c F3TEXT 'F3=Exit';dcl-c F5TEXT 'F5=Refresh';dcl-c F12TEXT 'F12=Cancel';dcl-c F7TEXT1 'F7=By ';dcl-s F7Text2 char(5) inz(' ');dcl-s F7Text char(11) inz(' ');//SortSeq is used in SQL Order By in a CASE construct.dcl-s SQLSortSeq char(4) inz(' ');dcl-s SortbyName char(4) inz('Name');dcl-s SortbyCode char(4) inz('Code');//=== Options Text ==============================================dcl-c OPT1TEXT '1=Select';//=== Search Criteria Screen Fields =============================dcl-ds SearchCriteria inz; SC_NAME;end-ds;//=== Last Search Criteria Fields ===============================dcl-ds LastSearchCriteria inz; LastSC_NAME like(sc_name);end-ds;//=== SQL Search Variables ======================================dcl-s DESCLike varchar(12);//=== Global Switches ===========================================dcl-s EofData ind;dcl-s CursorOpen ind;dcl-s NewSearchCriteria ind;dcl-s SflMsgSnt ind;dcl-s Opt1OK ind;dcl-s OptError ind;//=== Work Fields ===============================================dcl-s inx int(10);//=== Set SQL Options =========================================exec sql set option datfmt=*iso, closqlcsr=*endmod;//=== SQL Cursor Definitions ==================================// Sort Order is controlled by field SQLSortSeq which is// used in a CASE statement.exec SQL declare DataCur cursor for select STATE, NAME from STATES where upper(NAME) like :DESCLike order by case :SQLSortSeq when :SortbyName then NAME when :SortbyCode then STATE else '1' end for fetch only;//=============================================================//== Program Starts Here ======================================//=============================================================//--- Analyse parameters ---Opt1OK = *off;if %parms() > 0; Opt1OK = *on;endif;Init();BldFkeyText();// === Initial screen display =================================write SH_HDR;SflClear();ProcessSearchCriteria();SflLoadAll();//=============================================================// === Main Program Loop ======================================//=============================================================dow *INLR = *OFF; // To exit this program, some procedures tuen on *INLR // Put the last search criteria back on the screen. SearchCriteria = LastSearchCriteria; // Set "*More" display scSflEnd = EofData; // If switching display order, reload first page if Key = F07; ProcessSearchCriteria(); SflLoadAll(); endif; // Write/Read the screen ScreenIO(); //-- Enter Key -------------------------------------------- If Key = Enter; // Either new Search Criteria entered or option(s) entered. // New Search Criteria takes precedence over option(s). if SearchCriteria <> LastSearchCriteria or NewSearchCriteria = *on; SflClear(); ProcessSearchCriteria(); SflLoadAll(); else; ProcessOption(); endif; iter; endif; //--- Any other entry must be a function key --------------- ProcessFunctionKey();enddo;return; // to Caller//=============================================================//=== End of Main Program Loop ================================//=============================================================//=== ScreenIO ================================================// Writes and Reads the screenDcl-Proc ScreenIO; write SH_HDR; write SFT_FKEY; // Show any messages in the error subfile. if SflMsgSnt = *on; write MSGCTL; endif; // If we have records in the subfile, display them. if RcdsInSfl > 0; scSflDsp = *ON; else; scSflDsp = *OFF; ENDIF; // Write/read the subfile. SC_CSR_RCD contains a RRN and // determines which page will be on the screen and where the // cursor will be. exfmt SFLCTL; // Clear most display file indicators clear dfIndClr; // Clear any messages in the error subfile. if SflMsgSnt = *on; SflMsgSnt = ClrMsgPgmQ(MainProc); write MSGCTL; endif;End-Proc;//=== ProcessFunctionKey ======================================// Process whatever keyboard entry was made.// Will not return from subroutine if F3 or F12 was pressed.// May not return from subroutine when an option is entered.Dcl-Proc ProcessFunctionKey; select; //--- F3 or F12: Exit, close down program ----------------------- when (Key = F03 or Key = F12); CloseDownPgm(); *inlr = *on; return; //--- F5: Refresh all search fields ---------------------- when Key = F05; clear LastSearchCriteria; NewSearchCriteria = *on; SflClear(); //--- F7: Toggle Sort Sequence --------------------------- when Key = F07; if SQLSortSeq=SortbyName; SQLSortSeq = SortbyCode; SC_SORTED = SortbyCode; scCodeHi = *on; scNameHi = *off; F7Text2 = SortbyName; else; SQLSortSeq = SortbyName; SC_SORTED = SortbyName; scNameHi = *on; scCodeHI = *off; F7Text2 = SortbyCode; endif; F7Text = F7TEXT1 + F7Text2; BldFkeyText(); NewSearchCriteria = *on; SflClear(); //--- Other keys: Function key not active message --------- other; SflMsgSnt= SndSflMsg('DEM0003'); endsl;End-Proc;//=== ProcessOption ===========================================// Did user enter an option? If so, process it.// May not return from this subroutine.Dcl-Proc ProcessOption; if RcdsInSfl > 0; OptError = *off; // Don't know yet which page to display next time. SC_CSR_RCD = 0; // Loop through changed records in the subfile. readc SFL; dow not %eof; select; //--- 1 = Select ------------------------------------------ when SF_OPT = '1' and Opt1OK; // Return Code to caller pState = SF_CODE; CloseDownPgm(); *inlr = *on; return; //--- Opt is blank ---------------------------------------- when SF_OPT = ' '; // If changed, assume clearing an error from last time sfOPT_PC = *off; sfOPT_RI = *off; update SFL; //--- Other ----------------------------------------------- other; // Send message about invalid selection. // Position cursor and page at first error. // Always force to be read again next time & reverse image. // Not a valid option at this time SflMsgSnt= SndSflMsg('DEM0004':SF_OPT); // Leave cursor at first invalid option SetScreenCursorPosition(); OptError = *on; // SFLNXTCHG forces this record to be read again // even if user doesn't correct it, so we can // check it again for validity. sfSflNxtChg = *on; sfOPT_RI = *on; update SFL; // set off indicators applying to just this recd. sfSflNxtChg = *off; sfOPT_RI = *off; endsl; readc SFL; enddo; endif; // If no positioning done, display last page, cursor on 1st recd. // (Enter with no option takes you to the last page of subfile.) if SC_CSR_RCD = 0; SC_CSR_RCD = ( %int( (RcdsInSfl-1) / SFLPAGESIZE ) * SFLPAGESIZE ) + 1; endif;End-Proc;//=== SflLoadAll ==============================================// Loads all selected records to the subfile.// Returns:// EofData = *on (there are no more data records.)// RcdsInSfl contains relative record number of last record// written to the subfile.// SC_CSR_RCD contains relative record number of 1st record// on the page & positions cursor there.Dcl-Proc SflLoadAll; // Position cursor at first record on the subfile page. SC_CSR_RCD = 1; for inx = 1 to SflMaxRecd; EofData = FetchNextData(); if EofData = *on; leave; endIf; // Build/Format the subfile record clear SF_OPT; SF_CODE = FetchData.STATE; SF_NAME = FetchData.NAME; SflRRN = inx; RcdsInSfl = RcdsInSfl + 1; write SFL; // Can't display more than 9,9999 records. if SflRRN = SflMaxRecd; EofData = *on; SflMsgSnt= SndSflMsg('DEM0006'); leave; endif; endfor;End-Proc;//=== ProcessSearchCriteria====================================// Examines the data entered in the search fields and sets up// variables used in the SQL Cursor.//// Success:// NewSearchCriteria is set off// SQL Cursor is open//// Failure:// NewSearchCriteria is left on// Error message is sent to the msg sufile// Cursor is postioned at the field in errorDcl-Proc ProcessSearchCriteria; // Reset switches NewSearchCriteria = *off; // Save entered values. (Never change screen fields.) LastSearchCriteria = SearchCriteria; CloseCursor(); //--------------------------------------------------------------- if SC_NAME = ' '; // Not searching, take all DESCLike = '%%'; else; DESCLike = '%' + %trim(SC_NAME) + '%'; endif; //--------------------------------------------------------------- // If no errors in search criteria, open the SQL cursor if NewSearchCriteria = *off; exec sql open DataCur; if SQLSTT <> SQLSUCCESS; SQLProblem('Open DataCur'); endif; CursorOpen = *on; endif;End-Proc;//=== SetScreenCursorPostion ===================================// If Invalid Option, position screen cursor on first one,// else postion cursor on the last valid option.Dcl-Proc SetScreenCursorPosition; if OptError = *off; SC_CSR_RCD=SflRRN; endif;End-Proc;//=== BldFKeyText =============================================// Build the Function key text for the bottom of the screen.Dcl-Proc BldFkeyText; SFT_KEYS=' '; SFT_KEYS = CatB(SFT_KEYS : F3TEXT); SFT_KEYS = CatB(SFT_KEYS : F5TEXT); SFT_KEYS = CatB(SFT_KEYS : F7Text); SFT_KEYS = CatB(SFT_KEYS : F12TEXT);End-Proc;//=== CloseDownPgm ============================================// Things to do before we issue a return to the callerDcl-Proc CloseDownPgm; CloseCursor(); if %open(PMTSTATED); close PMTSTATED; endif;End-Proc;//=== Init ====================================================// Must be executed each time program is enteredDcl-Proc Init; SQLSortSeq = SortbyName; SC_SORTED = SortbyName; scNameHi = *on; // Name highlighted scCodeHi = *off; F7Text2 = SortbyCode; F7Text = F7TEXT1 + F7Text2; // Set up for subfile message queue MainProc = PgmName; MSGPGMQF = MainProc; MSGPGMQC = MSGPGMQF; SH_PGM = PgmName; if not %open(PMTSTATED); open PMTSTATED; endif; // Clear fields left over from previous F12. reset LastSearchCriteria; reset SearchCriteria; // Build options string. clear SC_OPTIONS; if Opt1OK; SC_OPTIONS = OPT1TEXT; endif;End-Proc;//=== CatB ====================================================// Concatenates a string to another string with a blank between.// If the target string is all blank to start with it will not// end up with a leading blank.dcl-proc CatB; dcl-pi CatB varchar(79); ToStr varchar(79) value; AddStr varchar(79) value; end-pi; if ToStr=' '; return AddStr; else; return %trimr(ToStr) + ' ' + AddStr; endif;end-proc;// === SQLProblem ================================================// For those "Never should happen" SQL errors.// Issues DUMP(A) to dump memory, then ends program by// sending an *ESCAPE message of the supplied debugging text.// dcl-proc SQLProblem;// dcl-pi SQLProblem;// piSQLDebug varchar(1024) value;// end-pi;// //--- Local Variables ---------------------------------// dcl-s wkSQLDebug varchar(1024);// wkSQLDebug = 'SQLSTT ' + SQLSTT// + ' << Unexpected SQL Return Code: '// + piSQLDebug;// dump(a);// SndEscMsg(wkSQLDebug);// return;// end-proc;//--------------------------------------------------// Procedure name: FetchNextData// Purpose: Fetch the next row from the cursor// Returns: End of data Indicator:// *ON No more data, nothing returned// *OFF Data returned//--------------------------------------------------dcl-proc FetchNextData; dcl-pi FetchNextData ind end-pi;// Local fields dcl-s wkEof ind; wkEof= *off; exec sql fetch DataCur into :FetchData.STATE, :FetchData.NAME ; select; when SQLSTT = SQLSUCCESS; wkEof = *off; when SQLSTT = SQLNOMOREDATA; wkEof = *on; Other; SQLProblem('Fetch DATACUR'); endsl; RETURN wkEof;end-proc;//--------------------------------------------------// Procedure name: SndSflMsg// Purpose: Send a message to the Error Subfile// Returns: *ON// Parameter: ErrMsgId => Msg Id to Send// Parameter: ErrMsgData => Optional Error Message Data// Parameter: ErrMsgFile => Optional Error Message File// Defaults to CUSTMSGF//--------------------------------------------------dcl-proc SndSflMsg; dcl-pi SndSflMsg ind; ErrMsgId char(7) const; ErrMsgData char(80) const options(*nopass:*varsize); ErrMsgFile char(10) const options(*nopass); end-pi;// Local fields dcl-s retField ind; dcl-s wkMsgId char(7); dcl-s wkMsgFile char(10); dcl-s wkMsgData varchar(512); if %parms >2; wkMsgFile = ErrMsgFile; else; wkMsgFile = 'CUSTMSGF'; ENDIF; if %parms > 1; wkMsgData = ErrMsgData; else; wkMsgData = ' '; ENDIF; wkMsgId = ErrMsgId; SndMsgPgmQ(MainProc: wkMsgId: wkMsgFile: wkMsgData); retField = *on; RETURN retField;end-proc;//--------------------------------------------------// Procedure name: CloseCurssor// Purpose: Closes the SQL Cursor//--------------------------------------------------dcl-proc CloseCursor; dcl-pi CloseCursor end-pi; if CursorOpen = *on; exec sql close DataCur; if SQLSTT <> SQLSUCCESS; SQLProblem('Close DATACUR'); endif; CursorOpen = *off; endif; RETURN;end-proc;//--------------------------------------------------// Procedure name: SflClear// Purpose: Clears the Subfile// Returns://--------------------------------------------------dcl-proc SflClear; dcl-pi SflClear end-pi; clear SflRRN; clear RcdsInSfl; scSflClr = *ON; write SFLCTL; scSflClr = *OFF; return;end-proc;