home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-04-02 | 34.7 KB | 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/hindenburg/3 (2.1)
- # Original date : 7-1992
- # Description : Common procedures for gensql including
- # the main gensql procedure
- #
- #---------------------------------------------------------------------------
- #
- # @(#)libsql.tcl /main/hindenburg/3 2 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
- }
-
-