· Jun 27, 2023

Full Db backup cbk file from Cache 2017.2.2 needs to be restored for SQL access

We are retiring a hosted application for an electronic health care records (EHR) system which stored the data on Cache for UNIX (Red Hat Enterprise Linux for x86-64) 2017.2.2 (Build 867_4_20245) Thu Oct 8 2020 16:58:40 EDT.  The hosting company is providing me with a single CBK file.  I need to install a database system to restore the database and provide occasional SQL access for reports when necessary.  I'll need to maintain access to the data for an approximately 10 year retention period.  Not sure how to approach restoring this old of a database and eventually upgrading it to a newer release, the IRIS platform, or other alternative.  I've exported select CSV files via SQL for current data data and imported it into our new EHR, but need the complete Db for archival purposes. I would appreciate any advice!   - Mark

Product version: Caché 2017.1
$ZV: Cache for UNIX (Red Hat Enterprise Linux for x86-64) 2017.2.2 (Build 867_4_20245)
Discussion (36)1
Log in or sign up to continue

Hi Mark,

Some thoughts on this:

Anticipate the online backup (CBK) may tie-in with operating system and Cache version to run the restore

It may be better to have "at rest" CACHE.DAT files:

They can be:

  • Renamed to IRIS.DAT
  • Mounted and "upgraded"
  • Endian converted if needed

Having md5 checksum of CBK / DAT files can help identify transfer issues to / from offline media.

An integrity check can also be a useful confirmation tool to trace back if the original backup had issue.

Having undeployed SQL table definitions maybe useful future proofing.

For older versions of Cache install media contact the

Anticipate IRIS will be here after another 45 years, so will easily meet the 10 year requirement.

 Well I got the CACHE.DAT files from our hosting company and renamed them to IRIS.DAT.  I also got hold of the cache.cpf file which I used to merged into a iris.cpf file.  So using IRIS 2023.1 I was able to mount the databases and I can see the schema and table definitions.  I cannot yet see any data.  So not sure what is wrong.  The IRIS.DAT files are large, 30GB and 53.4GB for each database.  The hosted environment was Linux, and now I'm on Windows, but I believe the endian is the same (little).  Using the Management Portal I don't see any options to upgrade or even verify the database.  Let me know if you have any ideas.  Thanks!

Yes Danny good idea.  When I look at the cpf file, I actually see that I'm missing 2 databases: AVCWSTMP and AVPMTMP, but since they appeared to be for the purpose of temporary storage, I just created blank databases to take their place.  And since they never gave me the corresponding DAT files, I didn't think they were important.  Here's a snippet of the cpf file.  I commented out the original entries of the cache.cpf file and replaced them with what I'm using in the IRIS.cfg.  There appears to be some mapping of globals into the AVCWSTMP and AVPMTMP databases, but most of the mappings are into AVCWS and AVPM.


## Must mount at startup
## end must mount at startup







<End of Message>

Hi Mark,

Can you also check that you received the correct CACHE.DAT files by looking at the label inside the files (they might be copied from the wrong directories).
Do you still have the original .DAT files ? After renaming them from CACHE.DAT to IRIS.DAT, before you mount them in Iris, you can check the label stored inside the .DAT file.

when in terminal (%SYS) :
%SYS> Write $$ROOT^LABEL("c:\directory-unmounted-irisdat-file\")
It should display the original path of the CACHE.DAT from the Unix directory.

Wow!  Using the Management Portal, under System  > Globals  > View Global Data, I can see data by looking at my ^DocM.DocumentImageD global!  But when I use SQL: select ID, ... from DocM.DocumentImage (no where clause) I get: Row count: 0 Performance: 0.0660 seconds  327 global references 5390 commands executed 0 disk read latency (ms)  Cached Query: %sqlcq.AVCWS.cls4  Last update: 2023-09-20 11:34:26.644

Hi Danny I did a head for the DAT files and they appear to be correct.  I'm not sure how indexing works in IRIS, but I have a suspicion that data indexes are stored in the missing “TMP” databases.  That might explain why I can see data by directly looking at the globals but not getting results with SQL queries.  When I search the iris.cpf file for global mappings containing the word index, I can get the following:


Almost every instance is mapped to a TMP database.  I’m asking our hosting company for these files now. 

The exact index global for e.g. your class DocM.DocumentImage will by default be ^DocM.DocumentImageI (unless the class definition storage was changed).

You can rebuild the indices from the data by using the portal, click on the sql tabel and click on Actions->Rebuild indices.
Or go to terminal and Do ##class(DocM.DocumentImage).%BuildIndices()

(When doing an SQL query in the portal, you can view the query plan to see wheter an index was used.)

Hi Danny, the recompile worked well (just a few errors logged).  The Upgrade() command just said "No classes were modified".  But after those commands I was able to rebuild the indexes with no errors!  Still SQL queries come back empty.  Will keep scratching my head!  I increase the row limit of my view of the global values to 5K, and the data looks great, just can't get it via SQL yet.

Hi Mark,

What can you see in the management portal (Explorer -> SQL) when you click on a table in Catalog Details -> Maps/Indices : should list your globals that are being used.
What can you see when you click on Open Table ?
How about the user that you use : does it have %All rights? 

Have you tried opening an instance with Set obj = ##CLASS(DocM.DocumentImage).%OpenId( <some id> ) ?

Hi Danny, yes I see a list of 20 indexes and their hyperlinked globals.  This is where I click on the DocM.DocumentImageD global I can clearly see the data.  When I clicked on Open Table I get a separate window: http://localhost:8972/csp/sys/exp/UtilSqlOpen.csp?$NAMESPACE=AVCWS&$ID1=DocM&$ID2=DocumentImage but it remains a blank page.  The table is huge, about 500K records, so wondering if Open Table will paginate.

The first part of the 1st record of the DocumentImageD global is 
1: ^DocM.DocumentImageD(1,1) = $lb("",1,"26179","PATIENT.USER_DEFINED",1,0,...

So I assume an id of 1 will suffice.
AVCWS>Set obj = ##CLASS(DocM.DocumentImage).%OpenId(1)

I assume a property will be any column name?  But any writes I try come up with <INVALID OREF>.
AVCWS>write obj.ID

Can you do the following (assuming the namespace USER is empty):
- copy the class definition of one class to the USER namespace (take a class that does not refer to other of your classes)
- do a SQL Insert into that table in USER
- do an SQL Select of that table in USER
- look if the global ^...D exists in USER.
- now copy the ^...D global from your orignal namespace to USER (using Merge command, or export/import in mgmnt portal) 
- Rebuild the indexes in USER of the class
- do the SQL Select again in USER

Hi Mark, If you can do inserts but not selects, the class might have row security enabeled.
Is there a parameter  ROWLEVELSECURITY = 1, and a method %SecurityPolicy present ? In that method, you can exclude rows based on e.g. $username and $roles. Even if your user has the %All role, you could be excluded to see a row in this security.
If you see that, you can or create the correct user/role, or set the parameter to 0 (and rebuild all indexes).
Can you send the class definition of one of the tables, so I can try the class on my server ?

Yes, the security parameter is set to 1 inside the NTSTLIB.SecurityPolicy class.

<Method name="%SecurityPolicy">
<Implementation><![CDATA[    q FACILITY

The account I've been using is my installation account.  Maybe I need to assign addition roles.  Thanks!

Hi Mark,
It is stated in the doc that %All is not enough : you have to have the exact role or be the exact username that matches row level security (in your case : the property FACILITY in each row).
Alternatively, you can disable it by setting the securitypolicy param to 0 (but then you need to recompile the classes that depend on it and rebuild the indices)

Hi Danny,  I see! I vaguely remember now there was a security setting to prevent personal from one facility seeing data generated from a different facility.  But that wasn't important to us since we were setup as a single facility.  As a result, the FACILITY column in every table is set to 1.  It's not clear to me what IRIS role would allow pass this row level security, but it seems easier than re-compiling all the classes.