# DBENG (Bbuuzzb) configuration module. This module reads the
# settings in the DBENG config file (DBENG_CONFIG_FILE).
# This module also provides the 'get' and 'set' access
# procedures. Used in single user database applications
# and the database server.
# Rick Smereka, Copyright (C) 2005.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, get a copy via the Internet at
# http://gnu.org/copyleft/gpl.html or write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
# MA 02111-1307 USA

# You can contact the author via email at rsmereka@future-lab.com

# This tcl version stores the configuration settings in an
# array called 'dbeng_config'. This module also depends on
# the variable 'MULTIUSER' being defined zero for single
# user or one for the database server.

# The DBENG config file is a normal ASCII file that can
# contain the following settings:

#    tmp_path path
#    log file
#    session_table file
#    catalog file

# 'tmp_path' specifies the complete path to use for
# DBENG temporary files. If not specified, the
# path used will be 'DBENG_DEFAULT_TMP_PATH'.
# 'log' is the path and file name of the
# DBENG error log. If not specified, the file
# used will be 'DBENG_DEFAULT_LOG'.
# 'session_table' is the path and file name of
# the system session table. If not specified,
# the file used will be 'DBENG_DEFAULT_SESSION_TABLE'.
# 'catalog' is the path and file name of the
# system catalog. If not specified, the file
# used will be 'DBENG_DEFAULT_CATALOG'.
# The session table is only used with
# the c/s version. It is currently used by 'dbsrv'.
# All data on the configuration lines after the
# required parameters and all lines not containing
# a valid keyword will be ignored.

# Initial tcl version. Jul/2005, Rick Smereka

# default configuration values based on platform
if {$tcl_platform(platform) == "unix"} {
   const DBENG_DEFAULT_TMP_PATH "/home/rick/tmp"
   const DBENG_DEFAULT_LOG "/home/rick/logs/dbeng.log"
   const DBENG_DEFAULT_SESSION "/home/rick/tmp/dbeng.ses"
   const DBENG_DEFAULT_CATALOG "/home/rick/tmp/dbeng.cat"
}

if {$tcl_platform(platform) == "windows"} {
   const DBENG_DEFAULT_TMP_PATH "c:/tmp"
   const DBENG_DEFAULT_LOG "c:/tmp/dbeng.log"
   const DBENG_DEFAULT_SESSION "c:/tmp/dbeng.ses"
   const DBENG_DEFAULT_CATALOG "c:/tmp/dbeng.cat"
}

# config file name
const DBENG_CONFIG_FILE "dbeng.cfg"

# configuration data
set dbeng_config(tmp_path) ""
set dbeng_config(log) ""
set dbeng_config(log_flag) 0
set dbeng_config(catalog) ""
set dbeng_config(catalog_flag) 0

if {$MULTIUSER} {
   set dbeng_config(session_table) ""
   set dbeng_config(session_flag) 0
   set dbeng_config(replicate_flag) 0
}

proc dbeng_config_read {fname} {
   # Read and parse the DBENG config file 'fname'.
   # Returns 1 upon success, 0 otherwise.
   # Upon successful completion, the configuration
   # data will be loaded from the file. Note that missing
   # data will be filled in from default data as defined
   # above. Returns a 'dbeng' code.
   global DBENG_OK DBENG_DEFAULT_TMP_PATH DBENG_DEFAULT_LOG
   global DBENG_DEFAULT_SESSION DBENG_DEFAULT_CATALOG
   global DBENG_CONFIG_UNABLE_TO_OPEN DBENG_CONFIG_PARAMETER_MISSING
   global dbeng_config DBENG_INTERNAL_ERROR MULTIUSER
   set mname "dbeng_config_read"
   
   logman "$mname:enter"

   # attempt to open config file, if not found, attempt
   # to load compiled defaults and exit

   if {[catch {open $fname r} in]} {
      set ret [db_config_set_tmp_path $DBENG_DEFAULT_TMP_PATH]

      if {$ret != $DBENG_OK} {
         db_io_code_log $mname "exit:bad ret from db_config_set_tmp_path" $ret
         return $ret
      }

      set ret [db_config_set_log $DBENG_DEFAULT_LOG]

      if {$ret != $DBENG_OK} {
         db_io_code_log $mname "exit:bad ret from db_config_set_log" $ret
         return $ret
      }

      if {$MULTIUSER} {
         set ret [db_config_set_session $DBENG_DEFAULT_SESSION]

         if {$ret != $DBENG_OK} {
            db_io_code_log $mname "exit:bad ret from db_config_set_session" $ret
            return $ret
         }
      }

      set ret [db_config_set_catalog $DBENG_DEFAULT_CATALOG]

      if {$ret != $DBENG_OK} {
         db_io_code_log $mname "exit:bad ret from dbeng_config_set_catalog" \
                        $ret
         return $ret
      }

      db_io_code_log $mname "exit:no config file, loaded defaults" \
                     $DBENG_CONFIG_UNABLE_TO_OPEN
      return $DBENG_CONFIG_UNABLE_TO_OPEN
   }

   # get first record/line
   set line [get_rec $in]

   while {![eof $in]} {
      # number of command words on line
      set nwords [command_words $line]

      # must have at least two command words per record/line

      if {$nwords < 2} {
         close $in
         db_io_code_log $mname "exit:missing parameter" \
                        $DBENG_CONFIG_PARAMETER_MISSING
         return $DBENG_CONFIG_PARAMETER_MISSING
      }

      # get first command word on line
      if {![command_word $line word 1]} {
         close $in
         db_io_code_log $mname "exit:command_word[1] fail" \
                        $DBENG_INTERNAL_ERROR
         return(DBENG_INTERNAL_ERROR);
         }

      # force it to upper case
      set ucase_word [ucase $word]

      # is it the 'tmp_path' keyword?

      if {$ucase_word == "TMP_PATH"} {
         set word ""

         # get second command word
         if {![command_word $line word 2]} {
            close $in
            db_io_code_log $mname "exit:command_word[2,tmp_path] fail" \
                           $DBENG_INTERNAL_ERROR
            return $DBENG_INTERNAL_ERROR
         }

         # set path
         set ret [db_config_set_tmp_path $word]

         if {$ret != $DBENG_OK} {
            close $in
            db_io_code_log $mname "exit:bad rc db_config_set_tmp_path" \
                           $ret
            return $ret
         }
      }

      # is it the 'log' keyword?
      if {$ucase_word == "LOG"} {
         set word ""

         if {![command_word $line word 2]} {
            close $in
            db_io_code_log $mname "exit:command_word[2,log] fail" \
                           $DBENG_INTERNAL_ERROR
            return $DBENG_INTERNAL_ERROR
         }

         # set log name
         set ret [db_config_set_log $word]

         if {$ret != $DBENG_OK} {
            close $in
            db_io_code_log $mname "exit:bad rc db_config_set_log" $ret
            return $ret
         }
      }

      if {$MULTIUSER} {
         # is it the 'session_table' keyword?
         # which is valid only for the database
         # server
         if {$ucase_word == "SESSION_TABLE"} {
            set word ""

            if {![command_word $line word 2]} {
               close $in
               db_io_code_log $mname "exit:command_word[2,session_table] fail" \
                              $DBENG_INTERNAL_ERROR
               return $DBENG_INTERNAL_ERROR
            }

            set ret [db_config_set_session $word]

            if {$ret != $DBENG_OK} {
               close $in
               db_io_code_log $mname "exit:bad rc db_config_set_session" $ret
               return $ret
            }
         }
      }

      # is it the 'catalog' keyword?
      if {$ucase_word == "CATALOG"} {
         set word ""

         if {![command_word $line word 2]} {
            close $in
            db_io_code_log $mname "exit:command_word[2,catalog] fail" \
                           $DBENG_INTERNAL_ERROR
            return $DBENG_INTERNAL_ERROR
         }

         # set catalog name
         set ret [db_config_set_catalog $word]

         if {$ret != $DBENG_OK} {
            close $in
            db_io_code_log $mname "exit:bad rc db_config_set_catalog" $ret
            return $ret
         }
      }

      # get next line/record
      set line [get_rec $in]
   }

   close $in

   # handle defaults in the case of missing data
   if {$dbeng_config(tmp_path) == ""} {
      set ret [db_config_set_tmp_path $DBENG_DEFAULT_TMP_PATH]

      if {$ret != $DBENG_OK} {
         db_io_code_log $mname "exit:bad ret db_config_set_tmp_path" $ret
         return $ret
      }
   }

   if {$dbeng_config(log) == ""} {
      set ret [db_config_set_log $DBENG_DEFAULT_LOG]

      if {$ret != $DBENG_OK} {
         db_io_code_log $mname "exit:bad ret db_config_set_log" $ret
         return $ret
      }
   }

   if {$MULTIUSER} {
      if {$dbeng_config(session_table) == ""} {
         set ret [db_config_set_session $DBENG_DEFAULT_SESSION]

         if {$ret != $DBENG_OK} {
            db_io_code_log $mname "exit:bad ret db_config_set_session" $ret
            return $ret
         }
      }

      # we set the default if no catalog given for the database
      # server, single user apps will have no default if no
      # catalog is given
      if {$dbeng_config(catalog) == ""} {
         set ret [db_config_set_catalog $DBENG_DEFAULT_CATALOG]

         if {$ret != $DBENG_OK} {
            db_io_code_log $mname "exit:bad ret db_config_set_catalog" $ret
            return $ret
         }
      }
   } else {
      # single user apps have the catalog enabled if it was
      # supplied in the config file
      if {$dbeng_config(catalog) != ""} {
         set ret [db_config_set_catalog_flag 1]

         if {$ret != $DBENG_OK} {
            db_io_code_log $mname \
                           "exit:bad rc from db_config_set_catalog_flag" $ret
         return(ret);
         }
      }
   }

   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc db_config_get_tmp_path {path} {
   # Load the global 'dbeng_config(tmp_path)' into 'path'.
   # Returns a 'dbeng' code.
   global dbeng_config DBENG_INVALID_FUNCTION DBENG_OK
   upvar $path upath
   set mname "db_config_get_tmp_path"

   logman "$mname:enter"

   if {$dbeng_config(tmp_path) == ""} {
      db_io_code_log $mname "exit:tmp path not loaded" $DBENG_INVALID_FUNCTION
      set upath ""
      return $DBENG_INVALID_FUNCTION
   }

   set upath $dbeng_config(tmp_path)
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}
 
proc db_config_get_log {slog} {
   # Load the global 'dbeng_config(log)' into 'slog'.
   # Returns a 'dbeng' code.
   global dbeng_config DBENG_INVALID_FUNCTION DBENG_OK
   upvar $slog uslog
   set mname "db_config_get_log"

   logman "$mname:enter"

   if {$dbeng_config(log) == ""} {
      db_io_code_log $mname "exit:log not loaded" $DBENG_INVALID_FUNCTION
      set uslog ""
      return $DBENG_INVALID_FUNCTION
   }

   set uslog $dbeng_config(log)
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc db_config_is_session {fname} {
   # Determine whether 'fname' is the session table.
   # Returns 1 if 'fname' is the session table, 0
   # otherwise.
   global MULTIUSER DBENG_ACCESS_DENIED
   set mname "db_config_is_session"

   # not allowed from single user
   if {!$MULTIUSER} {
      db_io_code_log $mname "exit(0):valid only for database server" \
                     $DBENG_ACCESS_DENIED
      return 0
   }

   if {$fname == ""} {
      logman "$mname:exit(0):empty(fname)"
      return 0
   }

   logman "$mname:enter:fname=$fname,l=[string length $fname]"
   db_config_get_session_flag session_flag

   # if session table is not active, cannot be the session table
   # even if the name matches
   if {!$session_flag} {
      logman "$mname:exit(0):session table not active"
      return 0
   }

   db_config_get_session ses_table

   if {$fname == $ses_table} {
      logman "$mname:exit(1):matches session table"
      return 1
   }

   logman "$mname:exit(0):no match"
   return 0
}

proc db_config_is_catalog {fname} {
   # Determine whether 'fname' is the catalog. Returns 1 if
   # the catalog was found, 0 otherwise.
   set mname "db_config_is_catalog"

   if {$fname == ""} {
      logman "$mname:exit(0):empty(fname)"
      return 0
   }
   
   logman "$mname:enter:fname=$fname,l=[string length $fname]"
   db_config_get_catalog_flag catalog_flag

   # if catalog is not active, cannot be the catalog even if
   # the name matches
   if {!$catalog_flag} {
      logman "$mname:exit(0):catalog not active"
      return 0
   }

   db_config_get_catalog cat

   if {$fname == $cat} {
      logman "$mname:exit(1):matches catalog"
      return 1
   }

   logman "$mname:exit(0):no match"
   return 0
}

proc db_config_get_session {ses_table} {
   # Load the global 'dbeng_config(session_table)' into 'ses_table'
   # Returns a 'dbeng' code.
   global dbeng_config DBENG_INVALID_FUNCTION DBENG_OK
   global MULTIUSER DBENG_ACCESS_DENIED
   upvar $ses_table uses_table
   set mname "db_config_get_session"

   logman "$mname:enter"

   # not allowed from single user
   if {!$MULTIUSER} {
      db_io_code_log $mname "valid only for database server" \
                     $DBENG_ACCESS_DENIED
      set uses_table ""
      return $DBENG_ACCESS_DENIED
   }

   if {$dbeng_config(session_table) == ""} {
      db_io_code_log $mname "exit:session table not loaded" \
                     $DBENG_INVALID_FUNCTION
      set uses_table ""
      return $DBENG_INVALID_FUNCTION
   }

   set uses_table $dbeng_config(session_table)
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc db_config_get_catalog {cat} {
   # Load the global 'dbeng_config(catalog)' into 'cat'.
   # Returns a 'dbeng' code.
   global dbeng_config DBENG_INVALID_FUNCTION DBENG_OK
   upvar $cat ucat
   set mname "db_config_get_catalog"

   logman "$mname:enter"

   if {$dbeng_config(catalog) == ""} {
      db_io_code_log $mname "exit:catalog not loaded" $DBENG_INVALID_FUNCTION
      set ucat ""
      return $DBENG_INVALID_FUNCTION
   }

   set ucat $dbeng_config(catalog)
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc db_config_get_log_flag {flag} {
   # Get the value of 'dbeng_config(session_flag)' and load
   # the value into 'flag'. Returns a 'dbeng' code.
   global dbeng_config DBENG_OK
   upvar $flag uflag
   set mname "db_config_get_log_flag"

   logman "$mname:enter"
   set uflag $dbeng_config(log_flag)
   logman "$mname:normal exit(0),flag=$dbeng_config(log_flag)"
   return $DBENG_OK
}

proc db_config_get_session_flag {flag} {
   # Get the value of 'dbeng_config(session_flag)' and load
   # the value into 'flag'. Returns a 'dbeng' code.
   global dbeng_config DBENG_INVALID_FUNCTION DBENG_OK
   global MULTIUSER DBENG_ACCESS_DENIED
   upvar $flag uflag
   set mname "db_config_get_session_flag"

   logman "$mname:enter"

   # not allowed from single user
   if {!$MULTIUSER} {
      db_io_code_log $mname "valid only for database server" \
                     $DBENG_ACCESS_DENIED
      set uflag 0
      return $DBENG_ACCESS_DENIED
   }

   set uflag $dbeng_config(session_flag)
   logman "$mname:normal exit(0),flag=$dbeng_config(session_flag)"
   return $DBENG_OK
}

proc db_config_get_catalog_flag {flag} {
   # Get the value of 'dbeng_config(catalog_flag)' and load
   # the value into 'flag'. Returns a 'dbeng' code.
   global dbeng_config DBENG_OK
   upvar $flag uflag
   set mname "db_config_get_catalog_flag"

   logman "$mname:enter"
   set uflag $dbeng_config(catalog_flag)
   logman "$mname:normal exit(0),flag=$dbeng_config(catalog_flag)"
   return $DBENG_OK
}

proc db_config_get_replicate_flag {flag} {
   # Get the value of 'dbeng_config(replicate_flag)' and load
   # the value into 'flag'. Returns a 'dbeng' code.
   global dbeng_config DBENG_INVALID_FUNCTION DBENG_OK
   global MULTIUSER DBENG_ACCESS_DENIED
   upvar $flag uflag
   set mname "db_config_get_replicate_flag"

   logman "$mname:enter"

   # not allowed from single user
   if {!$MULTIUSER} {
      db_io_code_log $mname "valid only for database server" \
                     $DBENG_ACCESS_DENIED
      set uflag 0
      return $DBENG_ACCESS_DENIED
   }

   set uflag $dbeng_config(replicate_flag)
   logman "$mname:normal exit(0),flag=$dbeng_config(replicate_flag)"
   return $DBENG_OK
}

proc db_config_get_version {ver} {
   # Get the 'dbeng' version ID string. Returns a 'dbeng' code
   # with the version ID loaded into 'ver' upon success.
   global DBENG_VERSION DBENG_OK
   upvar $ver uver
   set mname "db_config_get_version"

   logman "$mname:enter"
   set uver $DBENG_VERSION
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc db_config_set_tmp_path {path} {
   # Load 'dbeng_config(tmp_path)' with the data from 'path'.
   # Returns a 'dbeng' code.
   global dbeng_config DBENG_OK DBENG_INVALID_FUNCTION
   set mname "db_config_set_tmp_path"

   logman "$mname:enter"

   if {$path == ""} {
      db_io_code_log $mname "exit:empty(tmp_path)" $DBENG_INVALID_FUNCTION
      return $DBENG_INVALID_FUNCTION
   }

   set ret [dbeng_config_valid_tmp_path $path]

   if {$ret != $DBENG_OK} {
      db_io_code_log $mname "exit:bad ret db_config_valid_tmp_path" $ret
      return $ret
   }

   set dbeng_config(tmp_path) $path
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc db_config_set_log {slog} {
   # Load 'dbeng_config(log)' with the data from 'slog'.
   # Returns a 'dbeng' code.
   global dbeng_config DBENG_OK DBENG_INVALID_FUNCTION
   set mname "db_config_set_log"

   logman "$mname:enter"

   if {$slog == ""} {
      db_io_code_log $mname "exit:empty(slog)" $DBENG_INVALID_FUNCTION
      return $DBENG_INVALID_FUNCTION
   }

   set dbeng_config(log) $slog
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc db_config_set_catalog {cat} {
   # Load 'dbeng_config(catalog)' with the data from 'cat'.
   # The catalog file must exist.
   # Returns a 'dbeng' code.
   global dbeng_config DBENG_OK DBENG_INVALID_FUNCTION
   set mname "db_config_set_catalog"

   logman "$mname:enter"

   if {$cat == ""} {
      db_io_code_log $mname "exit:empty(cat)" $DBENG_INVALID_FUNCTION
      return $DBENG_INVALID_FUNCTION
   }

   set ret [dbeng_config_valid_catalog $cat]

   if {$ret != $DBENG_OK} {
      db_io_code_log $mname "exit:bad ret db_config_vaid_catalog" $ret
      return $ret
   }

   set dbeng_config(catalog) $cat
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc db_config_set_session {ses_table} {
   # Load 'dbeng_config(session_table)' with the data from 'ses_table'.
   # Applies to database server only.
   # If the file does not already exist, an attempt will be made
   # to create it.
   # Returns a 'dbeng' code.
   global dbeng_config DBENG_OK DBENG_INVALID_FUNCTION DBENG_ACCESS_DENIED
   global MULTIUSER DBENG_CANNOT_CREATE_TABLE
   set mname "db_config_set_session"

   logman "$mname:enter"

   # not allowed from single user
   if {!$MULTIUSER} {
      db_io_code_log $mname "valid only for database server" \
                     $DBENG_ACCESS_DENIED
      return $DBENG_ACCESS_DENIED
   }

   if {$ses_table == ""} {
      db_io_code_log $mname "exit:empty(ses_table)" $DBENG_INVALID_FUNCTION
      return $DBENG_INVALID_FUNCTION
   }

   # attempt to create the file if it does not exist
   if {![exist $ses_table]} {
      if {![zcreate $ses_table]} {
         db_io_code_log $mname "exit:cannot create session table" \
                        $DBENG_CANNOT_CREATE_TABLE
         return $DBENG_CANNOT_CREATE_TABLE
      }
   }

   set ret [dbeng_config_valid_session $ses_table]

   if {$ret != $DBENG_OK} {
      db_io_code_log $mname "exit:bad ret db_config_vaid_session" $ret
      return $ret
   }

   set dbeng_config(session_table) $ses_table
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc db_config_set_log_flag {flag} {
   # Set 'dbeng_config(log_flag)' to the value of 'flag' which
   # must be zero or one and activate or de-activate logging.
   # Returns a 'dbeng' code.
   global dbeng_config DBENG_INVALID_FUNCTION DBENG_CONFIG_INVALID_LOG DBENG_OK
   set mname "db_config_set_log_flag"

   logman "$mname:enter"

   if {$flag != 1 && $flag != 0} {
      db_io_code_log $mname "exit:flag not 0 or 1" $DBENG_INVALID_FUNCTION
      return $DBENG_INVALID_FUNCTION
   }

   if {$flag} {
      set ap [appinit_get_name]

      if {$ap == ""} {
         db_io_code_log $mname "exit:bad rc(empty) from appinit_get_name" \
                        $DBENG_INVALID_FUNCTION
         return $DBENG_INVALID_FUNCTION
      }

      if {[logman_start $dbeng_config(log) $ap]} {
         db_io_code_log $mname "exit:bad rc(1) from logman_start" \
                        $DBENG_CONFIG_INVALID_LOG
         return $DBENG_CONFIG_INVALID_LOG
      }
   } else {
      logman_end
   }

   set dbeng_config(log_flag) $flag
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc db_config_set_session_flag {flag} {
   # Set 'dbeng_config(session_flag)' to the value of 'flag'
   # which must be zero or one. The session table will be
   # flushed when the session flag is set to on. Returns
   # a 'dbeng' code.
   global dbeng_config MULTIUSER DBENG_INVALID_FUNCTION DBENG_OK
   global DBENG_ACCESS_DENIED
   set mname "db_config_set_session_flag"

   logman "$mname:enter"

   # not allowed from single user
   if {!$MULTIUSER} {
      db_io_code_log $mname "valid only for database server" \
                     $DBENG_ACCESS_DENIED
      return $DBENG_ACCESS_DENIED
   }

   if {$flag != 1 && $flag != 0} {
      db_io_code_log $mname "exit:(flag) not 0 or 1" $DBENG_INVALID_FUNCTION
      return $DBENG_INVALID_FUNCTION
   }

   set dbeng_config(session_flag) $flag

   # if {$flag} {
   #    set ret [dbeng_session_flush_all]
   #
   #    if {$ret != $DBENG_OK} {
   #       db_io_code_string $mname "exit:bad rc from dbeng_session_flush_all" \
   #                         $ret
   #    }
   # }

   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc db_config_set_catalog_flag {flag} {
   # Set 'dbeng_config(catalog_flag)' to the value of
   # 'flag' which must be zero or one.
   # Returns a 'dbeng' code.
   global dbeng_config DBENG_INVALID_FUNCTION DBENG_NO_CATALOG DBENG_OK
   set mname "db_config_set_catalog_flag"

   logman "$mname:enter"

   if {$flag != 1 && $flag != 0} {
      db_io_code_log $mname "exit:not 0 or 1(flag)" $DBENG_INVALID_FUNCTION
      return $DBENG_INVALID_FUNCTION
   }

   # if activating catalog, make sure catalog name is loaded
   if {$flag == 1} {
      if {$dbeng_config(catalog) == ""} {
         db_io_code_log $mname "exit:no catalog name" $DBENG_NO_CATALOG
         return $DBENG_NO_CATALOG
      }
   }

   set dbeng_config(catalog_flag) $flag
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc db_config_set_replicate_flag {flag} {
   # Set 'dbeng_config(replicate_flag)' to the value of 'flag'
   # which must be zero or one. Returns a 'dbeng' code.
   global dbeng_config MULTIUSER DBENG_INVALID_FUNCTION DBENG_OK
   global DBENG_ACCESS_DENIED
   set mname "db_config_set_replicate_flag"

   logman "$mname:enter"

   # not allowed from single user
   if {!$MULTIUSER} {
      db_io_code_log $mname "valid only for database server" \
                     $DBENG_ACCESS_DENIED
      return $DBENG_ACCESS_DENIED
   }

   if {$flag != 1 && $flag != 0} {
      db_io_code_log $mname "exit:(flag) not 0 or 1" $DBENG_INVALID_FUNCTION
      return $DBENG_INVALID_FUNCTION
   }

   if {$flag && !$dbeng_config(catalog_flag)} {
      db_io_code_log $mname "exit:catalog not active" $DBENG_ACCESS_DENIED
      return $DBENG_ACCESS_DENIED
   }

   set dbeng_config(replicate_flag) $flag
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc dbeng_config_valid_tmp_path {path} {
   # Validate the temporary 'path' by attempting to open
   # a file for writing. Returns a 'dbeng' code.
   global DBENG_OK DBENG_CONFIG_INVALID_TMP_PATH
   set mname "dbeng_config_valid_tmp_path"

   if {$path == ""} {
      db_io_code_log $mname "exit:empty(path)" $DBENG_CONFIG_INVALID_TMP_PATH
      return $DBENG_CONFIG_INVALID_TMP_PATH
   }

   if {![unique $path rname]} {
      db_io_code_log $mname "bad ret unique" $DBENG_CONFIG_INVALID_TMP_PATH
      return $DBENG_CONFIG_INVALID_TMP_PATH
   }

   set tname "$path/$rname"

   if {[catch {open $tname w} out]} {
      db_io_code_log $mname "exit:cannot create tmp file" \
                     $DBENG_CONFIG_INVALID_TMP_PATH
      return $DBENG_CONFIG_INVALID_TMP_PATH
   }

   close $out
   file delete $tname
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc dbeng_config_valid_catalog {cat} {
   # Validate the system catalog path/name by attempting
   # to open it. Returns a 'dbeng' code.
   global DBENG_OK DBENG_CONFIG_INVALID_TMP_PATH
   set mname "dbeng_config_valid_catalog"

   if {$cat == ""} {
      db_io_code_log $mname "exit:empty(cat)" $DBENG_CONFIG_INVALID_CATALOG
      return $DBENG_CONFIG_INVALID_CATALOG
   }

   set ret [db_open $cat tid]

   if {$ret != $DBENG_OK} {
      db_io_code_log $mname "exit:bad ret db_open" $ret
      return $ret
   }

   db_close $tid
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}

proc dbeng_config_valid_session {ses_table} {
   # Validate the session table path/name by attempting
   # to open it. Returns a 'dbeng' code.
   global DBENG_OK DBENG_CONFIG_INVALID_SESSION_TABLE DBENG_ACCESS_DENIED
   global MULTIUSER
   set mname "dbeng_config_valid_session"

   logman "$mname:enter"

   # not allowed from single user
   if {!$MULTIUSER} {
      db_io_code_log $mname "valid only for database server" \
                     $DBENG_ACCESS_DENIED
      return $DBENG_ACCESS_DENIED
   }

   if {$ses_table == ""} {
      db_io_code_log $mname "exit:empty(ses_table)" \
                     $DBENG_INVALID_SESSION_TABLE
      return $DBENG_INVALID_SESSION_TABLE
   }

   set ret [db_open $ses_table tid]

   if {$ret != $DBENG_OK} {
      db_io_code_log $mname "exit:bad ret from db_open" $ret
      return $ret
   }

   db_close $tid
   db_io_code_log $mname "normal exit" $DBENG_OK
   return $DBENG_OK
}
