Files
MBS/PROYECTO/otrodir/dbadministrator/fgldbsch.4gl
T

476 lines
15 KiB
Plaintext

-- Warning: Uses fgldbslib.4gl
DEFINE params RECORD
dbname STRING,
filename STRING,
compat SMALLINT,
igncve SMALLINT,
verbose SMALLINT
END RECORD
CONSTANT toolname = "fgldbsch"
CONSTANT fext_coltypes = ".sch"
CONSTANT fext_colvalid = ".val"
CONSTANT fext_colattrs = ".att"
#-------------------------------------------------------------------------------
MAIN
DEFINE i, s SMALLINT
DEFINE fn STRING
DEFER INTERRUPT
DEFER QUIT
IF num_args()==0 THEN
CALL display_usage()
EXIT PROGRAM 1
END IF
CALL fgldbsch_init()
-- Check if program was called by fglschema script
IF cmdarg_option_used("om") THEN
CALL parse_fglschema_options()
ELSE
CALL parse_fgldbsch_options()
END IF
IF ( params.dbname IS NULL OR LENGTH(params.dbname) = 0 ) THEN
CALL display_usage()
EXIT PROGRAM 1
END IF
CALL fgldbsch_set_parameter("dbname",params.dbname)
LET s = fgldbsch_connect()
IF s<>0 THEN
DISPLAY "Connection to database '", params.dbname, "' failed."
IF SQLCA.SQLCODE<>0 THEN
DISPLAY SQLCA.SQLCODE, ": ", SQLERRMESSAGE
ELSE
DISPLAY s, ": ", err_get(s)
END IF
EXIT PROGRAM 1
END IF
IF fgldbsch_get_db_type() IS NULL THEN
DISPLAY "Could not identify the database type..."
EXIT PROGRAM 1
END IF
IF params.compat AND fgldbsch_get_db_type() == "IFX" THEN
CALL fgldbsch_set_parameter( "systabs", "Y" )
END IF
LET int_flag=FALSE
LET quit_flag=FALSE
IF params.filename IS NULL THEN
LET params.filename = params.dbname
LET i = params.dbname.getIndexOf("@",2) -- "dbname@informixserver"
IF i>0 THEN LET params.filename = params.dbname.subString(1,i-1) END IF
LET i = params.dbname.getIndexOf("+",2) -- "dbsource+driver='xxx'"
IF i>0 THEN LET params.filename = params.dbname.subString(1,i-1) END IF
END IF
IF params.verbose THEN
DISPLAY ""
DISPLAY toolname
DISPLAY "----------------------------------------------------------------"
DISPLAY ""
DISPLAY "Extracting database schema from '", params.dbname, "'"
DISPLAY " Database server type detected : ", fgldbsch_get_db_type()
DISPLAY ""
END IF
IF fgldbsch_extract() < 0 THEN
DISPLAY "Could not extract database schema..."
EXIT PROGRAM 1
END IF
LET fn = params.filename, fext_coltypes
CALL output_schema(fn)
IF params.compat THEN
DISPLAY "File \"", fn, "\" created."
END IF
IF fgldbsch_get_db_type() == "IFX" THEN
CALL extract_upscol()
END IF
LET s = fgldbsch_disconnect()
CALL fgldbsch_fini()
END MAIN
#-------------------------------------------------------------------------------
FUNCTION parse_fglschema_options()
DEFINE i INTEGER
DEFINE opt, tmp STRING
LET params.compat = TRUE
CALL fgldbsch_set_parameter("compat","Y")
FOR i=1 TO num_args()
LET tmp = arg_val(i)
IF tmp.getCharAt(1) == "-" THEN
LET opt = tmp.subString(2, tmp.getLength())
CASE opt
WHEN "om" -- ignore
WHEN "c"
CALL fgldbsch_set_parameter("cvmeth", "BBBBBBBBBBBBBB")
WHEN "r"
LET params.igncve = TRUE
OTHERWISE
CALL display_usage()
EXIT PROGRAM 1
END CASE
ELSE
LET params.dbname = tmp
END IF
END FOR
END FUNCTION
#-------------------------------------------------------------------------------
FUNCTION parse_fgldbsch_options()
-- Warning: om option just used to detect old mode usage (see scripts)
IF cmdarg_option_check( "*|V|h|H|v|om|ct|db+|dv+|un+|up+|ow+|tn+|cv+|of+|ie|cu|cl|cc|st" ) != 0 THEN
CALL display_usage()
EXIT PROGRAM 1
END IF
IF cmdarg_option_used( "V" ) THEN
DISPLAY "WARNING: Version info is displayed by calling script!"
EXIT PROGRAM 0
END IF
IF cmdarg_option_used( "h" ) THEN
CALL display_usage()
EXIT PROGRAM 0
END IF
IF cmdarg_option_used( "H" ) THEN
CALL display_help()
EXIT PROGRAM 0
END IF
IF cmdarg_option_used( "ct" ) THEN
CALL fgldbsch_display_convtables()
EXIT PROGRAM 0
END IF
LET params.dbname = cmdarg_option_param("db")
LET params.filename = cmdarg_option_param( "of" )
LET params.igncve = cmdarg_option_used( "ie" )
LET params.verbose = cmdarg_option_used( "v" )
IF params.verbose THEN
CALL fgldbsch_set_parameter("verbose", "Y")
END IF
CALL fgldbsch_set_parameter("dbdriver", cmdarg_option_param("dv"))
CALL fgldbsch_set_parameter("dbowner", cmdarg_option_param("ow"))
CALL fgldbsch_set_parameter("username", cmdarg_option_param("un"))
CALL fgldbsch_set_parameter("userpswd", cmdarg_option_param("up"))
CALL fgldbsch_set_parameter("tabname", cmdarg_option_param("tn"))
CASE
WHEN cmdarg_option_used( "cc" )
CALL fgldbsch_set_parameter("casens","C")
WHEN cmdarg_option_used( "cu" )
CALL fgldbsch_set_parameter("casens","U")
WHEN cmdarg_option_used( "cl" )
CALL fgldbsch_set_parameter("casens","L")
END CASE
IF cmdarg_option_used( "st" ) THEN
CALL fgldbsch_set_parameter( "systabs", "Y" )
END IF
IF cmdarg_option_used( "cv" ) THEN
CALL fgldbsch_set_parameter("cvmeth", cmdarg_option_param("cv"))
END IF
END FUNCTION
#-------------------------------------------------------------------------------
FUNCTION output_schema(fn)
DEFINE fn STRING
DEFINE c,x INTEGER
DEFINE tmp STRING
DEFINE ch base.Channel
DEFINE cl DYNAMIC ARRAY OF RECORD
tabname STRING,
colname STRING,
nattype STRING,
ifxtype INTEGER,
ifxleng INTEGER,
ordinal INTEGER
END RECORD
LET ch = base.Channel.create()
CALL ch.setDelimiter("^")
CALL ch.openFile(fn,"w")
WHILE fgldbsch_next_table() == 1
IF params.verbose THEN
DISPLAY "Table : ", fgldbsch_get_table_name()
END IF
LET x=1
FOR c=1 TO fgldbsch_get_column_count()
CALL fgldbsch_get_column_info(c)
RETURNING cl[x].tabname,
cl[x].colname,
cl[x].nattype,
cl[x].ifxtype,
cl[x].ifxleng
LET cl[x].ordinal = c
IF cl[x].ifxtype = -1 THEN
LET tmp = SFMT("Table \"%1.%2\" has not a valid datatype [%3]",
cl[x].tabname, cl[x].colname, cl[x].nattype)
IF params.compat THEN
IF params.igncve THEN
CONTINUE FOR
ELSE
DISPLAY "Warning: ", tmp, " - table is ignored."
CONTINUE WHILE
END IF
ELSE
IF params.igncve THEN
DISPLAY "Warning: ", tmp, " - table is ignored."
CONTINUE WHILE
ELSE
DISPLAY "ERROR: ", tmp
EXIT PROGRAM 1
END IF
END IF
END IF
LET x=x+1
END FOR
FOR c=1 TO x-1
CALL ch.write([cl[c].tabname,cl[c].colname,cl[c].ifxtype,cl[c].ifxleng,cl[c].ordinal])
END FOR
END WHILE
CALL ch.close()
END FUNCTION
FUNCTION extract_upscol()
DEFINE fn STRING
DEFINE ct INTEGER
WHENEVER ERROR CONTINUE
SELECT COUNT(*) INTO ct FROM syscolval
WHENEVER ERROR STOP
IF status = 0 THEN
LET fn = params.filename, fext_colvalid
UNLOAD TO fn DELIMITER "^"
SELECT UNIQUE tabname, colname, attrname, attrval
FROM syscolval
ORDER BY tabname, colname
IF params.compat THEN
DISPLAY "File \"", fn, "\" created."
END IF
END IF
WHENEVER ERROR CONTINUE
SELECT COUNT(*) INTO ct FROM syscolatt
WHENEVER ERROR STOP
IF status = 0 THEN
LET fn = params.filename, fext_colattrs
UNLOAD TO fn DELIMITER "^"
SELECT UNIQUE tabname, colname, seqno, color, inverse,
underline, blink, left, def_format, condition
FROM syscolatt
ORDER BY tabname, colname, seqno
IF params.compat THEN
DISPLAY "File \"", fn, "\" created."
END IF
END IF
END FUNCTION
FUNCTION display_usage()
DISPLAY "Usage: ", toolname, " [options]"
DISPLAY " -V : Display version information."
DISPLAY " -h : Display this help."
DISPLAY " -H : Display complete help."
DISPLAY " -v : Verbose mode. Default is silent."
DISPLAY " -ct : Show data type conversion tables."
DISPLAY " -db name : Database name."
DISPLAY " -dv name : Database driver."
DISPLAY " -un user : Database User name."
DISPLAY " -up pswd : Database User password."
DISPLAY " -ow name : Database schema/tables owner."
DISPLAY " -tn name : Extract specific table schema."
DISPLAY " -cv strg : Specify conversion method."
DISPLAY " -of name : Output filename prefix. Default is database name."
DISPLAY " -ie : Ignore tables with columns that cannot be converted."
DISPLAY " -cu : Generate upper case names."
DISPLAY " -cl : Generate lower case names."
DISPLAY " -cc : Generate case sensitive names."
DISPLAY " -st : Generate database system tables."
END FUNCTION
FUNCTION display_help()
CALL display_usage()
DISPLAY ""
DISPLAY "This program generates database schema description files from system"
DISPLAY "catalog tables."
DISPLAY ""
DISPLAY "List of generated files:"
DISPLAY " . schemaname.sch : Column definitions with data types."
DISPLAY " . schemaname.val : Validation rules and attributes."
DISPLAY " . schemaname.att : Video attributes (upscol compatibility)."
DISPLAY ""
DISPLAY "The database type is detected automatically after connection, you do"
DISPLAY "not have to specify any database server type."
DISPLAY ""
DISPLAY "You must at least give the database name with the '-db' option. For"
DISPLAY "example : ' -db stores '."
DISPLAY ""
DISPLAY "If the operating system user is not the database user, you can give"
DISPLAY "a database login and password with the '-un' and '-up' options."
DISPLAY ""
DISPLAY "For some databases you may need to specify the schema owner otherwise"
DISPLAY "you may get all the system tables too. Use the '-ow' option to give"
DISPLAY "the database schema owner."
DISPLAY ""
DISPLAY "By default table and column names are converted to lower case letters"
DISPLAY "to enforce compatibility with Informix. But you can force lower case,"
DISPLAY "upper case or case sensitive generation by giving the '-cl', '-cu' or"
DISPLAY "'-cc' options."
DISPLAY ""
DISPLAY "Data types generation in schema files can be controlled with the -cv"
DISPLAY "option. Each character position of the string passed to this option"
DISPLAY "corresponds to a data type in the conversion table."
DISPLAY "For example, ' -cv AAB' indicates that the first and second data type"
DISPLAY "in the conversion table must use the convertion A, while the third"
DISPLAY "type uses conversion B."
DISPLAY "When using X as conversion code, the columns using the corresponding"
DISPLAY "data types will be ignored and not written to the .sch file. This is"
DISPLAY "particularly useful in the case of auto-generated columns like with"
DISPLAY "SQL Server's uniqueidentifier data type, using DEFAULT NEWID()."
DISPLAY "Run this program with the '-ct' option to see the conversion tables."
DISPLAY ""
DISPLAY "Use the -tn option to extract the description of only one specific"
DISPLAY "table from the database. This option is useful if you have created"
DISPLAY "new tables in your database, and you need to extract the schema of"
DISPLAY "the new tables without overwriting the existing schema files."
DISPLAY ""
DISPLAY "Some data types may not be converted to BDL types, and cause an"
DISPLAY "error during schema extraction. To ignore unsupported types, use"
DISPLAY "the -ie option (you still get warnings)."
DISPLAY ""
DISPLAY "Use the -st option to include system tables in the schema. System"
DISPLAY "tables description are not needed if you do not explicitly use"
DISPLAY "them in the programs."
DISPLAY ""
END FUNCTION
#-------------------------------------------------------------------------------
FUNCTION cmdarg_option_used(optname)
DEFINE optname STRING -- The option name without '-'
RETURN ( cmdarg_option_index(optname)>0 )
END FUNCTION
FUNCTION cmdarg_option_param(optname)
DEFINE optname STRING -- The option name without '-'
DEFINE optidx INTEGER
DEFINE paramval STRING -- Can be a directory path !
LET paramval = NULL
LET optidx = cmdarg_option_index(optname)
IF (optidx>0) AND (optidx<num_args()) THEN
-- Get value ( follows option argument )
LET paramval = arg_val(optidx+1)
END IF
RETURN paramval
END FUNCTION
FUNCTION cmdarg_option_index(optname)
DEFINE optname STRING -- The option name without '-'
DEFINE idx, cnt, optidx INTEGER
DEFINE fopt STRING
LET optidx = -1
LET cnt = num_args()
LET fopt = "-", optname -- UNIX convention
FOR idx=1 TO cnt
IF (arg_val(idx)=fopt) THEN
LET optidx = idx
EXIT FOR
END IF
END FOR
RETURN optidx
END FUNCTION
FUNCTION cmdarg_option_isopt(name)
DEFINE name STRING
RETURN ( name.getCharAt(1) == "-" )
END FUNCTION
-- Syntax:
-- <option>+ = option has parameter (next arg must not use -)
-- * = simple string is allowed as argument
FUNCTION cmdarg_option_check(optlist)
DEFINE optlist STRING -- The possible options (v|x|cv|of+|*)
DEFINE optspec STRING
DEFINE optpara STRING
DEFINE i, j INTEGER
DEFINE indiv, found INTEGER
DEFINE tok base.StringTokenizer
DEFINE optarr DYNAMIC ARRAY OF RECORD
optname STRING,
hasparam INTEGER
END RECORD
LET tok = base.StringTokenizer.create(optlist, "|")
WHILE tok.hasMoreTokens()
LET optspec = tok.nextToken()
IF optspec = "*" THEN
LET indiv = TRUE
CONTINUE WHILE
END IF
LET i = optspec.getIndexOf("+",1)
CALL optarr.appendElement()
IF i > 0 THEN
LET optarr[optarr.getLength()].hasparam = 1
LET optspec = optspec.substring(1,i-1)
END IF
LET optarr[optarr.getLength()].optname = optspec
END WHILE
FOR i=1 TO num_args()
LET optspec = arg_val(i)
IF NOT cmdarg_option_isopt(optspec) THEN
IF indiv THEN CONTINUE FOR ELSE RETURN i END IF
END IF
LET optspec = optspec.substring(2,optspec.getLength())
LET found = FALSE
FOR j=1 TO optarr.getLength()
IF optarr[j].optname == optspec THEN
LET found = TRUE
LET optpara = arg_val(i+1)
IF optarr[j].hasparam THEN
IF optpara IS NULL OR cmdarg_option_isopt(optpara) THEN
LET found = FALSE
ELSE
LET i = i + 1
END IF
ELSE
IF optpara IS NOT NULL AND NOT cmdarg_option_isopt(optpara) THEN
LET found = FALSE
END IF
END IF
EXIT FOR
END IF
END FOR
IF NOT found THEN RETURN i END IF
END FOR
RETURN 0
END FUNCTION