ibmi-brunch-learn

Announcement

Collapse
No announcement yet.

Using standalone field in data structure

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Using standalone field in data structure

    Hello,

    I have this program so far;

    Code:
    0001.00 D xDate           S              8  0                
    0002.00 D xTime           S              6  0                
    0003.00 D xRefno          S              8  0                
    0004.00                                                      
    0005.00 D DatTim         Ds                  DTAARA(CHKERROR)
    0005.01 D xDatTim                 1     14  0
    0006.00 D xDat                    1      8  0                
    0007.00 D xTim                    9     14  0                
    0008.00                                                      
    0009.00 D SdatStim       Ds  
    0010.00 D xSDatStim               1     14  0                                    
    0010.01 D xDate                   1      8  0              
    0011.00 D xTime                   9     14  0                
    0012.00                                                      
    0013.00  /free                                                
    0014.00    // Read CHKERROR data area                      
    0015.00    in xDatTim;                                        
    0016.00                                                      
    0017.00    // Run SQL to check for more recent examples      
    0018.00    Exec SQL                                          
    0019.00       SELECT DATE, TIME, REFNO                        
    0020.00         INTO :xDate, :xTime, :xRefno
    0021.00         FROM FILE                  
    0022.00       ORDER BY DATE DESC, TIME DESC
    0023.00       FETCH FIRST ROW ONLY;        
    0024.00
    0025.00    // End program
    0026.00    *INLR = *ON
    0027.00
    0028.00  /End-Free
    My thoughts here are pretty simple;

    Fetch most recent record from FILE
    Check the date/time of the record retrieved;
    if it's greater that the last stored value in CHKERROR- email me some details via SNDDST
    if it's the same or less, end program

    So I have gotten as far as the above and I thought I'd compile it to check the data structures are defined correctly so far and unfortunately it fails during the SQL part stating;

    Code:
    MSG ID  SEV  RECORD  TEXT                                      
    SQL0314  35      20  Position 20 Host variable XDATE not unique.
    SQL0314  35      20  Position 28 Host variable XTIME not unique.
    I thought I could just define xDate/xTime in their own data structure and then compare xDatTim with xSdatStim - so either I can't do this or I've set it up wrong.

    So my question is; can I use xDate/xTime for SQL variables and define them in a data structure? Or do I need 2 different fields in the DS and then just move xDate/xTime into them and compare that way? (For now; I'll do the latter, as I need something in place but I'd rather do the former)

    Thanks,
    Ryan
    Last edited by RDKells; January 24, 2018, 09:16 AM.

  • #2
    In RPG one field name = one location in memory. Therefore xTime cannot be both in a data structure _and_ in a stand-alone field because those would require separate memory locations. You could add the keyword "Qualified" to the DS definition - but it is not needed. Simply deleting the standalone fields will deal with this problem.

    Since you are new to RPG a couple of points. First using From/To notation as you have done is only supported for compatibility with previous versions of RPG - in other words it is a feature that was deprecated 20+ years ago. Don't use it. Something like this would be better ... not tested.

    Code:
    D xDatTim Ds DTAARA(CHKERROR)
    D  xDat                          8S 0                
    D  xTim                          6S 0                
    
    D SdatStim        Ds  
    D  xDate                         8S 0              
    D  xTime                         6S 0                
    
    D xRefNo          S              8S 0
    Even better would be to use the current version of the language which would look like this:

    Code:
    Dcl-ds xDatTim DTAARA('CHKERROR');
      xDat  Zoned(8);
      xTim  Zoned(6);
    End-ds;
    
    Dcl-ds SdatStim;
      xDate  Zoned(8);
      xTime  Zoned(6);
    End-ds;
    
    D cl-s xRefNo Zoned(8);
    Hope this helps.
    Last edited by JonBoy; January 24, 2018, 10:23 AM.

    Comment


    • #3
      Why do you need to define the xDate an xTime fields as stand alone field and as data structure sub-field?
      AFAIK that never worked.
      You either need a different name for the stand alone field or you need to qualify your data structure (and use the qualified sub-fields or the data structure in your FETCH Statement.

      Code:
      DCL-DS SdatTim  Qualified  Inz;
         xDate  Zoned(8);
         xTime  Zoned(6);
      End-DS;
       ...
      Exec SQL Select Date, Time, RefNo
                  into :SDatTim, :xRefNo
               From ....
       ....
      I hope DATE and TIME are dummy field names in your example, if not it would be better to embedd them into double quotes.

      Birgitta

      Comment


      • #4
        Hello again Jon,


        Thanks for your reply, that makes sense - I wasn't aware of that but it explains what the error message is trying to convey.

        So I guess how I'm doing things now; where I move xDate & xTime into 2 different fields defined under SdatStim is the way to do achieve what I want.


        Regarding free definitions; I would like to use them because I think it looks better and it makes more sense to write the entire program in free, rather than half of it? But unfortunately here programs are either half and half or fully fixed, I guess some people are just set in their ways.
        The issue this causes me is that if I try to define things in free and get stuck, I can't search programs here for examples so that leaves me with google and then pestering you when google fails me! Lol.

        I do have a couple of queries here;

        A. Without using the from/to how would I define something in the middle? I.e. the hours?

        Code:
         
         D xDatTim Ds DTAARA(CHKERROR) D  xDat                          8S 0      D  xHour                         2S 0            D  xTim                          6S 0
        I guess that wouldn't work? Since it is basically saying 1-8 is the date 9-10 is the hours, 11-16 is the time (out of range)


        B. You've included an 'S' within your definitions, I exclused that because of the help prompt which states;

        Leave the field blank for a character field, or a packed decimal standalone field, or a zoned decimal field data structure subfield.
        For zoned or packed data types, the decimal positions field must be non-blank.
        ...

        S
        Type S if this is a zoned field.



        Should I always include an S for decimal stand alone fields? Does this actually do anything different to leaving it blank?

        Thanks,
        Ryan

        Comment


        • #5
          B.Hauser

          I wanted to compare 2 CCYYMMDDHHMMSS values where one comes from separate date/time fields. For example, the data area is CCYYMMDDHHMMSS but the other date & time values come from 2 fields; date and time.
          Since I've not used data structures before, thought I'd try and incorporate them.

          This is what I currently have - I had to ditch the decimal definitions as it was causing a decimal data error if the data area was blank or 0 and rather than put some monitor in to change it to 0's if it errors, I just changed it to character and this works as I need it to;

          Code:
          D xDate           S              8
          D xTime           S              6
          D xRefn           S              8
          
          D DatTim         UDs                  DTAARA(CHKERROR)
          D xDatTim                 1     14                      
          D xDat                    1      8                      
          D xTim                    9     14                    
          
          D CdatTim         Ds              
          D xCdatTim                1     14
          D xCdat                   1      8
          D xCtim                   9     14
          
          ...
             in DatTim;
          ...
          SELECT DATE, TIME, REFNO
            INTO :xDate, :xTime, :xRefn
            FROM FILE;
          ...
          xCdat = xSdat;        
          xCtim = xStim;        
           If xCdatTim > xDatTim;
          ...
          Yes they are dummy fields, SQL won't let you use reserved field names in queries usually (unless, as suggested, they are surrounded by quotes)

          I'm not familiar with the use of qualified, I have seen it kicking about but I'd need to read up on it.

          Comment


          • #6
            I do have a couple of queries here;

            A. Without using the from/to how would I define something in the middle? I.e. the hours?
            This can be done using the OVERLAY keyword. e.g.
            Code:
            D DatTim          DS
            D  xDat                          8a
            D  xTim                          6a
            D  xHour                         2a   Overlay(DatTim : 9)
            D  xMinute                       2a   Overlay(DatTim : 11)
            D  xSecond                       2a   Overlay(DatTim : 13)
            Incidentally, you can refer to the DS name just as any other variable. e.g.
            Code:
            IF  DatTim = CDatTim;
            B. You've included an 'S' within your definitions, I exclused that because of the help prompt which states;
            Just because you don't have to do something doesn't mean you shouldn't. It's a personal preference. I personally always add the data type to the variable as that makes it obvious what it is. People who are not familiar with the language will look at your definitions with confusion.

            I'm not familiar with the use of qualified, I have seen it kicking about but I'd need to read up on it.
            Qualification is a nice thing to use, particularly with the sort of code you are doing here. When you qualify a DS, to reference a DS field you specify the DS name followed by a dot and then the field name. e.g.:
            Code:
            D Start           DS                  Qualified
            D  Date                          8a
            D  Time                          6a
            D End             DS                  Qualified
            D  Date                          8a
            D  Time                          6a
            
            Start.Date = '20180124';
            Start.Time = '120000';
            End.Date = '20180125';
            End.Time = '120000';
            This makes it more obvious what each field is referring to rather than wondering what xDat, xTim, xCdat, xCtim etc refer to. As you can see, it also means you can use the same field name in multiple DS so you don't have to worry about thinking of a prefix/suffix to make them unique. It also means you are unlikely to re-use a variable name.

            Comment


            • #7
              Thank you so much for this info, it's extremely helpful!

              The way of defining fields in data structures you've mentioned is brilliant - I'll be using that from now on.

              I didn't realise you could use the DS name, that's why I made xDatTim - amateur, lol.

              I was actually getting confused with what fields are what, so the ability to use qualified would make this so much easier.

              Thanks again to all for your help

              Comment


              • #8
                For those of you that are interested, this is what I ended up with in the end - have tested it and it works as I'd like. Any criticisms/improvement suggestions are welcome.

                Code:
                0001.00  * Work fields                                                    
                0002.00 D xSDAT           S              8a                               
                0003.00 D xSTIM           S              6a                               
                0004.00 D xSUSR           S             10a                               
                0005.00 D xFSIT           S              4a                               
                0006.00 D xTSIT           S              4a                               
                0007.00 D xSREF           S              8a                               
                0008.00 D xCOM1           S             60a                               
                0009.00                                                                   
                0010.00  * Email program                                                  
                0011.00 D xMailme         Pr                  EXTPGM(CHKSMDPEMA)
                0012.00 D  Pr_xSDAT                           Like(xSDAT)                 
                0013.00 D  Pr_xSTIM                           Like(xSTIM)                 
                0014.00 D  Pr_xSUSR                           Like(xSUSR)                 
                0015.00 D  Pr_xFSIT                           Like(xFSIT)                 
                0016.00 D  Pr_xTSIT                           Like(xTSIT)                 
                0017.00 D  Pr_xSREF                           Like(xSREF)                 
                0018.00 D  Pr_xCOM1                           Like(xCOM1)                 
                0019.00                                                                            
                0020.00  * Data structures                                                         
                0021.00 D xPrevious      UDs                  DTAARA(CHKSMDPDA) Qualified
                0022.00 D xDate                          8a                                        
                0023.00 D xTime                          6a                                        
                0024.00                                                                            
                0025.00 D xLatest         Ds                  Qualified                            
                0026.00 D xDate                          8a                                        
                0027.00 D xTime                          6a                                        
                0028.00  *                                                                         
                0029.00                                                                            
                0030.00   // Mainline                                                              
                0031.00                                                                            
                0032.00  /Free                                                                     
                0033.00                                                                            
                0034.00    // Get previous date/time values                          
                0035.00    In xPrevious;                                                   
                0036.00                                                                                                  
                0037.00    // Get latest date/time from file                               
                0038.00    Exec SQL                                                        
                0039.00       SELECT MHSDAT, MHSTIM, MHSUSR, MHFSIT, MHTSIT, MHSREF, MHCOM1
                0040.00         INTO :xSDAT, :xSTIM, :xSUSR, :xFSIT, :xTSIT, :xSREF, :xCOM1
                - - - - ------------- 9 data records excluded -----------------------------
                0050.00       ORDER BY MHSDAT DESC, MHSTIM DESC                            
                0051.00       FETCH FIRST ROW ONLY;                                      
                0052.00                                                                      
                0053.00     xLatest.xDate = xSdat;                                           
                0054.00     xLatest.xTime = xStim;                                           
                0055.00                                                                      
                0056.00   // Check if latest date/time is more recent than previous date/time
                0057.00     If xLatest > xPrevious;                                          
                0058.00                                                                      
                0059.00   // Email details if latest is more recent                          
                0060.00     xMailMe(xSDAT:xSTIM:xSUSR:xFSIT:xTSIT:xSREF:xCOM1);              
                0061.00                                                                      
                0062.00   // Update xPrevious value for next run.                            
                0063.00     xPrevious.xDate = xSdat;                                         
                0064.00     xPrevious.xTime = xStim;                                         
                0065.00     Out xPrevious;                                                   
                0066.00                                                                      
                0067.00     Endif;                                                                                                         
                0068.00                 
                0069.00   // End program
                0070.00     *INLR = *ON;
                0071.00                 
                0072.00  /End-Free

                Comment


                • #9
                  Do you really want suggestions for improvement? I hope you don't regret that :-)

                  1) Use longer, more meaningful names. Names like "xSDAT" are really hard to understand. If this stands for "start date" then name it something like startDate. Or if you must use "x" for some reason, use xStartDate.

                  2) Use free-format RPG. It may "not look right" at first, but after a few months you'll never go back, and when you hire new people out of school, they'll be much happier without any fixed format code.

                  3) Stop using SEU!!! IBM hasn't added any of the new features of RPG in the past 10 years to SEU. TEN YEARS.

                  4) When you post code, don't include the line numbers, and don't have "--- X records included ---" in the middle of it. This way, people can copy/paste your code and try it if they want.

                  5) Don't use both "UDS" and the In/Out opcodes in the same program because that confuses people. "UDS" on the data structure means that RPG will automatically read the data area when the program begins, and write it when it ends. The In/Out opcodes are used to manually read/write it. Sure, it's possible to do both in the same program, but it tends to confuse people -- if you're going to do it manually, then omit the"U" (so you have DS instead of UDS) and do it with the In/Out opcodes so that it's clear exactly when/where the updates take place.

                  Comment


                  • #10
                    The two data structures are intended to be identical, so rather than code the subfields for both data structures, I think it would be better to define the second one using LIKEDS. That way, it's impossible for someone to come along later and modify one data structure without also modifying the other.
                    Code:
                     * Data structures                                                         
                    D xPrevious      UDs                  DTAARA(CHKSMDPDA) Qualified
                    D xDate                          8a                                        
                    D xTime                          6a                                        
                    
                    D xLatest         Ds                  Likeds(xPrevious)
                    When you use LIKEDS, the second data structure is automatically qualified.

                    Comment


                    • #11
                      Regarding not using free-form declarations because your shop has a mixture of half-and-half or all fixed-form ... If you write new code in free-form, it will gradually increase the percentage of code that's free-form, hopefully to the point where free-form beats fixed form. About searches for samples, if you only search for fixed-form examples, you'll miss out on the ones that are in free-form. If you're familiar with fixed-form syntax, you can/should search both ways.

                      Me, I wouldn't throw a free-form declaration into the middle of code that has fixed-form declarations, any more than I'd throw a free-form calculation into the middle of fixed-form calculations. When I'm making small-ish modifications, I make my mods in the style of the code I'm modifying. But if I was writing a new procedure in a module with all fixed-form code, I'd probably write the new procedure in free-form.

                      Comment


                      • #12
                        I don't regret it - I know I suck at this, so always open to suggestions to help me improve.


                        Explaining myself;

                        1) Use longer, more meaningful names. Names like "xSDAT" are really hard to understand. If this stands for "start date" then name it something like startDate. Or if you must use "x" for some reason, use xStartDate.
                        As this program is just for me; I used xSDAT because the field feeding it is MHSDAT and I prefer short, concise names they are meaningful to me and I use x to help me identify standalone fields. But, for production programs, I will bear this in mind.

                        2) Use free-format RPG. It may "not look right" at first, but after a few months you'll never go back, and when you hire new people out of school, they'll be much happier without any fixed format code.
                        I would like to but there aren't many examples here so if I get stuck I couldn't look for other examples in use (like I do now)

                        3) Stop using SEU!!! IBM hasn't added any of the new features of RPG in the past 10 years to SEU. TEN YEARS.
                        We recently had RADi implemented but there wasn't much of a training session on it and since I'm not programming everyday, it's difficult to pick up so I just stick with what I know... Which is probably a poor mentality but it's quicker.
                        I'll give RADi a shot to add Barbara's suggested changes (or is RADi crap as well?)


                        4) When you post code, don't include the line numbers, and don't have "--- X records included ---" in the middle of it. This way, people can copy/paste your code and try it if they want.
                        Oh I thought the line numbers would help, lol - I just excluded the SQL I used, as I didn't think it was relevant - I'll bear that in mind for the future though.

                        5) Don't use both "UDS" and the In/Out opcodes in the same program because that confuses people...
                        Initially I had "DS" and in/out, but it said it wasn't open for update upon the Out - I changed it to UDS and this worked, I'll remove the in/out.

                        =================

                        Barbara; Again, another thing learned here - that looks a lot neater.
                        You do have a point, using it is a good way to learn so I'm going to try and to do the entire program in free, gotta start somewhere. Unfortunately we have free format code in with fixed format code and it isn't rare, it's quite a frequent occurrence lol.



                        Thank you both for your responses here.

                        Comment


                        • #13
                          Ok you crazy peeps, behold the beauty! I also did all the changes in Rad-i too.

                          Usually I find IBM official pages difficult to understand, especially when they don't give examples however this site is actually amazing and really easy to understand.

                          After doing some reading on UDS's, apparently you should only only really use it for the LDA? So I ditched it for an in *lock.

                          Rad-i is a bit odd to use, some things really cheese me off like how ENTER functions but after 40 minutes of trying to find out what keybind I needed to change it to and speaking with people who use it here, I've just accepted it is what it is.

                          Since it's Friday and I didn't want to break anything, I compiled it from WRKMBRPDM - not sure how to compile in Rad-i yet and thought it would just be easier this time to do it how I know.

                          Only a few issues encountered with compile, like I put EXPGM instead of EXTPGM and also when using LIKEDS you don't need an END-DS (which that IBM site clearly shows, but I overlooked it as Rad-i added it automatically) that was it.

                          Have tested it and it works, surprisingly.

                          Code:
                                // Header specs
                                 CTL-OPT;
                          
                                // Work fields
                                 DCL-S SendDate Char(10);
                                 DCL-S SendTime Char(6);
                                 DCL-S SendUser Char(10);
                                 DCL-S FromSite Char(4);
                                 DCL-S ToSite Char(4);
                                 DCL-S SysRef Char(8);
                                 DCL-S OrderNo Char(60);
                          
                                // Email prototype
                                 DCL-PR xMailMe EXTPGM('RAKELLR/CHKSMDPEMA');
                                  Pr_SendDate Char(10);
                                  Pr_SendTime Char(6);
                                  Pr_SendUser Char(10);
                                  Pr_FromSite Char(4);
                                  Pr_ToSite Char(4);
                                  Pr_SysRef Char(8);
                                  Pr_OrderNo Char(60);
                                 END-PR;
                          
                                // Data structures
                                 DCL-DS xPrevious DTAARA('RAKELLR/CHKSMDPDA') Qualified;
                                  xDate Char(8);
                                  xTime Char(6);
                                 END-DS;
                          
                                 DCL-DS xLatest LikeDS(xPrevious);
                          
                                // Mainline
                          
                                  // Get previous date/time values
                                  In *lock xPrevious;
                          
                                  // Get latest date/time from file
                                  Exec SQL
                                     SELECT MHSDAT, MHSTIM, MHSUSR, MHFSIT, MHTSIT, MHSREF, MHCOM1
                                       INTO :SendDate, :SendTime, :SendUser, :FromSite, :ToSite, :SysRef,
                                            :OrderNo
                                       FROM ORDERFILE
                                     ORDER BY MHSDAT DESC, MHSTIM DESC
                                     FETCH FIRST ROW ONLY;
                          
                                   xLatest.xDate = SendDate;
                                   xLatest.xTime = SendTime;
                          
                                 // Check if latest date/time is more recent than previous date/time
                                   If xLatest > xPrevious;
                          
                                   // Email order details if so
                                     xMailMe(SendDate:SendTime:SendUser:FromSite:ToSite:SysRef:OrderNo);
                          
                                   // Update xPrevious value for next run.
                                     xPrevious.xDate = SendDate;
                                     xPrevious.xTime = SendTime;
                                     Out xPrevious;
                          
                                   Endif;
                          
                                 // End program
                                   *INLR = *ON;

                          Comment


                          • #14
                            Nice!

                            Just one terminology note: It's called "RDi", not "Rad-i". I've always heard it pronounced arr dee eye, but maybe some people pronounce it Rad-i. There's a Rational product called "RAD" (Rational Application Developer), that's maybe somewhat related to RDi, but different.

                            About RDi automatically adding the END-DS, for what it's worth, it doesn't do that if you already have the LIKEDS or LIKEREC keyword there before you press ENTER.

                            Comment

                            Working...
                            X