with concrete_package; use concrete_package; with text_io; use text_io; with linked_list; with string_pack; use string_pack; with enumeration_image; with variable_io; -- *********************************************************************** -- Programmer Name : S. Phillips -- Program Name : abstract_interface_generator generic package body -- Revision Number : Rev 1.0 -- Date Created : December 1, 1989 -- Functional Description : This package contains the generic bodies that -- provide semantic checks for consistency on the procedure written by -- the abstract interface programmer to describe the interface. The -- package also creates the two Ada programs (files) which represent the -- abstract interface specification and abstract interface body. The -- procedure written by the abstract interface programmer is the only -- code which calls this package. --************************************************************************* package body abstract_interface_generator is -- integer types real_length : integer := 0; -- string types ops_string, ops_string1 : string (1..max_ops_string_length) := (others => ' '); -- record objects type static_component_info is record the_component_name : string (1..max_comp_name_length); its_base_type : base_specific_domain_types; string_indicator_record : boolean := false; end record; -- array types and objects used for consistency checking during execution type record_name_array is array (record_names) of boolean; record_defined : record_name_array := (others => false); type procedure_array is array (procedure_names) of boolean; procedure_defined : procedure_array := (others => false); -- files for output which will contain the Ada spec and body of the abstract interface -- the concrete interface and file containing information useful when generating DBMS -- specific concrete interfaces abstract_spec : file_type; abstract_body : file_type; concrete_spec : file_type; dbms_specific : file_type; -- exceptions specific to this package duplicate_record : exception; duplicate_component : exception; duplicate_parameter : exception; duplicate_procedure : exception; parameter_not_defined : exception; component_not_defined : exception; unequal : exception; -- used when the user provides an unequal number of errors expected and sqlcodes. too_many_result_parameters : exception; -- used when user provides more than one result parameter. no_result_parameter : exception; -- used when user provides no result parameter and one is expected. too_many_errors_for_type_bool : exception; -- used when user provides too many possible errors for a parameter of type -- boolean illegal_parameter_profile : exception; -- used when user describes a procedure which requires parameters as one that -- has no parameters invalid_parameter_to_concrete_procedure : exception; -- Raised when user provides a parameter to the concrete -- module which has not been passed to the abstract procedure -- previously. This does not include the sqlcode parameter or -- indicator variables. record_type_not_allowed : exception; no_ops_package : exception; -- Raised when a user is trying to send a variable of some null bearing domain type -- type over to the database when the ops package has not been instantiated for that -- type. -- boolean checks error_occured : boolean := false; -- to keep track of whether or not to build files -- instantiations package spec_io is new variable_io(75); -- for inputting text into the abstract i/f spec package body_io is new variable_io (75);-- for inputting text into the abstract i/f body package concrete_io is new variable_io (75); -- for inputting text into the concrete spec package specific_io is new variable_io(75); -- for inputting text into the dbms specific file function error_enum is new enumeration_image(error_conditions_allowed); package list_of_recs is new linked_list(static_component_info); use list_of_recs; type rec_array is array (record_names) of list; -- an array of all records each pointing to a list of its components all_row_records : rec_array; all_indic_records : rec_array; package body record_generator is -- the following two declarations are used to verify that two -- components are not named the same type component_info is record defined : boolean := false; its_type : base_specific_domain_types; end record; type component_array is array (components_in_record) of component_info; component_information : component_array; component : static_component_info; -- the following generic is instantiated once for each -- component within the record package body component_generator is not_complete : boolean := false; begin if component_information(component_name).defined -- if this component has been described previously then raise duplicate_component; else component_information(component_name).defined := true; -- save the component informantion for later reference component_information(component_name).its_type := component_domain_type; move(components_in_record'image(component_name), component.the_component_name); component.its_base_type := component_domain_type; if is_string_indicator_record then component.string_indicator_record := true; add_member(all_indic_records(record_name),component); else add_member(all_row_records(record_name),component); end if; end if; exception when duplicate_component => put_line (error & components_in_record'image(component_name) & multiple_description); error_occured := true; end component_generator; procedure generate_record is begin if error_occured -- don't edit the spec with this information..errors occured in generation then null; else -- here is where editting to generate record definitions takes place spec_io.put_line(abstract_spec, indent4 & "type " & record_names'image(record_name) & " is record"); for i in components_in_record loop -- loop through each component of this record if is_string_indicator_record -- if this record is used to hold string indicators then spec_io.put_line (abstract_spec, indent5 & components_in_record'image(i) & " : sql_standard.indicator_type;"); -- it is a record of indicators for string lengths else declare temp : components_in_record; begin if not component_information(i).defined -- this component not described then temp := i; raise component_not_defined; else spec_io.put_line (abstract_spec, indent5 & components_in_record'image(i) & " : " & base_specific_domain_types'image(component_information(i).its_type) & ";"); end if; exception when component_not_defined => text_io.put_line(error & components_in_record'image(i) & " in record " & record_names'image (record_name) & missing_description); error_occured := true; end; end if; end loop; spec_io.put_line (abstract_spec, indent4 & "end record;"); -- record generation complete spec_io.put_line (abstract_spec, indent1); -- for a blank line between record declarations end if; end generate_record; begin -- record_generator if record_defined (record_name) -- if this record has already been described then raise duplicate_record; else record_defined (record_name) := true; end if; exception when duplicate_record => put_line (error & record_names'image(record_name) & multiple_description); error_occured := true; end record_generator; -- the following generic, procedure_generator, is instantiated -- once for each procecdure in the interface package body procedure_with_parameters_generator is -- the following declarations are used to keep track of -- procedure information for editting the abstract_interface spec type parm_type is (rec, bool, dom, err); -- all possible parameter 'types' type parm_info is record -- record type containing all information about parameters defined : boolean := false; parm : parm_type; parm_base_type : base_specific_domain_types := null_domain_type; parm_rec_type : record_names; parm_err_type : error_conditions_allowed; end record; err_params_name, rec_params_name, bool_params_name, indic_params_name : parameters; type parameter_array is array (parameters) of parm_info; parameter_information : parameter_array; got_to_exit : boolean := false; have_err_type : boolean := false; -- to keep track of which kind of result parameter is present have_bool_type : boolean := false;-- to keep track of which kind of result parameter is present have_rec_type : boolean := false; -- to determine if one of the parameters to the abstract procedure -- is a record have_indic_type : boolean := false; -- to determine if one of the parameters to the abstract procedures -- is a record containg only string indicators type record_type_array is array (1..max_num_of_indic_records) of record_names; records_type : record_type_array; -- which record type this record is number_of_records : integer := 0; package body params_of_domain_type_generator is begin if parameter_information(params).defined -- if this parameter has been described previously then raise duplicate_parameter; else parameter_information(params).defined := true; end if; -- save parameter information for later editting parameter_information(params).parm := dom; parameter_information(params).parm_base_type := its_type; exception when duplicate_parameter => -- if this parameter has been previously described put_line(error & parameters'image(params) & " of procedure " & procedure_names'image(procedure_name) & multiple_description); error_occured := true; end params_of_domain_type_generator; package body params_of_error_conditions_generator is begin if parameter_information(params).defined -- if this parameter has been described previously then raise duplicate_parameter; else parameter_information(params).defined := true; have_err_type := true; err_params_name := params; end if; -- save parameter information for later editting parameter_information(params).parm := err; exception when duplicate_parameter => -- if this parameter has been previously described put_line(error & parameters'image(params) & " of procedure " & procedure_names'image(procedure_name) & multiple_description); error_occured := true; end params_of_error_conditions_generator; package body params_of_record_type_generator is begin if parameter_information(params).defined -- if this parameter has been described previously then raise duplicate_parameter; else parameter_information(params).defined := true; end if; -- save parameter information for later editting parameter_information(params).parm := rec; parameter_information(params).parm_rec_type := its_type; rewind (all_row_records(its_type)); if list_size(all_row_records(its_type)) = 0 -- then this was a string indicator record then have_indic_type := true; number_of_records := number_of_records + 1; records_type(number_of_records) := its_type; indic_params_name := params; else have_rec_type := true; number_of_records := number_of_records + 1; records_type(number_of_records) := its_type; rec_params_name := params; end if; exception when duplicate_parameter => -- if this paramter has been described previously put_line(error & parameters'image(params) & " of procedure " & procedure_names'image(procedure_name) & multiple_description); error_occured := true; end params_of_record_type_generator; package body params_of_boolean_type_generator is begin if parameter_information(params).defined -- if this parameter has been described previously then raise duplicate_parameter; else parameter_information(params).defined := true; have_bool_type := true; bool_params_name := params; end if; -- save parameter information for later editting parameter_information(params).parm := bool; exception when duplicate_parameter => -- if this paramter has been described previously put_line(error & parameters'image(params) & " of procedure " & procedure_names'image(procedure_name) & multiple_description); error_occured := true; end params_of_boolean_type_generator; procedure generate_procedure is temp_string, final_string : string (1..max_enum_length) := (others => ' '); type_string : string (1..max_length_domain_type_name) := (others => ' '); parm_counter : integer := 0; -- to keep track which paramter we are printing global_param : params_to_concrete_procedure; concrete_string : string (1..max_concrete_call_string) := (others => ' '); concrete_decl : string (1..max_concrete_call_string) := (others => ' '); mode_string : string (1..6) := (others => ' '); type string_array is array (integer range 1..200) of string (1..200); assign_statements, if_then_else_array : string_array := (others => (others => ' ')); string_indic_assign_statements : string_array := (others => (others => ' ')); which_parameter, which_indic_parameter : integer := 0; procedure status_of_type_bool is begin if valid_errors'length > 1 -- Only one possible error is expected if the result -- parameter is of type boolean. then raise too_many_errors_for_type_bool; end if; if valid_errors = null_array then body_io.put_line(abstract_body, indent5 & "if sqlcode /= 0 then"); body_io.put_line(abstract_body, indent5 & indent1 & parameters'image(bool_params_name) & " := false;"); body_io.put_line(abstract_body, indent5 & "else " & parameters'image(bool_params_name) & " := true;"); else -- user had one error expected body_io.put_line(abstract_body, indent5 & "if sqlcode = " & error_conditions_allowed'image (valid_errors(1)) & "_VALUE" & " then"); body_io.put_line(abstract_body, indent5 & indent1 & parameters'image(bool_params_name) & " := false;"); body_io.put_line(abstract_body, indent5 & "elsif sqlcode /= 0 then "); body_io.put_line(abstract_body, indent5 & indent1 & "process_database_error;"); body_io.put_line(abstract_body, indent5 & indent1 & "raise sql_database_error;"); body_io.put_line(abstract_body, indent5 & "else " & parameters'image(bool_params_name) & " := true;"); end if; end status_of_type_bool; procedure status_of_type_err is begin body_io.put_line(abstract_body, indent5 & "if sqlcode = " & error_conditions_allowed'image(valid_errors(1)) & "_VALUE" & " then"); body_io.put_line(abstract_body, indent5 & indent1 & parameters'image(err_params_name) & " := " & error_conditions_allowed'image(valid_errors(1)) & ";"); for i in valid_errors'range loop if i /= valid_errors'last(1) then -- the last element of the array will have been printed -- on the next to last time thru the loop..don't try to -- print if this is the last time thru body_io.put_line(abstract_body, indent5 & "elsif sqlcode = " & error_conditions_allowed'image(valid_errors(i + 1)) & "_VALUE" & " then"); body_io.put_line(abstract_body, indent5 & indent1 & parameters'image(err_params_name) & " := " & error_conditions_allowed'image(valid_errors(i+1)) & ";"); end if; end loop; body_io.put_line(abstract_body, indent5 & "elsif sqlcode /= 0 then "); body_io.put_line(abstract_body, indent5 & indent1 & "process_database_error;"); body_io.put_line(abstract_body, indent5 & indent1 & "raise sql_database_error;"); -- Back in generate_procedure the if-then-else statement will be completed depending on what -- type of statement this was. If it was a select or fetch, the last else branch will assign -- correct values back to the abstract procedure parameters. If not the if-then-else statement -- will be completed with end if; end status_of_type_err; procedure check_concrete_parameters is -- This procedure will generate all information needed about the calls to concrete procedures -- for the generate_procedure procedure. It will determine when parameters to the concrete procedures -- are valid, and what conversions must be done to them to send them to the concrete procedure. concrete_call_string : string (1..max_concrete_call_string) := (others => ' '); indic_end, at_end, valid_parameter, found : boolean := false; info, indic_info : static_component_info; sql_type_string, dcl_string : string (1..100) := (others => ' '); which_if_then_else : integer := 0; begin move(concrete_module_name & "." & sql_module_procedure_name & " (", concrete_call_string); -- first input call to the concrete module procedure for i in params_to_concrete_procedure loop valid_parameter := false; for j in parameters loop -- first check to see if it's a simple parameter of the abstract procedure -- if so then we know it is an "in" only parameter because only row record -- parameters are defined by SAME to be in out. if comstr(params_to_concrete_procedure'image(i), parameters'image(j), false) = equal then valid_parameter := true; if (j = err_params_name and have_err_type) or (j = bool_params_name and have_bool_type) then exit; -- exits j loop because this is valid but it has no other code associated with it. end if; if (j = rec_params_name and have_rec_type) then global_param := i; raise invalid_parameter_to_concrete_procedure; else -- The following statement moves the concrete type of this parameter into sql_type_string. -- If the concrete type is an enumeration type, then CHAR is moved into the type string -- as this implementation stores Ada enumeration values as strings. move (find_concrete_type(parameter_information(j).parm_base_type), sql_type_string); if indx(base_specific_domain_types'image (parameter_information(j).parm_base_type),"not_null") /= 0 then -- This is a plain type that cannot contain null..just convert -- and send to the database if is_enumeration then move(strip(concrete_call_string) & " " & strip(sql_type_string) & "(" & parameters'image(j) & ")),",concrete_call_string); else move(strip(concrete_call_string) & " " & strip(sql_type_string) & "(" & parameters'image(j) & "),",concrete_call_string); end if; else -- This is a null bearing value. If the statement is an update or insert -- subquery (two abstract procedure types that take individual params) then -- must declare -- variables of the non-null type along with indicator variables to tell the -- database if these values are null or not. Also must include if then else -- statements which determine if the values coming in are null and set the -- appropriate indicator parameters. If the values coming in are not null -- the newly declared variables are set to the values. If the statement is -- not an update none of this needs to be done. Just do the conversion to a -- non-null bearing type and then to the concrete type when sending an 'in' param. if sql_statement_type = update_positioned or sql_statement_type = update_searched or sql_statement_type = insert_subquery then move (find_concrete_type(parameter_information(j).parm_base_type), sql_type_string); if strip(sql_type_string) = "char" or -- not an enum type and concrete type is char strip(sql_type_string) = "CHAR" then if indx(base_specific_domain_types'image (parameter_information(j).parm_base_type), "NOT_NULL") /= 0 or indx(base_specific_domain_types'image (parameter_information(j).parm_base_type), "not_null") /= 0 then null; else move ("(" & base_specific_domain_types'image (parameter_information(j).parm_base_type)(1..strip (base_specific_domain_types'image (parameter_information(j).parm_base_type))'length - 4) & "NOT_NULL" & "'range) := (others => ' ');", dcl_string); end if; -- saving information in the if_then_else array which_if_then_else := which_if_then_else + 1; move(indent5 & "if is_null(" & parameters'image(j) & ")", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & "then " & parameters'image(j) & "_indic := -1;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & "else " & parameters'image(j) & "_indic := 0;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & indent5 & parameters'image(j) & "_c := char(without_null_base(" & parameters'image(j) & "));", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move (indent5 & "end if;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move (" ", if_then_else_array(which_if_then_else)); elsif is_enumeration then body_io.put_line(abstract_body, indent5 & parameters'image(j) & "_c : char (1.." & integer'image(longest_enum_value) & ") := (others => ' ');"); -- saving information in the if_then_else array which_if_then_else := which_if_then_else + 1; move(indent5 & "if is_null(" & parameters'image(j) & ")", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & "then " & parameters'image(j) & "_indic := -1;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & "else " & parameters'image(j) & "_indic := 0;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & indent5 & parameters'image(j) & "_c := char(" & base_specific_domain_types'image (parameter_information(j).parm_base_type)(1..strip (base_specific_domain_types'image (parameter_information(j).parm_base_type))'length - 4) & "NOT_NULL'image(without_null(" & parameters'image(j) & ")));", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move (indent5 & "end if;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move (" ", if_then_else_array(which_if_then_else)); elsif not is_enumeration -- and we know already its not a char then move (";", dcl_string); -- saving information in the if_then_else array which_if_then_else := which_if_then_else + 1; move(indent5 & "if is_null(" & parameters'image(j) & ")", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & "then " & parameters'image(j) & "_indic := -1;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & "else " & parameters'image(j) & "_indic := 0;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & indent5 & parameters'image(j) & "_c := " & strip(sql_type_string) & "(without_null_base(" & parameters'image(j) & "));", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move (indent5 & "end if;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move (" ", if_then_else_array(which_if_then_else)); end if; -- putting in the declaration for the not_null type if not is_enumeration -- already put in the enumeration one then body_io.put_line(abstract_body, indent5 & parameters'image(j) & "_c : " & strip(sql_type_string) & strip (dcl_string)); end if; -- printing out the indicator declaration body_io.put_line(abstract_body, indent5 & parameters'image(j) & "_indic : indicator_type;"); -- putting in the indicator declaration -- putting in the newly declared variable of some sql_standard type into the -- concrete call string move (strip(concrete_call_string) & " " & parameters'image(j) & "_c, " & parameters'image(j) & "_indic,", concrete_call_string); elsif is_enumeration -- and not one of the above statement types then move(strip(concrete_call_string) & " " & strip(sql_type_string) & params_to_concrete_procedure'image(i) & "))), ", concrete_call_string); else move(strip(concrete_call_string) & " " & strip(sql_type_string) & "(without_null_base(" & params_to_concrete_procedure'image(i) & ")), ", concrete_call_string); end if; end if; end if; -- save information for the concrete declaration and output information to the base -- specific file move(strip(concrete_decl) & " " & parameters'image(j) & " : in " & --know its mode is 'in' -- because only row records are in out find_only_concrete_type(parameter_information(j).parm_base_type) & "; ", concrete_decl); if indx(base_specific_domain_types'image (parameter_information(j).parm_base_type),"not_null") = 0 -- this type contains null then if sql_statement_type = update_positioned or sql_statement_type = update_searched or sql_statement_type = insert_subquery then move (strip(concrete_decl) & " " & strip(parameters'image(j)) & "_indic" & " : in sql_standard.indicator_type; ", concrete_decl); -- note mode difference else move (strip(concrete_decl) & " " & strip(parameters'image(j)) & "_indic" & " : out sql_standard.indicator_type; ", concrete_decl); -- note mode difference end if; end if; specific_io.put(dbms_specific, sql_module_procedure_name & " " & parameters'image(j) & " in " & find_only_concrete_type(parameter_information(j).parm_base_type)); if find_only_concrete_type(parameter_information(j).parm_base_type) = "CHAR" or find_only_concrete_type(parameter_information(j).parm_base_type) = "char" then specific_io.put_line(dbms_specific, " " & find_length(parameter_information(j).parm_base_type)); else specific_io.put_line(dbms_specific, " "); end if; if indx(base_specific_domain_types'image (parameter_information(j).parm_base_type),"not_null") = 0 then if sql_statement_type = update_positioned or sql_statement_type = update_searched or sql_statement_type = insert_subquery then specific_io.put_line(dbms_specific, sql_module_procedure_name & " " & strip(parameters'image(j)) & "_indic" & " " & "in indicator_type"); else specific_io.put_line(dbms_specific, sql_module_procedure_name & " " & strip(parameters'image(j)) & "_indic" & " " & "out indicator_type"); end if; end if; exit; end if; end loop; -- j loop if valid_parameter -- already found match..do nothing then null; elsif have_rec_type -- check the parameter against the components of the record then got_to_exit := false; for m in 1..number_of_records loop rewind(all_row_records(records_type(m))); for x in 1..list_size(all_row_records(records_type(m))) loop current_member(all_row_records(records_type(m)), info, at_end); if not (at_end) and string_pack.strip(info.the_component_name) = params_to_concrete_procedure'image(i) then valid_parameter := true; -- this is a valid component of the record sent as a parameter -- to the abstract procedure..can be in or in_out move(find_concrete_type(info.its_base_type), sql_type_string); if indx(base_specific_domain_types'image (info.its_base_type),"not_null") /= 0 then -- this is a plain type..no indicator variable needs to be declared..just convert -- and send to the database .. mode will only matter in the enumeration case because -- we cannot update the result of an enumeration'image... -- if it is an in only param then this is fine...other wise we need to declare a variable -- just like the _type to send over because we can't update (ie in_out) something -- sent over that has been converted with the 'image function..it will be an in_out when -- the statement types are fetch and selec if is_enumeration and (sql_statement_type /= fetch and sql_statement_type /= selec) then move(strip(concrete_call_string) & " " & strip(sql_type_string) & "(" & parameters'image(rec_params_name) & "." & strip(info.the_component_name) & ")), ",concrete_call_string); elsif is_enumeration and (sql_statement_type = fetch or sql_statement_type = selec) then body_io.put_line(abstract_body, indent5 & strip(info.the_component_name) & "_c : char (1.." & integer'image(longest_enum_value) & ") := (others => ' ');"); which_parameter := which_parameter + 1; move(parameters'image(rec_params_name) & "." & strip(info.the_component_name) & " := " & base_specific_domain_types'image(info.its_base_type) & "'value(string(" & strip(info.the_component_name) & "_c));" ,assign_statements(which_parameter)); move(strip(concrete_call_string) & " " & strip(info.the_component_name) & "_c,", concrete_call_string); else move(strip(concrete_call_string) & " " & strip(sql_type_string) & "(" & parameters'image(rec_params_name) & "." & strip(info.the_component_name) & "),",concrete_call_string); end if; if (sql_statement_type /= fetch and sql_statement_type /= selec) then move(strip(concrete_decl) & " " & strip(info.the_component_name) & ": in " & find_only_concrete_type(info.its_base_type) & ";" , concrete_decl); else move(strip(concrete_decl) & " " & strip(info.the_component_name) & ": in out " & find_only_concrete_type(info.its_base_type) & ";" , concrete_decl); end if; if (sql_statement_type /= fetch and sql_statement_type /= selec) then specific_io.put(dbms_specific, sql_module_procedure_name & " " & string_pack.strip(info.the_component_name) & " in " & find_only_concrete_type(info.its_base_type)); else specific_io.put(dbms_specific, sql_module_procedure_name & " " & string_pack.strip(info.the_component_name) & " in_out " & find_only_concrete_type(info.its_base_type)); end if; if find_only_concrete_type(info.its_base_type) = "CHAR" or find_only_concrete_type(info.its_base_type) = "char" then specific_io.put_line(dbms_specific, " " & find_length(info.its_base_type)); else specific_io.put_line(dbms_specific, " "); end if; else -- This is a null bearing value..must declare a variable of the concrete type and an -- indicator variable if -- this is a fetch or a select or insert values. If it's an insert we need -- the indicator to tell the database this is a null value (if it actually is). -- If it is any other statement, convert the to its non-null type -- variable and just send it over. If the variable is a numeric type and -- has no ops package then sending -- this parameter to the database is illegal because the value will have to be -- re-assigned back to the null-bearing variable and no assignment statement -- exists if there is no ops_package. if sql_statement_type = fetch or sql_statement_type = selec or sql_statement_type = insert_values -- then this is an out or in/out parameter or an insert and -- we must declare an indicator variable and send it -- to the database along with the actual variable -- After determining if an ops_package exists, determine if it's -- of base type char. If it is it will have additional length information -- in the declaration. then if sql_statement_type = fetch or sql_statement_type = selec -- the ops package only matters with these two types then found := false; for x in ops_packages loop if strip_this(base_specific_domain_types'image(info.its_base_type),"_TYPE") = strip_this(ops_packages'image(x), "_OPS") then found := true; exit; end if; end loop; if not found then if find_only_concrete_type(info.its_base_type) = "CHAR" or find_only_concrete_type(info.its_base_type) = "char" then null; -- don't need the ops package for assign of chars else global_param := i; raise no_ops_package; end if; end if; end if; which_parameter := which_parameter + 1; -- if not enum and base type is char if strip(sql_type_string) = "char" or strip(sql_type_string) = "CHAR" then -- length part of declaration move ("(1.." & strip(find_length(info.its_base_type)) & ") := (others => ' ');", dcl_string); -- The following move statement will build up the string representing -- the assign statements to be generated after a return from the database. -- Note there are separate statements for char as it is converted to the -- _BASE type while all other types get converted to the _TYPE type. -- Note we first remove the "_type" by not taking the last 4 characters -- of the type string and concatenate _base. if sql_statement_type = fetch or sql_statement_type = selec then move("assign(" & parameters'image(rec_params_name) & "." & strip(info.the_component_name) & ", " & base_specific_domain_types'image(info.its_base_type) (1..strip(base_specific_domain_types'image(info.its_base_type))'length - 4) & "base(convert(" & strip(info.the_component_name) & "_c" & ", " & strip(info.the_component_name) & "_indic)));",assign_statements(which_parameter)); else which_if_then_else := which_if_then_else + 1; move(indent5 & "if is_null(" & parameters'image(rec_params_name) & "." & strip(info.the_component_name) & ")", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & "then " & strip(info.the_component_name) & "_indic := -1;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & "else " & strip(info.the_component_name) & "_indic := 0;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & indent5 & strip(info.the_component_name) & "_c := char(without_null_base(" & parameters'image(rec_params_name) & "." & strip(info.the_component_name) & "));", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move (indent5 & "end if;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move (" ", if_then_else_array(which_if_then_else)); end if; -- Must determine if the record containing this component had -- a corresponding string indicator record. If so, we must assign -- the returned indicator values back to the components of this string -- indicator record. The following statements check to see if a corresponding -- indicator_component exists then the move statement builds up -- these assignments. if have_indic_type then for r in record_names loop if list_size(all_indic_records(r)) /= 0 then rewind (all_indic_records(r)); current_member(all_indic_records(r), indic_info, indic_end); for q in 1..list_size(all_indic_records(r)) loop if string_pack.strip(indic_info.the_component_name) = params_to_concrete_procedure'image(i) -- then this is a corresponding -- string indicator that must be assigned a value then which_indic_parameter := which_indic_parameter + 1; move(parameters'image(indic_params_name) & "." & string_pack.strip(indic_info.the_component_name) & " := " & strip(info.the_component_name) & "_indic;", string_indic_assign_statements(which_indic_parameter)); exit; end if; next_member(all_indic_records(r),indic_info, indic_end); end loop; -- q end if; end loop; -- r end if; -- have_indic_type elsif not is_enumeration -- and we know already its not a char then move (";", dcl_string); if sql_statement_type = fetch or sql_statement_type = selec then move("assign(" & parameters'image(rec_params_name) & "." & strip(info.the_component_name) & ", " & base_specific_domain_types'image(info.its_base_type) & "(convert(" & strip(info.the_component_name) & "_c" & ", " & strip(info.the_component_name) & "_indic)));",assign_statements(which_parameter)); else which_if_then_else := which_if_then_else + 1; move(indent5 & "if is_null(" & parameters'image(rec_params_name) & "." & strip(info.the_component_name) & ")", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & "then " & strip(info.the_component_name) & "_indic := -1;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & "else " & strip(info.the_component_name) & "_indic := 0;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & indent5 & strip(info.the_component_name) & "_c := " & strip(sql_type_string) & "(without_null_base(" & parameters'image(rec_params_name) & "." & strip(info.the_component_name) & "));", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move (indent5 & "end if;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move (" ", if_then_else_array(which_if_then_else)); end if; else -- this is an assign for a null bearing enumeration value move (";", dcl_string); if sql_statement_type = fetch or sql_statement_type = selec then move ("assign(" & parameters'image(rec_params_name) & "." & strip(info.the_component_name) & ", " & "with_null(" & strip_this(base_specific_domain_types'image(info.its_base_type),"_TYPE") & "_NOT_NULL'value(string(" & strip(info.the_component_name) & "_c))));", assign_statements(which_parameter)); else which_if_then_else := which_if_then_else + 1; move(indent5 & "if is_null(" & parameters'image(rec_params_name) & "." & strip(info.the_component_name) & ")", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & "then " & strip(info.the_component_name) & "_indic := -1;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & "else " & strip(info.the_component_name) & "_indic := 0;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move(indent5 & indent5 & strip(info.the_component_name) & "_c := char(" & base_specific_domain_types'image (info.its_base_type)(1..strip (base_specific_domain_types'image (info.its_base_type))'length - 4) & "NOT_NULL'image(without_null(" & parameters'image(rec_params_name) & "." & strip(info.the_component_name) & ")));", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move (indent5 & "end if;", if_then_else_array(which_if_then_else)); which_if_then_else := which_if_then_else + 1; move (" ", if_then_else_array(which_if_then_else)); end if; end if; if not is_enumeration -- this is some SQL type..not enumeration -- putting in the declaration for the not_null type then body_io.put_line(abstract_body, indent5 & strip(info.the_component_name) & "_c : " & strip(sql_type_string) & strip (dcl_string)); else -- it is an enumeration body_io.put_line(abstract_body, indent5 & strip(info.the_component_name) & "_c : char (1.." & integer'image(longest_enum_value) & ") := (others => ' ');"); end if; -- indicator declaration is same whether or not its an enumeration type body_io.put_line(abstract_body, indent5 & strip(info.the_component_name) & "_indic : indicator_type;"); -- putting in the indicator declaration -- putting in the newly declared variable of some sql_standard type into the -- concrete call string move (strip(concrete_call_string) & " " & strip(info.the_component_name) & "_c, " & strip(info.the_component_name) & "_indic,", concrete_call_string); move (strip(concrete_decl) & " " & strip(info.the_component_name) & " : in out " & find_only_concrete_type(info.its_base_type) & "; ", concrete_decl); if sql_statement_type = insert_values then move (strip(concrete_decl) & " " & strip(info.the_component_name) & "_indic" & " : in sql_standard.indicator_type; ", concrete_decl); else move (strip(concrete_decl) & " " & strip(info.the_component_name) & "_indic" & " : out sql_standard.indicator_type; ", concrete_decl); end if; -- save this information in the base_specific file too specific_io.put(dbms_specific, sql_module_procedure_name & " " & strip(info.the_component_name) & " in_out " & find_only_concrete_type( info.its_base_type)); if find_only_concrete_type(info.its_base_type) = "CHAR" or find_only_concrete_type(info.its_base_type) = "char" then specific_io.put_line(dbms_specific, " " & find_length(info.its_base_type)); else specific_io.put_line(dbms_specific, " "); end if; if sql_statement_type = insert_values then specific_io.put_line(dbms_specific, sql_module_procedure_name & " " & strip(info.the_component_name) & "_indic" & " " & "in indicator_type"); else specific_io.put_line(dbms_specific, sql_module_procedure_name & " " & strip(info.the_component_name) & "_indic" & " " & "out indicator_type"); end if; elsif sql_statement_type /= insert_values and sql_statement_type /= insert_subquery then raise record_type_not_allowed; end if; end if; got_to_exit := true; exit; end if; next_member(all_row_records(records_type(m)),info,at_end); end loop; if got_to_exit then exit; end if; end loop; if not valid_parameter then global_param := i; -- to use the value in the error message raise invalid_parameter_to_concrete_procedure; -- it wasn't a record component either end if; else global_param := i; -- to use the value in the error message raise invalid_parameter_to_concrete_procedure; -- if don't have a record type in this procedure then -- obviously it won't be there so raise invalid parameter. end if; end loop; -- i loop -- taking off the last semicolon put on the declaration and replacing it with a ');' move(strip(concrete_decl) & " sqlcode : out sql_standard.sqlcode_type);", concrete_decl); specific_io.put_line(dbms_specific, sql_module_procedure_name & " " & "sqlcode out sqlcode_type"); body_io.put_line (abstract_body, indent4 & "begin"); if which_if_then_else = 0 -- then there were no null bearing in parameters then null; else for i in 1..which_if_then_else loop body_io.put_line(abstract_body, strip(if_then_else_array(i), trailing)); end loop; end if; body_io.put_line (abstract_body, indent5 & strip(concrete_call_string) & " SQLCODE);"); end check_concrete_parameters; begin -- generate_procedure if have_bool_type and have_err_type -- can only have one sqlcode result parameter then raise too_many_result_parameters; end if; -- here is where you edit the file to contain procedure information spec_io.put_line(abstract_spec, " "); spec_io.put_line(abstract_spec, indent4 & "procedure " & procedure_names'image( procedure_name) & "("); -- printing the procedure name body_io.put_line(abstract_body, " "); body_io.put_line(abstract_body, indent4 & "procedure " & procedure_names'image( procedure_name) & "("); for i in parameters loop -- print information about each parameter declare temp : parameters; begin if not parameter_information(i).defined then raise parameter_not_defined; else case parameter_information(i).parm is -- the type portion of the parameter declaration -- depends upon the paramters type as given by the i/f programmer when bool => move("boolean", type_string); when rec => move(record_names'image( parameter_information(i).parm_rec_type), type_string); when dom => move(base_specific_domain_types'image( parameter_information(i).parm_base_type), type_string); when err => move("valid_status_result_type", type_string); end case; if (parameter_information(i).parm = err) or (parameter_information(i).parm = bool) then move ("out", mode_string); -- printing the mode of the parameter elsif parameter_information(i).parm = dom then move("in", mode_string); elsif sql_statement_type = insert_values then move ("in", mode_string); else move ("in out", mode_string); end if; -- if this is the last parameter, finish procedure declaration if i = parameters'last then move(strip(type_string) & ");", type_string); else move(strip(type_string) & ";", type_string); end if; move (parameters'image(i) & " : " & strip(mode_string) & " " & strip(type_string), temp_string); move (strip(final_string) & " " & strip(temp_string), final_string); move (strip(final_string, leading), final_string); -- if there was only one parameter, then the -- leading blank inserted by the previous move is removed so -- that the real length will be calculated correctly. end if; exception when parameter_not_defined => text_io.put_line(error & parameters'image(i) & " in procedure " & procedure_names'image (procedure_name) & missing_description); error_occured := true; end; end loop; spec_io.put_line (abstract_spec, indent5 & strip(final_string)); -- putting procedure declaration -- in the spec spec_io.put_line (abstract_spec, " "); -- for blank line between procedure declarations real_length := strip(final_string)'length - 1; -- to keep all of the specification procedure -- declaration except ';' move (final_string(1..real_length) & " is", final_string); -- adding 'is' for procedure declaration -- in the body body_io.put_line (abstract_body, indent5 & strip(final_string));-- putting procedure declaration -- in the body case sql_statement_type is -- depending on the type of SQL statement the concrete module contains -- will determine the structure of the body of the abstract procedure -- bodies. when close | commit | delete_positioned | rollback => -- these 4 statement types will have at most -- one parameter body_io.put_line (abstract_body, indent4 & "begin"); body_io.put_line(abstract_body, indent5 & concrete_module_name & "." & sql_module_procedure_name & " (sqlcode);"); -- first input call to the concrete module procedure -- Generally, the close, commit, delete_positioned and rollback procedures will have no parameters. -- If they do have a parameter it must be a result parameter to return success/failure status -- information to the application. The user must have provided a result parameter of either -- boolean type or of type error_conditions_allowed type. The corresponding integer constants are -- compared to the returned error and the result parameter is set. If there is no result parameter, -- then the user has described an invalid SAME procedure. if have_bool_type then status_of_type_bool; elsif have_err_type then status_of_type_err; else raise no_result_parameter; end if; body_io.put_line(abstract_body, indent5 & indent1 & "null;"); body_io.put_line(abstract_body, indent5 & "end if;"); body_io.put_line(abstract_body, indent4 & "end " & procedure_names'image(procedure_name) & ";"); body_io.put_line(abstract_body, " "); -- input concrete interface information here concrete_io.put_line(concrete_spec, "procedure " & sql_module_procedure_name & "(sqlcode : out sql_standard.sqlcode_type);"); -- The following line is specific to the VAX/RDB/SQL platform..other implementations may not -- implement the pragma the same way. concrete_io.put_line(concrete_spec, "pragma interface (sql, " & sql_module_procedure_name & ");"); concrete_io.put_line(concrete_spec, " "); -- input information into the dbms specific file here..these procedures will always only have one parameter specific_io.put_line(dbms_specific, sql_module_procedure_name & " " & "sqlcode out sqlcode_type"); when others => -- input first part of concrete interface information here move(strip(concrete_decl) & "procedure " & sql_module_procedure_name & "(", concrete_decl); check_concrete_parameters; -- Procedure to output the indicator parameter declarations and the -- actual procedure call to the concrete module. -- check to see if the user provided a result parameter. If so, call the corresponding procedure. if have_bool_type then status_of_type_bool; elsif have_err_type then status_of_type_err; else -- only sqlcode expected from the database is success..any others raise unrecoverable error body_io.put_line(abstract_body, indent5 & "if sqlcode /= 0 then "); body_io.put_line(abstract_body, indent5 & indent1 & "process_database_error;"); body_io.put_line(abstract_body, indent5 & indent1 & "raise sql_database_error;"); body_io.put_line(abstract_body, indent5 & "end if;"); end if; if sql_statement_type = fetch or sql_statement_type = selec then -- (DO ASSIGNMENTS BACK TO PARAMETERS OF THE ABSTRACT_INTERFACE) -- (AND END THE IF THEN ELSE STATEMENT) if which_parameter = 0 -- then there were no null bearing out parameters to the database then body_io.put_line(abstract_body, indent5 & "end if;"); else body_io.put_line(abstract_body, indent5 & "else"); for i in 1..which_parameter loop -- print out the assign statements back to the variables body_io.put_line(abstract_body, indent5 & indent1 & strip(assign_statements(i))); end loop; body_io.put_line(abstract_body, indent5 & "end if;"); end if; else -- The assignments were done before the call to -- the concrete module so there is no processing -- of values done after the call...just end the if-then-else -- statement which determines the result of the result value. body_io.put_line(abstract_body, indent5 & "end if;"); end if; if which_indic_parameter /= 0 -- then there were string_indicators then for i in 1..which_indic_parameter loop body_io.put_line(abstract_body, indent5 & strip(string_indic_assign_statements(i))); end loop; end if; body_io.put_line(abstract_body, indent4 & "end " & procedure_names'image(procedure_name) & ";"); body_io.put_line(abstract_body, " "); -- Finish up the concrete declaration. -- The following line is specific to the VAX/RDB/SQL platform..other implementations may not -- implement the pragma the same way. concrete_io.put_line(concrete_spec, strip(concrete_decl)); concrete_io.put_line(concrete_spec, "pragma interface (sql, " & sql_module_procedure_name & ");"); concrete_io.put_line(concrete_spec, " "); end case; exception when too_many_result_parameters => text_io.put_line(error & "Cannot provide more than one result parameter for procedure " & procedure_names'image(procedure_name)); error_occured := true; when no_result_parameter => text_io.put_line(error & "Must provide result parameter for procedure " & procedure_names'image(procedure_name)); error_occured := true; when too_many_errors_for_type_bool => text_io.put_line(error & "A result parameter of type boolean has too many possible errors associated with it"); error_occured := true; when invalid_parameter_to_concrete_procedure => text_io.put_line(error & params_to_concrete_procedure'image(global_param) & " in procedure " & procedure_names'image(procedure_name) & " is not a valid parameter to send to a concrete procedure."); error_occured := true; when no_ops_package => text_io.put_line(error & params_to_concrete_procedure'image(global_param) & " in procedure " & procedure_names'image(procedure_name) & " is a null bearing type"); text_io.put_line(indent5 & indent5 & indent4 & "with no ops package instantiated for it.." & "therefore it cannot be re-assigned to a variable of a concrete type."); error_occured := true; when record_type_not_allowed => text_io.put_line (error & "Record types are only allowed to be sent to abstract"); text_io.put_line("procedures which represent select, fetch or insert SQL statements."); error_occured := true; end generate_procedure; begin -- procedure_with_parameters_generator if procedure_defined (procedure_name) -- if this procedure has been defined previously then raise duplicate_procedure; else procedure_defined (procedure_name) := true; end if; exception when duplicate_procedure => -- if this procedure has been described previously put_line (error & procedure_names'image(procedure_name) & multiple_description); error_occured := true; end procedure_with_parameters_generator; -- This package body will generate the procedures which have no parameters (close, commit, etc); package body procedure_without_parameters_generator is procedure generate_procedure is begin if sql_statement_type /= close and sql_statement_type /= commit and sql_statement_type /= delete_positioned and sql_statement_type /= rollback then raise illegal_parameter_profile; end if; spec_io.put_line(abstract_spec, indent4 & "procedure " & procedure_names'image( procedure_name) & ";"); -- printing the procedure name spec_io.put_line(abstract_spec, " "); body_io.put_line(abstract_body, indent4 & "procedure " & procedure_names'image( procedure_name) & " is"); -- printing the procedure name body_io.put_line(abstract_body, indent4 & "begin"); body_io.put_line(abstract_body, indent5 & concrete_module_name & "." & sql_module_procedure_name & " (sqlcode);"); -- This procedure expected no errors returned because it has no parameters to return the result in.. -- Therefore if ANY code except success is returned then the sql_database_error is raised. body_io.put_line(abstract_body, indent5 & "if sqlcode /= 0 then"); body_io.put_line(abstract_body, indent5 & indent3 & "process_database_error;"); body_io.put_line(abstract_body, indent5 & indent3 & "raise sql_database_error;"); body_io.put_line(abstract_body, indent5 & "end if;"); body_io.put_line(abstract_body, indent4 & "end " & procedure_names'image(procedure_name) & ";"); body_io.put_line(abstract_body, " "); -- input concrete interface information here concrete_io.put_line(concrete_spec, "procedure " & sql_module_procedure_name & "(sqlcode : out sql_standard.sqlcode_type);"); -- The following line is specific to the VAX/RDB/SQL platform..other implementations may not -- implement the pragma the same way. concrete_io.put_line(concrete_spec, "pragma interface (sql, " & sql_module_procedure_name & ");"); concrete_io.put_line(concrete_spec, " "); -- input information into dbms specific file here..these procedures will always only have 1 parameter specific_io.put_line(dbms_specific, sql_module_procedure_name & " " & "sqlcode out sqlcode_type"); exception when illegal_parameter_profile => text_io.put_line(error & "The procedure " & procedure_names'image(procedure_name) & "of SQL statement type " & sql_statement_types'image(sql_statement_type) & " must have parameters."); error_occured := true; end generate_procedure; begin -- procedure without_parameters_generator if procedure_defined (procedure_name) -- if this procedure has been defined previously then raise duplicate_procedure; else procedure_defined (procedure_name) := true; end if; exception when duplicate_procedure => -- if this procedure has been described previously put_line (error & procedure_names'image(procedure_name) & multiple_description); error_occured := true; end; -- procedure without_parameters_generator -- The following procedure will perform the final consistency checks before completing the -- abstract interface specification. It will check to make sure each procedure and record -- declared has been described. If they have not, or if any other errors have occured during -- processing, the program will print an error message and no files will be produced. procedure generate_interface is temp_rec : record_names; temp_proc : procedure_names; begin for i in record_names loop if not record_defined(i) then put_line (error & record_names'image(i) & missing_description); error_occured := true; end if; end loop; for i in procedure_names loop if not procedure_defined(i) then put_line (error & procedure_names'image(i) & missing_description); error_occured := true; end if; end loop; if error_occured then delete(abstract_spec); delete(abstract_body); delete(concrete_spec); delete(dbms_specific); else spec_io.put_line (abstract_spec, " "); spec_io.put_line (abstract_spec, "end " & abstract_interface_name & ";"); body_io.put_line (abstract_body, " "); body_io.put_line (abstract_body, "end " & abstract_interface_name & ";"); concrete_io.put_line(concrete_spec, "end " & concrete_module_name & ";"); close(concrete_spec); close(abstract_spec); close(abstract_body); close(dbms_specific); end if; end generate_interface; begin create (abstract_spec, name => abstract_interface_name & spec_extension); -- create file to hold spec text_io.put_line("creating abstract specification => " & abstract_interface_name & spec_extension); create (abstract_body, name => abstract_interface_name & body_extension); -- create file to hold body text_io.put_line("creating abstract body => " & abstract_interface_name & body_extension); create (concrete_spec, name => concrete_module_name & spec_extension); -- create file to hold concrete spec text_io.put_line("creating concrete module specification => " & concrete_module_name & spec_extension); create (dbms_specific, name => dbms_specific_info_file & ".txt"); -- create file to hold dbms specific information -- this file holds procedure and parameter information about the concrete interface (ada spec) text_io.put_line("creating dbms specific information file => " & dbms_specific_info_file & ".txt"); -- input the with and use clauses in the specification for i in domain_package_names'range loop -- print out with & use clauses for all domains spec_io.put_line(abstract_spec, "with " & valid_domain_names'image(domain_package_names(i)) & ";"); spec_io.put_line(abstract_spec, "use " & valid_domain_names'image(domain_package_names(i)) & ";"); end loop; spec_io.put_line(abstract_spec, "with sql_standard;"); spec_io.put_line(abstract_spec, "use sql_standard;"); spec_io.put_line(abstract_spec, "package " & abstract_interface_name & " is"); spec_io.put_line(abstract_spec, " "); spec_io.put_line(abstract_spec, indent4 & error_enum("valid_status_result_type")); spec_io.put_line(abstract_spec, " "); -- input the with and use clauses in the body body_io.put_line (abstract_body, "with sql_communications_pkg, sql_database_error_pkg, conversions, " & concrete_module_name & ";"); body_io.put_line (abstract_body, "use sql_communications_pkg, sql_database_error_pkg, conversions;"); body_io.put_line(abstract_body, "package body " & abstract_interface_name & " is"); body_io.put_line(abstract_body, " "); -- The following loop builds up the use clause for all ops packages. The assumption -- here is that there are ops packages to be used. If for some reason, the domain -- packages for this application contain no ops_packages, then no use clauses will -- be built up. --********************************************************************************** move ("use ", ops_string1); for i in ops_packages loop if ops_packages'image(i) /= "there_are_no_packages" or ops_packages'image(i) /= "THERE_ARE_NO_PACKAGES" then if i = ops_packages'last and i = ops_packages'first -- this is the only ops package then move (ops_packages'image(i) & ";", ops_string); elsif i /= ops_packages'last -- its the first or a middle one then move(strip(ops_string,all_but_one) & ops_packages'image(i) & ", ", ops_string); else -- its the last one move (strip(ops_string, all_but_one) & ops_packages'image(i) & ";", ops_string); end if; else move (" ", ops_string); move (" ", ops_string1); end if; end loop; body_io.put_line(abstract_body, indent4 & strip(ops_string1,all_but_one) & strip(ops_string)); body_io.put_line (abstract_body, " "); -- blank line after use clause for ops --********************************************************************************** if matching_sqlcode_values'last(1) = -- comparing the number of expected errors with the number of sqlcodes (error_conditions_allowed'pos(error_conditions_allowed'last) + 1) then null; else raise unequal; end if; for i in error_conditions_allowed loop body_io.put_line(abstract_body, indent4 & error_conditions_allowed'image(i) & "_VALUE" & " : constant := " & integer'image(matching_sqlcode_values (error_conditions_allowed'pos(i)+ 1)) & ";"); end loop; body_io.put_line (abstract_body, " "); -- blank line after all sqlcode constant declarations -- input the with and use clauses in the concrete spec concrete_io.put_line(concrete_spec, "with sql_standard; use sql_standard;"); concrete_io.put_line(concrete_spec, " "); concrete_io.put_line(concrete_spec, "package " & concrete_module_name & " is"); -- input the -- package declaration concrete_io.put_line(concrete_spec, " "); exception when unequal => put_line (error & unequal1); error_occured := true; end abstract_interface_generator;