A SuperFile whose sub-files are INDEXes (not DATASETs) is a SuperKey. As described previously in the Indexing Into SuperFiles article, there is a problem with using a SuperKey to try to index into a SuperFile. So what good are SuperKeys?
In the Using ECL Keys (INDEX Files) article, the technique of creating and using INDEXes that contain payload fields was demonstrated. By putting the payload fields in the INDEX itself, there becomes no need to directly access the base dataset from which the INDEX was built. Thus, the problem becomes moot.
SuperKeys are built with payload keys. And, since the primary operation for a payload key is the half-keyed JOIN, that also becomes the primary SuperKey operational use.
Both SuperFiles and SuperKeys may be used in Thor or Roxie operations.
The following attribute definitions used by the code examples in this article are declared in the DeclareData MODULE structure attribute:
EXPORT SubKey1 := '~PROGGUIDE::SUPERKEY::Accounts1'; EXPORT SubKey2 := '~PROGGUIDE::SUPERKEY::Accounts2'; EXPORT SubKey3 := '~PROGGUIDE::SUPERKEY::Accounts3'; EXPORT SubKey4 := '~PROGGUIDE::SUPERKEY::Accounts4'; EXPORT SubIDX1 := '~PROGGUIDE::SUPERKEY::KEY::AcctsIDX1'; EXPORT SubIDX2 := '~PROGGUIDE::SUPERKEY::KEY::AcctsIDX2'; EXPORT SubIDX3 := '~PROGGUIDE::SUPERKEY::KEY::AcctsIDX3'; EXPORT SubIDX4 := '~PROGGUIDE::SUPERKEY::KEY::AcctsIDX4'; EXPORT AcctSKname := '~PROGGUIDE::SUPERKEY::KEY::AcctsSK'; EXPORT AcctSK := INDEX(Accounts,{PersonID},
Before you can create a SuperKey, you must first have some INDEXes to use. The following code (contained in SuperKey1.ECL) builds four separate payload keys from the Account dataset:
IMPORT $; IMPORT Std; s1 := $.DeclareData.Accounts(Account[1] = '1'); s2 := $.DeclareData.Accounts(Account[1] = '2'); s3 := $.DeclareData.Accounts(Account[1] = '3'); s4 := $.DeclareData.Accounts(Account[1] IN ['4','5','6','7','8','9']); Rec := $.DeclareData.Layout_Accounts_Link; RecPlus := {Rec,UNSIGNED8 RecPos{virtual(fileposition)}}; d1 := DATASET($.DeclareData.SubKey1,RecPlus,THOR); d2 := DATASET($.DeclareData.SubKey2,RecPlus,THOR); d3 := DATASET($.DeclareData.SubKey3,RecPlus,THOR); d4 := DATASET($.DeclareData.SubKey4,RecPlus,THOR); i1 := INDEX(d1,{PersonID}, {Account,OpenDate,IndustryCode,AcctType,AcctRate, Code1,Code2,HighCredit,Balance,RecPos}, $.DeclareData.SubIDX1); i2 := INDEX(d2,{PersonID}, {Account,OpenDate,IndustryCode,AcctType,AcctRate, Code1,Code2,HighCredit,Balance,RecPos}, $.DeclareData.SubIDX2); i3 := INDEX(d3,{PersonID}, {Account,OpenDate,IndustryCode,AcctType,AcctRate, Code1,Code2,HighCredit,Balance,RecPos}, $.DeclareData.SubIDX3); i4 := INDEX(d4,{PersonID}, {Account,OpenDate,IndustryCode,AcctType,AcctRate, Code1,Code2,HighCredit,Balance,RecPos}, $.DeclareData.SubIDX4); BldDat := PARALLEL( IF(~Std.File.FileExists($.DeclareData.SubKey1), OUTPUT(s1, {PersonID,Account,OpenDate,IndustryCode,AcctType, AcctRate,Code1,Code2,HighCredit,Balance}, $.DeclareData.SubKey1)), IF(~Std.File.FileExists($.DeclareData.SubKey2), OUTPUT(s2, {PersonID,Account,OpenDate,IndustryCode,AcctType, AcctRate,Code1,Code2,HighCredit,Balance}, $.DeclareData.SubKey2)), IF(~Std.File.FileExists($.DeclareData.SubKey3), OUTPUT(s3, {PersonID,Account,OpenDate,IndustryCode,AcctType, AcctRate,Code1,Code2,HighCredit,Balance}, $.DeclareData.SubKey3)), IF(~Std.File.FileExists($.DeclareData.SubKey4), OUTPUT(s4, {PersonID,Account,OpenDate,IndustryCode,AcctType, AcctRate,Code1,Code2,HighCredit,Balance}, $.DeclareData.SubKey4))); BldIDX := PARALLEL( IF(~Std.File.FileExists($.DeclareData.SubIDX1), BUILDINDEX(i1)), IF(~Std.File.FileExists($.DeclareData.SubIDX2), BUILDINDEX(i2)), IF(~Std.File.FileExists($.DeclareData.SubIDX3), BUILDINDEX(i3)), IF(~Std.File.FileExists($.DeclareData.SubIDX4), BUILDINDEX(i4))); SEQUENTIAL(BldDat,BldIDX);
This code sequentially builds logical files by taking sub-sets of records from the Accounts dataset and writing those records to files on disk. Once the logical files physically exist, then the BUILDINDEX actions write the payload keys to disk.
One interesting twist to this code is the use of the Std.File.FileExists function to detect whether these files have already been created. The code in the next section also uses the Std.File.SuperFileExists function to detect whether the SuperFile has already been created, and create it only if it hasn't been. This technique allows the example code in this article to run correctly whether another user has already gone through the examples or not.