home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World 1998 October
/
PCWorld_1998-10_cd.bin
/
software
/
prehled
/
komix
/
DATA.Z
/
libsql.tcl
< prev
next >
Wrap
Text File
|
1997-04-03
|
36KB
|
1,187 lines
#---------------------------------------------------------------------------
#
# Copyright (c) 1992-1996 by Cayenne Software Inc.
#
# This software is furnished under a license and may be used only in
# accordance with the terms of such license and with the inclusion of
# the above copyright notice. This software or any other copies thereof
# may not be provided or otherwise made available to any other person.
# No title to and ownership of the software is hereby transferred.
#
# The information in this software is subject to change without notice
# and should not be construed as a commitment by Cayenne Software Inc.
#
#---------------------------------------------------------------------------
#
# File : @(#)libsql.tcl /main/titanic/3 (2.1)
# Original date : 7-1992
# Description : Common procedures for gensql including
# the main gensql procedure
#
#---------------------------------------------------------------------------
#
# @(#)libsql.tcl /main/titanic/3 3 Apr 1997 Copyright 1992-1995 Cayenne Software Inc.
#
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------
#
# INCLUDE THE ERROR MESSAGE FILE
#
#---------------------------------------------------------------------------
require libsql_msg.tcl
#---------------------------------------------------------------------------
#
# CONDITIONS TO SELECT A SET OF COLUMNS. USED IN "get_col_list"
#
#---------------------------------------------------------------------------
global column_selector
set column_selector(ALL) {1}
set column_selector(NONE) {0}
set column_selector(KEYS) {[$col getColumnType] == "key"}
set column_selector(KEYS_NO_TYPE) {[$col getColumnType] == "key" &&
[$col getName] != $TYPE_ID_NM}
set column_selector(KEYS_TYPE) {[$col getColumnType] == "key" &&
[$col getName] == $TYPE_ID_NM}
set column_selector(TYPE) {[$col getUniqueName] == $TYPE_ID_NM}
set column_selector(NONKEYS) {[$col getColumnType] != "key"}
set column_selector(NONKEYFIELDS) {[$col get_obj_type] == "column" &&
[$col getColumnType] != "key"}
set column_selector(FKEYS) {[$col get_obj_type] == "imp_column"}
set column_selector(ALLNONIMP) {[$col get_obj_type] == "column"}
set column_selector(NONIMPKEYS) {[$col get_obj_type] == "column" &&
[$col getColumnType] == "key"}
set column_selector(IMPKEYS) {[$col get_obj_type] == "imp_column" &&
[$col getColumnType] == "key"}
set column_selector(IMPKEYS_NO_TYPE) {[$col get_obj_type] == "imp_column" &&
[$col getColumnType] == "key" &&
[$col getName] != $TYPE_ID_NM}
set column_selector(IMPFIELDS) {[$col get_obj_type] == "imp_column" &&
[$col getColumnType] != "key"}
set column_selector(KEYS_FIELDS) {[$col getColumnType] == "key" ||
[$col get_obj_type] == "column"}
set column_selector(KEYS_IMPFIELDS) {[$col getColumnType] == "key" ||
[$col get_obj_type] == "imp_column"}
set column_selector(NULLABLES) {[$col isNullable]}
set column_selector(NOT_NULLABLES) {![$col isNullable]}
set column_selector(NOT_NULL_OR_INIT) {![$col isNullable] ||
[$col getPropertyValue initial_value] != ""}
set column_selector(NULL_AND_NO_INIT) {[$col isNullable] &&
[$col getPropertyValue initial_value] == ""}
set column_selector(NOT_NULL_FIELDS) {![$col isNullable] &&
[$col getColumnType] == "field" &&
[$col get_obj_type] == "column"}
#---------------------------------------------------------------------------
#
# The variable "get_type_4gl" contains the name of the procedure to
# get the 4gl type from a column. This indirection is needed because
# for some targets the 4gl type needs postprocessing (e.g. for Informix)
# If the variable is not set, set it to the original get_type_4gl
#
#---------------------------------------------------------------------------
global get_type_4gl
if {![info exists get_type_4gl]} {
set get_type_4gl get_type_4gl
}
#---------------------------------------------------------------------------
#
# TARGET INDEPENDENT GENERAL PURPOSE PROCEDURES
#
#---------------------------------------------------------------------------
# Select those columns from 'table' that satisfy the 'selector' condition
# If the selector is IMPKEYS or IMPKEYS_NO_TYPE, 'master_table' can be
# specified to return only those columns that are imported from that table.
#
proc get_col_list {table selector {master_table ""}} {
set list {}
if {$selector == "EXPKEYS"} {
foreach link [$table exportSet] {
foreach col [[$link friendLink] columnSet] {
lappend list $col
}
}
} else {
foreach col [$table columnSet] {
if [expr $column_selector($selector)] {
if {$master_table == "" || [$col master] == $master_table} {
lappend list $col
}
}
}
global debug
if {$debug == "1"} {
set imports {}
foreach col $list {
lappend imports [$col getUniqueName]
}
if {$selector == "IMPKEYS" || $selector == "IMPKEYS_NO_TYPE"} {
puts " >>> table '[$table getName]' imports '$imports' from\
'[$master_table getName]'"
}
}
}
return $list
}
# Generate a list of names from a object list. The object must have
# an attribute "unique_name"
#
proc gen_name_list {section objlist {prefix ""} {postfix ""} {separator ", "} \
{newline ""}} {
if {[lempty $objlist]} {
return
}
$section pushIndent
set newpf $separator$newline$prefix
set obj [lvarpop objlist]
expand_text $section {~$prefix~[$obj getUniqueName]~$postfix}
foreach obj $objlist {
expand_text $section {~$newpf~[$obj getUniqueName]~$postfix}
}
$section append $newline
$section popIndent
}
# Generate a list of column names for the given link
#
proc gen_col_listl {section link {prefix ""} {postfix ""} {separator ", "} \
{newline ""}} {
gen_col_listc $section [$link columnSet] $prefix $postfix \
$separator $newline
}
# Generate a compare of master and detail column names:
#
# if a detail colomn is prefixed it will be compared with it's foreign
# name. I.e. the name in the master table.
#
proc gen_md_comparec {section columns {prefix1 ""} {postfix1 ""} \
{prefix2 ""} {postfix2 ""} {separator ", "} {newline ""}} {
if {[lempty $columns]} {
return;
}
$section pushIndent
set newpf $separator$newline$prefix1
set col [lvarpop columns]
set dname [$col getUniqueName]
if {[$col get_obj_type] == "imp_column"} {
set mname [$col getForeignName]
} else {
set mname [$col getUniqueName]
}
set dname [$col getUniqueName]
expand_text $section {~$prefix1~$mname~$postfix1 = ~$prefix2~$dname~$postfix2}
while {![lempty $columns]} {
set col [lvarpop columns]
set dname [$col getUniqueName]
if {[$col get_obj_type] == "imp_column"} {
set mname [$col getForeignName]
} else {
set mname [$col getUniqueName]
}
expand_text $section {
~$newpf~$mname~$postfix1 = ~$prefix2~$dname~$postfix2}
}
$section append $newline
$section popIndent
}
# Generate a list of column names for the given list of columns
#
proc gen_col_listc {section columns {prefix ""} {postfix ""} {separator ", "} \
{newline ""}} {
if {[lempty $columns]} {
return;
}
$section pushIndent
set newpf $separator$newline$prefix
set col [lvarpop columns]
expand_text $section {~$prefix~[$col getUniqueName]~$postfix}
foreach col $columns {
expand_text $section {~$newpf~[$col getUniqueName]~$postfix}
}
$section append $newline
$section popIndent
}
# Generate a list of column names for the given table
# The list of columns is determined by the value of the selector
#
proc gen_col_list {section table selector {prefix ""} {postfix ""} \
{separator ", "} {newline ""} {master_table ""}} {
gen_col_listc $section [get_col_list $table $selector $master_table] \
$prefix $postfix $separator $newline
}
# The same as proc gen_col_list, however don't put the result in a section,
# but return it as a string
#
proc gen_col_list_str {table selector {prefix ""} {postfix ""} \
{separator ", "} {newline ""} {master_table ""}} {
set tmpSect [TextSection new]
gen_col_list $tmpSect $table $selector $prefix $postfix $separator \
$newline $master_table
return [$tmpSect contents]
}
# Generate a list of variables with indicator variables
#
proc gen_var_ind_list {section table selector {prefix1 ""} {prefix2 ""}
{separator ", "} {newline ""}} {
set columns [get_col_list $table $selector]
if {[lempty $columns]} {
return;
}
$section pushIndent
set newpf $separator$newline$prefix1
set col [lvarpop columns]
set name [$col getUniqueName]
expand_text $section {~$prefix1~$name~$prefix2~$name}
while {![lempty $columns]} {
set col [lvarpop columns]
set name [$col getUniqueName]
expand_text $section {
~$newpf~$name~$prefix2~$name}
}
$section append $newline
$section popIndent
}
# Generate a compare of column names:
#
# Example: <col_name_1> = <col_name_1> AND
# <col_name_2> = <col_name_2>
#
proc gen_comparec {section columns {prefix1 ""} {postfix1 ""} \
{prefix2 ""} {postfix2 ""} {separator ", "} {newline ""}} {
if {[lempty $columns]} {
return;
}
$section pushIndent
set newpf $separator$newline$prefix1
set col [lvarpop columns]
set name [$col getUniqueName]
expand_text $section {~$prefix1~$name~$postfix1 = ~$prefix2~$name~$postfix2}
while {![lempty $columns]} {
set col [lvarpop columns]
set name [$col getUniqueName]
expand_text $section {
~$newpf~$name~$postfix1 = ~$prefix2~$name~$postfix2}
}
$section append $newline
$section popIndent
}
# Generate a compare of column names with indicator vars:
#
# Example: <col_name_1> = <col_name_1> AND
# <col_name_2> = <col_name_2>
#
proc gen_comparec_ind {section columns {prefix1 ""} {postfix1 ""} \
{prefix2a ""} {postfix2a ""} {prefix2b ""} {postfix2b ""} \
{separator ", "} {newline ""}} {
if {[lempty $columns]} {
return;
}
$section pushIndent
set newpf $separator$newline$prefix1
set col [lvarpop columns]
set name [$col getUniqueName]
expand_text $section {~$prefix1~$name~$postfix1 = ~$prefix2a~$name~$postfix2a~$prefix2b~$name~$postfix2b}
while {![lempty $columns]} {
set col [lvarpop columns]
set name [$col getUniqueName]
expand_text $section {
~$newpf~$name~$postfix1 = ~$prefix2a~$name~$postfix2a~$prefix2b~$name~$postfix2b}
}
$section append $newline
$section popIndent
}
# See: gen_comparec_ind
#
proc gen_compare_ind {section table selector {prefix1 ""} {postfix1 ""} \
{prefix2a ""} {postfix2a ""} {prefix2b ""} {postfix2b ""} \
{separator ", "} {newline ""}} {
gen_comparec_ind $section [get_col_list $table $selector] $prefix1 \
$postfix1 $prefix2a $postfix2a $prefix2b $postfix2b \
$separator $newline
}
# See: gen_comparec
#
proc gen_compare {section table selector {prefix1 ""} {postfix1 ""} \
{prefix2 ""} {postfix2 ""} {separator ", "} {newline ""}} {
gen_comparec $section [get_col_list $table $selector] $prefix1 \
$postfix1 $prefix2 $postfix2 $separator $newline
}
# Generate a compare for a single column
#
proc gen_compare_elem {section column {prefix1 ""} {postfix1 ""} {prefix2 ""} \
{postfix2 ""}} {
$section pushIndent
set name [$column getUniqueName]
expand_text $section {
~$prefix1~$name~$postfix1 = ~$prefix2~$name~$postfix2}
$section popIndent
}
# Generate a compare list for imported/exported columns i.e.
# the list of columns must have obj_type "imp_column".
# If the link is a export_link get the friend of the link
# and this procedure will work.
#
proc gen_compare_cl {section link {prefix1 ""} {postfix1 ""} \
{prefix2 ""} {postfix2 ""} {separator ", "} {newline ""}} {
if {[$link getLinkType] == "export"} {
set link [$link friendLink]
}
set columns [$link columnSet]
if {[lempty $columns]} {
return ;
}
set col [lvarpop columns]
set tcol_nm [$col getUniqueName]
set mcol_nm [$col getForeignName]
$section pushIndent
expand_text $section {
~$prefix1~$tcol_nm~$postfix1 = ~$prefix2~$mcol_nm~$postfix2}
set newpf $separator$newline$prefix1
while {![lempty $columns]} {
set col [lvarpop columns]
set tcol_nm [$col getUniqueName]
set mcol_nm [$col getForeignName]
expand_text $section {
~$newpf~$tcol_nm~$postfix1 = ~$prefix2~$mcol_nm~$postfix2}
}
$section popIndent
$section append $newline
}
# Generate for a link between the current table and the detail
# a compare list of the exported columns.
#
proc gen_compare_dno {section table detail {prefix1 ""} {postfix1 ""} \
{prefix2 ""} {postfix2 ""} {separator ", "} {newline ""}} {
set t_columns ""
set d_columns ""
foreach dlink [$table exportSet] {
if {[$dlink detail] == $detail} {
set t_columns [$dlink columnSet]
set d_columns [[$dlink friendLink] columnSet]
break
}
}
if {[lempty $t_columns]} {
return
}
set tcol_nm [[lvarpop t_columns] getUniqueName]
set dcol_nm [[lvarpop d_columns] getUniqueName]
$section pushIndent
expand_text $section {
~$prefix1~$tcol_nm~$postfix1 = ~$prefix2~$dcol_nm~$postfix2}
set newpf $separator$newline$prefix1
while {![lempty $t_columns]} {
set tcol_nm [[lvarpop t_columns] getUniqueName]
set dcol_nm [[lvarpop d_columns] getUniqueName]
expand_text $section {
~$newpf~$tcol_nm~$postfix1 = ~$prefix2~$dcol_nm~$postfix2}
}
$section popIndent
$section append $newline
}
# As gen_compare_m but without prefixing the column names
# with "table_name.".
#
proc gen_compare_mno {section table master {prefix1 ""} {postfix1 ""} \
{prefix2 ""} {postfix2 ""} {separator ", "} {newline ""}} {
set t_columns ""
set m_columns ""
foreach mlink [$table importSet] {
if {[$mlink master] == $master} {
set t_columns [$mlink columnSet]
set m_columns [[$mlink friendLink] columnSet]
break
}
}
if {[lempty $t_columns]} {
return
}
set tcol_nm [[lvarpop t_columns] getUniqueName]
set mcol_nm [[lvarpop m_columns] getUniqueName]
$section pushIndent
expand_text $section {
~$prefix2~$mcol_nm~$postfix2 = ~$prefix1~$tcol_nm~$postfix1}
set newpf $separator$newline$prefix1
while {![lempty $t_columns]} {
set tcol_nm [[lvarpop t_columns] getUniqueName]
set mcol_nm [[lvarpop m_columns] getUniqueName]
expand_text $section {
~$newpf~$tcol_nm~$postfix1 = ~$prefix2~$mcol_nm~$postfix2}
}
$section popIndent
$section append $newline
}
# Generate for a link between the current table and the master
# a compare list of the imported columns.
# The names of the columns are prefixed by the name of the table.
#
proc gen_compare_m {section table master {prefix1 ""} {postfix1 ""} \
{prefix2 ""} {postfix2 ""} {separator ", "} {newline ""}} {
set t_columns ""
set m_columns ""
foreach mlink [$table importSet] {
if {[$mlink master] == $master} {
set t_columns [$mlink columnSet]
set m_columns [[$mlink friendLink] columnSet]
break
}
}
if {[lempty $t_columns]} {
return
}
set ttab_nm [$table getUniqueName]
set mtab_nm [$master getUniqueName]
set tcol_nm [[lvarpop t_columns] getUniqueName]
set mcol_nm [[lvarpop m_columns] getUniqueName]
$section pushIndent
expand_text $section {
~$prefix1~$ttab_nm.~$tcol_nm~$postfix1 = ~$prefix2~$mtab_nm.~$mcol_nm~$postfix2}
set newpf $separator$newline$prefix1
while {![lempty $t_columns]} {
set tcol_nm [[lvarpop t_columns] getUniqueName]
set mcol_nm [[lvarpop m_columns] getUniqueName]
expand_text $section {
~$newpf~$ttab_nm.~$tcol_nm~$postfix1 = ~$prefix2~$mtab_nm.~$mcol_nm~$postfix2}
}
$section popIndent
$section append $newline
}
# Generate a full data declaration for a given table
#
proc gen_data_decl_4gl {section table selector {separator ", "} {newline ""}} {
set columns [get_col_list $table $selector]
if {[lempty $columns]} {
return
}
set col [lvarpop columns]
$section pushIndent
expand_text $section {
~[$col getUniqueName] ~[$get_type_4gl $col] ~[sqlpostfix_needed $col]}
set newpf $separator$newline
foreach col $columns {
expand_text $section {
~$newpf~[$col getUniqueName] ~[$get_type_4gl $col] ~[sqlpostfix_needed $col]}
}
$section popIndent
$section append $newline
}
# Generate a full SQLdata declaration for a given table
#
proc gen_data_decl_sql {section table selector {separator ", "} {newline ""}} {
set columns [get_col_list $table $selector]
if {[lempty $columns]} {
return
}
set col [lvarpop columns]
$section pushIndent
expand_text $section {
~[$col getUniqueName] ~[get_type_4gl $col] ~[sqlpostfix_needed $col]}
set newpf $separator$newline
foreach col $columns {
expand_text $section {
~$newpf~[$col getUniqueName] ~[get_type_4gl $col] ~[sqlpostfix_needed $col]}
}
$section popIndent
$section append $newline
}
# Generate a 3gl data declaration
#
proc gen_data_decl_3gl {section table selector {prefix ""} \
{newline ""} {postfix ""}} {
set columns [get_col_list $table $selector]
if {[lempty $columns]} {
return
}
$section pushIndent
set col [lvarpop columns]
# first col
build_type_3gl [$col getType3GL] result_type result_range
set result_type $prefix$result_type
set result_range $result_range$postfix
expand_text $section {\~[create_3gl_var {~$name} {~$type} {~$range}
]} \
name [$col getUniqueName] type $result_type range $result_range
set newprefix $newline$prefix
foreach col $columns {
# next cols
build_type_3gl [$col getType3GL] result_type result_range
set result_type $newprefix$result_type
set result_range $result_range$postfix
expand_text $section {\~[create_3gl_var {~$name} {~$type} {~$range}
]} \
name [$col getUniqueName] type $result_type range $result_range
}
$section append $newline
$section popIndent
}
# Generate a 3gl data declaration directly (without calling create_3gl_var)
#
proc gen_dir_data_decl_3gl {section object selector {separator ", "}
{newline ""} {prefix ""} {postfix ""} {prefix2 ""}} {
gen_dir_data_decl_3glc $section [get_col_list $object $selector] \
$separator $newline $prefix $postfix $prefix2
}
# Generate a 3gl data declaration for a link directly (without calling
# create_3gl_var)
#
proc gen_dir_data_decl_3gl_link {section link {separator ", "}
{newline ""} {prefix ""} {postfix ""}
{prefix2 ""}} {
gen_dir_data_decl_3glc $section [$link columnSet] \
$separator $newline $prefix $postfix $prefix2
}
proc gen_dir_data_decl_3glc {section columns {separator ", "}
{newline ""} {prefix ""} {postfix ""} {prefix2 ""}} {
if {[lempty $columns]} {
return
}
set col [lvarpop columns]
$section pushIndent
$section append $prefix[mk_3gl_decl $col $postfix $prefix2]
set newpf $separator$newline$prefix
foreach col $columns {
$section append $newpf[mk_3gl_decl $col $postfix $prefix2]
}
$section popIndent
$section append $newline
}
# Make a 3gl variable declaration
# {name, simpel_type} becomes "simpel_type name"
# {name, char[index]} becomes "char name[index + 1]"
#
proc mk_3gl_decl {col {postfix ""} {prefix ""}} {
set name [$col getUniqueName]
set type [$col getType3GL]
if [regsub {(var)?char\[} $type "char $prefix$name\[" type] {
regexp {\[(.*)\]$} $type dummy index
set index [expr {$index + 1}]
regsub {\[(.*)\]$} $type "$postfix\[$index]" type
return $type
}
return "$type $prefix$name$postfix"
}
# Generate a 4gl data declaration, without sqlpostfix
#
proc gen_simple_data_decl_4glc {section columns {prefix ""} \
{separator ", "} {newline ""}} {
if {[lempty $columns]} {
return
}
$section pushIndent
set col [lvarpop columns]
expand_text $section {
~$prefix~[$col getUniqueName] ~[$get_type_4gl $col]}
set newpf $separator$newline$prefix
while {![lempty $columns]} {
set col [lvarpop columns]
expand_text $section {
~$newpf~[$col getUniqueName] ~[$get_type_4gl $col]}
}
$section append $newline
$section popIndent
}
# See: gen_simple_data_decl_4glc
#
proc gen_simple_data_decl_4gl {section table selector {prefix ""} \
{separator ", "} {newline ""}} {
set columns [get_col_list $table $selector]
gen_simple_data_decl_4glc $section $columns $prefix $separator $newline
}
# Generate an assignment of columns in a master detail link
#
proc gen_assign_cl {section link {prefix1 ""} {postfix1 ""} \
{prefix2 ""} {postfix2 ""}} {
$section pushIndent
foreach col [$link columnSet] {
$section append \
[assign_elem_md $col $prefix1 $postfix1 $prefix2 $postfix2 $section]
}
$section popIndent
}
# Generate an assign of column names. string variables are assigned via strcpy
#
#
proc gen_assignc {section columns {prefix1 ""} {postfix1 ""} \
{prefix2 ""} {postfix2 ""}} {
$section pushIndent
foreach col $columns {
$section append \
[assign_elem $col $prefix1 $postfix1 $prefix2 $postfix2 $section]
}
$section popIndent
}
# See: gen_assignc
#
proc gen_assign {section table selector {prefix1 ""} {postfix1 ""} \
{prefix2 ""} {postfix2 ""}} {
gen_assignc $section [get_col_list $table $selector] $prefix1 $postfix1 \
$prefix2 $postfix2
}
#
# Generate an assign of column names. No support for string variables
#
proc gen_simple_assign {section table selector {prefix1 ""} {postfix1 ""} \
{prefix2 ""} {postfix2 ""}} {
$section pushIndent
foreach col [get_col_list $table $selector] {
set name [$col getUniqueName]
$section append "$prefix1$name$postfix1 = $prefix2$name$postfix2;\n"
}
$section popIndent
}
# Return the string for one assignment
#
proc assign_elem {col {prefix1 ""} {postfix1 ""} {prefix2 ""}
{postfix2 ""} {sect "src"}} {
set name [$col getUniqueName]
if [type_is_char_array $col] {
add_[determine_sect_type $sect]_inc_name "string" "h"
return "strcpy($prefix1$name$postfix1, $prefix2$name$postfix2);\n"
}
return "$prefix1$name$postfix1 = $prefix2$name$postfix2;\n"
}
# Return the string for one assignment in a master-detail relationship
#
proc assign_elem_md {col {prefix1 ""} {postfix1 ""} {prefix2 ""}
{postfix2 ""} {sect "src"}} {
set name [$col getUniqueName]
set fname [$col getForeignName]
if [type_is_char_array $col] {
add_[determine_sect_type $sect]_inc_name "string" "h"
return "strcpy($prefix1$name$postfix1, $prefix2$fname$postfix2);\n"
}
return "$prefix1$name$postfix1 = $prefix2$fname$postfix2;\n"
}
# Determine if the 3gl type is a character array
#
proc type_is_char_array {obj} {
return [string match {*char\[*} [$obj getType3GL]]
}
proc strip_trailing_spaces {section columns {prefix ""} {postfix ""}} {
$section pushIndent
foreach col $columns {
if {[type_is_char_array $col]} {
expand_text $section {
stripTrailingSpaces(~$prefix~[$col getUniqueName]~$postfix);
}
}
}
$section popIndent
}
# Declare a variable which is expanded by gen4gl
#
proc declare_4gl_var {section varname vartype} {
expand_text $section {\~[create_var ~$varname {~$vartype}
]} \
varname $varname vartype $vartype
}
# Determine if the column needs a sqlpostfix, if not this
# procedure returns an empty string else the sqlpostfix.
#
proc sqlpostfix_needed {col} {
if {[$col get_obj_type] == "column"} {
return [$col getSqlPostfix];
}
set link [$col getImport]
if {[$link getDetailType] == "optional" &&
[$col getColumnType] == "field"} {
return "";
}
return [$col getSqlPostfix];
}
# Parse i.e. expand the constraint string. The following
# variables are in the context of the constraint known:
#
# o ~$col_name - the name of the current column
# o ~$column - handle to the current column
#
# o ~$tab_name - the name of the current table
# o ~$table - handle to the current table
#
# You can only use one of these depending if you defined
# the constraint for a column or table object.
#
proc parse_constr {current_section object {prefix ""}} {
set constr [$object getConstraint]
if {$constr == ""} {
return
}
if {[$object get_obj_type] == "table"} {
set t_obj $object
set t_name [$object getUniqueName]
set c_obj ""
set c_name ""
} else {
set c_obj $object
set c_name $prefix[$object getUniqueName]
set t_obj [$object table]
set t_name [$t_obj getUniqueName]
}
# Replace ~~currfield by ~$col_name and
# replace ~~currtab by ~$tab_name.
#
regsub -all {~~currfield} $constr "~\$col_name" constr
regsub -all {~~currtab} $constr "~\$tab_name" constr
$current_section pushIndent
expand_text $current_section "$constr"\
col_name $c_name column $c_obj\
tab_name $t_name table $t_obj
$current_section popIndent
}
#---------------------------------------------------------------------------
#
# EMPTY PROCEDURE DETECTION
#
#---------------------------------------------------------------------------
# Determine for each table if for a specific rule_type and
# for all links (import or export) the rule is "none".
# This used to prevent empty PROCEDRURES generation.
#
proc detect_empty_procs {model} {
global empty_imports_procs
global empty_exports_procs
set link_types {imports exports}
set oper_types {ins del upd}
m4_message $M_EMPTY_PROC_CHECK
foreach table [$model tableSet] {
foreach link_type $link_types {
foreach oper $oper_types {
set empty [all_rules_none $table $link_type $oper]
set empty_${link_type}_procs($oper,$table) $empty
}
}
}
}
# Test if all rules have the value "none"
#
proc all_rules_none {table link_type oper} {
set links [get_$link_type $table]
set empty 1
foreach link $links {
if {[get_${oper}_type $link] != "none"} {
set empty 0
break
}
}
return $empty
}
#---------------------------------------------------------------------------
#
# CYCLE DETECTION IN THE SQLMODEL
#
#---------------------------------------------------------------------------
# Build an array of impossible operations on a table.
# A valid "operation" is one of: ins, upd, del.
#
proc detect_cycli {model} {
# Look for cascade DELETE cycli
#
m4_message $M_DEL_CYCLE_CHECK
set cycle [check_cascade_cycle $model "del" "del_in_detail"]
if {![lempty $cycle]} {
m4_error $E_CYCLE "Delete" [format_cycle $cycle]
}
global impossible_procs
foreach table $cycle {
set impossible_procs(del,$table) 1
}
# Look for cascade UPDATE cycli
#
m4_message $M_UPD_CYCLE_CHECK
set cycle [check_cascade_cycle $model "upd" "upd_in_detail"]
if {![lempty $cycle]} {
m4_error $E_CYCLE "Update" [format_cycle $cycle]
}
foreach table $cycle {
set impossible_procs(upd,$table) 1
}
}
# Check cascade cycle for detail tables.
#
proc check_cascade_cycle {model oper rule_type} {
set dep_list ""
build_dep_list $model dep_list $oper $rule_type
topo_sort dep_list sort unsort
return $unsort
}
# Format a string of table names separated by a ","
#
proc format_cycle {cycle} {
lappend result '[[lvarpop cycle] getUniqueName]'
set separator ", "
foreach table $cycle {
lappend result $separator'[$table getUniqueName]'
}
# Make one string of a list of strings
#
return [join $result]
}
# Build cascade dependency list for all tables in 'model'
#
proc build_dep_list {model dl oper rule_type} {
upvar $dl dep_list
catch {unset dep_list}
foreach table [$model tableSet] {
set count($table) 0
set dep_list($table) ""
}
foreach table [$model tableSet] {
foreach link [$table exportSet] {
if {[get_${oper}_type $link] == $rule_type} {
lappend dep_list([$link detail]) $table
incr count($table)
}
}
}
foreach table [$model tableSet] {
set dep_list($table) [linsert $dep_list($table) 0 $count($table)]
}
}
#
#
proc print_dep_list {dl} {
upvar $dl dep
foreach table [array names dep] {
puts stdout "[$table getUniqueName]\t" nonewline
puts stdout "[lindex $dep($table) 0]\t" nonewline
foreach tdep [lrange $dep($table) 1 end] {
puts stdout "[$tdep getUniqueName] " nonewline
}
puts stdout ""
}
}
#---------------------------------------------------------------------------
#
# DETECTION OF POLICIES CONFLICTS
#
#---------------------------------------------------------------------------
# Detect policy conflicts for the INSERT operation. A conflict would occur if
# an insert into a detail table demands the existence of the
# foreign key in the master table and visa versa i.e. you never will
# be able to insert a tuple in both tables.
# The solution is to make a transaction in which you do the inserts
# into both tables and do not create the procedures which checks the RI
# after an insert.
#
proc detect_pol_conflicts {model} {
global impossible_procs
m4_message $M_POL_CONFLICT_CHECK
foreach table [$model tableSet] {
foreach link [$table importSet] {
detect_pol_conflict $link "insert" "rej_not_exist"
detect_pol_conflict $link "delete" "rej_exist"
}
}
}
# Check for one link if the policies conflict between master and
# detail table
#
proc detect_pol_conflict {link oper rule_type} {
set op [string range $oper 0 2]
set detail_strat [get_${op}_type $link]
set master_strat [get_${op}_type [$link friendLink]]
if {$detail_strat == $rule_type && $master_strat == $rule_type} {
set impossible_procs($op,[$link detail]) 1
set master_name [[$link master] getUniqueName]
set detail_name [[$link detail] getUniqueName]
m4_message $M_NEWL
m4_error $E_POL_CONFLICT $oper $detail_name $master_name
}
}
#---------------------------------------------------------------------------
#
# GENSQL PROCEDURES
#
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------
#
# MAPPING FROM SOURCE FILETYPES TO TARGET FILETYPES
# (See also the progtypes file in your etc/.. directory)
#
#---------------------------------------------------------------------------
global prog_types
set prog_types(g_ptmpl_3) predef_3gl
set prog_types(g_ptmpl_4) predef_4gl
set prog_types(g_ptmpl) predef_4gl
set prog_types(g_stmpl) sql_script
set prog_types(s_ptmpl_3) predef_3gl
set prog_types(s_ptmpl_4) predef_4gl
set prog_types(s_ptmpl) predef_4gl
set prog_types(s_stmpl) sql_script
set prog_types(stmpl) sql_script
#---------------------------------------------------------------------------
#
# MAPPING FROM FILE EXTENSION TO TARGET FILETYPES AND VISA VERSA
#
#---------------------------------------------------------------------------
global prog_files
set prog_files(pt4) predef_4gl
set prog_files(predef_4gl) pt4
set prog_files(pt3) predef_3gl
set prog_files(predef_3gl) pt3
set prog_files(sql) sql_script
set prog_files(sql_script) sql
# Global variabale used to check if the model already is loaded.
#
global model_loaded; set model_loaded 0;
# Global variabale used to store the loaded SQL and OOPL model.
#
# SqlModel
global model
# OoplModel
global oomodel
# Global array contains the database procedures which can
# not be generated because the table they are operating on
# is a part of a cycle.
#
# SYNTAX: impossible_proc(oper,table) value
#
# oper : "ins", "upd", "del"
# table: table_handle
# value: 0 or 1
#
global impossible_procs
# Global array contains the database procedures which can
# cause generation of empty procedures. An empty procedure
# can be generated if all the policies i.e. the rules contain
# the value "none".
#
# SYNTAX: empty_imports_procs(oper,table) value
#
# oper : "ins", "upd", "del"
# table: table_handle
# value: 0 or 1 (0 means empty, 1 not)
#
global empty_imports_procs
global empty_exports_procs
#---------------------------------------------------------------------------
#
# MAIN GENSQL PROCEDURE & FRIENDS
#
#---------------------------------------------------------------------------
# If the before_gensql procedure does not exist declare it.
#
if {[info procs before_gensql] != "before_gensql"} {
proc before_gensql {model} {
# Dummy procedure, do nothing!
#
}
}
#
#
proc gensql {} {
global model oomodel
set model [$oomodel sqlModel]
if {[$model tableSet] == ""} {
m4_message $M_NO_TABLES
return
}
# Call a procedure which can be declared in the target
# depended Tcl script gensql.tcl. It is not nessecary for
# before_gensql to have an implementation
#
before_gensql $model
# Some additional checks
#
detect_cycli $model
detect_pol_conflicts $model
detect_empty_procs $model
gensql_omt
}
# Generate Tcl include commands for the external tables
#
proc gen_includes {sect model name type} {
foreach currtab [$model tableSet] {
if [$currtab isExternal] {
set refd_systems([get_system $currtab]) 1
}
}
if {![info exists refd_systems]} {
return
}
foreach sysname [array names refd_systems] {
$sect append "~\[@include $name $type $sysname]\n"
}
}
#
# Sort the imported columns in the same order as they appear in
# the master table.
#
proc gen_sorted_columns {import} {
set masterTable [$import master]
set masterColumns [get_col_list $masterTable "KEYS"]
set linkColumns [$import columnSet]
set list {}
foreach masterCol $masterColumns {
foreach linkCol $linkColumns {
if {$masterCol == [$linkCol column]} {
lappend list $linkCol
}
}
}
return $list
}