#
############################################################################
# File : sq-hal.pl #
# Author : Supun Ruwanpura #
# Date : 19-10-2000 #
############################################################################
use strict;
############################################################################
# Required Modules
use Tk;
use Tk::Table;
use Tk::Text;
use Tk::Photo;
use Tk::Balloon;
############################################################################
# Global variables
use vars qw ( $user_input ); # English query typed by the user
use vars qw ( $win_sq_hal ); # the main window for SQ-HAL
use vars qw ( $parser ); # SQ-HAL parser which contains all the grammar
use vars qw ( $results ); # results of SQ-Hal parsing of the English query
use vars qw ( $save_parser ); # whether parser need to be required at the end (0 or 1)
use vars qw ( @learn_strs ); # temporary hold new grammar to be learned
use vars qw ( $results_table ); # table to display database records
use vars qw ( $status_text ); # status bar text to be displayed
use vars qw ( $default_status_text ); # default status bar text
use vars qw ( $txt_output ); # text area where the output of SQ-HAL is displayed
# SQ-HAL configuration variables
use vars qw ( $user ); # user name to login to the database
use vars qw ( $passwd ); # password for the database login
use vars qw ( $db_source ); # database source
use vars qw ( $db_type ); # type of database
use vars qw ( $learn_enabled ); # enable/disable learning grammar (0 - disable, 1 - enable)
use vars qw ( $rows_displayed ); # number of rows from the results query to be displayed to the user
use vars qw ( $config_file_found ); # status of the configuration file (0 or 1)
############################################################################
# Modular level variables
my $txt_input; # text area for users to type the query
############################################################################
# Combine all the required files and
# load the subroutines from various files
do "configure.pl"; # configuration window definitions
load_config(); # load the configuration data from a file
do "parser.pl"; # SQ-HAL parser definitions
do "splash.pl"; # splash sceen definitions
do "database.pl"; # definitions for various database functionalities
# if the configuration file is not found then
# (either due to first-time running or confgureation file got deleted)
# show the SQ-HAL confiugration window to get required info
if ($config_file_found == 0) { show_config(); }
do "login.pl"; # get database login password
save_config(); # user name might have changed when login screen is
# called. So save the new configuration data
do "db_structure.pl"; # window definition to show/get database structure
do "create_sql.pl"; # window definition to create SQL statements manually
do "learning.pl"; # window definition to display new grammar to be learnt
do "relationships.pl"; # window definition to display/get table relationships
############################################################################
### Show the splash screen while loading the parser ###
### as the parser may take some time to load ###
show_splash();
### Create and show the main SQ-HAL window ###
create_main_window();
############################################################################
# Display the spalsh screen and load parser grammar in the background
sub create_main_window
############################################################################
{
$win_sq_hal = MainWindow->new; # create the main SQ-HAL window
$win_sq_hal->appname("SQ-HAL");
$win_sq_hal->title("SQ-HAL: The Natural Language to SQL Translator");
### maximize and position the SQ-HAL main window ###
my $w = $win_sq_hal->screenwidth()-10; # window width = screen width
my $h = $win_sq_hal->screenheight()-100; # window height = screen height
$win_sq_hal->geometry("${w}x${h}+0+20");
########################################################################
### define and place window controls ###
my $tooltip = $win_sq_hal->Balloon( -statusbar => $status_text );
my $win_sq_hal1 = $win_sq_hal->Frame( -relief => 'flat',
-borderwidth => 10)
->pack( -ipadx => 10,
-fill => 'both',
-expand => 1);
$win_sq_hal1->Label( -text => "Type your question below:",
-anchor => "sw")
->pack( -fill => "x");
### user input text area -----------------------------------------------
$txt_input = $win_sq_hal1->Scrolled( 'Text', -scrollbars => 'e',
-height => 2,
-wrap => "word")
->pack( -side => "top",
-fill => "x",
-expand => 0);
$tooltip->attach($txt_input,
-msg => "Type your English query here and then press Tranlate button.");
my $fra_buttons1 = $win_sq_hal1->Frame->pack( -side => 'top',
-fill => 'x',
-expand => 0 );
### button to activate translate the English query ---------------------
my $cmd_translate = $fra_buttons1->Button( -text => "Translate the query to SQL",
-command => \&parse_input)
->pack( -side => "left",
-ipadx => 10,
-anchor => "ne");
$tooltip->attach($cmd_translate,
-msg => "Translate the English query into SQL.");
### button to clear the content in the query text area -----------------
my $cmd_clear = $fra_buttons1->Button( -text => "Clear",
-command =>
sub
{
### delete everything in the text area ###
$txt_input->delete("1.0", "end");
}
)
->pack( -side => "left",
-ipadx => 10,
-padx => 10,
-anchor => "ne");
$tooltip->attach($cmd_clear,
-msg => "Clear the text in the English query area.");
### button to bring up the create_sql window ---------------------------
my $cmd_create_sql = $fra_buttons1->Button( -text => "Create your own SQL",
-command => \&show_create_sql)
->pack( -side => "right",
-ipadx => 10,
-anchor => "ne");
$tooltip->attach($cmd_create_sql,
-msg => "Bring up the window where you can create your own SQL statements with ease.");
my $fra_output = $win_sq_hal1->Frame->pack( -side => 'top',
-fill => 'x',
-expand => 0 );
### text area to display output results --------------------------------
$txt_output = $fra_output->Scrolled( 'Text', -scrollbars => 'e',
-height => 3,
-wrap => "word")
->pack( -side => "left",
-anchor => "nw",
-fill => "x",
-expand => 1);
$tooltip->attach($txt_output,
-msg => "Translated SQL statments are displayed here.
You may can modify this and press execute button\n to see the results of the SQL statment");
### button to execute SQL in the txt_output area -----------------------
my $cmd_exec = $fra_output->Button( -text => "Execute SQL",
-command =>
sub
{
### copy the content of the txt_output ###
### (SQL statement) to the varaiable $results ###
$results = $txt_output->get("1.0", "end");
### execute SQL and show the results ###
if ( $results ne "")
{
show_data();
}
}
)
->pack( -side => "right",
-ipadx => 10,
-pady => 10,
-anchor => "ne");
$tooltip->attach($cmd_exec,
-msg => "Execute the SQL statment and display the results.");
### $status_text bar text area -----------------------------------------
$default_status_text = "SQ-HAL: The Natural Language to SQL Translator";
$status_text = $default_status_text;
$win_sq_hal->Label( -textvariable => \$status_text,
-relief => "sunken",
-anchor => "nw",
-borderwidth => 2)
->pack( -side => "top",
-fill => "x",
-padx => 10,
-expand => 0);
my $fra_buttons2 = $win_sq_hal1->Frame
->pack( -side => "bottom");
### button to bring up the database structure window -------------------
my $cmd_database = $fra_buttons2->Button( -text => "Database",
-underline => 1,
-command => \&show_database)
->pack( -fill => "x",
-ipadx => 20,
-padx => 10,
-pady => 5,
-side => "left",
-expand => 0);
$tooltip->attach($cmd_database,
-msg => "Display the current database structure.");
### button to bring up the configuration window ------------------------
my $cmd_config = $fra_buttons2->Button( -text => "Configure",
-underline => 2,
-command => \&show_config)
->pack( -fill => "x",
-side => "left",
-ipadx => 20,
-padx => 10,
-pady => 5,
-expand => 0);
$tooltip->attach($cmd_config,
-msg => "Configure SQ-HAL.");
### button to exit to the system ---------------------------------------
my $cmd_exit = $fra_buttons2->Button( -text => "Exit",
-underline => 1,
-command => \&exit_sq_hal )
->pack( -fill => "x",
-ipadx => 40,
-padx => 10,
-pady => 5,
-side => "left");
$tooltip->attach($cmd_exit,
-msg => "End SQ-HAL and Exit to the system.");
### table to display results from the SQL statements -------------------
$results_table = $win_sq_hal1->Table( -rows => 1,
-columns => 1,
-scrollbars => "se",
-relief => "groove",
-borderwidth => 2,
-fixedrows => 1)
->pack( -side => "top",
-fill => "both",
-expand => 1);
$tooltip->attach($results_table,
-msg => "Display data retrieved from the database.");
### exit the program when destroying this main window ##################
$win_sq_hal->bind("", \&exit_sq_hal);
### set the focus to the query entering area ###
$txt_input->focus;
### display this window and start handling events ###
MainLoop;
}
############################################################################
# parse user input and show results
sub parse_input
############################################################################
{
### update the statusbar text ###
$status_text = "Translating the English statement to a SQL statement...";
$win_sq_hal->update();
### the input and output files and commented lines below ###
### are used for testing purposes only ###
#my $inputFile = "data.txt";
#my $outputFile = "output.txt";
#open(DATA, "< $inputFile") || die $!;
#open(OUT, "> $outputFile") || die $!;
#while ()
#{
# if (!/^#/ && !/^[\s]*\n/) # Ignore commented lines and empty lines
# {
# print "> ";
# sleep 1;
# print;
### copy the English query to the variable $user_input ###
$user_input = $txt_input->get("1.0", "end");
### remove special characters from the input ###
$user_input =~ s/[:.'?!]//g;
### translate the user query to SQL ###
eval{ $results = $parser->translate("\L$user_input"); };
### clear the current content of the output area and insert new translated SQL ###
$txt_output->delete("1.0", "end");
$txt_output->insert("end", $results);
$_ = $results;
### if the first word of the results is "SELECT" then it is an ###
### SQL statement. Otherwise it is and untranslated error message ###
if (/^SELECT/)
{
### display the SQL statement in bule colour ###
$txt_output->configure( -foreground => "blue" );
### execute SQL and show the results ###
show_data();
### if there are anything to be leart, then display the learning window ###
if ($#learn_strs >= 0) { show_learn(); }
}
else ### English query not translated into SQL ###
{
### if the learning is enabled, then add this English query ###
### to the query list that to be learnt ###
if ($learn_enabled)
{
$learn_strs[++$#learn_strs] = "\L$user_input";
}
### display the error message in red ###
$txt_output->configure( -foreground => "red" );
}
### update window controls ###
$win_sq_hal->update();
### save the results in the outupt file ###
#print OUT $user_input, $results, "\n";
# }
#}
### close all the open files ###
#close(DATA);
#close(OUT);
### update the statusbar with default text ###
$status_text = $default_status_text;
$win_sq_hal->update();
}
############################################################################
# retrieve data from the database and display on to the screen
sub show_data()
############################################################################
{
### change the mouse icon to be busy icon ###
$win_sq_hal->Busy;
### update statusbar text ###
$status_text = "Retrieving data from the database...";
$txt_output->configure( -foreground => "blue" );
$win_sq_hal->update();
### execute the SQL results ###
### this will update the results table as well ###
execute_sql( $results );
### update status bar text back to default ###
$status_text = $default_status_text;
### change the mouse icon back to normal ###
$win_sq_hal->Unbusy;
}
### used as a flag to determine the exit function is called once ###
### multiple calls to the function is posible if the user press ###
### exit button as well as destorying the window calls the func. ###
my $already_exited = 0;
############################################################################
# exit SQ-HAL by disconnecting from the database and saving the parser
sub exit_sq_hal
############################################################################
{
### do not repeat this subroutine twice ###
if ($already_exited) { return }
$already_exited = 1;
### change the mouse icon to be busy icon ###
$win_sq_hal->Busy;
### disconnect the current database connection ###
disconnect_from_db();
### if required, save the parser to a file ###
if ($save_parser)
{
### update statusbar text
$status_text = "Saving the parser to a file. Please wait...";
$win_sq_hal->update;
save_parser();
}
### save database structure to a file ###
#save_db_info();
### exit to the system ###
exit;
}