Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Getting data from MS SQL on Win Server using Perl

Status
Not open for further replies.

cxw

Programmer
Joined
Aug 17, 2007
Messages
20
Location
US
I am trying to get data from a Microsoft SQL database.
All the players are on the same box.
The Microsoft SQL server is sitting on a Microsoft 2003 server and so is Perl and the application that needs the data. I am also the Administrator on that box. I have set up an ODBC connection that works and have gotten some code from the web to get me started. I have gotten to the following part where I have note the Perl code stops. I have added the "use diagnostics;" but receive no messages. I am not completely understanding what I am doing but have worked with ASP and SQL record sets before. I have done some Perl and am stuck here. I expect to see at least one email address come back.
Here is the code on the pl page. I run these pages through the web, IIS. When I run this pl page this is what it returns:


"Test 2
DSN connected to database.
Test 3
Test 4
SELECT EMAIL FROM LMS_USER
"

Code below. It seems to fail where i have noted in the code.

#!/usr/bin/perl
use diagnostics;
use URI::Escape;
use LWP::UserAgent;
use XML::Simple;
use Data::Dumper;
use DBI;

print "Content-type:text/html\n\n";

#print "test 1";

#SQL_test_1.pl

# Function: dbh_connect
# Description: Creates a connection to a database
# Arguments: none
# Returns: $db_conn - database connection handle
#

$db_user = "xxx";
$db_pass = "xxxx";
$dsn_name = 'dbi:ODBC:iLincEmailAddress';

sub dbh_connect
{
my ($dbh);
$dbh = DBI->connect($dsn_name, $db_user, $db_pass, {
PrintError => 0,
AutoCommit => 1
});

if (! defined($dbh) )
{
print "Error connecting to DSN '$dsn_name'\n";
print "Error was:\n";
print "$DBI::errstr\n"; # $DBI::errstr is the error
# received from the SQL server
return 0;
}

return $dbh;
}

dbh_connect;
print"Test 2<BR>";

#Opens DB ODBC connection

if (! dbh_connect() )
{
print "Unable to connect to database.\n";
exit; # Unable to reconnect, exit the script gracefully
}
else
{
print "DSN connected to database.\n <BR>";
}

print"Test 3 <BR>";

my ($sql, $sth, $rc);

$sql = shift;

if (! ($sql) )
{
print ("Must pass SQL statement to db_sql!\n");

return 0;
}

print "Test 4 <BR>";

my ($sql, $sth, $href);

$sql = "SELECT EMAIL FROM LMS_USER";
print "$sql <BR>";

# failing here <-------------------------> failing here
$sth = $dbh->prepare($sql); # Prepare the SQL statement passed to db_sql

$sth = db_sql($sql); # Pass the SQL statement to server

print "Test 5 <BR>";

if ( ! defined( $sth ) || ! ($sth) )
{
print "Unable to prepare SQL statement:\n";
print "$sql\n";
return 0;

}

$rc = $sth->execute;
print "Test 6";

#
# Check that we received a statement handle
#
if (! ($sth) )
{
return 0;
}

while( $href = $sth->fetchrow_hashref )
{
print "EMAIL: " . $$href{"EMAIL"} . "\n";

}

return 1;

print"Test 7 <BR>";


print"Test 8<BR>";
return $sth;

print"Test 9<BR>";

 
# failing here <-------------------------> failing here
$sth = $dbh->prepare($sql); # Prepare the SQL statement passed to db_sql

$sth = db_sql($sql); # Pass the SQL statement to server


Are you sure that's where it's failing? as you have nothing between that line and the next.

Where db_sql coming from? I don't see it in your code nor the DBI code.

I would super simply your script down to a connect a prepare a execute and a return and see what you get.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[noevil]
Travis - Those Who Say It Cannot Be Done Are Usually Interrupted by Someone Else Doing It; Give the wrong symptoms, get the wrong solutions;
 
Yes that is where it is failing. I added a print out after that line and it does not appear.

$sth = $dbh->prepare($sql);
print "Test 4a <BR>";

I looked at the db_sql but do not find anything other than:
print ("Must pass SQL statement to db_sql!\n");

Thanks,
Chip
 
maybe change it to
prepare($sql) || die "can't prepare : $!\n";

and see if it has any error messages.



~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[noevil]
Travis - Those Who Say It Cannot Be Done Are Usually Interrupted by Someone Else Doing It; Give the wrong symptoms, get the wrong solutions;
 
No, no error messages and the print out of:
print "Test 4a <BR>";
did not occur.

#maybe change it to
prepare($sql) || die "can't prepare : $!\n";
#$sth = $dbh->prepare($sql);
print "Test 4a <BR>";

Thnks for your help on this,
Chip
 
I googled an article on DB_Sql and am looking to see if it is part of Perl or what it is. Also why would it be needed in this code?

DB_Sql Examples
Use a subclass to provide the appropriate parameters for a database connect. You may overwrite halt() to customize the error message, although a sensible default is provided.

class DB_Article extends DB_Sql {
var $classname = "DB_Article";

var $Host = "sales.doma.in";
var $Database = "shop_project";
var $User = "webuser";
var $Password = "";

function haltmsg($msg) {
printf("</td></table><b>Database error:</b> %s<br>\n", $msg);
printf("<b>MySQL Error</b>: %s (%s)<br>\n",
$this->Errno, $this->Error);
printf("Please contact shopmaster@doma.in and report the ");
printf("exact error message.<br>\n");
}
}
Use an instance of the subclass to manage your queries:

$q = new DB_Article;

$query = sprintf("select * from articles where article like '%%%s%%'",
$searchword);
$q->query($query);

while($q->next_record()) {
printf("<tr><td>%s</td><td>%s</td></tr>\n",
$q->f("art_id"),
$q->f("article"));
}
Thanks,
Chip
 
OK it looks like the code I found on the web (this code I am trying to use, is PHP not Perl). It looked like Perl to me but then what do I know I am a beginner in Perl. That is what DB_Sql is, a part of PHP.
"PHPlib also has several helper classes, prominent amongst them are the DB_sql, template, OOH forms and cart."

So I will either need to go with this code or start over. I can try both?
Thanks,
Chip
 
The DBI module in perl is really easy to use. I would read the perldoc on it. You code looks really close to correct anyway so I would just change it to perl (plus .. PERL RULES!! )

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
[noevil]
Travis - Those Who Say It Cannot Be Done Are Usually Interrupted by Someone Else Doing It; Give the wrong symptoms, get the wrong solutions;
 
I have ordered the book:
Real World SQL Server Administration with Perl
hoping that it will shed some light on getting data from SQL. I have also been looking for the DBI docs in Perl but have not found them. time to google them.
Thanks,
Chip
 
I use win32::ODBC and it works like a dream ;-)

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!
 
Do you use Win32 ODBC in a web page .pl?
Can you send me some sample code? A simple select statement and a retrieval of a filed printed to the web page?
Much appreciated.
I have ordered another book "Programming the Perl DBI [Illustrated] [Paperback] by Bunce, Tim
because the first one (book)is not helping or I do not get it.
Thanks
Chip
 
You are ignoring any errors from the prepare statement.

Try
Code:
$sth = $dbh->prepare($sql) or die $DBI::errstr;
and see what comes out.


[&quot;]As soon as we started programming, we found to our surprise that it wasn't as easy to get programs right as we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs.[&quot;]
--Maur
 
OK I tried your line of code but it does not print out anything to the web page. We are running Windows 2003 server with IIS. The web site that I am working with is written in Perl.
Why does perl not print the errors? Am I missing a module?
The web site is a distant learning piece of software from a vender. I need to look up an email address to see if it already exists to solve a problem we are having with it.


Here is the print out of the web page and the code.

Test 2
DSN connected to database.
Test 3
Test 4
SELECT EMAIL FROM LMS_USER
prepare sql ststment before


Code:
#!/usr/bin/perl -w
#use strict;
use diagnostics;
use URI::Escape;
use LWP::UserAgent;
use Getopt::Std;
use Data::Dumper;
use DBI;

#my %opts;
#getopts('oi:p:' \%opts);
#print Dumper(\%opts);



print "Content-type:text/html\n\n";

#print "test 1";

#SQL_test_1.pl

# Function: dbh_connect
# Description: Creates a connection to a database
# Arguments: none
# Returns: $db_conn - database connection handle
#


$db_user = "sa";
$db_pass = "sa55";
$dsn_name = 'dbi:ODBC:iLincEmailAddress';


sub dbh_connect
{
my ($dbh);

$dbh = DBI->connect($dsn_name, $db_user, $db_pass, {
PrintError => 0,
AutoCommit => 1
});

if (! defined($dbh) )
{
print "Error connecting to DSN '$dsn_name'\n";
print "Error was:\n";
print "$DBI::errstr\n"; # $DBI::errstr is the error
# received from the SQL server

return 0;
}

return $dbh;
}



dbh_connect;
print"Test 2<BR>";

#Opens DB ODBC connection

if (! dbh_connect() )
{
print "Unable to connect to database.\n";

exit; # Unable to reconnect, exit the script gracefully
}
else
{
print "DSN connected to database.\n <BR>";
}

print"Test 3 <BR>";

my ($sql, $sth, $rc);

$sql = shift;

if (! ($sql) )
{
print ("Must pass SQL statement to db_sql!\n");

return 0;
}


print "Test 4 <BR>";

my ($sql, $sth, $href);

$sql = "SELECT EMAIL FROM LMS_USER";
print "$sql <BR>";


#maybe change it to
#prepare($sql) || die "can't prepare : $!\n";

print "prepare sql ststment before <BR>";

$sth = $dbh->prepare($sql) or die $DBI::errstr;

print "prepare sql ststment after <BR>";


#$sth = $dbh->prepare($sql); # Prepare the SQL statement passed to db_sql
print "Test 4a <BR>";
$sth = db_sql($sql); # Pass the SQL statement to the server
print "Test 5 <BR>";

if ( ! defined( $sth ) || ! ($sth) )
{
print "Unable to prepare SQL statement:\n";

print "$sql\n";

return 0;

}

$rc = $sth->execute;
print "Test 6";


#
# Check that we received a statement handle
#
if (! ($sth) )
{
return 0;
}

while( $href = $sth->fetchrow_hashref )
{
print "EMAIL: " . $$href{"EMAIL"} . "\n";

}

return 1;

print"Test 7 <BR>";





print"Test 8<BR>";
return $sth;

print"Test 9<BR>";

 
or I could supply you with my module and you simply change the DSN part to your requirements, then fetching records is easy peasy :-)

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!
 
Now that would be great!
Thanks,
Chip
 
ok here you go....You will need to change the DSN accordingly, and if you don't understand anything , just ask.

Firstly copy the code below and save as Sql.pm
Code:
######################
# Set Error Trapping #
######################

use CGI::Carp qw(fatalsToBrowser warningsToBrowser); 
use warnings;
use strict;

##########################
# Use WIN32::ODBC Module #
##########################
use Win32::ODBC;

##########################
# Set Package Name Space #
##########################
package Sql;

################
# Start Module #
################

BEGIN {

	# Invoke Exporter
	use Exporter;

	# Set Variables
	our (@ISA, @EXPORT);
	@ISA = qw(Exporter);

	# Define global vars and subs to be exported
	@EXPORT = qw( &getSQL &insSQL &updSQL &delSQL &cntSQL &sumSQL $DSN $FILEDSN);

}


########################################################################
########################### GLOBAL SUBROUTINES #########################
########################################################################

########################
#  INIT DSN VARIABLES  #
########################

# Set Default DSN
our $DSN = "DSN=dsnName;UID=myUID;PWD=myPWORD;";
our $FILEDSN = 0;

###############################################
############## Get SQL Routine ################
###############################################

sub getSQL {

#_0 = Table
#_1 = Columns
#_2 = Where
#_3 = Order By

# Define Record Set Array & Hash
my @rs;

#Build SQL Statement
my $sel = "SELECT $_[1] FROM $_[0] WHERE $_[2]";

# Check for ORDER BY
if($_[3]){$sel .= " ORDER BY $_[3]";}

# Open DB Connection
my $db;

if(!$FILEDSN){
    $db = new Win32::ODBC($DSN) || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}
else{ 

    $db = new Win32::ODBC("FILEDSN=$DSN;") || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}

# Run SQL Command
if(!$db->Sql("$sel")) {

	# Loop SQL Record Set
		while($db->FetchRow()){ 
				# Build Array of Hashes with SQL Data
				my %dt = $db->DataHash();
			    $rs[@rs] = \%dt;	
		}
	# Close DB Connection
	$db->Close();

	# Return Record Set Array of Hashes
	@rs;

} 
else{die "Error in getSQL ($sel)" . Win32::ODBC::Error();}

}

##################################################
############## Update SQL Routine ################
##################################################
sub updSQL {

#_0 = Table
#_1 = Values
#_2 = Where

# Set Variables
my ($rowcount);

#Build SQL Statement
my $sel = "UPDATE $_[0] SET $_[1] WHERE $_[2]";

# Open DB Connection
my $db;

if(!$FILEDSN){
    $db = new Win32::ODBC($DSN) || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}
else{ 
    $db = new Win32::ODBC("FILEDSN=$DSN;") || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}

# Run SQL Command
if(! $db->Sql("$sel") ) {
	# Set rows updated count 
	$rowcount = $db->RowCount(); 

	#Close DB Connection
	$db->Close(); 
} 
else{die "Error in updSQL ($sel)" . Win32::ODBC::Error();}

# Return number of rows updated
$rowcount;

}

##################################################
############## Insert SQL Routine ################
##################################################

sub insSQL {

#_0 = Table
#_1 = Columns
#_2 = Values

# Set Variables
my ($rowcount);

#Build SQL Statement
my $sel = "INSERT INTO $_[0] ($_[1]) VALUES ($_[2])";

# Open DB Connection
my $db;

if(!$FILEDSN){
    $db = new Win32::ODBC($DSN) || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}
else{ 
    $db = new Win32::ODBC("FILEDSN=$DSN;") || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}

# Run SQL Command
if(! $db->Sql("$sel") ) {
	# Set rows inserted count 
	$rowcount = $db->RowCount(); 
	#Close DB Connection
	$db->Close(); 
} 
else{die "Error in insSQL ($sel)" . Win32::ODBC::Error();}

# Return number of rows inserted
$rowcount;

}

##################################################
############## Delete SQL Routine ################
##################################################

sub delSQL {

#_0 = Table
#_1 = Where

# Set Variables
my ($rowcount);

#Build SQL Statement
my $sel = "DELETE FROM $_[0] WHERE $_[1]";

# Open DB Connection
my $db;

if(!$FILEDSN){
    $db = new Win32::ODBC($DSN) || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}
else{ 
    $db = new Win32::ODBC("FILEDSN=$DSN;") || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}

# Run SQL Command
if(! $db->Sql("$sel") ) {
	# Set rows deleted count 
	$rowcount = $db->RowCount(); 
	#Close DB Connection
	$db->Close(); 
} 
else{die "Error in delSQL ($sel)" . Win32::ODBC::Error();}

# Return number of rows deleted
$rowcount;

}

#################################################
############## COUNT SQL Routine ################
#################################################

sub cntSQL {

#_0 = Table
#_1 = Where

# Define Record Set Array & Hash
my @rs;

#Build SQL Statement
my $sel = "SELECT COUNT(1) as COUNT FROM $_[0] WHERE $_[1]";

# Open DB Connection
my $db;

if(!$FILEDSN){
    $db = new Win32::ODBC($DSN) || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}
else{ 
    $db = new Win32::ODBC("FILEDSN=$DSN;") || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}

# Run SQL Command
if(!$db->Sql("$sel")) {

	# Loop SQL Record Set
		while($db->FetchRow()){ 
				# Build Array of Hashes with SQL Data
				my %dt = $db->DataHash();
			    $rs[@rs] = \%dt;	
		}
	# Close DB Connection
	$db->Close();

	# Return Count
	$rs[0]->{'COUNT'};

} 
else{die "Error in cntSQL ($sel)" . Win32::ODBC::Error();}

}

###############################################
############## SUM SQL Routine ################
###############################################

sub sumSQL {

#_0 = Table
#_1 = Column
#_2 = Where

# Define Record Set Array & Hash
my @rs;

#Build SQL Statement
my $sel = "SELECT SUM($_[1]) as MYTOT FROM $_[0] WHERE $_[2]";

# Open DB Connection
my $db;

if(!$FILEDSN){
    $db = new Win32::ODBC($DSN) || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}
else{ 
    $db = new Win32::ODBC("FILEDSN=$DSN;") || die "getSQL Error Connecting: " . Win32::ODBC::Error();
}

# Run SQL Command
if(!$db->Sql("$sel")) {

	# Loop SQL Record Set
		while($db->FetchRow()){ 
				# Build Array of Hashes with SQL Data
				my %dt = $db->DataHash();
			    $rs[@rs] = \%dt;	
		}
	# Close DB Connection
	$db->Close();

	# Return Count
	$rs[0]->{'MYTOT'};

} 
else{die "Error in sumSQL ($sel)" . Win32::ODBC::Error();}

}

###########################
# END OF MODULE RETURN 1; #
###########################
1;

upload the module to the same place as the script going to use it....then you use the module like so....
Code:
#!/usr/bin/perl

######################
# Set Error Trapping #
######################

use CGI::Carp qw(fatalsToBrowser); 
use warnings;
use strict;

# Set path to user modules
use FindBin qw($Bin);
use lib "$Bin";

##################
# Use SQL Module #
##################
use Sql;

####################
# Get Some Records #
####################

my @rs = &getSQL("myTable","myCol1,myCol2,myCol3","myCol1='myValue'","myCol2 DESC");

for(@rs){
   print "$_->{'myCol1'} - $_->{'myCol2'} - $_->{'myCol3'}\n"
}
exit();

the module is commented so you know what data is passed into each routine.

As you see using the module to get a record set is easy , which is stored as an ARRAY of HASHES.

for SQL commands that don't return an array (record set) you only need to use a scalar assignment to capture the result, be it a COUNT, SUM, or No. records inserted, deleted etc...

so if I want to insert a record you'd use it like so..
Code:
my $rec = &insSQL("myTable","myCol1,myCol2,myCol3","myVal1,'myVal2','myVal3'");
$rec will = 1 (true) if insert is OK, also you notice you use the same syntax for inserting, deleting for variable types, numbers are entered raw, character fields have '' around them, just like normal SQL commands.

So if you are allowing user input to a form and you try to insert into the DB you must first escape the entered data.

You could always add a load of extra checking and data validation to the module, I decided to keep it simple and do any escaping , data handling within the script instead.

deleting and counting syntax's are the same Table,Where like so...
Code:
my $rec = &delSQL("myTable","myCol1='myVal1'");
$ rec will = number of records deleted.

or
Code:
my $rec = &cntSQL("myTable","myCol1='myVal1'");
So $rec will = number of records where myCol1 = myVal1.

Also remember the FILEDSN flag and also DSN variables, they can be changed accordingly from within the script so you can use it to connect via a fileDSN or a system ODBC DSN already defined.

if the variable DSN is to contain the path to a fileDSN , you simply change the global variable from withing the script...

Code:
$Sql::FILEDSN = 1;

to change the DSN being used to connect to different DB's just change the DSN value like so
Code:
$Sql::DSN = "DSN=myNewdsnName;UID=myNewUID;PWD=myNewPWORD;";
I hope this gives you what you need, if you need any further help, just ask :-)

"In complete darkness we are all the same, only our knowledge and wisdom separates us, don't let your eyes deceive you."

"If a shortcut was meant to be easy, it wouldn't be a shortcut, it would be the way!
 
Why does perl not print the errors? Am I missing a module?

It prints them to the webserver log. If you want them to go to the webpage, add
Code:
use CGI::Carp qw{ fatalsToBrowser };
to your code. See for more details.

Yours,

[&quot;]As soon as we started programming, we found to our surprise that it wasn't as easy to get programs right as we had thought. Debugging had to be discovered. I can remember the exact instant when I realized that a large part of my life from then on was going to be spent in finding mistakes in my own programs.[&quot;]
--Maur
 
Wow! I am impressed. This module worked on the first try! This makes life a lot easier and it is Friday to boot. Thanks so much for taking the time to help out.
Hope I can return the favor to some one.
Chip
 
OK how do I put the values into var?

my @rs = &getSQL("LMS_USER","USER_NAME,EMAIL","USER_NAME='005861539'");

my $NewValue = "$_->{'EMAIL'}\n"; #<- how to assign to var?
print "$NewValue\n";


for(@rs){
print "$_->{'EMAIL'}\n"
}
Thanks
Chip
 
Also to bother you more:
I am traying to delete by email address. I think "@" is not a legal char in perl to use so i have tried this:

my $rec = &delSQL("LMS_USER","EMAIL='<![CDATA[ameer.alam@home.com]]>'");

But it does not work. I get a script failed error.

This works fine.
my $rec = &delSQL("LMS_USER","USER_ID='79290'");
Any ideas on how to delete by email address?

If not I can probibly use the ID.
Thanks
Chip
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top