2025-03 You deprecated, are?

This month I wish to bring along a few things of future interest. It all started in Valencia at the IDUG EMEA in 2024, shortly before the catastrophic floods. Haakon Roberts held his “trends and directions” presentation at the very beginning and this text was in his slide deck on page 4:

Now, we all know that IBM *never* announces “Db2 V14 is coming soon!” But they do talk about Vnext, and it is pretty obvious that this list will stop you migrating from Db2 13 to Db2 14 if any of these items exist or, even worse, are in use at your shop.

What Can You Do?

Well, way back in 2020, I wrote a Migration HealthCheck for Db2 z/OS program as our yearly “give-away” and guess what? It does all the stuff in that list *apart* from VTAM. Not only that, but in the intervening years Audit has grown and grown in importance. Then, in January 2025, DORA came out, for which I wrote another yearly “give-away” called SecurityAudit HealthCheck for Db2 z/OS . This checks everything an auditor would like to have checked, and *also* checks for VTAM/SNA usage in the Communication Database (CDB).

VTAM/SNA??

Cast your mind back about 25 years or so, and you might well remember that TCP/IP was some weird new-fangled way of sending “packets of information” – Not something responsible mainframers did at all! All we had was VTAM/SNA and 3270 with green screens – It was (is!) enough for us!

The Cheque is in the Post …

These days, VTAM/SNA has long overstayed its welcome, as it was a “I trust you” style of communication. The rationale was, “If you have logged onto one Db2 system, I must trust you on any other Db2 system – Who would lie to me?” So, it is not recommended any more and, in fact, with DORA and other Audit requirements it is a *bad* idea to even allow it to be “on its perch” – it must be carried out and buried!

When the B was big!

Back in DB2 V9 (remember when the B was BIG?), IBM brought in the IPNAME “ZPARM” to enable the complete disabling of VTAM/SNA communication in the DDF as it is was known, even way back then, to be an inherent security risk.

Why “ZPARM”?

Well, here is another twist to the story: IBM introduced this like a ZPARM but it is actually a parameter of the DDF and is stored in the Bootstrap Dataset (BSDS). So, run a DSNJU004 and you might see something like this:

LOCATION=xxxxxxxx IPNAME=(NULL) PORT=nnnn SPORT=nnnnn RPORT=nnnn
ALIAS=(NULL)                                                   
IPV4=xxx.xxx.xxx.xxx IPV6=NULL                                    
GRPIPV4=xxx.xxx.xxx.xxx GRPIPV6=NULL                              
LUNAME=xxxxxxxx PASSWORD=(NULL) GENERICLU=(NULL)


Here you can plainly see the IPNAME=(NULL) telling you it is not set and thus allows VTAM/SNA.

When DDF starts, it reports all of its parameters, slightly differently of course just to be awkward, in the xxxxMSTR output:

12.15.25 STC04347  DSNL003I  -xxxx DDF IS STARTING       
12.15.26 STC04347  DSNL004I  -xxxx DDF START COMPLETE 
   605                        LOCATION  xxxxxxxx         
   605                        LU        xxxxxxxx.xxxxxxxx
   605                        GENERICLU -NONE            
   605                        DOMAIN    xxx.xxx.xxx.xxx  
   605                        TCPPORT   nnnn             
   605                        SECPORT   nnnnn            
   605                        RESPORT   nnnn             
   605                        IPNAME    -NONE            
   605                        OPTIONS:                   
   605                         PKGREL = COMMIT

Here VTAM/SNA usage is not disallowed as IPNAME is -NONE. You can also issue the -DIS DDF command on your stand-alone Db2 subsystem or on all members of your Db2 data-sharing group and verify that the output looks like:

DSNL080I  xxxxx DSNLTDDF DISPLAY DDF REPORT FOLLOWS:          
DSNL081I STATUS=STARTD                                        
DSNL082I LOCATION           LUNAME            GENERICLU       
DSNL083I xxxxxxxx           xxxxxxxx.xxxxxxxx -NONE           
DSNL084I TCPPORT=nnnn  SECPORT=nnnnn RESPORT=nnnn  IPNAME=-NONE
DSNL085I IPADDR=::xxx.xxx.xxx.xxx

DSNL084I value IPNAME=-NONE is what you must look for and hopefully *not* find!

Now, in another subsystem, I have IPNAME set so the BSDS print looks like:

LOCATION=xxxxxxxx IPNAME=yyyyyyy PORT=nnnn SPORT=nnnnn RPORT=nnnn
ALIAS=(NULL)                                                    
IPV4=xxx.xxx.xxx.xxx IPV6=NULL                                     
GRPIPV4=xxx.xxx.xxx.xxx GRPIPV6=NULL                               
LUNAME=xxxxxxxx PASSWORD=(NULL) GENERICLU=(NULL)

and when DDF starts it reports:

12.15.36 STC04358  DSNL003I  -xxxx DDF IS STARTING  
12.15.37 STC04358  DSNL004I  -xxxx DDF START COMPLETE
   713                        LOCATION  xxxxxxxx    
   713                        LU        -NONE       
   713                        GENERICLU -NONE       
   713                        DOMAIN    -NONE       
   713                        TCPPORT   nnnn        
   713                        SECPORT   nnnnn       
   713                        RESPORT   nnnn        
   713                        IPNAME    yyyyyyy     
   713                        OPTIONS:              
   713                         PKGREL = COMMIT      
   713                         WLB = DFLT

The IPNAME is set to something and the LU is not set, even though it *is* set in the BSDS – much better!

Again, you can also issue the -DIS DDF command on your stand-alone Db2 subsystem or on all members of your Db2 data-sharing group and verify that the output looks like:

DSNL080I  xxxxx DSNLTDDF DISPLAY DDF REPORT FOLLOWS:               
DSNL081I STATUS=STARTD                                             
DSNL082I LOCATION           LUNAME            GENERICLU         WLB
DSNL083I xxxxxxxx           -NONE             -NONE             DFLT
DSNL084I TCPPORT=nnnn  SECPORT=nnnnn RESPORT=nnnn  IPNAME=yyyyyyy  
DSNL085I IPADDR=::xxx.xxx.xxx.xxx

Now in the DSNL084I the value IPNAME=yyyyyyy is what you must look for and hopefully find!

Delete Delete Delete

The last piece of the VTAM/SNA puzzle, is to clean up your CDB afterwards just to make sure no old and unused, and now completely unusable, definitions are lying around. They annoy auditors and so I would recommend deleting all of the VTAM/SNA definitions that you might still have. Our DORA give-away last year (SecurityAudit HealthCheck) listed all these out for you to do exactly that. It is well worth downloading and running as it is free! Putting it simply, just review, and then delete, all the rows in the tables SYSIBM. LULIST, LUMODES, LUNAMES and MODESELECT.

Hooray!

With these two freebies you can easily check if your systems are:

  1. Db2 Vnext ready
  2. DORA and PCI DSS V4.0.1 Compliant!

Pretty cool for nothing huh?

TTFN

Roy Boxwell

2025-02 It SIEMs good to me!

Hi! Excuse the horrible pun, but the SIEM world has intruded into my quiet COBOL / SQL world over the last month or two quite badly!

SIEM?

You hear it a lot but what exactly is it? It is Security Information and Event Management, hence SIEM. It is a field within computer security that combines Security Information Management (SIM) and Security Event Management (SEM) which enables real-time analysis of security alerts generated by applications and network hardware.

DORA

DORA kicked it all off for me with the EU bringing in brand new laws to make FinTech more resilient against cyber threats which in turn means doing more auditing and testing of the complete infrastructure.

WorkLoadExpert

Now SQL WorkloadExpert for Db2 z/OS (WLX) was designed many many moons ago for performance monitoring and tuning SQLs but over the last five to six years has slowly turned into an auditing tool. Naturally, we collect all the SQL on your machine to do the performance monitoring so this is a very good start for doing audit and test. Then we added more and more IFCID data to finally get the complete audit picture with our WLX Audit for Db2 z/OS.

A bit LEEFy on the Street…

This was all well and good but then of course came the time when the mainframe did not stand alone (At least from the auditor’s point of view!) which meant we had to create a method to transfer the data required for audit from the mainframe down to “the boxes you can carry”. The first way we developed was using the LEEF record format.

LEEF?

The Log Event Extended Format (LEEF) is a customized event format for IBM® Security QRadar®. QRadar can integrate, identify, and process LEEF events. LEEF events must use UTF-8 character encoding. Looking at the EBCDIC native data:

This is OPUT down to USS and then looks like:

Which is then iconv’d into UTF-8 which (after a DISPLAY UTF in browse) looks nearly the same:

The final step, for LEEF processing, was then a GZIP call which dramatically shrinks the size of the file but, of course, is not human readable any more:

CEF?

SPLUNK then came along…I love these names! So, we added the Common Event Format (CEF) to make it work deep down in the caves… That is mentioned in the company profile by the way: From its founding in 2003, Splunk has helped organizations explore the vast depths of their data like spelunkers in a cave (hence, “Splunk”).

LOGger heads?

Then we had some customers who did not want LEEF/CEF format but wanted a “direct to analyze tool” solution using SYSLOGGER and JSON. We then created the SYSLOGGER API which TCP/IP connects directly with your system logger and directly sends the data. Which, in trace mode, looks like this:

A Bit of a Stretch?

What we now have is even more customers asking for a mix of both of these systems. So, a JSON payload but in a flat file that can be directly ingested by Elastic… The things I do!!!

Here’s how the Elastic Common Schema (ECS) data looks when looking at the EBCDIC native data:

Just like LEEF it is then OPUT down to USS and iconv’d to UNICODE so it eventually looks like:

Here with Browse you can see the data again:

JSON Format?

Naturally, you can then ingest it as a JSON file which looks a little like this:

All done?

Probably never! But what SIEM systems are you all using out there? Have you all been “hit by the Audit” bug? I would love to hear your war stories!

TTFN,

Roy Boxwell

2025-01 Compress and Replicate This!

This month, I want to delve into one of those newish, but well-hidden, features of Db2 that arrived some years ago but did not get that much publicity!

Compress Yes!

We all love compression! It saves tons of disk space and, over the years, we even got Index Compression. Yes, I know it is *not* really compression at all – just the leading bytes – but it is better than nothing! We also got better, newer, Table compression algorithms (Looking at you Mr. Huffman!) and we always had the problems of un-compressing data if “we” needed to look at it off-line.

Dictionaries Anymore?

Db2, at least for Tables, uses dictionaries of varying sizes to save “common strings” mapped to small numbers. These dictionaries are pretty obviously only valid for one set of data from one table and/or partition. If you do a REORG after inserting a ton of new data then the new dictionary can be very different from the prior one. Db2 writes the *previous* dictionary to the log and we carry on fine …

Or Do We?

Well, what happens when you wish to read data from the log that was inserted *before* your current dictionary was created? This is, and will always be, a small technical problem! The programs out there now simply crawl back through the Db2 log looking for the compression dictionary that matches to your timescales. This obviously takes time, I/O and CPU!

Online?

Even if the dictionary you are looking for is the current one, accessing it might well cause DBD Locks to happen when it has to be opened, and it can even cause Db2 GBP dependency problems. The fun continues if the logs you need have been archived to tape, of course.

DCC

Data Capture Changes are the keywords here. DCC for the standard TLA. As you are probably aware, setting this at the table level enables Db2 to support data replication using the log. IBM Db2 call their version DataPropagator. The DDL syntax in CREATE/ALTER TABLE is DATA CAPTURE NONE/CHANGES:

DATA CAPTURE Specifies whether the logging of the following actions on the table includes additional information to support data replication processing:

• SQL data change operations

• Adding columns (using the ADD COLUMN clause)

• Changing columns (using the ALTER COLUMN clause)

NONE Do not record additional information to the log. This is the default.

CHANGES Write additional data about SQL updates to the log.

This Changes Everything!

Indeed, it does! DATA CAPTURE CHANGES (DCC and also CDC sometimes!) causes a full row to be logged for every update. If there was an update of just the very last byte of data in a row then it was a tiny log record of basically just that last byte. With DCC you always get the full row. For INSERT and DELETE you always got the full row anyway. Why the change? So that the replication software has it easy! Simple as that!

Side Effects?

There are a few side effects, of course. Mainly, the log size grows as you are logging more data, and any use of the SQL TRUNCATE will behave like a MASS DELETE (so no IGNORE DELETE TRIGGERS or IMMEDIATE options, for example). There are also a few ZPARMs that must all be reviewed and/or changed. Firstly, the ZPARM UTILS_BLOCK_FOR_CDC with options YES/NO and default NO. If set to NO then no utilities are barred from working on these DCC tables. If set to YES then:

  • CHECK DATA with DELETE YES LOG NO
  • LOAD with SHRLEVEL NONE or REFERENCE
  • RECOVER with TOLOGPOINT, TORBA, TOCOPY, TOLASTCOPY, or TOLASTFULLCOPY
  • REORG TABLESPACE with DISCARD
  • REPAIR with LOCATE DELETE

Terminated with Extreme Prejudice!

Will all be terminated. Why, you may wonder? Well, all of these can obviously *flood* the log with rows, millions of rows of data. If using data replication then their usage should be “evaluated” before attempting them – hence the ZPARM. Too many customers shot themselves in the foot with a badly timed LOAD, for example, so we got this “protection” ZPARM. Naturally, it is changeable online, so once you have reviewed the requirement for the utility you can still fire it off, if desired, and then, very quickly, switch back!

More?

Yes, there is always more! ZPARM REORG_DROP_PBG_PARTS with options DISABLE/ENABLE and default DISABLE. If set to ENABLE to allow REORG to drop empty PBG partitions after a successful REORG, and the table within is DCC, then this drop of empty partitions will be ignored! Finally, we have the ZPARM RESTRICT_ALT_COL_FOR_DCC with options YES/NO and default NO. It specifies whether to allow ALTER TABLE ALTER COLUMN for DCC tables. If it is set to YES you will get an SQLCODE -148 if ALTERing a DCC object using any of the options SET DATA TYPE, SET DEFAULT or DROP DEFAULT. Again, this is to stop accidental log and data replication flooding!

Compression Woes

So now you can fully see the quandary! If the rows are all compressed on the log you must access the dictionary to un-compress them on the “other side”, where you do the replication, or just locally if you want to see the data. As mentioned, getting our grubby little hands on the dictionary can cause performance issues so what can we do?

CDDS!

This arrived in Db2 11 for data-sharing people out there with a, and I quote, “GDPS® Continuous Availability with zero data loss environment.” It actually stands for Compression Dictionary Data Set and it brought in a couple of new ZPARMs:

  • CDDS_MODE with options NONE, SOURCE and PROXY and default NONE.
  • CDDS_PREFIX a 1 – 39 Byte z/OS dataset prefix for the VSAM Dataset where the “magic” happens.

VSAM???

Yep you read that right! The CDDS VSAM dataset (CDDS_PREFIX.CDSS) stores up to three versions of the dictionaries that your table/tableparts are using, thus enabling fast, problem-free access to the dictionaries. Naturally, the CDDS must be available to *both* systems – and this is why VSAM was chosen, of course!

Start Me Up!

Some new commands also came in here. -START CDDS instructs all members of a data-sharing group to allocate the CDDS and start using it. -STOP CDDS tells all members to stop using CDDS, close and deallocate it. This must be done before recovering the CDDS, for example.

So???

So now you have a possible way of getting great performance in data replication, but how do you get it all running and how do you review what’s going on? This is where REORG and a new standalone utility DSNJU008 come in.

Reorg Yes But No…

The way to initialize your CDDS is simply to REORG all of your tables/table partitions  with the INITCDDS option. Do not panic! If this option is set to YES it will *not* do a REORG! It will purely externalize the current dictionary and carry on. This means you can use a “generator” SQL statement like this:

SELECT DISTINCT 'REORG TABLESPACE ' CONCAT STRIP(A.DBNAME)
                        CONCAT '.' CONCAT STRIP(A.TSNAME)
                        CONCAT ' INITCDDS YES'
FROM SYSIBM.SYSTABLES A
WHERE A.DATACAPTURE = 'Y'
;

To get all your REORG cards, and then one mass pseudo Reorg later your CDDS is up and running!

Standalone

The DSNJU008 utility can be executed using JCL like this:

//CDDSPRIN EXEC PGM=DSNJU008

//STEPLIB  DD DSN=<Your Db2 exit lib>,DISP=SHR

//         DD DSN=<Your Db2 load lib>,DISP=SHR

//SYSUT1   DD DSN=<Your CDDS prefix>.CDDS,DISP=SHR

//SYSPRINT DD SYSOUT=*

//SYSIN    DD *

LIMIT(9999)

/*

Please refer to the Db2 for z/OS Utilities Guide and Reference for all the details about other keywords, but the interesting factoid is that VERSIONS are stored 1, 2, 3 with 1 being the most recent and the rest going backwards in time.

What Time Was It?

The program outputs everything you could ever wish for about your data sharing systems’ use of compression dictionaries. Including the Dictionary timestamp, which I find very nice as every now and again it really can pay to analyze the data with a new compression test, just to see if you can squeeze any more onto your SSDs!

Why All This Trouble, Again?

The idea behind all of this work is to make using IFCID 306 better, faster and cheaper. It also has a knock-on affect into the “vendor scape”, as lots of vendors offer tooling for data replication or log reading/analysis and they all should now work with this feature enabling you, the DBA, to be more productive at less cost. If their version of REORG/LOAD does *not* handle the CDDS then you must always schedule a new pseudo Reorg with INITCDDS afterwards to handle the VSAM Updates correctly.

Using It?

My question for this month, dear readers, is: Are any of you using this feature or are planning to use it soon?

TTFN

Roy Boxwell

2024-12 Security & Audit Check

Hi all! Welcome to the end-of-year goody that we traditionally hand out to guarantee you have something to celebrate at the end-of-year party! This time, I wish to introduce to you a full vulnerability check of your Db2 for z/OS systems.

DORA!

You should all be aware, and scared, of DORA by now. If not, read my prior newsletter 2024-11 DORA or check out my IDUG presentation or my recorded webinar. Whatever you do, you must get up to speed with DORA as it comes into force on the 17th Jan 2025 which is only one month away from the publishing date of this newsletter!

Not just Born in the USA!

Remember, DORA is valid for the whole wide world, not just businesses within the EU. If you do *any* sort of financial trading within the EU you are under the remit of DORA, just like you are with GDPR! Even if you are not trading within the EU block, doing a full vulnerability check is still a pretty good idea!

PCI DSS V4.0.1

We also now have the Payment Card Industry Data Security Standard (PCI DSS) V4.0.1 going live at the end of March 2025… Coincidence? I don’t think so. Mind you, at least the Americans do not fine anyone who fails!

What are We Offering?

This year, the product is called the SecurityAudit HealthCheck for Db2 z/OS or SAC2 for short. It is a very lightweight and robust tool which basically does all of the CIS Vulnerability checks as published by the Center for Internet Security (CIS) in a document for Db2 13 on z/OS:

CIS IBM Z System Benchmarks (cisecurity.org)

https://www.cisecurity.org/benchmark/ibm_z

This contains everything you should do for audit and vulnerability checking and is well worth a read!

Step-By-Step

First Things First!

The first thing SAC2 does, is evaluate *all* security-relevant ZPARMs and report which ones are not set to a “good” value. It then goes on to check that any default values have not been left at the default value. This especially means the TCP/IP Port number, for example. Then it finishes off by validating that SSL has been switched on for TCP/IP communications and that any and all TCP/IP ALIAS defs also have the correct settings.

Communication is Important!

Next up, is a full evaluation of your Communication Data Base (CDB). This data has been around for decades and started life for SNA and VTAM connections between Host Db2s. These days, SNA is dead and most of the connections are coming from PCs or Servers. That means that there *could* be a lot of dead data in the CDB and, even worse, ways of connecting to your mainframe that you did not even know, or forgot, existed! Think plain text password with SQLID translation for example!

Danger in the Details

Naturally, blindly changing CDB rows is asking for trouble, and if SAC2 finds anything odd/old/suspicious here, you must create a project to start removal. There is a strong correlation between “Oh I can delete that row!” and “Why can’t any of my servers talk to the mainframe anymore?”. The tool points out certain restrictions and pre-reqs that have to be done *before* you hit the big button on the wall! JDBC version for example.

Taking it All for GRANTed?

GRANTs can be the root of all evil! GRANT TO PUBLICs just make auditors cry, and use of WITH GRANT OPTION makes them jump up and down. Even IBM is now aware that blanket GRANTing can be dangerous for your health! SAC2 analyzes *all* GRANTs to make sure that PUBLIC ones are discovered on the Catalog and Directory as these should NEVER be done (with the one tiny exception of, perhaps on a good day when the sun is shining, the SYSIBM.SYSDUMMY1), then further checking all User Data as PUBLIC is just lazy. Checking everything for WITH GRANT OPTION is just making sure you are working with modern security standards!

Fun Stuff!

These days you should be using Trusted Contexts to access from outside the Host. This then requires Roles and all of this needs tamper-proof Audit Policies. On top of all this are the extra bits and pieces of Row Permissions and Column Masks. All of these must be validated for the auditors!

Elevated Users?

Then it lists out the group of privileged User IDs. These all have elevated rights and must all be checked in detail as who has what and why?

Recovery Status Report

Finally, it lists out a full Recovery Status Report so that you can be sure that, at the time of execution, all of your data was Recoverable.

It is a Lot to Process!

It is indeed. The first time you run it, you might well get tens of thousands of lines of output but the important thing is to run it and break it down into little manageable sections that different groups can then work on. This is called “Due Diligence” and can save your firm millions of euros in fines.

Lead Overseer

Great job title, but if this person requests data then you have 30 days to supply everything they request. Not long at all! SAC2 does the lion’s share of the work for you.

Again and Again and Again

Remember, you must re-run this vulnerability check on a regular basis for two major reasons:

  1. Things change – Software, Malware, Attackers, Defenders, Networks, Db2 Releases etc.
  2. Checks get updated – The auditors are alway looking for more!

Stay Out of Trouble!

Register, download, install and run today!

I hope it helps you!

TTFN

Roy Boxwell

Future Updates:

The SAC2 licensed version will be getting upgraded in the first quarter of 2025 to output the results of the run into a Comma Separated File (CSV) to make management reporting and delegation of projects to fix any found problems easier. It will also get System Level Backup (SLB) support added. SLB is good but you *still* need Full Image Copies! Further, it will be enhanced to directly interface with our WLX Audit product.

2024-11 DORA

A title that should strike fear into the hearts of all readers! Nah! I really hope not! This month, I wish to run through the parts of DORA that impact the Db2 for z/OS world mostly…

What is DORA?

Dora is the Digital Operational Resilience Act and it was created on the 14th of December 2022 with an enablement date of 17th January 2025, giving us all over two years to read it, understand it, action the requirements from it, and accept it fully into our computing culture.

How many of those things have you accomplished in the last two years? You mean you had a day job as well?

Not just Born in the USA!

DORA is valid for the whole wide world, not just businesses within the EU. If you do *any* sort of financial trading within the EU you are under the remit of DORA, just like you are with GDPR!

PCI SSC DSS new update!

As well as DORA, there is a “new” version of Payment Card Industry Security Standards Council Data Security Standard 4.0.1. It comes into force on the 31st March 2025 and it contains a lot of overlap with “our” DORA here in the EU! Here’s a link to their website.

What is the Aim of DORA?

The idea is to bring together all the disparate EU regulations into one new regulation for nearly every financial trading house (FINTEC), apart from a few exclusions e.g. microenterprises, thus simplifying the requirements and easing audit and control.

Is it Just a New Level of Audit?

Most definitely not! As the name suggests, Digital Resilience is all about surviving an attack, or a disaster, and being back and processing data (money) as soon as possible. Included within is indeed a bunch of auditable things, but I will get to them later in this newsletter.

What does DORA Cover then?

Security, Operations, Recoverability and Test. Not only these, but these are, at least for me, the biggies. The last of them – Test – is incredibly important in what they mean by “Test”. They mean Performance Test, Reliability Test and Vulnerability Test. These are not all new for us but some are. We all remember GDPR and friends, where types of data had to be “respected” otherwise you got a hefty fine. Now, with DORA, the way you work, run, update and check your systems must all be proven and reported. If you do not deliver you get – guess what? – hefty fines!

Who’s the Boss?

You might have read about this, or seen a presentation, but the absolute “boss” for this regulation is the English PDF version here:

All other versions are translated and so may have errors.

Just the Facts, Ma’am

Well, no, I am not actually going to list all the facts of DORA here, but the highlights for me are the following opening paragraphs:

46 Mandates vulnerability testing

48 Maintained systems (Current release/PTF/APAR etc.)

49 & 50 Recoverability and RTO

56 Performance, Testing and Scanning

This is a brave new world for lots of us! One of the buzzwords is ICT which is basically IT.

Book, Chapter and Verse

Chapter 2 Section II Article 6 ICT risk management framework Paragraphs 2, 4 & 6

This is all about risk management and covers unauthorized access, segregation of duties and regular internal audits.

Chapter 2 Section II Article 8 Identification Paragraphs 1, 3 & 7

Hammers home the requirement for regular updates and risk assessments after major changes.

Chapter 2 Section II Article 9 Protection and prevention Paragraphs 1, 2, 3 & 4

This is pure audit: Monitor continuously what is happening, get tooling and policies in place. Make sure that all data is secure at rest, in use and in transit. Validate authenticity and guarantee strong authentication.

This is the most important part for me – It means encrypt at rest, use SSL for *all* things remote, do not use technical user ids with passwords, use Certificates and/or use Trusted Contexts and implement at least MFA for all users. The “in use” part is a bit crazy, especially for Db2, but I am pretty sure that the Bufferpool is “trusted” and so we, as z/OS users, can ignore this part for now…

Chapter 2 Section II Article 10 Detection Paragraphs 1 & 3

Detect whether weird stuff is happening and monitor user activity!

Chapter 2 Section II Article 11 Response and recovery Paragraphs 1 & 3

Make sure you have the ability to recover quickly, and in a timely manner, making sure you have response and recovery plans all ironed out.

Chapter 2 Section II Article 12 Backup policies Paragraphs 1 & 2

Guarantee that your image copies are enough and available to minimize downtime and limit disruption. These must be regularly tested!

Chapter 4 Article 24 Testing Paragraphs 1 & 2

Test! Test and test again – at least yearly!

Chapter 4 Article 25 Testing of ICT tools and systems Paragraphs 1 & 2

Performance Testing, Penetration Testing and Vulnerability Testing.

Chapter 4 Article 26 Advanced testing and TLPT Paragraphs 1, 2 & 6

More advanced testing including a Thread-Led Penetration Test on live production systems at least every three years! All must be documented of course…

Chapter 5 Article 35 Powers of the Lead Overseer Paragraphs 1, 6, 7 & 8

Lead Overseer – I get this mixed up with Supreme Leader all the time…

The Lead Overseer is the DORA God in a given country and can simply ask for any of the details I have just listed. Failure to deliver the goods within 30 days (Calendar days, not working days!) will result in fines…

I am Fine!

Well, the fines are pretty nasty… The Lead Overseer can fine any firm up to 1% of the average daily turnover from the previous financial year. This is then compounded by the fact that the Lead Overseer can levy this fine *every* day for up to six months!!! Ouch!!!

An Example Calculation

Taking a large bank as an example, just to show the math. The turnover in 2023 was nearly 60 billion euros. Divided by 365 gives us 164 million euros per day. Taking 1% of this (worst case) gives 1.64 million euros. Assuming the Lead Overseer is being especially nasty and levels the fines for 182 days leads to around 298 million euros in fines.

I, for one, do *not* want to be the first firm in Europe getting this… and it is all in the public domain which is then a massive image loss as well!

What can I do?

Well, first up, make sure all data is encrypted at rest – This should be a no-brainer due to modern disks/SSDs anyway.

Then, make sure that *all* remote access is using the SECPORT and is being encrypted in flight – again, this should be easy but remember to then set the PORT to be the same as the SECPORT which then forces all of this. Do not forget to check your TCP/IP ALIASs!

Do a full recoverability test to guarantee that you have all the Image Copies, Logs, Archive logs that you require to actually do a full recovery. If you can also meet your RTOs here then even better! Here our RealTime DBAExpert (RTDX) software can really help out, with timely Image Copies and a verification of complete recoverability.

Audit your Db2 Systems!

Do a Vulnerability Test on your Db2 Systems!

Audit?

I have done a lot of blogs and Webinars just about Audit, so I will spare you the details, but you must actually get it done. You will almost certainly require an external auditor who does a final check/validation that your audit is good to go and then you are done. Here, our excellent WLX Audit product can suddenly become your best friend!!!

Feeling Vulnerable Today?

The Center for Internet Security (CIS) has released a document for Db2 13 on z/OS:
CIS IBM Z System Benchmarks

It contains everything you should do for Audit and vulnerability checking and is well worth a read and then action the reports within.

Docu Docu Docu

All of these things must be performed, documented and repeated on a regular basis and sometimes even after a simple “change” has occurred.

The world is a bad place and DORA is here to help us really, but the start will, as always, be a hard climb!

TTFN,

Roy Boxwell

2024-10 Soundex and other cool features part eight(!) for Db2 z/OS 12 and 13

In this, obviously, never ending series of new features, I will roll up all the new ones since my “SOUNDEX and other „cool“ features – Part seven All new for Db2 12” newsletter from 2021-05.

Starting with Db2 12 – PTFs first

APAR PH36071 added support for the SUBSTR_COMPATIBILITY ZPARM parameter with default PREVIOUS and other valid value CURRENT. In Db2 12 FL500 and above, with this APAR applied and the value set to CURRENT, then the SUBSTR Built-in Function (BiF) will return an error message for invalid input.

APAR PH42524 added MULTIPLY_ALT support to the IBM Db2 Analytics Accelerator (IDAA).

APAR PH47187 added support for UNI_90 locale in the LOWER, TRANSLATE and UPPER BiFs.

APAR PH48480 added LISTAGG and RAND to the IDAA offload support. Note: you must enter YES in ENABLE ACCELERATOR SPECIFIC RESULTS field on panel DSNTIPBA to get this boost.

Db2 12 FL 100

Yes, they introduced a new BiF for this level way after I wrote my last newsletter all about BiFs and Functions. The new BiF is the BLOCKING_THREADS table function. This is very handy when DBAs are about to start doing DDL work. Adding or ALTERing a Column or what have you! The output is a table about who is blocking access to the database in question and can really save a massive amount of work if you can check *before* you do all your ALTERs that you can indeed succeed in getting them all done!

Now Db2 13 – PTFs first

APAR PH47187 added support for UNI_90 locale in the LOWER, TRANSLATE and UPPER built-in functions (BiFs).

APAR PH48480 added LISTAGG and RAND to the IBM Db2 Analytics Accelerator (IDAA) offload support. Remember, you must enter YES in ENABLE ACCELERATOR SPECIFIC RESULTS field on panel DSNTIPBA.

APAR PH51892 introduced vector prefetch for SQL Data Insights and improves the BiF AI_SEMANTIC_CLUSTER. You must also go to Db2 13 FL504.

APAR PH55212 enhanced SQL Data Insights and added support of numeric data types to the BiF AI_ANALOGY.

Db2 13 FL500

This was the release that introduced the Db2 SQL Data Insights with the new BiFs AI_ANALOGY, AI_SEMANTIC_CLUSTER and AI_SIMILARITY.

Db2 13 FL504

A new AI BiF: AI_COMMONALITY was released and when you use LISTAGG you can now add an ORDER BY to the full select.

Db2 13 FL505

Another new BiF: INTERPRET which can change nearly any argument to nearly any other data type. The most useful thing you can do with it is something like:

INTERPRET(BX'0000000000B0370D' AS BIGINT)    --     11548429

So this is taking a hex RID and interpreting it as a BIGINT. This is very useful when you get RID problems with the LOAD utility, for example. You can then simply plug in the BIGINT value into a query like:

SELECT * FROM TABLE1 A WHERE RID(A) = 11548429;

And then you’ll find the bad guy(s) very easily!

Naturally, I will be keeping this newsletter up-to-date, as necessary.

Any questions or ideas, do not hesitate to drop me a line,

TTFN,

Roy Boxwell

2024-09 CREATOR conumdrum

This month I wish to “rake over” some hot coals from yesteryear…

The good ol’ days!

Remember when we had just eight-byte CREATORs ? Prior to the “big bang” DB2 V8 all the creators and table names were limited to eight and eighteen bytes respectively. This was then changed in DB2 V8 to both be VARCHAR(128). So far so good!

And?

What went wrong was the way IBM development handled the SYSIBM creator…

Why is this a problem?

Well if you are writing SQL to access the Db2 Catalog and you wish to use wild cards, E.g. % or _, then you must start taking care of your predicate texts!

Here are some examples of SQL that should do the same thing, but don’t!

Baseline counts

First, here’s a little SQL to simply show us some numbers:

SELECT COUNT(*), CREATOR
FROM SYSIBM.SYSINDEXES
WHERE (CREATOR LIKE 'SYSIB_'
OR CREATOR LIKE 'SYSIBM_'
OR CREATOR LIKE 'SYSIBM _'
OR CREATOR LIKE 'SYSIB%'
OR CREATOR LIKE 'SYSIBM%'
OR CREATOR LIKE 'SYSIBM %')
AND NOT CREATOR = 'SYSIBMTS'
GROUP BY CREATOR
FOR FETCH ONLY
WITH UR
;

When I run this in my Db2 13 system I get this result:

---------+---------+---------+---------
CREATOR
---------+---------+---------+---------
317 SYSIBM
DSNE610I NUMBER OF ROWS DISPLAYED IS 1

and??

Now comes the interesting bit…

Here are six SQLs all nearly the same but look at the COUNT values.

SELECT COUNT(*)                         
FROM SYSIBM.SYSINDEXES
WHERE CREATOR LIKE 'SYSIB_'
AND NOT CREATOR = 'SYSIBMTS'
FOR FETCH ONLY
WITH UR
;
---------+---------+---------+---------+

---------+---------+---------+---------+
187
DSNE610I NUMBER OF ROWS DISPLAYED IS 1


SELECT COUNT(*)
FROM SYSIBM.SYSINDEXES
WHERE CREATOR LIKE 'SYSIBM_'
AND NOT CREATOR = 'SYSIBMTS'
FOR FETCH ONLY
WITH UR
;
---------+---------+---------+---------+

---------+---------+---------+---------+
0
DSNE610I NUMBER OF ROWS DISPLAYED IS 1


SELECT COUNT(*)
FROM SYSIBM.SYSINDEXES
WHERE CREATOR LIKE 'SYSIBM _'
AND NOT CREATOR = 'SYSIBMTS'
FOR FETCH ONLY
WITH UR
;
---------+---------+---------+---------+

---------+---------+---------+---------+
130
DSNE610I NUMBER OF ROWS DISPLAYED IS 1


SELECT COUNT(*)
FROM SYSIBM.SYSINDEXES
WHERE CREATOR LIKE 'SYSIB%'
AND NOT CREATOR = 'SYSIBMTS'
FOR FETCH ONLY
WITH UR
;
---------+---------+---------+---------+

---------+---------+---------+---------+
317
DSNE610I NUMBER OF ROWS DISPLAYED IS 1


SELECT COUNT(*)
FROM SYSIBM.SYSINDEXES
WHERE CREATOR LIKE 'SYSIBM%'
AND NOT CREATOR = 'SYSIBMTS'
FOR FETCH ONLY
WITH UR
;
---------+---------+---------+---------+

---------+---------+---------+---------+
317
DSNE610I NUMBER OF ROWS DISPLAYED IS 1


SELECT COUNT(*)
FROM SYSIBM.SYSINDEXES
WHERE CREATOR LIKE 'SYSIBM %'
AND NOT CREATOR = 'SYSIBMTS'
FOR FETCH ONLY
WITH UR
;
---------+---------+---------+---------+

---------+---------+---------+---------+
130
DSNE610I NUMBER OF ROWS DISPLAYED IS 1

You see the difference? The reason is clear as “some” of the SYSIBM creators, 130 in this example, got the varchar length of *eight* when the change to V8 happened. However, 187 got the correct length of six.

This is normally never seen of course as it is SYSIBM stuff but if you write SQL against the catalog and you are using host variables then be careful when predicates use the CREATOR!

The same results come from Static SQL of course.

Is there a fix?

Now in SQL you can fix this by either adding a STRIP around the CREATOR -> WHERE STRIP(CREATOR) LIKE = :HOST-VAR or you can “cheat” by *not* using a VARCHAR host variable and then the trailing two spaces and the extra two bytes in the length are then “ignored” by predicate processing.

Which one to do?

You gotta CHEAT! Why? because STRIP is a non-indexable function! If the tables are very small probably ok but for normal ones a very bad idea!!!

Just for fun!

Here’s some “discovery” SQL that builds a bunch of SELECT statements that you can then simply run in SPUFI. Take the output and then, after deleting the generator output SQL, the last sets of SPUFI output and adding at the front the

--#SET TERMINATOR $

Plus adding the

--#SET TERMINATOR ;

at the end – Just for good style! – You can then also execute it in SPUFI.

DECLARE GLOBAL TEMPORARY TABLE T (LINENO INTEGER NOT NULL)      
;
-- INSERT SIX LINES
INSERT INTO SESSION.T VALUES 1
;
INSERT INTO SESSION.T VALUES 2
;
INSERT INTO SESSION.T VALUES 3
;
INSERT INTO SESSION.T VALUES 4
;
INSERT INTO SESSION.T VALUES 5
;
INSERT INTO SESSION.T VALUES 6
;
SELECT CASE LINENO
WHEN 1 THEN 'SELECT DISTINCT SUBSTR(' CONCAT SUBSTR(NAME, 1, 18)
CONCAT ' , 1 , 8) AS CREATOR '
WHEN 2 THEN ' ,LENGTH(' CONCAT SUBSTR(NAME, 1, 18)
CONCAT ') AS LEN'
WHEN 3 THEN 'FROM SYSIBM.' CONCAT SUBSTR(TBNAME , 1, 18)
WHEN 4 THEN 'WHERE '
CONCAT SUBSTR(NAME, 1, 18) CONCAT ' LIKE ''SYSIBM%'' '
WHEN 5 THEN 'AND NOT '
CONCAT SUBSTR(NAME, 1, 18) CONCAT ' = ''SYSIBMTS'' '
WHEN 6 THEN ' $'
END
FROM SYSIBM.SYSCOLUMNS
,SESSION.T
WHERE NAME LIKE '%CREATOR%'
AND TBCREATOR = 'SYSIBM'
AND COLTYPE = 'VARCHAR'
ORDER BY TBCREATOR
,TBNAME
,NAME
,LINENO
FOR FETCH ONLY
WITH UR
;

My output, after I have edited the start, looks like this:

EDIT       BOXWELL.SPUFI.IN(AAA1) - 01.07                          Co
Command ===>
****** ********************************* Top of Data ****************
000001 --#SET TERMINATOR $
000002 SELECT DISTINCT SUBSTR(CREATOR , 1 , 8) AS CREATOR
000003 ,LENGTH(CREATOR ) AS LEN
000004 FROM SYSIBM.DSNPROGAUTH
000005 WHERE CREATOR LIKE 'SYSIBM%'
000006 AND NOT CREATOR = 'SYSIBMTS'
000007 $
000008 SELECT DISTINCT SUBSTR(CREATOR , 1 , 8) AS CREATOR
000009 ,LENGTH(CREATOR ) AS LEN
000010 FROM SYSIBM.SYSCHECKS
000011 WHERE CREATOR LIKE 'SYSIBM%'
000012 AND NOT CREATOR = 'SYSIBMTS'
000013 $
000014 SELECT DISTINCT SUBSTR(CREATOR , 1 , 8) AS CREATOR
000015 ,LENGTH(CREATOR ) AS LEN
000016 FROM SYSIBM.SYSCOLAUTH
000017 WHERE CREATOR LIKE 'SYSIBM%'
000018 AND NOT CREATOR = 'SYSIBMTS'
000019 $
.
.
.

When you then run this, you will get a nice list of all tables with either zero, one or two rows of output. The ones with two rows are the dodgy CREATOR lengths! Here’s one from my system:

SELECT DISTINCT SUBSTR(TBCREATOR          , 1 , 8) AS CREATOR
,LENGTH(TBCREATOR ) AS LEN
FROM SYSIBM.SYSCOLUMNS
WHERE TBCREATOR LIKE 'SYSIBM%'
AND NOT TBCREATOR = 'SYSIBMTS'
$
---------+---------+---------+---------+---------+---------+-
CREATOR LEN
---------+---------+---------+---------+---------+---------+-
SYSIBM 6
SYSIBM 8
DSNE610I NUMBER OF ROWS DISPLAYED IS 2

TTFN

Roy Boxwell

2024-08 BSDS What is actually in it?

I have been asked on numerous occasions where in the wide, wide world of Db2 does it store the sizes and settings of buffer pools and group buffer pools?

Survivability

Naturally, these things must survive a Db2 stop/start and also an IPL – so where do they live?

Buried in the IBM Db2 documentation is one place where it just mentions that buffer pool data is stored in the BSDS. In fact, under ALTER BUFFERPOOL, is this text:

Altering buffer pools

Last Updated: 2024-05-14

Db2 stores buffer pool attributes in the Db2 bootstrap data set (BSDS). You can change buffer pool attributes.

IBM Db2 ALTER Command

Just the Facts, Ma’am

OK, as you are all aware, a DSNJU004 print log map shows this BSDS data:

  • The data set name (DSN) of the BSDS.
  • The system date and time (SYSTEM TIMESTAMP), and the date and time that the BSDS was last changed by the change log inventory utility (UTILITY TIMESTAMP).
  • The ICF catalog name that is associated with the BSDS.
  • The highest-written RBA. The value is updated each time the log buffers are physically written to disk.
  • The highest RBA that was offloaded.
  • Log RBA ranges (STARTRBA and ENDRBA), and data set information for active and archive log data sets. The last active log data set that is listed in the output is the current active log.
  • Information about each active log data set.
  • Information about each archive log data set.
  • Conditional restart control records.
  • The contents of the checkpoint description queue.
  • Archive log command history.
  • The distributed data facility (DDF) communication record. This record contains the location name as defined by Db2, any alias names for the location name, and the LU name as defined by VTAM. Db2 uses this information to establish the distributed database environment.
  • The tokens for all BACKUP SYSTEM utility records.
  • The ENFM START RBA/LRSN field contains one of the following values:
    • In a non-data sharing environment, the RBA when the most recent enabling-new-function mode job started on the subsystem

    • In a data sharing environment, the LRSN when the most recent enabling-new-function mode job started on a member
  • Information about members of a data sharing group, including deactivated members and destroyed members whose slots were reclaimed.

You may have noticed that in this list the BPs and GBPs are noticeably(!) absent!

Pulled up with Your Own Bootstraps!

Now the BSDS is arguably the most important dataset for Db2 as it literally “pulls itself up with its own bootstraps” – hence the name. It is a simple VSAM dataset with a four-byte key that you can browse while Db2 is up and running or, if you are worried, just REPRO it to a flat file like this:         

//*
//* REPRO VSAM OVER                                     
//*                                                      
//REPRO    EXEC PGM=IDCAMS                              
//SYSPRINT DD SYSOUT=*                                  
//INDD     DD DISP=SHR,DSN=my.db2.BSDS01                 
//OUTDD    DD DISP=(,CATLG,DELETE),DSN=my.flat.file,    
//            SPACE=(CYL,(5,5),RLSE),                   
//            DCB=(LRECL=8192,RECFM=VB)                 
//SYSIN    DD *                                         
 REPRO INFILE(INDD) OUTFILE(OUTDD)                      
/*  

Hidden Secrets

IBM have, to my knowledge, never documented the internal structure of the BSDS – and why should they? It is really just for Db2 internal use, but I love to figure things out. So, I REPRO’d a non-data sharing and a data sharing BSDS and ran the DSNJU004 and just looked for stuff in the BSDS that is not output by the utility.

Differences Aplenty!

What you notice, is that there are quite a few bits of data not externalized, for whatever reason. The aforementioned buffer pools and group buffer pools, of course, and then the full list of DDF ALIASes, and also what I guess are a whole bunch of “recent log checkpoints” but I am not 100% sure and just ignored them!

ISPF F is Your Friend

You can page on down through or you can just do a “F WPAR” as in all my systems this was there and so I guess it is an eyecatcher of sorts! The VSAM key is x’0A000001’ and the start looks like:

Buffer Pool ID

Remember that internally, Db2 uses buffer pool ids to map the buffer pools. These numbers are *not* consecutive or in order for historical and, perhaps, even future growth reasons. Here’s a handy little cross reference table:

Buffer pool IDBuffer pool sizeBuffer pool name
0 – 494KBP0 – BP49
80 – 8932KBP32K – BP32K9
100 – 1098KBP8K0 – BP8K9
120 – 12916KBP16K0 – BP16K9

It is HEX Time!

Then at position 60, the data blocks begin with 32 bytes for each Bufferpool. Here is Buffer pool id 0 (BP0):

You can see that we have x’00004E20’ pages – 20,000 and also x’000007D0’ – 2000 simulated pages. The rest of the data is thresholds etc. This then repeats for all buffers out to the right.

And Now in Human-Readable Form

Here’s a -DISPLAY BUFFERPOOL(BP0) for comparison:

DSNB401I  -DD10 BUFFERPOOL NAME BP0, BUFFERPOOL ID 0, USE COUNT 751
DSNB402I  -DD10 BUFFER POOL SIZE = 20000 BUFFERS  AUTOSIZE = NO    
            VPSIZE MINIMUM  =         0  VPSIZE MAXIMUM  =         0
            ALLOCATED       =     20000  TO BE DELETED   =         0
            IN-USE/UPDATED  =       355  OVERFLOW ALLOC  =         0
DSNB431I  -DD10 SIMULATED BUFFER POOL SIZE = 2000 BUFFERS -        
            ALLOCATED       =      2000                            
            IN-USE          =      1988  HIGH IN-USE     =      2000
            SEQ-IN-USE      =      1495  HIGH SEQ-IN-USE =      1734
DSNB406I  -DD10 PGFIX ATTRIBUTE -                                  
             CURRENT = NO                                          
             PENDING = NO                                           
           PAGE STEALING METHOD -                                  
             CURRENT = LRU                                         
             PENDING = LRU                                         
DSNB404I  -DD10 THRESHOLDS -                                       
            VP SEQUENTIAL    = 80   SP SEQUENTIAL   = 80           
            DEFERRED WRITE   = 30   VERTICAL DEFERRED WRT  =  5,  0
            PARALLEL SEQUENTIAL =50   ASSISTING PARALLEL SEQT=  0   
DSNB546I  -DD10 PREFERRED FRAME SIZE 4K                            
        20000 BUFFERS USING 4K FRAME SIZE ALLOCATED                
DSN9022I  -DD10 DSNB1CMD '-DISPLAY BUFFERPOOL' NORMAL COMPLETION

Data-Sharing?

If you have data-sharing then you get some bonus lines in the BSDS:

As you can see, it lists out one line per GBP. Note how the VSAM Key is now x’0A0001nn’ where nn is the buffer pool id in hexadecimal. Remember: 0 – 49, 80 – 89, 100 – 109 and 120 – 129.

Now, Again, in Human-Readable Form

Here’s the -DISPLAY GROUPBUFFERPOOL output for comparison:

DSNB750I  -SD10 DISPLAY FOR GROUP BUFFER POOL GBP0 FOLLOWS
DSNB755I  -SD10 DB2 GROUP BUFFER POOL STATUS                       
             CONNECTED                                 = YES       
             CURRENT DIRECTORY TO DATA RATIO           = 10        
             PENDING DIRECTORY TO DATA RATIO           = 10        
             CURRENT GBPCACHE ATTRIBUTE                = YES       
             PENDING GBPCACHE ATTRIBUTE                = YES       
DSNB756I  -SD10   CLASS CASTOUT THRESHOLD                   = 5, 0 
             GROUP BUFFER POOL CASTOUT THRESHOLD       = 30%       
             GROUP BUFFER POOL CHECKPOINT INTERVAL     = 4 MINUTES 
             RECOVERY STATUS                           = NORMAL    
             AUTOMATIC RECOVERY                        = Y         
DSNB757I  -SD10 MVS CFRM POLICY STATUS FOR GSD10C11_GBP0    = NORMAL
             MAX SIZE INDICATED IN POLICY              = 24576 KB  
             DUPLEX INDICATOR IN POLICY                = DISABLED  
             CURRENT DUPLEXING MODE                    = SIMPLEX   
             ALLOCATED                                 = YES       
DSNB758I  -SD10     ALLOCATED SIZE                          = 16384
KB                                                                 
               VOLATILITY STATUS                       = VOLATILE  
               REBUILD STATUS                          = NONE      
               CFNAME                                  = CFSEG1    
               CFLEVEL - OPERATIONAL                   = 17        
               CFLEVEL - ACTUAL                        = 25        
DSNB759I  -SD10     NUMBER OF DIRECTORY ENTRIES             = 15964
               NUMBER OF DATA PAGES                    = 1595      
               NUMBER OF CONNECTIONS                   = 1         
DSNB798I  -SD10 LAST GROUP BUFFER POOL CHECKPOINT                  
                                          09:14:08 MAY 22, 2024    
             GBP CHECKPOINT RECOVERY LRSN              =           
00DF215E8A4B743F0000                                               
             STRUCTURE OWNER                           = MEMSD10   
DSNB790I  -SD10 DISPLAY FOR GROUP BUFFER POOL GBP0 IS COMPLETE     
DSN9022I  -SD10 DSNB1CMD '-DIS GROUPBUFFERPOOL' NORMAL COMPLETION

One interesting bit of info here is the DSNB758I message. Notice the CFLEVEL fields? The OPERATIONAL appears to be “stuck” at 17 as we are on a z16 using ACTUAL 25 and getting the new, in CFLEVEL 25, statistics so OPERATIONAL *should* be 25 as well!

What About the ALIAS?

The final piece is the strange case of the DDF ALIAS definition. If you simply create a DDF ALIAS it is, by definition, disabled until you complete the process. While it is in this state the DSNJU004 output just lists:

Elvis is Dead?

But in the BSDS you actually see:

And then on the same line to the right:

These were two test ALIASes I created for our SAX DBAT support.

Human-Readable Version Again

The SAX DBAT support records all the data from your DDF with the aim to show/warn you if you start running out of DBATs. It shows you all your DDF data like this:

Zooming In!

Primary cmd A for Alias:

So here you see that there are indeed two ALIASes but both are in STOPD status.

I presume that until “enabled” they are “not interesting” for DDF use … In fact, even with STATUS STARTD, I cannot find the data in the utility output…

That’s All, Folks!

These are the little nuggets I have found in the BSDS that I think are pretty interesting really, but for whatever reason IBM do not externalize them. I would hazard a guess, that this data may change at any given time and it is therefore not documented anywhere for “safety” reasons!

Aha!

Do you think it warrants an Aha idea to update the DSNJU004 to actually output the BPs, GBPs and ALIASes?

As usual I would love to hear what you think!

TTFN

Roy Boxwell

2024-07 One size fits all?

A really brief blog this month, as I found something out while playing with buffer pool tuning (I have no hobbies!)

Buffer Pools …

There has been a long debate down the years about buffer pool management. How big should they be? How many should you have? Which parameters for which type? And so on. I have written numerous blogs, held IDUG Presentations and discussed myriad times with colleagues and customers about this topic.

Something New???

I found something new! Well, new to me anyways!!!

There was a trend a few years ago, called “big memory” where people were encouraged to recombine many data-sharing members downwards so you went from a 14 way to eight way or six way to four way. This was then backed up with more DBATs and expanded buffer pools. The argument was pretty convincing: Let Db2 do the magic!

Too Much Work!

You, as a puny human, have no chance of really knowing what is going on. So just splitting the buffer pools at the highest possible level is all you can actually reasonably do! The argument went that it is easiest to go for around 9 – 10 buffer pools.

DISPLAY GROUPBUFFERPOOL Done on a Regular Basis?

Of course you do!!!

What I found out recently, is the ominous counter in message DSNB415I titled “PREFETCH DISABLED NO READ ENGINE”. Nowadays, each Db2 subsystem/member of a datasharing system has 900 read engines but before, it was split out in 14 or eight sub-systems and is now being used in far fewer.

Zero Counter No More!

This counter was *always* zero whenever and wherever I checked, until last week… Now I see PREFETCH DISABLED NO READ ENGINE on a regular basis. There is a great blog from Robert Catterall.

In the environments I am looking at, they also have PREFETCH DISABLED NO BUFFER occurrences and well over 100 I/Os /second, so it does indeed mean trouble!

Time to Tune!

All you can do here is:

  • Check your VPSEQT and see if you can nudge it up a bit.
  • Throw some memory at the problem by increasing the VPSIZE and hope that the requested pages are then found in the buffer pool.
  • Move smaller objects into PGSTEAL(NONE) buffer pools thus requiring no PREFETCH.
  • As a last gasp, try and tune the SQL to not use PREFETCH as a method – very tricky of course!

Keep on Truckin’

But let’s be honest for a minute, if you have 900 read engines all humming along then your system is really running under pressure and you should *expect* to get this counter, I guess!

As Robert says: No need to panic!

TTFN,

Roy Boxwell

2024-06 Time for a change?

This month I wish to share an interesting voyage of discovery to do with TIMESTAMP calculations.

How Interesting …

It all started decades ago, when I wanted to find out how many microseconds there were between two timestamps. A simple idea for a trace in various programs which, when analyzed, could highlight problematic code paths.

Use DISPLAY Stupid!

Just DISPLAY the current timestamp at the start of each SECTION. The trace analysis program would then simply subtract two timestamps – et Voila! You have a difference!

Nope … That Fails

Well, I found out very quickly that math on TIMESTAMPs does *not* work like that! What you actually get is a “duration” which, in my humble opinion, is worthless! Here’s an example:

SELECT TIMESTAMP('2023-12-21-15.06.40.120234') -
       TIMESTAMP('2023-12-21-15.06.40.120034') 
FROM SYSIBM.SYSDUMMY1  ;                       
---------+---------+---------+---------+--------
---------+---------+---------+---------+--------
           .000200

Looks good doesn’t it? Exactly 200 microseconds – as it should be.

Now look at this example:

SELECT TIMESTAMP('2023-12-21-15.06.41.120234') -
       TIMESTAMP('2023-10-22-17.08.55.130234') 
FROM SYSIBM.SYSDUMMY1  ;                        
---------+---------+---------+---------+--------
---------+---------+---------+---------+--------
  129215745.990000

What?

Yep, what the calculation does is really “subtract”… What you get is a decimal 14 containing the YYYY (leading zeroes blanked of course!) years, MM months, DD days HHMMSS then a decimal point and then your usual six digits for microseconds.

Not Good!

This, for me, was not actually usable! So, what I did, was then extract all the fields multiplying by the different values and adding them all together to get a SECONDS field. This gave me what I wanted but was a bit messy.

Months?

Whoever dreamed up the western calendar obviously was not a programmer! 31, 30, 28 sometimes 29 days in a month but then not always… The days in month has been, and always will be, a real PITA. However, IBM Db2 has a nice Built-in Function (BiF) called DAYS (not DAY – That just extracts the day portion of the calendar!)

DAYS ( expression ) – The result is 1 more than the number of days from January 1, 0001 to D, where D is the date that would occur if the DATE function were applied to the argument.

All in UTC and this is *very* handy as it bypasses the days-in-the-month problem completely!

Armed with this it made the COBOL code simpler and better.

TIMESTAMPDIFF to the Rescue!

Then in Db2 V8 came a new BiF – TIMESTAMPDIFF – will it be our savior?

When it was announced I thought: Wow! This is great – it will do all the work for me – just tell it what you want as output and give it two timestamps and you are done!

TIMESTAMPDIFF( numeric-expression, string-expression)

Not Really …

The problem is in the first sentence of the docu that most people do not bother to read:

The TIMESTAMPDIFF function returns an estimated number of intervals of the type that is defined by the first argument, based on the difference between two timestamps.

Seconds is Good?

Naturally, I used 2 (to get seconds) as the numeric-expression and, to begin with, was a happy bunny with the results.

Guestimate?

Then I noticed that all was not well in the world of TIMSTAMPDIFF and that the “estimated” number can be difficult to judge! The problem gets clearer when you review the “assumptions” list at the end of the docu:

The following assumptions are used in estimating a difference:

  • One year has 365 days
  • One year has 52 weeks
  • One year has 12 months
  • One month has 30 days
  • One day has 24 hours
  • One hour has 60 minutes
  • One minute has 60 seconds

Now we all know that this is not true… Not all years have 365 days or even 52 weeks and nearly all months do not have 30 days! Now in my trace program it was just a bit irritating, but if you are using TIMESTAMPDIFF believing you really get the number of DAYS between two dates then it is time to think again!

Seeing is Believing

Here’s an example showing where it first works fine and then one day earlier and it all goes astray:

SELECT                                                              
 TIMESTAMPDIFF( 2, CHAR(TIMESTAMP('2023-12-21-00.00.01') -          
                        TIMESTAMP('2023-10-22-00.00.01')))  AS TSDIFF
,           DAYS(       TIMESTAMP('2023-12-21-00.00.01')) -         
            DAYS(       TIMESTAMP('2023-10-22-00.00.01'))   AS DAYS 
FROM SYSIBM.SYSDUMMY1  ;                                            
---------+---------+---------+---------+---------+---------+---------
     TSDIFF         DAYS                                             
---------+---------+---------+---------+---------+---------+---------
    5184000           60                                             
DSNE610I NUMBER OF ROWS DISPLAYED IS 1                              
SELECT                                                              
 TIMESTAMPDIFF( 2, CHAR(TIMESTAMP('2023-12-21-00.00.01') -          
                        TIMESTAMP('2023-10-21-00.00.01')))  AS TSDIFF
,           DAYS(       TIMESTAMP('2023-12-21-00.00.01')) -         
            DAYS(       TIMESTAMP('2023-10-21-00.00.01'))   AS DAYS 
FROM SYSIBM.SYSDUMMY1  ;                                            
---------+---------+---------+---------+---------+---------+---------
     TSDIFF         DAYS                                            
---------+---------+---------+---------+---------+---------+---------
    5184000           61                                            
DSNE610I NUMBER OF ROWS DISPLAYED IS 1

 As you can easily see, the day has changed by one but the TSDIFF has not…Not good! The problem is naturally caused by going over some internal threshold. If you do not care about accuracy, it is fine.

I Do!

So, what I have done is write my own “timestampdiff” in SQL:

SELECT                                                              
       MIDNIGHT_SECONDS(TIMESTAMP('2023-12-21-00.00.01')) -         
       MIDNIGHT_SECONDS(TIMESTAMP('2023-10-22-00.00.01'))           
      + ( 86400 * (DAYS(TIMESTAMP('2023-12-21-00.00.01')) -         
                   DAYS(TIMESTAMP('2023-10-22-00.00.01')))) AS DIFF 
,TIMESTAMPDIFF( 2, CHAR(TIMESTAMP('2023-12-21-00.00.01') -          
                        TIMESTAMP('2023-10-22-00.00.01')))  AS TSDIFF
,           DAYS(       TIMESTAMP('2023-12-21-00.00.01')) -         
            DAYS(       TIMESTAMP('2023-10-22-00.00.01'))   AS DAYS 
FROM SYSIBM.SYSDUMMY1  ;                                            
---------+---------+---------+---------+---------+---------+---------
       DIFF       TSDIFF         DAYS                               
---------+---------+---------+---------+---------+---------+---------
    5184000      5184000           60                               
DSNE610I NUMBER OF ROWS DISPLAYED IS 1                              
DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL, SQLCODE IS 100         
---------+---------+---------+---------+---------+---------+---------
SELECT                                                              
       MIDNIGHT_SECONDS(TIMESTAMP('2023-12-21-00.00.01')) -         
       MIDNIGHT_SECONDS(TIMESTAMP('2023-10-21-00.00.01'))            
      + ( 86400 * (DAYS(TIMESTAMP('2023-12-21-00.00.01')) -         
                   DAYS(TIMESTAMP('2023-10-21-00.00.01')))) AS DIFF 
,TIMESTAMPDIFF( 2, CHAR(TIMESTAMP('2023-12-21-00.00.01') -          
                        TIMESTAMP('2023-10-21-00.00.01')))  AS TSDIFF
,           DAYS(       TIMESTAMP('2023-12-21-00.00.01')) -         
            DAYS(       TIMESTAMP('2023-10-21-00.00.01'))   AS DAYS 
FROM SYSIBM.SYSDUMMY1  ;                                            
---------+---------+---------+---------+---------+---------+---------
       DIFF       TSDIFF         DAYS                               
---------+---------+---------+---------+---------+---------+---------
    5270400      5184000           61                                
DSNE610I NUMBER OF ROWS DISPLAYED IS 1                              
DSNE616I STATEMENT EXECUTION WAS SUCCESSFUL, SQLCODE IS 100         
---------+---------+---------+---------+---------+---------+---------
SELECT                                                               
       MIDNIGHT_SECONDS(TIMESTAMP('2023-12-21-00.00.01')) -         
       MIDNIGHT_SECONDS(TIMESTAMP('2023-10-20-00.00.01'))           
      + ( 86400 * (DAYS(TIMESTAMP('2023-12-21-00.00.01')) -          
                   DAYS(TIMESTAMP('2023-10-20-00.00.01')))) AS DIFF 
,TIMESTAMPDIFF( 2, CHAR(TIMESTAMP('2023-12-21-00.00.01') -          
                        TIMESTAMP('2023-10-20-00.00.01')))  AS TSDIFF
,           DAYS(       TIMESTAMP('2023-12-21-00.00.01')) -         
            DAYS(       TIMESTAMP('2023-10-20-00.00.01'))   AS DAYS 
FROM SYSIBM.SYSDUMMY1  ;                                   
---------+---------+---------+---------+---------+---------+
       DIFF       TSDIFF         DAYS                       
---------+---------+---------+---------+---------+---------+
    5356800      5270400           62                      
DSNE610I NUMBER OF ROWS DISPLAYED IS 1

It all looks a lot better and actually returns the correct number of seconds between two timestamps!

How Does it Work?

The key part is just some math:

       MIDNIGHT_SECONDS(TIMESTAMP('from ts')) -         
       MIDNIGHT_SECONDS(TIMESTAMP('to ts'))           
      + ( 86400 * (DAYS(TIMESTAMP('from ts')) -         
                   DAYS(TIMESTAMP('to ts')))) AS DIFF

I use the MIDNIGHT_SECONDS BiF (First appeared in DB2 V6.1) that returns the number of seconds from midnight up to the given timestamp. I then simply subtract the “to ts” value from the “from ts” value and then use the DAYS BiF again subtracting from each other to get the days difference multiplying by 86400 as seconds/day. There is no need to subtract an extra day as, if that was required, it is automatically handled by the MIDNIGHT_SECONDS subtraction. Then these two results are simply added together.

Code Review Time?

I have re-reviewed all my code to make sure that any use of TIMESTAMPDIFF can accept “approximate” answers and in all other cases replaced it with the above code.

I might even open an Aha! Idea about getting this as a BiF – it is not that complex and is “better” than the best guess system we have now. In fact, I have – DB24ZOS-I-1599 – please vote if you think it would be great to get this as a simple BiF!

Db2 Does Not Stand Alone Here!

We are also not alone in this problem! Oracle, MySQL and JAVA all have the same “approximation” routines. I did a Google search for a web-based timestamp calculator and it made exactly the same mistakes. I guess that there is a “fast algorithm” out there that does the best guess quickly…but sadly not accurately!

This problem is right up there with Daylight Saving Time and the grief that causes! See my earlier blog.

TTFN,

Roy Boxwell