Thread overview
Generating table dependencies using templates
Apr 04, 2006
Aarti
Apr 04, 2006
Don Clugston
Apr 04, 2006
Georg Wrede
April 04, 2006
Hello!

In my program I need to generate dependencies between database tables, so I will always get information about below mentioned relations for every specific table:
1. parent tables
2. child tables
3. ancestor tables
4. descendant tables

To generate such a dependencies I have following matrix (table is much bigger in real program):

//tbl_vc,  tbl_ad,   tbl_dc, tbl_ic,  tbl_ct, tbl_root, tbl_end
const ubyte tablerel[tbl_end][tbl_end] = {
    {0,       1,        0,       1,      1,    	0}, //tbl_vc
    {0,       0,        1,       0,      0,    	0}, //tbl_ad
    {0,       0,        0,       0,      0,    	0}, //tbl_dc
    {0,       0,        0,       0,      0,    	0}, //tbl_ic
    {0,       0,        0,       0,      0,    	0}, //tbl_ct
    {1,       0,        0,       0,      0,    	0}, //tbl_root
};						    //tbl_end

Let's assume I want to find dependencies for table x:
- parents --> search x column and add to result every table from row label which on crossing with x column has 1 - e.g. parent of tbl_vc is tbl_root, parent for tbl_dc is tbl_ad
- children --> search x row and add to result every table from column label which on crossing with x row has 1 - e.g. children of tbl_vc are tbl_ad,  tbl_dt,  tbl_rlp,  tblrlo, tbl_ic,  tbl_ct,  tbl_dp,  tbl_ph, tbl_sn; for tbl_root the child is tbl_vc
- ancestor -> search for parents, add them to result and add also their parents
- descendants --> search for children, add them to result and add also their children

Now in C++ code I have two (at least these two I know) possibilities:
1. I can hardcode every relation in vector for every table, so I have:
int[] childrentables[tbl_end];

childrentables[tbl_vc][0]=tbl_ad; childrentables[tbl_vc][1]=tbl_ic; childrentables[tbl_vc][2]=tbl_ct;

childrentables[tbl_ad][0]=tbl_dc;
... much more definitions for every table ...

Now I make it with simple code generator, but this solution is very uncomfortable to use and difficult to modify when relations change.

2. I can generate these dependencies on runtime using recurence. This solution has runtime overhead and is more than I need as relations will never change on runtime.

I would be happy to find solution with D templates. Is it possible? How it should be implemented? Maybe you have some other suggestions?
I will appreciate your suggestions.

BR
Marcin Kuszczak
April 04, 2006
Aarti wrote:
> Hello!
> 
> In my program I need to generate dependencies between database tables, so I will always get information about below mentioned relations for every specific table:
> 1. parent tables
> 2. child tables
> 3. ancestor tables
> 4. descendant tables
> 
> To generate such a dependencies I have following matrix (table is much bigger in real program):
> 
> //tbl_vc,  tbl_ad,   tbl_dc, tbl_ic,  tbl_ct, tbl_root, tbl_end
> const ubyte tablerel[tbl_end][tbl_end] = {
>     {0,       1,        0,       1,      1,        0}, //tbl_vc
>     {0,       0,        1,       0,      0,        0}, //tbl_ad
>     {0,       0,        0,       0,      0,        0}, //tbl_dc
>     {0,       0,        0,       0,      0,        0}, //tbl_ic
>     {0,       0,        0,       0,      0,        0}, //tbl_ct
>     {1,       0,        0,       0,      0,        0}, //tbl_root
> };                            //tbl_end
> 
> Let's assume I want to find dependencies for table x:
> - parents --> search x column and add to result every table from row label which on crossing with x column has 1 - e.g. parent of tbl_vc is tbl_root, parent for tbl_dc is tbl_ad
> - children --> search x row and add to result every table from column label which on crossing with x row has 1 - e.g. children of tbl_vc are tbl_ad,  tbl_dt,  tbl_rlp,  tblrlo, tbl_ic,  tbl_ct,  tbl_dp,  tbl_ph, tbl_sn; for tbl_root the child is tbl_vc
> - ancestor -> search for parents, add them to result and add also their parents
> - descendants --> search for children, add them to result and add also their children
> 
> Now in C++ code I have two (at least these two I know) possibilities:
> 1. I can hardcode every relation in vector for every table, so I have:
> int[] childrentables[tbl_end];
> 
> childrentables[tbl_vc][0]=tbl_ad; childrentables[tbl_vc][1]=tbl_ic; childrentables[tbl_vc][2]=tbl_ct;
> 
> childrentables[tbl_ad][0]=tbl_dc;
> ... much more definitions for every table ...
> 
> Now I make it with simple code generator, but this solution is very uncomfortable to use and difficult to modify when relations change.
> 
> 2. I can generate these dependencies on runtime using recurence. This solution has runtime overhead and is more than I need as relations will never change on runtime.
> 
> I would be happy to find solution with D templates. Is it possible? How it should be implemented? Maybe you have some other suggestions?
> I will appreciate your suggestions.

It's hard without array literals, but you could do it with a const string. Untested, but I've done this sort of thing before...

const int numTables = 6;
const char [] tableDependencies
  = "010110"
    "001000"
    "000000"
    ...;

static assert(tableDependencies.length == numTables*numTables);

// true if dependencies[x][y] is '1'.
template dependsOn(int x, int y)
{
  const bool dependsOn = (tableDependencies[x*numTables+y]=='1';
}

// Returns an array of all the parents of table x.
// A bit of a hack -- we can concat char [] at compile time,
// but not const int[].
// int [] parentsOf!(x).

template parentsOf(int x, int row=0, dchar [] sofar="")
{
   static if (row==numTables)
	const int [] parentsOf = cast(int [])(sofar);
   else static if (dependsOn(x, row))
	const int [] parentsOf = parentsOf(x,
		row+1, sofar~cast(dchar)(row));
   else const int [] parentsOf = parentsOf(x,
		row+1, sofar);
}

// Usage:
const int tbl_vc = 1;
... etc.

int [] p  = parentsOf!(tbl_vc);
April 04, 2006
Aarti wrote:
> Hello!
> 
> In my program I need to generate dependencies between database tables, so I will always get information about below mentioned relations for every specific table:
> 1. parent tables
> 2. child tables
> 3. ancestor tables
> 4. descendant tables

I'm not sure whether this is posted in order to find a solution for the problem, or to find information on best practices with templates.

Since Don already started to tackle the latter, I'll merely mention how I'd resolve the former.

In general, with database tables and this kind of problem, I'd resort to recursive lookups. I'd have an extra table that contains the fields TABLE, ANCESTOR. (If there is a huge number of tables, then of course one could have this table indexed on both columns, but in practice neither index is needed because in real-life applications the total number of tables is "small".)

To find out whether table A is an ancestor to table B, one calls a function that checks for all "parents" to table B, and if A is found, then return A. If parents are found but not A, then check their parents. Conversely if one needs to know if A is a descendant.