<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Scripting MySQL</title>
	<atom:link href="http://scriptingmysql.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://scriptingmysql.wordpress.com</link>
	<description>- the world&#039;s most popular open source database.</description>
	<lastBuildDate>Thu, 19 Jan 2012 15:36:06 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='scriptingmysql.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://1.gravatar.com/blavatar/d853745e3dda3fc870832efb707ecb73?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>Scripting MySQL</title>
		<link>http://scriptingmysql.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://scriptingmysql.wordpress.com/osd.xml" title="Scripting MySQL" />
	<atom:link rel='hub' href='http://scriptingmysql.wordpress.com/?pushpress=hub'/>
		<item>
		<title>How To Sort Columns of MySQL Data on a Web Page With Perl</title>
		<link>http://scriptingmysql.wordpress.com/2011/12/02/how-to-sort-columns-of-mysql-data-on-a-web-page-with-perl/</link>
		<comments>http://scriptingmysql.wordpress.com/2011/12/02/how-to-sort-columns-of-mysql-data-on-a-web-page-with-perl/#comments</comments>
		<pubDate>Fri, 02 Dec 2011 11:00:19 +0000</pubDate>
		<dc:creator>Tony Darnell</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Scripting]]></category>

		<guid isPermaLink="false">http://scriptingmysql.wordpress.com/?p=655</guid>
		<description><![CDATA[A friend of mine was building a web site so his customers could view his current inventory of transportation containers, and he asked me for help on how to sort the rows of information that appeared on his site. So, in this post, I will give you a quick example on how to sort columns [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=655&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>A friend of mine was building a web site so his customers could view his current inventory of transportation containers, and he asked me for help on how to sort the rows of information that appeared on his site.  So, in this post, I will give you a quick example on how to sort columns on a web page.</p>
<p>First, let&#8217;s start with an inventory database that we will build in <a href="http://mysql.com">MySQL</a>:</p>
<table bgcolor="white">
<tr>
<td><code>CREATE TABLE `inventory` (<br />
  `id` int(6) NOT NULL AUTO_INCREMENT,<br />
  `item_name` varchar(30) NOT NULL,<br />
  `item_SKU` varchar(20) NOT NULL,<br />
  `item_cost` decimal(4,2) NOT NULL,<br />
  PRIMARY KEY (`id`)<br />
) ENGINE=InnoDB AUTO_INCREMENT=100000 DEFAULT CHARSET=latin1
</td>
</tr>
</table>
<p></code></p>
<p>Next, here are some SQL statements to populate the MySQL database with some sample data.  </p>
<table bgcolor="white">
<tr>
<td><code>use inventory;<br />
insert into inventory (item_name, item_SKU, item_cost) values ('Apple', '10001', '1.04');<br />
insert into inventory (item_name, item_SKU, item_cost) values ('Peach', '10004', '1.28');<br />
insert into inventory (item_name, item_SKU, item_cost) values ('Plum', '10301', '1.17');<br />
insert into inventory (item_name, item_SKU, item_cost) values ('Apricot', '13033', '1.92');<br />
insert into inventory (item_name, item_SKU, item_cost) values ('Grapes', '20422', '1.34');<br />
insert into inventory (item_name, item_SKU, item_cost) values ('Kiwi', '98561', '2.78');<br />
insert into inventory (item_name, item_SKU, item_cost) values ('Mango', '56231', '0.99');<br />
insert into inventory (item_name, item_SKU, item_cost) values ('Strawberry', '24689', '1.52');<br />
insert into inventory (item_name, item_SKU, item_cost) values ('Banana', '65213', '0.39');<br />
insert into inventory (item_name, item_SKU, item_cost) values ('Tangerine', '47112', '1.22');
</td>
</tr>
</table>
<p></code></p>
<p><i>For this example, I am not going to show you how to create a new record, edit or delete your information in a MySQL database, as I did that in an <a href="http://scriptingmysql.wordpress.com/2011/11/11/using-mysql-and-perl-to-create-edit-and-delete-information-via-a-web-page/">earlier post</a>.</i></p>
<p>Now that we have our data, we are going to need a Perl script that will retrieve all of the data and create our web page at the same time.  I have named the Perl script <font color="blue">inventory_view</font>.  Don&#8217;t forget to change all of the variables to match your system. I will explain the variables that we will use in the Perl Script after the script below:</p>
<table bgcolor="white">
<tr>
<td><code>#!/usr/bin/perl<br />
#--------------------------------------------------------------------------<br />
# inventory_view.pl<br />
#--------------------------------------------------------------------------</p>
<p>use DBI;<br />
use DBD::mysql;<br />
use CGI qw(:standard);</p>
<p>my $Database = "scripting_mysql";</p>
<p># get the sort parameters from the URL<br />
my $query = new CGI;<br />
# $sort is the order by which to sort - ascending or descending<br />
# you only need to set a value if it is descending (desc)<br />
$sort = $query-&gt;param("sort");<br />
# $sortby is the field name to be used for sorting<br />
$sortby = $query-&gt;param("sortby");</p>
<p># check for sort order - ascending or descending<br />
if ($sort =~ "asc")</p>
<p>{<br />
	$order_by = "order by $sortby";<br />
}</p>
<p>else</p>
<p>{<br />
	$order_by = "order by $sortby $sort";<br />
}</p>
<p># if the sort isn't set to a value, set it to a default sort of item_name<br />
if (length($sort) &lt; 1)</p>
<p>{<br />
	$order_by = "order by item_name";<br />
}</p>
<p># print HTML header<br />
print header;</p>
<p>	# connect to the database and pull every record<br />
	$dbh = ConnectToMySql($Database);<br />
	$query = "select item_name, item_SKU, item_cost from inventory $order_by";<br />
	$sth = $dbh-&gt;prepare($query);<br />
	$sth-&gt;execute();</p>
<p># print the table header<br />
print &lt;&lt;HTML;<br />
&lt;table border=0&gt;<br />
&lt;tr&gt;<br />
&lt;td style="text-align:center;border:1px solid gray;padding: 5px 10px 5px 10px;"&gt;&lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/inventory_view.pl?sort=asc&amp;sortby=item_name&gt;&lt;img alt="sort ascending" title="sort ascending" height=15 src=http://tonydarnell.com/mysql_blog//arrow_blue_up.png&gt;&lt;/a&gt;&nbsp;&nbsp;&lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/inventory_view.pl?sort=desc&amp;sortby=item_name&gt;&lt;img alt="sort descending" title="sort descending" height=15 src=http://tonydarnell.com/mysql_blog//arrow_blue_down.png&gt;&lt;/a&gt;&lt;/td&gt;<br />
&lt;td style="text-align:center;border:1px solid gray;padding: 5px 10px 5px 10px;"&gt;&lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/inventory_view.pl?sort=asc&amp;sortby=item_SKU&gt;&lt;img alt="sort ascending" title="sort ascending" height=15 src=http://tonydarnell.com/mysql_blog//arrow_blue_up.png&gt;&lt;/a&gt;&nbsp;&nbsp;&lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/inventory_view.pl?sort=desc&amp;sortby=item_SKU&gt;&lt;img alt="sort descending" title="sort descending" height=15 src=http://tonydarnell.com/mysql_blog//arrow_blue_down.png&gt;&lt;/a&gt;&lt;/td&gt;<br />
&lt;td style="text-align:center;border:1px solid gray;padding: 5px 10px 5px 10px;"&gt;&lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/inventory_view.pl?sort=asc&amp;sortby=item_cost&gt;&lt;img alt="sort ascending" title="sort ascending" height=15 src=http://tonydarnell.com/mysql_blog//arrow_blue_up.png&gt;&lt;/a&gt;&nbsp;&nbsp;&lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/inventory_view.pl?sort=desc&amp;sortby=item_cost&gt;&lt;img alt="sort descending" title="sort descending" height=15 src=http://tonydarnell.com/mysql_blog//arrow_blue_down.png&gt;&lt;/a&gt;&lt;/td&gt;<br />
&lt;/tr&gt;</p>
<p>&lt;td style="text-align:center;border:1px solid gray;padding: 5px 10px 5px 10px;font-size:12px;"&gt;Item Name&lt;/td&gt;<br />
&lt;td style="text-align:center;border:1px solid gray;padding: 5px 10px 5px 10px;"&gt;Item SKU&lt;/td&gt;<br />
&lt;td style="text-align:center;border:1px solid gray;padding: 5px 10px 5px 10px;"&gt;Item Price&lt;/td&gt;</p>
<p>HTML</p>
<p># set the second line background color<br />
$background_color = "#FFFFFF";</p>
<p>			# loop through the data fetched from the query<br />
			while (@data = $sth-&gt;fetchrow_array()) {</p>
<p>				$item_name = $data[0];<br />
				$item_SKU = $data[1];<br />
				$item_cost = $data[2];</p>
<p># alternate the background colors<br />
if ($background_color =~ "#FFFFFF")</p>
<p>{<br />
	$background_color="#FFFFCC";<br />
}</p>
<p>else</p>
<p>{<br />
	$background_color="#FFFFFF";<br />
}</p>
<p>				# print the table rows, one for each item from the database<br />
				print &lt;&lt;HTML;</p>
<p>				&lt;tr bgcolor="$background_color"&gt;<br />
				&lt;td style="text-align:right;border:1px solid gray;padding: 5px 10px 5px 10px;font-size:12px;"&lt;/td&gt;$item_name&nbsp;&lt;/td&gt;<br />
				&lt;td style="text-align:right;border:1px solid gray;padding: 5px 10px 5px 10px;font-size:12px;"&lt;/td&gt;$item_SKU&nbsp;&lt;/td&gt;<br />
				&lt;td style="text-align:right;border:1px solid gray;padding: 5px 10px 5px 10px;font-size:12px;"&lt;/td&gt;$item_cost&nbsp;&lt;/td&gt;<br />
				&lt;/tr&gt;<br />
HTML<br />
			}</p>
<p># close the table<br />
print "&lt;/table&gt;";</p>
<p>exit;</p>
<p># more on what I am doing with the accessSM file may be found at:<br />
# http://scriptingmysql.wordpress.com/2011/07/27/connecting-to-mysql-with-perl/<br />
#----------------------------------------------------------------------<br />
sub ConnectToMySql {<br />
#----------------------------------------------------------------------</p>
<p>   my ($db) = @_;</p>
<p>   open(PW, "&lt;..\/accessSM") || die "Can't access login credentials";<br />
   my $db= &lt;PW&gt;;<br />
   my $host= &lt;PW&gt;;<br />
   my $userid= &lt;PW&gt;;<br />
   my $passwd= &lt;PW&gt;;</p>
<p>   chomp($db);<br />
   chomp($host);<br />
   chomp($userid);<br />
   chomp($passwd);</p>
<p>   my $connectionInfo="dbi:mysql:$db;$host";<br />
   close(PW);</p>
<p>   # make connection to database<br />
   my $l_dbh = DBI-&gt;connect($connectionInfo,$userid,$passwd);<br />
   return $l_dbh;</p>
<p>}
</td>
</tr>
</table>
<p></code></p>
<p>When you run the script for the first time in a browser, you should see something like this:</p>
<p><img src="http://tonydarnell.com/mysql_blog/sort_01.png"></p>
<p>In our Perl script, we are using the <font color="blue">$query</font> variable to select the three columns from our MySQL database &#8211; <font color="blue">item_name</font>, <font color="blue">item_SKU</font> and <font color="blue">item_cost</font>.  And we will decide which one to sort by with the variable <font color="blue">$sortby</font>.  And we will assign ascending or descending order to the variable <font color="blue">$sort</font>.  This will give us a total of six options for sorting columns and in which order:</p>
<table bgcolor="white">
<tr>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">$sortby</td>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">$sort</td>
</tr>
<tr>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">item_name</td>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">ascending order</td>
</tr>
<tr>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">item_name</td>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">descending order</td>
</tr>
<tr>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">item_SKU</td>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">ascending order</td>
</tr>
<tr>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">item_SKU</td>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">descending order</td>
</tr>
<tr>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">item_cost</td>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">ascending order</td>
</tr>
<tr>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">item_cost</td>
<td style="text-align:center;border:1px solid gray;padding:5px 10px;">descending order</td>
</tr>
</table>
<p>To build the URL for each, we simply use the script name &#8211; <font color="blue">inventory_view.pl</font> &#8211; and add the variables <font color="blue">$sortby</font> and <font color="blue">$sort</font> along with their values, using an ampersand for the delimiter.</p>
<table bgcolor="white">
<tr>
<td><code>inventory_view.pl?sortby=[column_name]&amp;sort=[asc or desc]
</td>
</tr>
</table>
<p></code></p>
<p>Example:</p>
<table bgcolor="white">
<tr>
<td><code>inventory_view.pl?sortby=item_name&amp;sort=asc
</td>
</tr>
</table>
<p></code></p>
<p>We will then use an image of an arrow pointing upwards (for ascending order) and downwards (for descending order).  Here is an example of the HTML for &#8220;sort by item_name and ascending order&#8221;: <i>(don&#8217;t forget to add the full path names for both the location of the Perl script and the location of your image file)</i></p>
<table bgcolor="white">
<tr>
<td><code>&lt;a href="cgi-bin/inventory_view.pl?sortby=item_name&amp;sort=asc"&gt;&lt;img src="images/arrow_blue_up.png"&gt;&lt;/a&gt;
</td>
</tr>
</table>
<p></code></p>
<p>You simply have to build a link for each of the six sorting options (two per database column) to correspond to each of the blue up/down arrows.  All six links would look like this:</p>
<table bgcolor="white">
<tr>
<td><code></p>
<p>&lt;a href="cgi-bin/inventory_view.pl?sort=asc&amp;sortby=item_name"&gt;&lt;img alt="sort ascending" title="sort ascending" height="15" src="images/arrow_blue_up.png"&gt;&lt;/a&gt;<br />
&lt;a href="cgi-bin/inventory_view.pl?sort=desc&amp;sortby=item_name"&gt;&lt;img alt="sort descending" title="sort descending" height="15" src="images/arrow_blue_down.png"&gt;&lt;/a&gt;</p>
<p>&lt;a href="cgi-bin/inventory_view.pl?sort=asc&amp;sortby=item_SKU"&gt;&lt;img alt="sort ascending" title="sort ascending" height="15" src="images/arrow_blue_up.png"&gt;&lt;/a&gt;<br />
&lt;a href="cgi-bin/inventory_view.pl?sort=desc&amp;sortby=item_SKU"&gt;&lt;img alt="sort descending" title="sort descending" height="15" src="images/arrow_blue_down.png"&gt;&lt;/a&gt;</p>
<p>&lt;a href="cgi-bin/inventory_view.pl?sort=asc&amp;sortby=item_cost"&gt;&lt;img alt="sort ascending" title="sort ascending" height="15" src="images/arrow_blue_up.png"&gt;&lt;/a&gt;<br />
&lt;a href="cgi-bin/inventory_view.pl?sort=desc&amp;sortby=item_cost"&gt;&lt;img alt="sort descending" title="sort descending" height="15" src="images/arrow_blue_down.png"&gt;&lt;/a&gt;</p>
</td>
</tr>
</table>
<p></code></p>
<p>When the <font color="blue">inventory_view.pl</font> script is executed the first time, we have not set the <font color="blue">$sortby</font> column or <font color="blue">$sort</font> order, so it will default to sorting by <font color="blue">item_name</font> and <font color="blue">ascending</font> order (which really doesn&#8217;t have a value, as ascending order is the default sort order).  Each time a sort request is made, a new connection will be made to the database, so that is something to consider when you decide which columns you want to be available to sort.  And we aren&#8217;t putting a limit on the number of rows that are retrieved, so that you have multiple pages of items &#8211; but I will try to cover that in a future post.  </p>
<p>While there are other solutions that don&#8217;t require you to hit the database each time, this should give you a quick (and dirty) way to sort columns of information in a table on a web page. </p>
<p>&nbsp;
<p>
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<table width="100%">
<tr>
<td><img border="0" src="http://www.scriptingmysql.com/scriptingmysql/tony.jpg">
</td>
<td>
Tony Darnell is a Principal Sales Consultant for <a href="http://mysql.com/" />MySQL</a>, a division of <a href="http://oracle.com">Oracle</a>, Inc.  MySQL is the world&#8217;s most popular open-source database program.<br />
<br />Tony may be reached at info [at] ScriptingMySQL.com and on <a href="http://www.linkedin.com/in/tonydarnell">LinkedIn</a>.
</td>
</tr>
</table>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/scriptingmysql.wordpress.com/655/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/scriptingmysql.wordpress.com/655/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/scriptingmysql.wordpress.com/655/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/scriptingmysql.wordpress.com/655/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/scriptingmysql.wordpress.com/655/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/scriptingmysql.wordpress.com/655/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/scriptingmysql.wordpress.com/655/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/scriptingmysql.wordpress.com/655/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/scriptingmysql.wordpress.com/655/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/scriptingmysql.wordpress.com/655/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/scriptingmysql.wordpress.com/655/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/scriptingmysql.wordpress.com/655/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/scriptingmysql.wordpress.com/655/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/scriptingmysql.wordpress.com/655/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=655&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://scriptingmysql.wordpress.com/2011/12/02/how-to-sort-columns-of-mysql-data-on-a-web-page-with-perl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4a7803de89b97b14df8a346d36a1b9a1?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tonydarnell</media:title>
		</media:content>

		<media:content url="http://tonydarnell.com/mysql_blog/sort_01.png" medium="image" />

		<media:content url="http://www.scriptingmysql.com/scriptingmysql/tony.jpg" medium="image" />
	</item>
		<item>
		<title>Automatically Download MySQL Enterprise Monitor Graphs as PNG Files Using Perl</title>
		<link>http://scriptingmysql.wordpress.com/2011/11/18/automatically-download-mysql-enterprise-monitor-graphs-as-png-files-using-perl/</link>
		<comments>http://scriptingmysql.wordpress.com/2011/11/18/automatically-download-mysql-enterprise-monitor-graphs-as-png-files-using-perl/#comments</comments>
		<pubDate>Fri, 18 Nov 2011 10:00:08 +0000</pubDate>
		<dc:creator>Tony Darnell</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[MySQL Enterprise Monitor]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://scriptingmysql.wordpress.com/?p=557</guid>
		<description><![CDATA[I was giving a presentation of the MySQL&#8217;s Enterprise Monitor* application to a client recently. I was demonstrating the &#8220;graphs&#8221; section of MEM, where you can monitor MySQL sessions, connections, replication latency and more with 60+ graphs. Usually, you view the graphs from within the MEM Enterprise Dashboard (via a web browser). But the client [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=557&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I was giving a presentation of the <a href="http://www.mysql.com/products/enterprise/monitor.html">MySQL&#8217;s Enterprise Monitor</a>* application to a client recently.  I was demonstrating the &#8220;graphs&#8221; section of MEM, where you can monitor MySQL sessions, connections, replication latency and more with 60+ graphs.  Usually, you view the graphs from within the MEM Enterprise Dashboard (via a web browser).  But the client asked if there was a way to automatically download graphs.  I wasn&#8217;t sure why he wanted to download the graphs (I didn&#8217;t ask), but I knew it wasn&#8217;t possible by using MEM alone.  However, in the past I have written Perl scripts to automatically download files from web sites, so I thought I would see if it was possible with MEM.</p>
<table bgcolor="white">
<tr>
<td width="20">&nbsp;</td>
<td>
<font color="green"><br /><i>*The MySQL Enterprise Monitor (MEM) continuously monitors your MySQL servers and alerts you to potential problems before they impact your system. Its like having a &#8220;Virtual DBA Assistant&#8221; at your side to recommend best practices to eliminate security vulnerabilities, improve replication, optimize performance and more. As a result, the productivity of your developers, DBAs and System Administrators is improved significantly. (from:  <a href="http://www.mysql.com/products/enterprise/monitor.html">http://www.mysql.com/products/enterprise/monitor.html</a>)</i></font><br />&nbsp;
</td>
<td width="20">&nbsp;</td>
</tr>
</table>
<p>Of course, you have to install MEM and at least one agent.  Let&#8217;s assume that you have already accomplished this task, and that MEM is running properly.  Open MEM in your browser, login, click on the graphs tab, and then you will see a list of all of the available graphs.</p>
<p><img width="600" src="http://tonydarnell.com/mysql_blog/mem_graphs_tab.png"></p>
<p>For this example, we are going to automatically download the <font color="blue">Agent Reporting Delay</font> and the <font color="blue">Disk IO Usage</font> graphs.  We will download the first graph for all of the servers in a particular group, and the second graph for an individual server.  First, click on a server group in your server list on the left side of MEM.</p>
<p><img src="http://tonydarnell.com/mysql_blog/mem_server_list.png"></p>
<p>Next, we will need to change the Time Range settings to &#8220;From/To&#8221;, so that we can enter the a timeline for the graph in our script.  Don&#8217;t worry about the time settings that are in MEM, as we will change these settings later, but we need them so that they will be included in the URL that we will use (more on this later).  After you have changed the Time Range settings, click on the &#8220;Filter&#8221; button.</p>
<p><img width="600" src="http://tonydarnell.com/mysql_blog/mem_time_range.png"></p>
<p>Next, click on the plus sign for the graph that you want to use so that MEM will draw the graph.  For this example, we will click on the &#8220;Agent Reporting Delay&#8221; graph:</p>
<p><img width="600" src="http://tonydarnell.com/mysql_blog/mem_agent_reporting_delay_graph.png"></p>
<p>You will notice two icons to the right of the graph name.  The first icon (on the left) allows you click on the icon to download the graph as a .csv file.  The second icon (on the right) allows you to click on the icon and download the graph as a PNG image file.</p>
<p><img src="http://tonydarnell.com/mysql_blog/mem_graph_png_select.png"></p>
<p>We need some information from the actual link that is used when you click on the PNG icon.  So, we will need to <font color="blue">right-click</font> on the icon to get the URL link location information for the Agent Reporting Delay graph:</p>
<p><img src="http://tonydarnell.com/mysql_blog/mem_copy_link_location.png"></p>
<p>The URL for this graph is then copied to your clipboard.  This is the URL location (which is for all servers in the group that I selected):</p>
<table bgcolor="white">
<tr>
<td><code>http://192.168.1.2:18080/Graph.action?<font color="blue">dims_height</font>=300&amp;<font color="blue">dims_width</font>=800&amp;graph=f924cb42-fed5-11df-923c-a6466b4620ce&amp;locale=en_US&amp;noDefaults=false&amp;<font color="blue">servers_group=0</font>&amp;style=NORMAL&amp;<font color="blue">time_fromDate</font>=2011-11-16&amp;<font color="blue">time_fromTime</font>=11%3A24&amp;<font color="blue">time_toDate</font>=2011-11-16&amp;<font color="blue">time_toTime</font>=11%3A54&amp;time_type=FROMTO&amp;tzName=America%2FNew_York
</td>
</tr>
</table>
<p></code></p>
<p>As you can see in the URL above, there are several variable values that we will include in our script to produce our graphs (in <font color="blue">blue</font> text above).  In this example, we will only be working with the following variables:<br />
- dims_height<br />
- dims_width<br />
- time_fromDate<br />
- time_fromTime<br />
- time_toDate<br />
- time_toTime<br />
- graph name/ID (which is a UUID and is constant)<br />
- servers_group and servers_server<br />
<i>(the servers_server variable and value are not shown in the above example, but will be in the next example below)</i></p>
<p>We will be using a text file named <font color="blue">files.txt</font> to store some of the graph variable values that will be used by the script.  Now that you know how to copy the URL for a graph, you will need to extract the value for the graph variable and the value for the servers variable and place the values into your <font color="blue">files.txt</font> file.  The graph value for the above URL (shown again below) is in <font color="blue">blue</font> text, and the value for the server variable is in <font color="red">red</font> text:  (notice that all values are separated on the left by an equal sign &#8220;=&#8221; and on the right by an ampersand &#8220;&amp;&#8221;)</p>
<table bgcolor="white">
<tr>
<td><code>http://192.168.1.2:18080/Graph.action?dims_height=300&amp;dims_width=800&amp;graph=<font color="blue">f924cb42-fed5-11df-923c-a6466b4620ce</font>&amp;locale=en_US&amp;noDefaults=false&amp;<font color="red">servers_group=0</font>&amp;style=NORMAL&amp;time_fromDate=2011-11-16&amp;time_fromTime=11%3A24&amp;time_toDate=2011-11-16&amp;time_toTime=11%3A54&amp;time_type=FROMTO&amp;tzName=America%2FNew_York
</td>
</tr>
</table>
<p></code></p>
<p>In the above example, we had selected a group of servers in our server list (on the left side of MEM), and therefore the URL will not have a value for the individual server (variable named servers_server).  The graph that we will extract will be for this group of servers (in this case servers_group has a value of zero, which is still a value).  This is what we had chosen under our Servers list:</p>
<p><img src="http://tonydarnell.com/mysql_blog/mem_server_list.png"></p>
<p>Now, we want to select an individual server.  In this case, we will click on &#8220;iMac-Tony&#8221;:</p>
<p><img src="http://tonydarnell.com/mysql_blog/mem_server_list_single.png"></p>
<p>Now that we have chosen an individual server, in the URL for that graph, you will have a value for the variable named &#8220;servers_server&#8221;, as well as a value for servers_group &#8211; and you will need both values together.  So, if you want a graph for an individual server, you will need to click on that individual server in your servers list, reselect the &#8220;Time Range&#8221; value of &#8220;From/To&#8221;, click &#8220;Filter&#8221;, and re-copy the PNG graph URL.  Once we have copied the URL for this graph for an individual server, you will see a different value for the graph variable (in <font color="red">red</font>) and a value for servers_group and servers_server (in <font color="blue">blue</font>) like this: </p>
<table bgcolor="white">
<tr>
<td><code>http://192.168.1.2:18080/Graph.action?dims_height=300&amp;dims_width=800&amp;graph=<font color="red">6d9c8ac0-7a3b-11df-9df0-f30c5eb77a3c</font>&amp;locale=en_US&amp;noDefaults=false&amp;<font color="blue">servers_group=0&amp;servers_server=111</font>&amp;style=NORMAL&amp;time_fromDate=2011-11-16&amp;time_fromTime=15%3A27&amp;time_toDate=2011-11-16&amp;time_toTime=15%3A57&amp;time_type=FROMTO&amp;tzName=America%2FNew_York
</td>
</tr>
</table>
<p></code></p>
<p>We will use the above URL information for our second graph &#8211; the Disk IO Usage graph.  You will need to copy all of the graph and server values for the graphs that you want to download.  For the above URL, we will grab these values, to be placed in our <font color="blue">files.txt</font> file:<br />
graph = <font color="red">6d9c8ac0-7a3b-11df-9df0-f30c5eb77a3c</font><br />
server group and server name = <font color="blue">servers_group=0&amp;servers_server=111</font></p>
<p>This is a tedious process at first, but you should only have to do this once for each graph.  <a target="new" href="http://www.markleith.co.uk">Mark Leith</a> from the <a href="http://mysql.com">MySQL</a> software development team in the UK gave me some great information for finding out the graph names along with the graph UUID value (be sure to also check out <a target="new" href="http://www.markleith.co.uk">Mark&#8217;s blog</a>).  Mark stated <i>&#8220;The uuid per graph does not change over time/versions – it’s how we maintain the constant between them in fact.&#8221;</i>  The graph name and graph value (UUID) is stored in the MEM Service Manager repository database, which contains all of the statistical information for MEM.  To access this database, simply login to your MEM Service Manager MySQL repository database with the following syntax:</p>
<table bgcolor="white">
<tr>
<td><code>mysql -uroot -p -P13306 -h127.0.0.1
</td>
</tr>
</table>
<p></code></p>
<p>During the installation of MEM, if you decided to use your current MySQL database to store the repository information, you will need to just login to that database.  Once you have logged into the repository database, you can get a list of the graph names and graph UUID&#8217;s with this command:</p>
<table bgcolor="white">
<tr>
<td><code>
<pre>SELECT title, uuid FROM mem.graphs;<br />
mysql&gt; SELECT title, uuid FROM mem.graphs;<br />
+--------------------------------------------+--------------------------------------+<br />
| title                                      | uuid                                 |<br />
+--------------------------------------------+--------------------------------------+<br />
| agent_lua_mem_usage.name                   | 545e6c5e-ccab-457e-89ca-cc6e5eeb1e1d |<br />
| agent_reporting_delay.name                 | f924cb42-fed5-11df-923c-a6466b4620ce |<br />
| avg_row_accesses.name                      | f289dae0-82be-11df-9df0-f1c3fca44363 |<br />
| binlog_cache.name                          | f84b270e-7a21-11df-9df0-f30c5eb77a3c |<br />
.....
<pre></td>
</tr>
</table>
<p></code></p>
<p>This should make it easier than copying the variables in the links as described above, but I wanted to show you how to get the information and explain all of the variables in the graph URL links.  (Thanks Mark!)</p>
<p>In the <font color="blue">files.txt</font> file, we also want a name for the graph (which will also be used for the PNG image file name), the graph value, the servers value and the server or server group values from the above URLs, as well as the name of the server group or individual server.  You should separate the values with a delimiter of three tildes "~~~".  </p>
<p>So, for the two example graphs above, your <font color="blue">files.txt</font> file should contain the following values - Graph Name~~~graph value~~~server information~~~server or group name:  (please note that the graph values that I have here may not be the same values that you would have for the same graph)</p>
<table bgcolor="white">
<tr>
<td><code><font color="blue">Agent Reporting Delay</font><font color="red">~~~</font><font color="blue">f924cb42-fed5-11df-923c-a6466b4620ce</font><font color="red">~~~</font><font color="blue">servers_group=0</font><font color="red">~~~</font><font color="blue">All Servers</font><br />
<font color="blue">Disk IO Usage</font><font color="red">~~~</font><font color="blue">6d9c8ac0-7a3b-11df-9df0-f30c5eb77a3c</font><font color="red">~~~</font><font color="blue">servers_group=0&amp;servers_server=111</font><font color="red">~~~</font><font color="blue">iMac Tony</font>
</td>
</tr>
</table>
<p></code></p>
<p>The first line above will produce an "Agent Report Delay" graph for "All Servers".  The second line will produce a "Disk IO Usage" graph for only the server named "iMac-Tony".</p>
<p>Now that we have our <font color="blue">files.txt</font> file in place (it should be placed in the same folder as the Perl script - or you may modify the Perl script for a different file location), we will use this Perl script to download our graphs as PNG image files.  In case you want to place this script in a <a href="http://en.wikipedia.org/wiki/Cron">cron</a> job to run every X number of minutes, we will include a variable to allow you to select the previous number of minutes to include in your graph.  For example, in the Perl script, if you set the value of the variable <font color="blue">$time_interval</font> to <font color="blue">60</font> (minutes) and run the job at 30 minutes past the hour, the script will retrieve a graph for the past 60 minutes from the time of script execution.</p>
<p>For this example, we will name the Perl script "get_graphs.pl".  There will be some variables in the script that you will have to change once, to match your system's information.  The variables that you need to change are highlighted in <font color="blue">blue</font> text in the script:</p>
<table bgcolor="white">
<tr>
<td><code>#!/usr/bin/perl</p>
<p>use WWW::Mechanize;<br />
use Date::Calc qw(Add_Delta_DHMS); </p>
<p># file name for input - this contains the Graph Name and Graph URL<br />
$filename = "files.txt";</p>
<p># time interval must be in minutes<br />
$time_interval = '60';</p>
<p># the width of your graph<br />
$dims_width = "800";<br />
# the height of your graph<br />
$dims_height = "300";</p>
<p># IP and port number of your MEM server<br />
$server = "192.168.1.2:18080";</p>
<p># get the current time using the display_time_now subroutine<br />
$unixtimenow = &amp;display_time_now();<br />
($time_toDate, $time_toTime) = split(" ",$unixtimenow);</p>
<p># get the past time using the display_time_past subroutine<br />
$unixtimepast = &amp;display_time_past();<br />
($time_fromDate, $time_fromTime) = split(" ",$unixtimepast);</p>
<p># fool the web server into thinking we are a person<br />
my $mech = WWW::Mechanize-&gt;new();<br />
# look like a real person<br />
$mech-&gt;agent('User-Agent=Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5');<br />
# we need cookies<br />
$mech-&gt;cookie_jar(HTTP::Cookies-&gt;new);</p>
<p># Login to the MySQL Enterprise Monitor<br />
$mech-&gt;get('http://192.168.1.2:18080/Auth.action');<br />
$mech-&gt;success or die "login GET fail";</p>
<p># you will need to substitute your user name and password for MEM here<br />
my $user = 'tonydarnell';<br />
my $pass = 'tonyd999';</p>
<p># find a fill out the login form<br />
my $login = $mech-&gt;form_name("DoAuth");<br />
$login-&gt;value('username' =&gt; $user);<br />
$login-&gt;value('password' =&gt; $pass);<br />
$mech-&gt;submit();<br />
$mech-&gt;success or die "login POST fail";</p>
<p>open(line, "$filename") || die (print "\nERROR - could not open file: $filename\n");<br />
while (&lt;line&gt;)</p>
<p>{</p>
<p>chomp $_;</p>
<p>print "\n$_\n";</p>
<p>($imagefilename, $graph_to_get, $servers_to_get, $servers_name) = split(/~~~/);</p>
<p>if (length($imagefilename) &gt; 2)</p>
<p>{</p>
<p>	$time_toDate_for_filename = $time_toDate;<br />
	$time_toDate_for_filename =~ s/\-/_/g;</p>
<p>	$time_toTime_for_filename = $time_toTime;<br />
	$time_toTime_for_filename =~ s/\:/_/g;</p>
<p>	$servers_name =~ s/ /_/g;</p>
<p>	$imagefilename =~ s/ /_/g;<br />
	$imagefilename = $servers_name . "_" . $imagefilename . "_" . $time_toDate_for_filename . "_" . $time_toTime_for_filename . ".png";</p>
<p>	# you will need to change your settings here to match your URL for your graphs<br />
	$graph = "http://". $server . "/Graph.action?dims_height=" . $dims_height . "&amp;dims_width=" . $dims_width . "&amp;graph=" . $graph_to_get . "&amp;locale=en_US&amp;noDefaults=false&amp;" . $servers_to_get . "&amp;style=NORMAL&amp;time_fromDate=" . $time_fromDate . "&amp;time_fromTime=" . $time_fromTime . "&amp;time_toDate=" . $time_toDate . "&amp;time_toTime=" . $time_toTime . "&amp;time_type=FROMTO&amp;tzName=America%2FNew_York";</p>
<p>	print "\n$graph\n";</p>
<p>	#exit;</p>
<p>	# Get the PNG image file from the URL<br />
	$mech-&gt;get($graph);<br />
	$mech-&gt;save_content($imagefilename);</p>
<p>}</p>
<p>}</p>
<p>exit;</p>
<p>close($filename);</p>
<p># ------------------------------------------------<br />
# sub-routines</p>
<p>sub display_time_now {<br />
  my ($sec,$min,$hour,$mday,$mon,$year,undef,undef,undef) = localtime time();<br />
  $year += 1900;<br />
  $mon += 1;<br />
  return "$year-".sprintf("%02d-%02d %02d:%02d",$mon,$mday,$hour,$min);<br />
}</p>
<p>sub display_time_past {<br />
  my ($sec,$min,$hour,$mday,$mon,$year,undef,undef,undef) = localtime time() - ($time_interval*60);<br />
  $year += 1900;<br />
  $mon += 1;<br />
  return "$year-".sprintf("%02d-%02d %02d:%02d",$mon,$mday,$hour,$min);<br />
}</p>
<p># ------------------------------------------------</p>
</td>
</tr>
</table>
<p></code></p>
<p>When we executed the script, two files were created and downloaded - All_Servers_Agent_Reporting_Delay_2011_11_16_16_17.png and iMac_Tony_Disk_IO_Usage_2011_11_16_16_17.png:</p>
<p><img width="600" src="http://tonydarnell.com/mysql_blog/All_Servers_Agent_Reporting_Delay_2011_11_16_16_17.png"><br />
All_Servers_Agent_Reporting_Delay_2011_11_16_16_17.png</p>
<p><img width="600" src="http://tonydarnell.com/mysql_blog/iMac_Tony_Disk_IO_Usage_2011_11_16_16_17.png"><br />
iMac_Tony_Disk_IO_Usage_2011_11_16_16_17.png</p>
<p>You could also create a similar script to download the information as a .csv file, but the syntax is very different (maybe I will do that in a future post).  But for now, I have a possible solution for the client - and I hope that he likes it.</p>
<p>&nbsp;
<p>
-----------------------------------------<br />
<table width="100%">
<tr>
<td><img border="0" src="http://www.scriptingmysql.com/scriptingmysql/tony.jpg">
</td>
<td>
Tony Darnell is a Principal Sales Consultant for <a href="http://mysql.com/" />MySQL</a>, a division of <a href="http://oracle.com">Oracle</a>, Inc.  MySQL is the world's most popular open-source database program.<br />
<br />Tony may be reached at info [at] ScriptingMySQL.com and on <a href="http://www.linkedin.com/in/tonydarnell">LinkedIn</a>.
</td>
</tr>
</table>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/scriptingmysql.wordpress.com/557/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/scriptingmysql.wordpress.com/557/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/scriptingmysql.wordpress.com/557/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/scriptingmysql.wordpress.com/557/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/scriptingmysql.wordpress.com/557/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/scriptingmysql.wordpress.com/557/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/scriptingmysql.wordpress.com/557/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/scriptingmysql.wordpress.com/557/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/scriptingmysql.wordpress.com/557/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/scriptingmysql.wordpress.com/557/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/scriptingmysql.wordpress.com/557/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/scriptingmysql.wordpress.com/557/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/scriptingmysql.wordpress.com/557/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/scriptingmysql.wordpress.com/557/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=557&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://scriptingmysql.wordpress.com/2011/11/18/automatically-download-mysql-enterprise-monitor-graphs-as-png-files-using-perl/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4a7803de89b97b14df8a346d36a1b9a1?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tonydarnell</media:title>
		</media:content>

		<media:content url="http://tonydarnell.com/mysql_blog/mem_graphs_tab.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/mem_server_list.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/mem_time_range.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/mem_agent_reporting_delay_graph.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/mem_graph_png_select.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/mem_copy_link_location.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/mem_server_list.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/mem_server_list_single.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/All_Servers_Agent_Reporting_Delay_2011_11_16_16_17.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/iMac_Tony_Disk_IO_Usage_2011_11_16_16_17.png" medium="image" />

		<media:content url="http://www.scriptingmysql.com/scriptingmysql/tony.jpg" medium="image" />
	</item>
		<item>
		<title>Using MySQL and Perl to Create, Edit and Delete Information Via a Web Page</title>
		<link>http://scriptingmysql.wordpress.com/2011/11/11/using-mysql-and-perl-to-create-edit-and-delete-information-via-a-web-page/</link>
		<comments>http://scriptingmysql.wordpress.com/2011/11/11/using-mysql-and-perl-to-create-edit-and-delete-information-via-a-web-page/#comments</comments>
		<pubDate>Fri, 11 Nov 2011 15:10:11 +0000</pubDate>
		<dc:creator>Tony Darnell</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://scriptingmysql.wordpress.com/?p=474</guid>
		<description><![CDATA[A friend of mine was asking me for my recommendation of a good desktop database program to use to keep track of his inventory of cargo containers. I suggested to him that he should use MySQL and write a web page interface to do everything that he needed. He then reminded me that he is [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=474&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>A friend of mine was asking me for my recommendation of a good desktop database program to use to keep track of his inventory of cargo containers.  I suggested to him that he should use MySQL and write a web page interface to do everything that he needed.  He then reminded me that he is a lawyer by trade, and that he doesn&#8217;t have any computer programming experience.  Then I remembered that he has almost zero computer skills.  And his Texas Hold-Em skills are even worse, but I don&#8217;t mind taking his money.  In his case, he should just use a notepad and a pencil.  (As for the question &#8211; what is a lawyer doing with cargo containers? &#8211; that is a different story.)</p>
<p>If he did decide to broaden his horizons a bit, he could easily write his own software web application for creating and storing almost any kind of data.  In this post, I will show you how to create a MySQL database and then the web pages needed to create new addresses, edit the same data and delete the data as well.</p>
<p>Of course, you will need to download and install MySQL.  There are a ton of resources on the web for doing this, so let&#8217;s assume that you have already this part completed &#8211; and that you know how to use MySQL. First, let&#8217;s create a MySQL table.  In this example, we will create a simple address book, and populate it with a few fake names.  Here is the SQL, complete with the fake data to be inserted:</p>
<table width="800">
<tr bgcolor="white">
<td><code>SET NAMES latin1;<br />
SET FOREIGN_KEY_CHECKS = 0;</p>
<p>CREATE TABLE `address` (<br />
  `serial` int(4) NOT NULL AUTO_INCREMENT,<br />
  `name_first` varchar(30) NOT NULL,<br />
  `name_last` varchar(30) NOT NULL,<br />
  `address_01` varchar(40) NOT NULL,<br />
  `address_02` varchar(40) NOT NULL,<br />
  `address_city` varchar(30) NOT NULL,<br />
  `address_state` varchar(2) NOT NULL,<br />
  `address_postal_code` varchar(10) NOT NULL,<br />
  PRIMARY KEY (`serial`)<br />
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=latin1;</p>
<p>insert into `address` values('1','1','Clark','Kent','344 Clinton St','Apt. #3B','Metropolis','NY','10001'),<br />
 ('2','2','Dave','Jones','500 Second Avenue','Suite 100','Atlanta','GA','30303'),<br />
 ('3','3','Tom','Watson','123 Golf Course Lane','Suite A','Macon','GA','31066'),<br />
 ('4','4','Jack','Nicklaus','400 Laurel Oak Dr','Suite 49','Suwanee','GA','31044'),<br />
 ('5','1','Betty','Smith','100 Main Street','Suite 500','Buffalo','NY','14201'),<br />
 ('6','2','Bruce','Wayne','1007 Mountain Drive','','Gotham City','NY','10000');</p>
<p>SET FOREIGN_KEY_CHECKS = 1;<br />
</code></td>
</tr>
</table>
<p>We will be creating several Perl scripts as follows.  To keep it simple, we will use Perl to create all of the pages, even though the &#8220;add_entry.pl&#8221; script could be a standard HTML page.  This will allow you to put all of the scripts in your cgi-bin directory.  Here are the scripts that we will be creating and using:<br />
&nbsp;&nbsp;&#8212;&nbsp;<font color="blue">dashboard.pl</font> -&gt; This is your &#8220;home page&#8221;, and will list all of the entries in your address database.<br />
&nbsp;&nbsp;&#8212;&nbsp;<font color="blue">add_entry.pl</font> -&gt; This page will allow you to complete a form containing the new address information.<br />
&nbsp;&nbsp;&#8212;&nbsp;<font color="blue">add.pl</font> -&gt; This Perl script will save the information from the add.html web page.<br />
&nbsp;&nbsp;&#8212;&nbsp;<font color="blue">edit.pl</font> -&gt; This Perl script will allow you to edit an entry from your address database.<br />
&nbsp;&nbsp;&#8212;&nbsp;<font color="blue">edit_save.pl</font> -&gt; This will save the changes made from the edit.pl page.<br />
&nbsp;&nbsp;&#8212;&nbsp;<font color="blue">delete.pl</font> -&gt; This is step one in deleting a record, it takes you to the delete_confirm.pl page.<br />
&nbsp;&nbsp;&#8212;&nbsp;<font color="blue">delete_confirm.pl</font> -&gt; This will confirm the deletion of a record, or allow you to cancel the request.</p>
<p>For our home page (called dashboard), we need to create a web page (via a Perl script) that will list all of the addresses in the database.  In this example, we aren&#8217;t using any logic to restrict the number of entries that are displayed, so this page will just display all of them (adding limits to a web page like this is a bit more complicated, and I might try to cover this in a future post).  We will use a Perl script to display the HTML, as we will need to pull data from the database to be displayed in the web page.  So, you will need to put the &#8220;directory.pl&#8221; script (home page) and all of the other scripts in your cgi-bin directory (and don&#8217;t forget to make all of your Perl scripts executable &#8211; via &#8220;chmod 755&#8243;).  You could create a regular HTML page (.htm) using frames, with the top frame using HTML and then use a Perl script to pull the data for the bottom frame, but let&#8217;s just stick with this example for now.</p>
<p>Here is what the opening home page (dashboard.pl) should look like:</p>
<p><img src="http://tonydarnell.com/mysql_blog/dashboard-pl.png"></p>
<p>In this script, we will also create a link that will allow us to edit the information for a single address entry, as well as a link to delete the entry.  We will use the serial database field to point to the record that we want to edit or delete.  We will also display a link at the top for creating a new address entry, and this Perl script will be named &#8220;add.pl&#8221;.  But first, here is the &#8220;dashboard.pl&#8221; script:</p>
<table width="800">
<tr bgcolor="white">
<td><code>#!/usr/bin/perl</p>
<p>#--------------------------------------------------------------------------<br />
# dashboard.pl<br />
#--------------------------------------------------------------------------</p>
<p># DBI is the standard database interface for Perl<br />
# DBD is the Perl module that we use to connect to the &lt;a href=http://mysql.com/&gt;MySQL&lt;/a&gt; database<br />
use DBI;<br />
use DBD::mysql;<br />
use CGI qw(:standard);</p>
<p>my $Database = "scripting_mysql";</p>
<p>print header;<br />
print &lt;&lt;HTML;<br />
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;<br />
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;<br />
&lt;head&gt;<br />
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;<br />
&lt;title&gt;Scripting MySQL - Address Book - Dashboard&lt;/title&gt;<br />
&lt;/head&gt;</p>
<p>&lt;body&gt;<br />
&lt;center&gt;</p>
<p>HTML<br />
# leave the above line to the left of the page		</p>
<p># list my addresses</p>
<p>	$dbh = ConnectToMySql($Database);</p>
<p>	$query = "select serial, name_first, name_last, address_01, address_02, address_city, address_state, address_postal_code FROM address order by serial";</p>
<p>    $sth = $dbh-&gt;prepare($query);</p>
<p>    $sth-&gt;execute();</p>
<p>    $dbh-&gt;disconnect;</p>
<p># list all of the addresses in a table<br />
# be sure that the link for add.html is the correct path according to your system<br />
print "&lt;center&gt;&lt;font color=blue&gt;My Addresses - &lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/add_entry.pl&gt;Create New&lt;/a&gt;&lt;/font&gt;&lt;p&gt;";<br />
print "&lt;table border=0&gt;";<br />
# print table row headers<br />
print "&lt;tr&gt;&lt;td&gt;ID&lt;/td&gt;&lt;td&gt;First&lt;/td&gt;&lt;td&gt;Last&lt;/td&gt;&lt;td&gt;Address&lt;/td&gt;&lt;td&gt;Address&lt;/td&gt;&lt;td&gt;City&lt;/td&gt;&lt;td&gt;ST&lt;/td&gt;&lt;td&gt;ZIP&lt;/td&gt;&lt;/tr&gt;";</p>
<p># set your initial row background color<br />
$bgcolor = "#EEEEEE";</p>
<p>          while (@data = $sth-&gt;fetchrow_array()) {<br />
			$serial = $data[0];<br />
			$name_first = $data[1];<br />
			$name_last = $data[2];<br />
			$address_01 = $data[3];<br />
			$address_02 = $data[4];<br />
			$address_city = $data[5];<br />
			$address_state = $data[6];<br />
			$address_postal_code = $data[7];</p>
<p># print rows of data<br />
# for the $serial, we include the link to the edit.pl script - edit.pl?$serial<br />
print "&lt;tr bgcolor=$bgcolor&gt;&lt;td&gt;&lt;a href=edit.pl?id=$serial&gt;$serial&lt;/a&gt;&lt;/td&gt;&lt;td&gt;$name_first&lt;/td&gt;&lt;td&gt;$name_last&lt;/td&gt;&lt;td&gt;$address_01&lt;/td&gt;&lt;td&gt;$address_02&lt;/td&gt;&lt;td&gt;$address_city&lt;/td&gt;&lt;td&gt;$address_state&lt;/td&gt;&lt;td&gt;$address_postal_code&lt;/td&gt;&lt;/tr&gt;";</p>
<p># alternate background colors<br />
if ($bgcolor =~ "#EEEEEE") { $bgcolor = "white"; }</p>
<p>else</p>
<p>{$bgcolor = "#EEEEEE";}</p>
<p># end while (@data = $sth-&gt;fetchrow_array())<br />
			}<br />
# print bottom of page<br />
print &lt;&lt;HTML;<br />
&lt;table&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;</p>
<p>HTML<br />
# leave the above line to the left of the page		</p>
<p>exit;</p>
<p># more on what I am doing with the accessSM file may be found at:<br />
# http://scriptingmysql.wordpress.com/2011/07/27/connecting-to-mysql-with-perl/</p>
<p>#----------------------------------------------------------------------<br />
sub ConnectToMySql {<br />
#----------------------------------------------------------------------</p>
<p>   my ($db) = @_;</p>
<p>   open(PW, "&lt;..\/accessSM") || die "Can't access login credentials";<br />
   my $db= &lt;PW&gt;;<br />
   my $host= &lt;PW&gt;;<br />
   my $userid= &lt;PW&gt;;<br />
   my $passwd= &lt;PW&gt;;</p>
<p>   chomp($db);<br />
   chomp($host);<br />
   chomp($userid);<br />
   chomp($passwd);</p>
<p># or, you may comment out the above nine lines - starting with open(PW...<br />
# and just put in your database connection information below<br />
# and un-comment these lines<br />
# but I don't like putting my connection information in a Perl script<br />
#   my $db = "database_name";<br />
#   my $host = "host_name";<br />
#   my $userid = "user_name";<br />
#   my $passwd = "password";</p>
<p>   my $connectionInfo="dbi:mysql:$db;$host";<br />
   close(PW);</p>
<p>   # make connection to database<br />
   my $l_dbh = DBI-&gt;connect($connectionInfo,$userid,$passwd);<br />
   return $l_dbh;<br />
}<br />
</code></td>
</tr>
</table>
<p>The add_entry.pl web page will look like this (with the data for a new entry already entered):</p>
<p><img src="http://tonydarnell.com/mysql_blog/add_entry-pl.png"></p>
<p>And here is the script to create the add_entry.pl web page:</p>
<table width="800">
<tr bgcolor="white">
<td><code>#!/usr/bin/perl</p>
<p>#--------------------------------------------------------------------------<br />
# add_entry.pl<br />
#--------------------------------------------------------------------------</p>
<p>use CGI qw(:standard);</p>
<p>print header;</p>
<p>print &lt;&lt;HTML;</p>
<p>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;<br />
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;<br />
&lt;head&gt;<br />
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;<br />
&lt;title&gt;Scripting MySQL - Address Book - Add Entry&lt;/title&gt;<br />
&lt;/head&gt;</p>
<p>&lt;body&gt;<br />
&lt;center&gt;&lt;font color=blue&gt;My Addresses - &lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/dashboard.pl&gt;Dashboard&lt;/a&gt;&lt;/font&gt;&lt;p&gt;<br />
&lt;table&gt;<br />
&lt;form method="post" name="address" action="http://192.168.1.2/cgi-bin/scripting_mysql/add.pl"&gt;</p>
<p>&lt;table&gt;</p>
<p>&lt;tr&gt;&lt;td&gt;Name First&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME="name_first" id=name_first size=30&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;Name Last&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME="name_last" id=name_last size=30&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;Address 1&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME="address_01" id=address_01 size=40&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;Address 2&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME="address_02" id=address_02 size=40&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;City&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME="address_city" id=address_city size=30&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;State&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME="address_state" id=address_state size=2&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;Zip&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME="address_postal_code" id=address_postal_code size=10&gt;&lt;/td&gt;&lt;/tr&gt;</p>
<p>&lt;tr&gt;&lt;td colspan=2&gt;&lt;center&gt;&lt;input type="submit" value="Add Address" alt="Add Address"&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;/form&gt;</p>
<p>&lt;/body&gt;<br />
&lt;/html&gt;</p>
<p>HTML</p>
<p>exit;<br />
</code></td>
</tr>
</table>
<p>The form on this web page calls a Perl script named &#8220;add.pl&#8221;, which will insert the information to the MySQL database.</p>
<p>Here is the Perl script add.pl:</p>
<table width="800">
<tr bgcolor="white">
<td><code>#!/usr/bin/perl</p>
<p>#--------------------------------------------------------------------------<br />
# add.pl<br />
#--------------------------------------------------------------------------</p>
<p>use DBI;<br />
use DBD::mysql;<br />
use CGI qw(:standard);</p>
<p>read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});</p>
<p>$buffer =~ tr/+/ /;<br />
$buffer =~ s/\r/ /g;<br />
$buffer =~ s/'/ /g;<br />
$buffer =~ s/\n/ /g;<br />
$buffer =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;<br />
$buffer =~ s/&lt;!--(.|\n)*--&gt;/ /g;<br />
$buffer =~ tr/\\|[|]|&lt;|!|"|$|{|}|*|#|'|&gt;|||;|%/ /;</p>
<p>@pairs = split(/&amp;/,$buffer);<br />
foreach $pair(@pairs){<br />
($key,$value)=split(/=/,$pair);<br />
$formdata{$key}.="$value";<br />
}</p>
<p># here are the values from the HTML form<br />
$name_first = $formdata{'name_first'};<br />
$name_last = $formdata{'name_last'};<br />
$address_01 = $formdata{'address_01'};<br />
$address_02 = $formdata{'address_02'};<br />
$address_city = $formdata{'address_city'};<br />
$address_state = $formdata{'address_state'};<br />
$address_postal_code = $formdata{'address_postal_code'};</p>
<p>my $Database = "scripting_mysql";</p>
<p>print header;<br />
print &lt;&lt;HTML;<br />
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;<br />
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;<br />
&lt;head&gt;<br />
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;<br />
&lt;title&gt;Scripting MySQL - Address Book - New&lt;/title&gt;<br />
&lt;/head&gt;</p>
<p>&lt;body&gt;<br />
&lt;center&gt;</p>
<p>HTML<br />
# leave the above line to the left of the page		</p>
<p># list my addresses</p>
<p>	$dbh = ConnectToMySql($Database);</p>
<p>	$query = "insert into address (name_first, name_last, address_01, address_02, address_city, address_state, address_postal_code) values (?,?,?,?,?,?,?)";</p>
<p>    $sth = $dbh-&gt;prepare($query);</p>
<p>    $sth-&gt;execute("$name_first", "$name_last", "$address_01", "$address_02", "$address_city", "$address_state", "$address_postal_code");</p>
<p>    $dbh-&gt;disconnect;</p>
<p>print "$name_first $name_last - was added to the database.&lt;p&gt;";</p>
<p>print "Return to the &lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/dashboard.pl&gt;Dashboard&lt;/a&gt;";</p>
<p># print bottom of page<br />
print &lt;&lt;HTML;<br />
&lt;table&gt;<br />
&lt;/body&gt;<br />
&lt;/html&gt;</p>
<p>HTML<br />
# leave the above line to the left of the page		</p>
<p>exit;</p>
<p># more on what I am doing with the accessSM file may be found at:<br />
# http://scriptingmysql.wordpress.com/2011/07/27/connecting-to-mysql-with-perl/</p>
<p>#----------------------------------------------------------------------<br />
sub ConnectToMySql {<br />
#----------------------------------------------------------------------</p>
<p>   my ($db) = @_;</p>
<p>   open(PW, "&lt;..\/accessSM") || die "Can't access login credentials";<br />
   my $db= &lt;PW&gt;;<br />
   my $host= &lt;PW&gt;;<br />
   my $userid= &lt;PW&gt;;<br />
   my $passwd= &lt;PW&gt;;</p>
<p>   chomp($db);<br />
   chomp($host);<br />
   chomp($userid);<br />
   chomp($passwd);</p>
<p># or, you may comment out the above nine lines - starting with open(PW...<br />
# and just put in your database connection information below<br />
# and un-comment these lines<br />
# but I don't like putting my connection information in a Perl script<br />
#   my $db = "database_name";<br />
#   my $host = "host_name";<br />
#   my $userid = "user_name";<br />
#   my $passwd = "password";</p>
<p>   my $connectionInfo="dbi:mysql:$db;$host";<br />
   close(PW);</p>
<p>   # make connection to database<br />
   my $l_dbh = DBI-&gt;connect($connectionInfo,$userid,$passwd);<br />
   return $l_dbh;<br />
}<br />
</code></td>
</tr>
</table>
<p>After you add an entry to the database, this is the confirmation web page after a record has been added.  </p>
<p><img src="http://tonydarnell.com/mysql_blog/add_saved.png"></p>
<p>The add.pl page gives you a link to go back to the dashboard, which will then display all of your address database entries, including the one you just entered.</p>
<p>To edit an entry, from the dashboard web page, you simply click on the ID of the entry that you want to modify.  For example, when you click on the first entry with a serial number of &#8220;1&#8243;, you will see this link:</p>
<table width="800">
<tr bgcolor="white">
<td><code><font color="blue">http://192.168.1.2/cgi-bin/scripting_mysql/edit.pl?id=1</font><br />
</code></td>
</tr>
</table>
<p>Clicking on an serial number link will call the Perl script named &#8220;edit.pl&#8221;.  This will create a web page where you can edit the information and save it back to the database.  The edit.pl web page looks like this:</p>
<p><img src="http://tonydarnell.com/mysql_blog/edit_entry-pl.png"></p>
<p>Here is the edit.pl script:</p>
<table width="800">
<tr bgcolor="white">
<td><code>#!/usr/bin/perl</p>
<p>#--------------------------------------------------------------------------<br />
# edit.pl<br />
#--------------------------------------------------------------------------</p>
<p>use DBI;<br />
use DBD::mysql;<br />
use CGI qw(:standard);</p>
<p>$query = new CGI;</p>
<p>$id = $query-&gt;param(&quot;id&quot;);</p>
<p>print header;<br />
print &lt;&lt;HTML;<br />
&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD XHTML 1.0 Transitional//EN&quot; &quot;http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd&quot;&gt;<br />
&lt;html xmlns=&quot;http://www.w3.org/1999/xhtml&quot;&gt;<br />
&lt;head&gt;<br />
&lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot; /&gt;<br />
&lt;title&gt;Scripting MySQL - Address Book - Edit&lt;/title&gt;<br />
&lt;/head&gt;</p>
<p>&lt;body&gt;<br />
HTML</p>
<p># grab the information for this id</p>
<p>	$dbh = ConnectToMySql($Database);</p>
<p>	$query = &quot;select serial, name_first, name_last, address_01, address_02, address_city, address_state, address_postal_code FROM address where serial = &#039;$id&#039;&quot;;</p>
<p>    $sth = $dbh-&gt;prepare($query);</p>
<p>    $sth-&gt;execute();</p>
<p>    $dbh-&gt;disconnect;</p>
<p># list all of the addresses in a table<br />
# be sure that the link for add.html is the correct path according to your system<br />
print &quot;&lt;center&gt;&lt;font color=blue&gt;My Addresses - &lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/dashboard.pl&gt;Dashboard&lt;/a&gt;&lt;/font&gt;&lt;p&gt;&quot;;<br />
print &quot;&lt;table border=0&gt;&quot;;</p>
<p>          while (@data = $sth-&gt;fetchrow_array()) {<br />
			$id = $data[0];<br />
			$name_first = $data[1];<br />
			$name_last = $data[2];<br />
			$address_01 = $data[3];<br />
			$address_02 = $data[4];<br />
			$address_city = $data[5];<br />
			$address_state = $data[6];<br />
			$address_postal_code = $data[7];<br />
			}</p>
<p>print &lt;&lt;HTML;</p>
<p>&lt;form method=&quot;post&quot; name=&quot;address&quot; action=&quot;http://192.168.1.2/cgi-bin/scripting_mysql/edit_save.pl&quot;&gt;<br />
&lt;input type=hidden name=id value=&quot;$id&quot;&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Name First&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME=&quot;name_first&quot; id=name_first size=30 value=&quot;$name_first&quot;&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Name Last&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME=&quot;name_last&quot; id=name_last size=30 value=&quot;$name_last&quot;&gt;&lt;/td&quot;&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Address 1&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME=&quot;address_01&quot; id=address_01 size=40 value=&quot;$address_01&quot;&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Address 2&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME=&quot;address_02&quot; id=address_02 size=40 value=&quot;$address_02&quot;&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;City&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME=&quot;address_city&quot; id=address_city size=30 value=&quot;$address_city&quot;&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;State&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME=&quot;address_state&quot; id=address_state size=2 value=&quot;$address_state&quot;&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Zip&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;&lt;INPUT TYPE=text NAME=&quot;address_postal_code&quot; id=address_postal_code size=10 value=&quot;$address_postal_code&quot;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td colspan=2&gt;&lt;center&gt;&lt;input type=&quot;submit&quot; value=&quot;Save Changes&quot; alt=&quot;Save Changes&quot;&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;/form&gt;<br />
&lt;/table&gt;</p>
<p>&lt;/body&gt;<br />
&lt;/html&gt;</p>
<p>HTML</p>
<p>exit;</p>
<p># more on what I am doing with the accessSM file may be found at:<br />
# http://scriptingmysql.wordpress.com/2011/07/27/connecting-to-mysql-with-perl/</p>
<p>#----------------------------------------------------------------------<br />
sub ConnectToMySql {<br />
#----------------------------------------------------------------------</p>
<p>   my ($db) = @_;</p>
<p>   open(PW, &quot;&lt;..\/accessSM&quot;) || die &quot;Can&#039;t access login credentials&quot;;<br />
   my $db= &lt;PW&gt;;<br />
   my $host= &lt;PW&gt;;<br />
   my $userid= &lt;PW&gt;;<br />
   my $passwd= &lt;PW&gt;;</p>
<p>   chomp($db);<br />
   chomp($host);<br />
   chomp($userid);<br />
   chomp($passwd);</p>
<p># or, you may comment out the above nine lines - starting with open(PW...<br />
# and just put in your database connection information below<br />
# and un-comment these lines<br />
# but I don't like putting my connection information in a Perl script<br />
#   my $db = &quot;database_name&quot;;<br />
#   my $host = &quot;host_name&quot;;<br />
#   my $userid = &quot;user_name&quot;;<br />
#   my $passwd = &quot;password&quot;;</p>
<p>   my $connectionInfo=&quot;dbi:mysql:$db;$host&quot;;<br />
   close(PW);</p>
<p>   # make connection to database<br />
   my $l_dbh = DBI-&gt;connect($connectionInfo,$userid,$passwd);<br />
   return $l_dbh;<br />
}<br />
</code></td>
</tr>
</table>
<p>The edit.pl script will create the web page for you to make your changes.  After you have made the changes, the form will call another Perl script named &#8220;edit_save.pl&#8221; to apply those changes to the database.  Here is the edit_save.pl script:</p>
<table width="800">
<tr bgcolor="white">
<td><code>#!/usr/bin/perl</p>
<p>#--------------------------------------------------------------------------<br />
# edit_save.pl<br />
#--------------------------------------------------------------------------</p>
<p>use DBI;<br />
use DBD::mysql;<br />
use CGI qw(:standard);<br />
use LWP::UserAgent;</p>
<p>my $Database = "address";</p>
<p>read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});</p>
<p>$buffer =~ tr/+/ /;<br />
$buffer =~ s/\r/ /g;<br />
$buffer =~ s/'/ /g;<br />
$buffer =~ s/\n/ /g;<br />
$buffer =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C",hex($1))/eg;<br />
$buffer =~ s/&lt;!--(.|\n)*--&gt;/ /g;<br />
$buffer =~ tr/\\|[|]|&lt;|!|"|$|{|}|*|#|'|&gt;|||;|%/ /;</p>
<p>@pairs = split(/&amp;/,$buffer);<br />
foreach $pair(@pairs){<br />
($key,$value)=split(/=/,$pair);<br />
$formdata{$key}.="$value";<br />
}</p>
<p>$id = $formdata{'id'};<br />
$name_first = $formdata{'name_first'};<br />
$name_last = $formdata{'name_last'};<br />
$address_01 = $formdata{'address_01'};<br />
$address_02 = $formdata{'address_02'};<br />
$address_city = $formdata{'address_city'};<br />
$address_state = $formdata{'address_state'};<br />
$address_postal_code = $formdata{'address_postal_code'};</p>
<p>	$dbh = ConnectToMySql($Database);</p>
<p>	$query = "update address set name_first = '$name_first', name_last = '$name_last', address_01 = '$address_01', address_02 = '$address_02', address_city = '$address_city', address_state = '$address_state', address_postal_code = '$address_postal_code' where serial = '$id'"; </p>
<p>    $sth = $dbh-&gt;prepare($query);</p>
<p>    $sth-&gt;execute();</p>
<p>    $dbh-&gt;disconnect;</p>
<p>print header;<br />
print &lt;&lt;HTML;<br />
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;<br />
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;<br />
&lt;head&gt;<br />
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;<br />
&lt;title&gt;Scripting MySQL - Address Book - Edit Saved&lt;/title&gt;<br />
&lt;/head&gt;</p>
<p>&lt;body&gt;<br />
&lt;center&gt;<br />
&lt;center&gt;&lt;font color=blue&gt;My Addresses - &lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/dashboard.pl&gt;Dashboard&lt;/a&gt;&lt;/font&gt;&lt;p&gt;</p>
<p>The following information was updated:&lt;p&gt;<br />
&lt;table&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Name First&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$name_first&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Name Last&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$name_last&lt;/td"&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Address 1&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_01&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Address 2&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_02&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;City&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_city&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;State&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_state&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Zip&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_postal_code&lt;/td&gt;&lt;/tr&gt;<br />
&lt;/table&gt;</p>
<p>HTML<br />
# leave the above line to the left of the page		</p>
<p>exit;</p>
<p># more on what I am doing with the accessSM file may be found at:<br />
# http://scriptingmysql.wordpress.com/2011/07/27/connecting-to-mysql-with-perl/</p>
<p>#----------------------------------------------------------------------<br />
sub ConnectToMySql {<br />
#----------------------------------------------------------------------</p>
<p>   my ($db) = @_;</p>
<p>   open(PW, "&lt;..\/accessSM") || die "Can't access login credentials";<br />
   my $db= &lt;PW&gt;;<br />
   my $host= &lt;PW&gt;;<br />
   my $userid= &lt;PW&gt;;<br />
   my $passwd= &lt;PW&gt;;</p>
<p>   chomp($db);<br />
   chomp($host);<br />
   chomp($userid);<br />
   chomp($passwd);</p>
<p># or, you may comment out the above nine lines - starting with open(PW...<br />
# and just put in your database connection information below<br />
# and un-comment these lines<br />
# but I don't like putting my connection information in a Perl script<br />
#   my $db = "database_name";<br />
#   my $host = "host_name";<br />
#   my $userid = "user_name";<br />
#   my $passwd = "password";</p>
<p>   my $connectionInfo="dbi:mysql:$db;$host";<br />
   close(PW);</p>
<p>   # make connection to database<br />
   my $l_dbh = DBI-&gt;connect($connectionInfo,$userid,$passwd);<br />
   return $l_dbh;</p>
<p>}<br />
</code></td>
</tr>
</table>
<p>After you have edited your record, the edited results web page will look like this:</p>
<p><img src="http://tonydarnell.com/mysql_blogs/edit_entry_save-pl.png"></p>
<p>You can then click on the Dashboard link to go back to the main dashboard page.</p>
<p>If you want to delete a record, from the dashboard.pl page, you simply click on the red X image on the row that you want to delete.  For example, when you click on the <font color="red"><b>X</b></font> for the serial number of &#8220;1&#8243;, you will see this link:</p>
<table width="800">
<tr bgcolor="white">
<td><code><font color="blue">http://192.168.1.2/cgi-bin/scripting_mysql/delete.pl?id=1</font><br />
</code></td>
</tr>
</table>
<p>This link takes you to the delete.pl page, where you are asked if you want to confirm the deletion, or you may cancel and go back to the dashboard.  When you click on an <font color="red"><b>X</b></font> to delete a row, you will see a page like this:</p>
<p><img src="http://tonydarnell.com/mysql_blog/delete-pl.png"></p>
<p>And here is the delete.pl script:</p>
<table width="800">
<tr bgcolor="white">
<td><code>#!/usr/bin/perl</p>
<p>#--------------------------------------------------------------------------<br />
# delete.pl<br />
#--------------------------------------------------------------------------</p>
<p>use DBI;<br />
use DBD::mysql;<br />
use CGI qw(:standard);</p>
<p>$query = new CGI;<br />
$id = $query-&gt;param("id");</p>
<p>my $Database = "scripting_mysql";</p>
<p>print header;<br />
print &lt;&lt;HTML;<br />
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;<br />
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;<br />
&lt;head&gt;<br />
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;<br />
&lt;title&gt;Scripting MySQL - Address Book - Delete Record&lt;/title&gt;<br />
&lt;/head&gt;</p>
<p>&lt;body&gt;<br />
&lt;center&gt;</p>
<p>HTML</p>
<p># grab the information for this id</p>
<p>	$dbh = ConnectToMySql($Database);</p>
<p>	$query = "select serial, name_first, name_last, address_01, address_02, address_city, address_state, address_postal_code FROM address where serial = '$id'";</p>
<p>    $sth = $dbh-&gt;prepare($query);</p>
<p>    $sth-&gt;execute();</p>
<p>    $dbh-&gt;disconnect;</p>
<p># list all of the addresses in a table<br />
# be sure that the link for add.html is the correct path according to your system<br />
print "&lt;center&gt;&lt;font color=blue&gt;My Addresses - &lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/dashboard.pl&gt;Dashboard&lt;/a&gt;&lt;/font&gt;&lt;p&gt;";<br />
print "Are you sure you want to delete this record?&lt;p&gt;";<br />
print "&lt;table border=0&gt;";</p>
<p>          while (@data = $sth-&gt;fetchrow_array()) {<br />
			$id = $data[0];<br />
			$name_first = $data[1];<br />
			$name_last = $data[2];<br />
			$address_01 = $data[3];<br />
			$address_02 = $data[4];<br />
			$address_city = $data[5];<br />
			$address_state = $data[6];<br />
			$address_postal_code = $data[7];<br />
			}</p>
<p>print &lt;&lt;HTML;</p>
<p>&lt;form method="post" name="address" action="http://192.168.1.2/cgi-bin/scripting_mysql/delete_confirm.pl?id=$id"&gt;<br />
&lt;input type=hidden name=id value="$id"&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Name First&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$name_first&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Name Last&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$name_last&lt;/td"&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Address 1&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_01&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Address 2&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_02&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;City&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_city&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;State&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_state&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Zip&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_postal_code&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td&gt;&lt;center&gt;&lt;input type="submit" value="Delete Address" alt="Delete Address"&gt;&lt;/form&gt;&lt;/td&gt;&lt;td&gt;&lt;center&gt;&lt;form method="post" name="address" action="http://192.168.1.2/cgi-bin/scripting_mysql/dashboard.pl"&gt;&lt;input type="submit" value="Cancel" alt="Cancel"&gt;&lt;/form&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;/table&gt;</p>
<p>&lt;/body&gt;<br />
&lt;/html&gt;</p>
<p>HTML<br />
# leave the above line to the left of the page		</p>
<p>exit;</p>
<p># more on what I am doing with the accessSM file may be found at:<br />
# http://scriptingmysql.wordpress.com/2011/07/27/connecting-to-mysql-with-perl/</p>
<p>#----------------------------------------------------------------------<br />
sub ConnectToMySql {<br />
#----------------------------------------------------------------------</p>
<p>   my ($db) = @_;</p>
<p>   open(PW, "&lt;..\/accessSM") || die "Can't access login credentials";<br />
   my $db= &lt;PW&gt;;<br />
   my $host= &lt;PW&gt;;<br />
   my $userid= &lt;PW&gt;;<br />
   my $passwd= &lt;PW&gt;;</p>
<p>   chomp($db);<br />
   chomp($host);<br />
   chomp($userid);<br />
   chomp($passwd);</p>
<p># or, you may comment out the above nine lines - starting with open(PW...<br />
# and just put in your database connection information below<br />
# and un-comment these lines<br />
# but I don't like putting my connection information in a Perl script<br />
#   my $db = "database_name";<br />
#   my $host = "host_name";<br />
#   my $userid = "user_name";<br />
#   my $passwd = "password";</p>
<p>   my $connectionInfo="dbi:mysql:$db;$host";<br />
   close(PW);</p>
<p>   # make connection to database<br />
   my $l_dbh = DBI-&gt;connect($connectionInfo,$userid,$passwd);<br />
   return $l_dbh;<br />
}<br />
</code></td>
</tr>
</table>
<p>If you choose to not delete the record, you are simply taken back to the Dashboard.  If you choose to delete the record, then the delete-confirm.pl script is executed, and the record is deleted.  Here is the confirmation web page for a deletion:</p>
<p><img src="http://tonydarnell.com/mysql_blog/delete-confirm-pl.png"></p>
<p>And here is the delete_confirm.pl script:</p>
<table width="800">
<tr bgcolor="white">
<td><code>#!/usr/bin/perl</p>
<p>#--------------------------------------------------------------------------<br />
# delete_confirm.pl<br />
#--------------------------------------------------------------------------</p>
<p>use DBI;<br />
use DBD::mysql;<br />
use CGI qw(:standard);</p>
<p>$query = new CGI;<br />
$id = $query-&gt;param("id");</p>
<p>my $Database = "scripting_mysql";</p>
<p>print header;<br />
print &lt;&lt;HTML;<br />
&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;<br />
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;<br />
&lt;head&gt;<br />
&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;<br />
&lt;title&gt;Scripting MySQL - Address Book - Delete Record Confirmed&lt;/title&gt;<br />
&lt;/head&gt;</p>
<p>&lt;body&gt;<br />
&lt;center&gt;</p>
<p>Are you sure you want to delete this record?</p>
<p>HTML</p>
<p># grab the information for this id</p>
<p>	$dbh = ConnectToMySql($Database);</p>
<p>	$query = "select serial, name_first, name_last, address_01, address_02, address_city, address_state, address_postal_code FROM address where serial = '$id'";</p>
<p>    $sth = $dbh-&gt;prepare($query);</p>
<p>    $sth-&gt;execute();</p>
<p>    $dbh-&gt;disconnect;</p>
<p># list all of the addresses in a table<br />
# be sure that the link for add.html is the correct path according to your system<br />
print "&lt;center&gt;&lt;font color=blue&gt;My Addresses - &lt;a href=http://192.168.1.2/cgi-bin/scripting_mysql/dashboard.pl&gt;Dashboard&lt;/a&gt;&lt;/font&gt;&lt;p&gt;";<br />
print "The following information was deleted.&lt;p&gt;";<br />
print "&lt;table border=0&gt;";</p>
<p>          while (@data = $sth-&gt;fetchrow_array()) {<br />
			$id = $data[0];<br />
			$name_first = $data[1];<br />
			$name_last = $data[2];<br />
			$address_01 = $data[3];<br />
			$address_02 = $data[4];<br />
			$address_city = $data[5];<br />
			$address_state = $data[6];<br />
			$address_postal_code = $data[7];<br />
			}</p>
<p>print &lt;&lt;HTML;</p>
<p>&lt;tr&gt;&lt;td align=right&gt;Name First&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$name_first&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Name Last&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$name_last&lt;/td"&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Address 1&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_01&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Address 2&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_02&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;City&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_city&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;State&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_state&lt;/td&gt;&lt;/tr&gt;<br />
&lt;tr&gt;&lt;td align=right&gt;Zip&nbsp;&nbsp;&lt;/td&gt;&lt;td&gt;$address_postal_code&lt;/td&gt;&lt;/tr&gt;<br />
&lt;/table&gt;</p>
<p>&lt;/body&gt;<br />
&lt;/html&gt;</p>
<p>HTML<br />
# leave the above line to the left of the page		</p>
<p># here we delete the record<br />
	$dbh = ConnectToMySql($Database);</p>
<p>	$query = "delete from address where serial = '$id'";</p>
<p>    $sth = $dbh-&gt;prepare($query);</p>
<p>    $sth-&gt;execute();</p>
<p>	$dbh-&gt;disconnect;</p>
<p>exit;</p>
<p># more on what I am doing with the accessSM file may be found at:<br />
# http://scriptingmysql.wordpress.com/2011/07/27/connecting-to-mysql-with-perl/</p>
<p>#----------------------------------------------------------------------<br />
sub ConnectToMySql {<br />
#----------------------------------------------------------------------</p>
<p>   my ($db) = @_;</p>
<p>   open(PW, "&lt;..\/accessSM") || die "Can't access login credentials";<br />
   my $db= &lt;PW&gt;;<br />
   my $host= &lt;PW&gt;;<br />
   my $userid= &lt;PW&gt;;<br />
   my $passwd= &lt;PW&gt;;</p>
<p>   chomp($db);<br />
   chomp($host);<br />
   chomp($userid);<br />
   chomp($passwd);</p>
<p># or, you may comment out the above nine lines - starting with open(PW...<br />
# and just put in your database connection information below<br />
# and un-comment these lines<br />
# but I don't like putting my connection information in a Perl script<br />
#   my $db = "database_name";<br />
#   my $host = "host_name";<br />
#   my $userid = "user_name";<br />
#   my $passwd = "password";</p>
<p>   my $connectionInfo="dbi:mysql:$db;$host";<br />
   close(PW);</p>
<p>   # make connection to database<br />
   my $l_dbh = DBI-&gt;connect($connectionInfo,$userid,$passwd);<br />
   return $l_dbh;</p>
<p>}<br />
</code></td>
</tr>
</table>
<p>One alternative to deleting the record would be to include a separate database field called &#8220;active&#8221;, set the field value to &#8220;yes&#8221; for all current records (if you have already imported records) and set the default value for this field to &#8220;yes&#8221; for any new records.  Then, instead of deleting the information, you simply set &#8220;active&#8221; to &#8220;no&#8221;.  So when you retrieve your list on the dashboard.pl page, you will only look for records where &#8220;active&#8221; is equal to &#8220;yes&#8221;.  You will still have the &#8220;deleted&#8221; information available to you in the database.  You could even duplicate the dashboard.pl script to have a &#8220;delete&#8221; page that displays the records that have been deleted.</p>
<p>To use the &#8220;active&#8221; option, you will need to make the following changes:</p>
<p>You would need to add this line in your create table SQL statement:  (I would insert the line after the &#8220;serial&#8221; field in your create table statement)</p>
<table width="800">
<tr bgcolor="white">
<td><code>  `active` varchar(3) NOT NULL DEFAULT 'yes',<br />
</code></td>
</tr>
</table>
<p>Then, in your dashboard.pl script, you would simply change the $query to:</p>
<table width="800">
<tr bgcolor="white">
<td><code>$query = "select serial, name_first, name_last, address_01, address_02, address_city, address_state, address_postal_code FROM address where active = 'yes' order by serial";<br />
</code></td>
</tr>
</table>
<p>For your add.pl and add_entry.pl scripts. you don&#8217;t need to do anything as the &#8220;active&#8221; field has a default value of &#8220;yes&#8221; for new records.</p>
<p>For your edit.pl and edit_save.pl scripts, you don&#8217;t need to do anything as you aren&#8217;t changing the &#8220;active&#8221; field.</p>
<p>And in your delete_confirm.pl script, instead of deleting the record, simply change the <font color="blue">$query = &#8220;delete from address where serial = &#8216;$id&#8217;&#8221;;</font> to:</p>
<table width="800">
<tr bgcolor="white">
<td><code>$query = "update address set active = 'no' where serial = '$id'";<br />
</code></td>
</tr>
</table>
<p>With these scripts, you should be able to install everything and have it running in a few minutes.  And, if my lawyer friend gets tired of spending all day at the courthouse, he could always learn a new skill.</p>
<p>&nbsp;
<p>
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<table width="100%">
<tr>
<td><img border="0" src="http://www.scriptingmysql.com/scriptingmysql/tony.jpg">
</td>
<td>
Tony Darnell is a Principal Sales Consultant for <a href="http://mysql.com/" />MySQL</a>, a division of <a href="http://oracle.com">Oracle</a>, Inc.  MySQL is the world&#8217;s most popular open-source database program.<br />
<br />Tony may be reached at info [at] ScriptingMySQL.com and on <a href="http://www.linkedin.com/in/tonydarnell">LinkedIn</a>.
</td>
</tr>
</table>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/scriptingmysql.wordpress.com/474/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/scriptingmysql.wordpress.com/474/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/scriptingmysql.wordpress.com/474/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/scriptingmysql.wordpress.com/474/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/scriptingmysql.wordpress.com/474/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/scriptingmysql.wordpress.com/474/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/scriptingmysql.wordpress.com/474/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/scriptingmysql.wordpress.com/474/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/scriptingmysql.wordpress.com/474/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/scriptingmysql.wordpress.com/474/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/scriptingmysql.wordpress.com/474/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/scriptingmysql.wordpress.com/474/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/scriptingmysql.wordpress.com/474/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/scriptingmysql.wordpress.com/474/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=474&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://scriptingmysql.wordpress.com/2011/11/11/using-mysql-and-perl-to-create-edit-and-delete-information-via-a-web-page/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4a7803de89b97b14df8a346d36a1b9a1?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tonydarnell</media:title>
		</media:content>

		<media:content url="http://tonydarnell.com/mysql_blog/dashboard-pl.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/add_entry-pl.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/add_saved.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/edit_entry-pl.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blogs/edit_entry_save-pl.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/delete-pl.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/delete-confirm-pl.png" medium="image" />

		<media:content url="http://www.scriptingmysql.com/scriptingmysql/tony.jpg" medium="image" />
	</item>
		<item>
		<title>Checking on the Progress of Large DML Commands in MySQL Using Perl &#8211; Part Two</title>
		<link>http://scriptingmysql.wordpress.com/2011/11/04/checking-on-the-progress-of-large-dml-commands-in-mysql-using-perl-part-two/</link>
		<comments>http://scriptingmysql.wordpress.com/2011/11/04/checking-on-the-progress-of-large-dml-commands-in-mysql-using-perl-part-two/#comments</comments>
		<pubDate>Fri, 04 Nov 2011 11:01:33 +0000</pubDate>
		<dc:creator>Tony Darnell</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://scriptingmysql.wordpress.com/?p=451</guid>
		<description><![CDATA[Part Two of Two: Checking on database activity when running a large DML (Data Manipulation Language) statement &#8211; such as INSERT, DELETE, UPDATE or SELECT. Part Two: Monitoring the activity via Perl and SHOW ENGINE INNODB STATUS. (part of the InnoDB Monitors) In part one, I showed you how to use a Perl script to [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=451&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Part Two of Two:  Checking on database activity when running a large DML (Data Manipulation Language) statement &#8211; such as INSERT, DELETE, UPDATE or SELECT.</p>
<p>Part Two:  Monitoring the activity via Perl and <font color="blue">SHOW ENGINE INNODB STATUS</font><font color="black">.  (part of the <a href="http://dev.mysql.com/doc/refman/5.5/en/innodb-monitors.html">InnoDB Monitors</a>)</p>
<p>In <a href="http://scriptingmysql.wordpress.com/2011/11/02/checking-on-the-progress-of-large-dml-commands-in-mysql-using-perl-part-one/" />part one</a>, I showed you how to use a Perl script to insert a million rows of dummy data into a table.  I needed a large database in order to test a Perl script that I would use to monitor the activity when running a large DML statement.</p>
<p>The original reason for creating both of these scripts was to find a quick way to see if a large DML statement was actually being executed.  A customer was performing some modifications on tables with tens of millions of rows, and they wanted to know if they were making any progress.  Since the customer was using the InnoDB storage engine, I thought of a way that you could check on the progress &#8211; but only given the fact that nothing else was happening in the database (more on this reason later).</p>
<p>With InnoDB, you can issue the <font color="blue">SHOW ENGINE INNODB STATUS</font><font color="black"> and you will get a wealth of information.  I am not going to list any of it here as it would consume too much space.  However, towards the bottom of the output, you will notice under &#8220;ROW OPERATIONS&#8221; a line that contains the words &#8220;Number of rows inserted&#8230;&#8221;:</p>
<table width="500">
<tr bgcolor="white">
<td><code>--------------<br />
ROW OPERATIONS<br />
--------------<br />
0 queries inside InnoDB, 0 queries in queue<br />
1 read views open inside InnoDB<br />
Main thread id 2960240640, state: waiting for server activity<br />
<font color="blue">Number of rows inserted 1202598, updated 97249, deleted 806, read 56448551</font><font color="black"><br />
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s<br />
</code></td>
</tr>
</table>
<p>The above line gives you a quick snapshot of how many rows have been inserted, updated, deleted or selected (read).  So, by invoking the <font color="blue">SHOW ENGINE INNODB STATUS</font><font color="black"> command, you can figure what database activity is occurring. But, if you invoke this command while the database is being used for other purposes, it will be difficult to figure out your progress on any of the four values shown.</p>
<p>So, all I needed to do was to write a quick Perl script to monitor the changes to that particular line of output, and then I could figure out if a certain statement was indeed being executed.  My original thinking was that I needed a database with a lot of records in it.  So, I decide to first create a dummy table and then shove a million records into it.  But I figured out that by creating a database with a million rows, I could simply just monitor this activity versus issuing a command on the database once it had been built.</p>
<p>I created a quick Perl script that issues the <font color="blue">SHOW ENGINE INNODB STATUS</font><font color="black"> command every X number of seconds.  It then looks for the output total for whatever I want to track &#8211; either inserts, updates, deletes or selects (reads).  And yes, you could just do this manually, but if you have a command that you want to run overnight, you could execute this script and at least see what happened when you return in the morning.</p>
<p>One caveat &#8211; <font color="blue">SHOW ENGINE INNODB STATUS</font><font color="black"> does not correspond to a particular point in time, so it may not be consistent &#8211; as to ensure consistency would require a global lock which would consume too many resources.  But it is good enough for what we want to do here.</p>
<p>The script will check the status, and then depending upon what variable (inserts, updates, deletes, selects) you want to search for, it will show you the total for that variable as it increases.  I didn&#8217;t take time to add a lot of information about how long it would take to complete the original command, as this would be just a wild guess, given the fact that other things could be happening with the database.  You will need to change the variable that you want to look for, how many rows you are expecting to change, how many seconds you want it to refresh, and your database information:</p>
<table>
<tr bgcolor="white">
<td><code>#!/usr/bin/perl -w</p>
<p># DBI is the standard database interface for Perl<br />
# DBD is the Perl module that we use to connect to the MySQL database<br />
use DBI;<br />
use DBD::mysql;<br />
# use CGI for forms<br />
#use CGI qw(:standard);</p>
<p>$start = '';<br />
$begin = '';<br />
$now = 1;</p>
<p># How many rows are being changed?<br />
# (whole numbers only)<br />
<font color="blue">$rows = 200000;</font><font color="black"></p>
<p># how long do you want it to sleep? (seconds)<br />
# you can modify this to be a longer time interval than 60 seconds<br />
# which is advisable, as the SHOW ENGINE query will consume resources<br />
<font color="blue">$sleep_time = 60;</font><font color="black"></p>
<p># what action do you want to monitor?<br />
# based upon this output:  Number of rows inserted xxxxx, updated xxxxx, deleted xxxxx, read xxxxx<br />
# (use the word to the right of the equal sign)<br />
# inserts = inserted<br />
# update = updates<br />
# deletes = deleted<br />
# selects = read<br />
<font color="blue">$action = "inserted";</font><font color="black"></p>
<p><font color="blue">$Database = "scripting_mysql";</font><font color="black"></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dbh = ConnectToMySql($Database);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$query = "SHOW ENGINE INNODB STATUS";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth = $dbh-&gt;prepare($query);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth-&gt;execute();</p>
<p>$data = $sth-&gt;fetchrow_array();</p>
<p>@all_rows = split("\\n",$data);</p>
<p>foreach (@all_rows) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($_ =~ "Number of rows")</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#print "Line $_ \n";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@total = split (" ", $_);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# viewing this output from SHOW ENGINE INNODB STATUS<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# Number of rows inserted 912268, updated 96931, deleted 806, read 52052215<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($action =~ "inserted") { $column = 4 }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($action =~ "updated") { $column = 6 }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($action =~ "deleted") { $column = 8 }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($action =~ "read") { $column = 10 }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($_ =~ "Number of rows ")<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$total[$column] =~ s/,//;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$begin = $total[$column];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</p>
<p>print "Execute your SQL statement, and then press enter/return: ";<br />
$start = &lt;&gt;;</p>
<p>print "Beginning with $begin $action:\n";</p>
<p>while ($now &lt; $rows) {</p>
<p>$print_date_time = &amp;get_date_time;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dbh = ConnectToMySql($Database);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$query = "SHOW ENGINE INNODB STATUS";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth = $dbh-&gt;prepare($query);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth-&gt;execute();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$data = $sth-&gt;fetchrow_array();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@all_rows = split("\n",$data);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (@all_rows) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@total = split (" ", $_);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($action =~ "inserted") { $column = 4 }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($action =~ "updated") { $column = 6 }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($action =~ "deleted") { $column = 8 }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($action =~ "read") { $column = 10 }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($_ =~ "Number of rows ")<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$total[$column] =~ s/,//;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$now = $total[$column];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$now = $now - $begin;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$progress = $now / $rows;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$progress = $progress * 100;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "$print_date_time - $progress\% changed - $now out of $rows.\n";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</p>
<p># you can modify this to be a longer time interval than 60 seconds<br />
# which is advisable, as the SHOW ENGINE query will consume resources<br />
sleep $sleep_time;</p>
<p>}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth-&gt;finish;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dbh-&gt;disconnect;</p>
<p># from <a href="http://scriptingmysql.wordpress.com/2011/07/27/connecting-to-mysql-with-perl/" />Connecting to MySQL with Perl</a><br />
#----------------------------------------------------------------------<br />
sub ConnectToMySql {<br />
#----------------------------------------------------------------------</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my ($db) = @_;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;open(ACCESS_INFO, "<font color="blue">&lt;..\/accessBLOG</font><font color="black">") || die "Can't access login credentials";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $database = &lt;ACCESS_INFO&gt;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $host = &lt;ACCESS_INFO&gt;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $userid = &lt;ACCESS_INFO&gt;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $passwd = &lt;ACCESS_INFO&gt;;</p>
<p># the chomp() function will remove any newline character from the end of a string<br />
chomp ($database, $host, $userid, $passwd);<br />
#print "&lt;br&gt;$database $host $userid $passwd &lt;br&gt;";</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $connectionInfo="dbi:mysql:$database;$host";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(ACCESS_INFO);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# make connection to database<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $l_dbh = DBI-&gt;connect($connectionInfo,$userid,$passwd);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return $l_dbh;</p>
<p>}</p>
<p># ----------------------------------------------------------------------------------<br />
sub get_date_time {<br />
# ----------------------------------------------------------------------------------</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my ($sec,$min,$hour,$mday,$mon,$year) = localtime time;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$year = $year + 1900;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$mon = $mon + 1;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# add a zero if the value is less than 10</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($sec &lt; 10) { $sec = "0$sec"; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($min &lt; 10) { $min = "0$min"; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($hour &lt; 10) { $hour = "0$hour"; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($mday &lt; 10) { $mday = "0$mday"; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($mon &lt; 10) { $mon = "0$mon"; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($year &lt; 10) { $year = "0$year"; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$DateTime = "$year-$mon-$mday $hour:$min:$sec";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return $DateTime</p>
<p>}<br />
#----------------------------------------------------------------------<br />
</code></td>
</tr>
</table>
<p>Here is the output from the Perl script.  For this example, I was assuming that I would be inserting 200,000 rows.</p>
<table>
<tr bgcolor="white">
<td><code>sh-3.2# /usr/bin/perl monitor.pl<br />
Execute your SQL statement, and then press enter/return:<br />
Beginning with 1196128 inserted:<br />
2011-11-01 17:48:06 - 0.029% changed - 58 out of 200000.<br />
2011-11-01 17:48:16 - 0.464% changed - 928 out of 200000.<br />
2011-11-01 17:48:26 - 0.8645% changed - 1729 out of 200000.<br />
2011-11-01 17:48:36 - 1.259% changed - 2518 out of 200000.<br />
2011-11-01 17:48:46 - 1.628% changed - 3256 out of 200000.<br />
2011-11-01 17:48:56 - 2.0045% changed - 4009 out of 200000.<br />
2011-11-01 17:49:06 - 2.3845% changed - 4769 out of 200000.<br />
2011-11-01 17:49:16 - 2.7685% changed - 5537 out of 200000.<br />
2011-11-01 17:49:26 - 3.1415% changed - 6283 out of 200000.<br />
</code></td>
</tr>
</table>
<p>This script was just a quick hack.  Another way to potentially see if your script is still running is to check out the &#8220;TRANSACTIONS&#8221; section of the <font color="blue">SHOW ENGINE INNODB STATUS</font><font color="black"> output.  In this example below, you can see the insert statement that the Perl script was performing during part one (where I was inserting the 1,000,000 rows).  However, since the database that I was using doesn&#8217;t have a lot of activity on it, I was able to see the insert statement multiple times when I resubmitted the <font color="blue">SHOW ENGINE INNODB STATUS</font><font color="black"> command.  If you have a database with a lot of transactions running, you might not be able to see your statement in the output.  </p>
<table>
<tr bgcolor="white">
<td><code>------------<br />
TRANSACTIONS<br />
------------<br />
Trx id counter 1818DA1<br />
Purge done for trx's n:o &lt; 1817E3F undo n:o &lt; 0<br />
History list length 3830<br />
LIST OF TRANSACTIONS FOR EACH SESSION:<br />
---TRANSACTION 1818DA0, not started, OS thread id 2961469440 flushing log<br />
mysql tables in use 1, locked 1<br />
MySQL thread id 335232, query id 2818136 192.168.1.2 WebUser query end<br />
<font color="blue">insert into test_large (name_first, name_last, address_01, address_02, city, state, zip) values ('1BPnJiuWsyajA4b3SH7OjS4BFJgedK','JPuJ4xh_QEbNokZZGlpcHEHKLk2W__','24IT20mW0moAwWmoYTMOwsv44yRL9mAMoo0mLyLoGoTjaW78O6','6zX2j4PLShQ_IfiOzd0LbTVi8ZaYGk3_6LIafpnFfdFL7kRMTa','mbENuc0kHQz9NLGkn5iy','xR','81941')<br />
---TRANSACTION 0, not started, OS thread id 2960855040</font><font color="black"><br />
MySQL thread id 326621, query id 2818137 localhost root<br />
SHOW ENGINE INNODB STATUS<br />
---TRANSACTION 1815A3B, not started, OS thread id 2961059840<br />
MySQL thread id 322078, query id 2778540 192.168.1.5 WebUser<br />
---TRANSACTION 1815A32, not started, OS thread id 2960650240<br />
MySQL thread id 319917, query id 2778444 192.168.1.5 WebUser<br />
---TRANSACTION 0, not started, OS thread id 2962083840<br />
MySQL thread id 319845, query id 2771552 192.168.1.5 WebUser<br />
---TRANSACTION 0, not started, OS thread id 2963107840<br />
MySQL thread id 43198, query id 2817803 localhost 127.0.0.1 WebUser<br />
</code></td>
</tr>
</table>
<p>I am sure that there are better ways of monitoring large DML statements, and this will only work for InnoDB tables.  If you try the same command for MyISAM, <font color="blue">SHOW ENGINE MyISAM STATUS</font><font color="black">, the output is blank:</p>
<table>
<tr bgcolor="white">
<td><code>mysql&gt; SHOW ENGINE MyISAM STATUS;<br />
Empty set (0.00 sec)<br />
</code></td>
</tr>
</table>
<p>If you know of a better or different way to do this, please add your thoughts in the comment section below.</p>
<p>&nbsp;
<p>
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<table width="100%">
<tr>
<td><img border="0" src="http://www.scriptingmysql.com/scriptingmysql/tony.jpg">
</td>
<td>
Tony Darnell is a Principal Sales Consultant for <a href="http://mysql.com/" />MySQL</a>, a division of <a href="http://oracle.com">Oracle</a>, Inc.  MySQL is the world&#8217;s most popular open-source database program.<br />
<br />Tony may be reached at info [at] ScriptingMySQL.com and on <a href="http://www.linkedin.com/in/tonydarnell">LinkedIn</a>.
</td>
</tr>
</table>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/scriptingmysql.wordpress.com/451/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/scriptingmysql.wordpress.com/451/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/scriptingmysql.wordpress.com/451/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/scriptingmysql.wordpress.com/451/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/scriptingmysql.wordpress.com/451/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/scriptingmysql.wordpress.com/451/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/scriptingmysql.wordpress.com/451/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/scriptingmysql.wordpress.com/451/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/scriptingmysql.wordpress.com/451/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/scriptingmysql.wordpress.com/451/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/scriptingmysql.wordpress.com/451/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/scriptingmysql.wordpress.com/451/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/scriptingmysql.wordpress.com/451/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/scriptingmysql.wordpress.com/451/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=451&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://scriptingmysql.wordpress.com/2011/11/04/checking-on-the-progress-of-large-dml-commands-in-mysql-using-perl-part-two/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4a7803de89b97b14df8a346d36a1b9a1?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tonydarnell</media:title>
		</media:content>

		<media:content url="http://www.scriptingmysql.com/scriptingmysql/tony.jpg" medium="image" />
	</item>
		<item>
		<title>Checking on the Progress of Large DML Commands in MySQL Using Perl &#8211; Part One</title>
		<link>http://scriptingmysql.wordpress.com/2011/11/02/checking-on-the-progress-of-large-dml-commands-in-mysql-using-perl-part-one/</link>
		<comments>http://scriptingmysql.wordpress.com/2011/11/02/checking-on-the-progress-of-large-dml-commands-in-mysql-using-perl-part-one/#comments</comments>
		<pubDate>Wed, 02 Nov 2011 11:45:56 +0000</pubDate>
		<dc:creator>Tony Darnell</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://scriptingmysql.wordpress.com/?p=415</guid>
		<description><![CDATA[Part One of Two: Checking on database activity when running a large DML (Data Manipulation Language) statement &#8211; such as INSERT, DELETE, UPDATE or SELECT. Part One: Inserting a million rows into a database. A friend of mine had asked a question &#8211; &#8220;Is there any way you can track how far you have advanced [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=415&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Part One of <a href="http://scriptingmysql.wordpress.com/2011/11/04/checking-on-the-progress-of-large-dml-commands-in-mysql-using-perl-part-two/">Two</a>:  Checking on database activity when running a large DML (Data Manipulation Language) statement &#8211; such as INSERT, DELETE, UPDATE or SELECT.</p>
<p>Part One:  Inserting a million rows into a database.</p>
<p>A friend of mine had asked a question &#8211; &#8220;Is there any way you can track how far you have advanced in a slow-moving ALTER or OPTIMIZE statement?&#8221;.  A customer was performing some modifications on a database with tens of millions of rows, and they wanted to be able to see if the command was making any progress.</p>
<p>Since the customer was using the InnoDB storage engine, I thought of a way that you could check on the progress &#8211; but only given the fact that nothing else (major) was happening in the database (more on this reason later).</p>
<p>With InnoDB, you can issue the <font face="courier" color="blue">SHOW ENGINE INNODB STATUS</font><font color="black"> (part of the <a href="http://dev.mysql.com/doc/refman/5.5/en/innodb-monitors.html">InnoDB Monitors</a>) and you will get a wealth of information.  I am not going to list any of the output from the command here as it would consume too much space.  However, towards the bottom of the output from the command, you will notice under &#8220;ROW OPERATIONS&#8221; a line that contains the words &#8220;Number of rows inserted&#8230;&#8221;:</p>
<table width="500">
<tr bgcolor="white">
<td><code>--------------<br />
ROW OPERATIONS<br />
--------------<br />
0 queries inside InnoDB, 0 queries in queue<br />
1 read views open inside InnoDB<br />
Main thread id 2960240640, state: waiting for server activity<br />
<font color="blue">Number of rows inserted 1202598, updated 97249, deleted 806, read 56448551</font><font color="black"><br />
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s<br />
</code></td>
</tr>
</table>
<p>The above line starting with <font color="blue">&#8220;Number of rows&#8230;&#8221;</font><font color="black"> gives you a quick snapshot of how many rows have been inserted, updated, deleted or selected (read) up to that point in time.  So, by invoking the <font face="courier" color="blue">SHOW ENGINE INNODB STATUS</font><font color="black"> command, you can figure what database activity has occurred since the last time you issued the command. But, if you invoke this command while the database is being used for other purposes, it will be difficult to figure out your progress on any of the four values shown, as the stats aren&#8217;t just for your activity.</p>
<p>So, all I needed to do was to write a quick Perl script to monitor that particular line of output, and then I could figure out if a certain statement was indeed being executed, and I could monitor the progress (assuming nothing else was happening on the database).  The problem that I had was that I didn&#8217;t have a database with a lot of records in it.  But, I did have a database server that didn&#8217;t have much activity.  So, in part one, I will show you how to create a dummy table and then shove a million records into it.  In part two (my next blog entry), I will show you the Perl script to monitor the changes to the output from the <font face="courier" color="blue">SHOW ENGINE INNODB STATUS</font><font color="black"> command. (And yes, you can just run the <font face="courier" color="blue">SHOW ENGINE INNODB STATUS</font><font color="black"> command manually over and over again, but what fun would that be?)</p>
<p>First I created a dummy table named &#8220;test_large&#8221;:</p>
<table>
<tr bgcolor="white">
<td><code>CREATE TABLE `test_large` (<br />
  `id` int(9) NOT NULL AUTO_INCREMENT,<br />
  `name_first` varchar(30) NOT NULL,<br />
  `name_last` varchar(30) NOT NULL,<br />
  `address_01` varchar(50) NOT NULL,<br />
  `address_02` varchar(50) NOT NULL,<br />
  `city` varchar(20) NOT NULL,<br />
  `state` varchar(2) NOT NULL,<br />
  `zip` varchar(5) NOT NULL,<br />
  PRIMARY KEY (`id`)<br />
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1<br />
</code></td>
</tr>
</table>
<p>Next, I created a Perl script that would create dummy/fake data and insert it into the table.  This script uses a subroutine named &#8220;ConnectToMySql&#8221; that I covered in an earlier post &#8211; <a href="http://scriptingmysql.wordpress.com/2011/07/27/connecting-to-mysql-with-perl/" />Connecting to MySQL with Perl</a>.  It also uses a subroutine to create fake alpha/numeric data (generate_random_string) and one that creates fake numeric data (generate_random_numbers).  A third subroutine (get_date_time) is used to display the date and time (I use this subroutine when I want to insert a date and time into a MySQL database).</p>
<p>The script is fairly easy to use.  You only need to modify the $total_rows variable to the number of rows that you want to insert, as well as the information about your particular database.  I didn&#8217;t include anything in the script to show you the progress of this script, but you could certainly add that if you wish.</p>
<table>
<tr bgcolor="white">
<td><code>#!/usr/bin/perl -w</p>
<p># DBI is the standard database interface for Perl<br />
# DBD is the Perl module that we use to connect to the MySQL database<br />
use DBI;<br />
use DBD::mysql;</p>
<p># how many total dummy rows of data do you need?<br />
# (must be an integer)<br />
<font color="blue">$total_rows = 10000000;</font><font color="black"></p>
<p># make sure that $total_rows is an integer<br />
if ($total_rows =~ /\D/) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "Total rows is not an integer = value = $total_rows.\n";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;exit;<br />
}</p>
<p># keep count of how many rows we have inserted<br />
$total_completed = 0;</p>
<p># your database name<br />
$Database = "<font color="blue">scripting_mysql</font><font color="black">";</p>
<p># get the current system date and time<br />
$print_date_time = &amp;get_date_time;</p>
<p># print the starting time (optional)<br />
print "Starting $print_date_time\n";</p>
<p># keep looping until we reach the total number of $total_rows<br />
while ($total_completed &lt; $total_rows) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# create dummy data<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fake_data_01 = &amp;generate_random_string(30);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fake_data_02 = &amp;generate_random_string(30);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fake_data_03 = &amp;generate_random_string(50);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fake_data_04 = &amp;generate_random_string(50);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fake_data_05 = &amp;generate_random_string(20);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fake_data_06 = &amp;generate_random_string(2);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$fake_data_07 = &amp;generate_random_numbers(5);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dbh = ConnectToMySql($Database);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$query = "insert into test_large (name_first, name_last, address_01, address_02, city, state, zip) values (?,?,?,?,?,?,?)";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth = $dbh-&gt;prepare($query);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth-&gt;execute($fake_data_01, $fake_data_02, $fake_data_03, $fake_data_04, $fake_data_05, $fake_data_06, $fake_data_07);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth-&gt;finish;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$total_completed++;<br />
}</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dbh-&gt;disconnect;</p>
<p>$print_date_time = &amp;get_date_time;</p>
<p># print our finishing time<br />
print "Finishing $print_date_time\n";<br />
exit;</p>
<p># ----------------------------------------------------------------------------------<br />
# subroutines<br />
# ----------------------------------------------------------------------------------</p>
<p># ----------------------------------------------------------------------------------<br />
sub get_date_time {<br />
# ----------------------------------------------------------------------------------</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my ($sec,$min,$hour,$mday,$mon,$year) = localtime time;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$year = $year + 1900;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$mon = $mon + 1;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# add a zero if the value is less than 10</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($sec &lt; 10) { $sec = "0$sec"; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($min &lt; 10) { $min = "0$min"; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($hour &lt; 10) { $hour = "0$hour"; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($mday &lt; 10) { $mday = "0$mday"; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($mon &lt; 10) { $mon = "0$mon"; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if ($year &lt; 10) { $year = "0$year"; }</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$DateTime = "$year-$mon-$mday $hour:$min:$sec";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return $DateTime</p>
<p>}<br />
#----------------------------------------------------------------------</p>
<p># from <a href="http://scriptingmysql.wordpress.com/2011/07/27/connecting-to-mysql-with-perl/" />Connecting to MySQL with Perl</a><br />
#----------------------------------------------------------------------<br />
sub ConnectToMySql {<br />
#----------------------------------------------------------------------</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my ($db) = @_;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;open(ACCESS_INFO, "<font color="blue">&lt;..\/accessBLOG</font><font color="black">") || die "Can't access login credentials";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $database = &lt;ACCESS_INFO&gt;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $host = &lt;ACCESS_INFO&gt;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $userid = &lt;ACCESS_INFO&gt;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $passwd = &lt;ACCESS_INFO&gt;;</p>
<p># the chomp() function will remove any newline character from the end of a string<br />
chomp ($database, $host, $userid, $passwd);<br />
#print "&lt;br&gt;$database $host $userid $passwd &lt;br&gt;";</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $connectionInfo="dbi:mysql:$database;$host";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(ACCESS_INFO);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# make connection to database<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $l_dbh = DBI-&gt;connect($connectionInfo,$userid,$passwd);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return $l_dbh;</p>
<p>}<br />
#----------------------------------------------------------------------</p>
<p>#----------------------------------------------------------------------<br />
sub generate_random_string {<br />
#----------------------------------------------------------------------</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $length_of_randomstring=shift;# the length of<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # the random string to generate</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my @chars=('a'..'z','A'..'Z','0'..'9','_');<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $random_string;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (1..$length_of_randomstring)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# rand @chars will generate a random<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# number between 0 and scalar @chars<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$random_string.=$chars[rand @chars];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return $random_string;<br />
}<br />
#----------------------------------------------------------------------</p>
<p>#----------------------------------------------------------------------<br />
sub generate_random_numbers {<br />
#----------------------------------------------------------------------</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $length_of_randomstring=shift;# the length of<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; # the random string to generate</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my @chars=('0'..'9');<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $random_string;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;foreach (1..$length_of_randomstring)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# rand @chars will generate a random<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# number between 0 and scalar @chars<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$random_string.=$chars[rand @chars];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return $random_string;<br />
}<br />
#----------------------------------------------------------------------<br />
</code></td>
</tr>
</table>
<p>This script took about three hours to insert a million rows into the new database.  And since this was a new table, every so often I would just check to see how many rows were in the table with a simple select command:</p>
<table bgcolor="white">
<tr>
<td><code>mysql&gt; select count(*) from test_large;<br />
+----------+<br />
| count(*) |<br />
+----------+<br />
|    98187 |<br />
+----------+<br />
1 row in set (0.00 sec)<br />
</code></td>
</tr>
</table>
<p><a href="http://scriptingmysql.wordpress.com/2011/11/04/checking-on-the-progress-of-large-dml-commands-in-mysql-using-perl-part-two/" />In my next post</a>, I will show you the Perl script that I used to monitor the <font color="blue">SHOW ENGINE INNODB STATUS</font><font color="black"> results.</p>
<p>&nbsp;
<p>
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<table width="100%">
<tr>
<td><img border="0" src="http://www.scriptingmysql.com/scriptingmysql/tony.jpg">
</td>
<td>
Tony Darnell is a Principal Sales Consultant for <a href="http://mysql.com/" />MySQL</a>, a division of <a href="http://oracle.com">Oracle</a>, Inc.  MySQL is the world&#8217;s most popular open-source database program.<br />
<br />Tony may be reached at info [at] ScriptingMySQL.com and on <a href="http://www.linkedin.com/in/tonydarnell">LinkedIn</a>.
</td>
</tr>
</table>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/scriptingmysql.wordpress.com/415/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/scriptingmysql.wordpress.com/415/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/scriptingmysql.wordpress.com/415/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/scriptingmysql.wordpress.com/415/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/scriptingmysql.wordpress.com/415/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/scriptingmysql.wordpress.com/415/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/scriptingmysql.wordpress.com/415/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/scriptingmysql.wordpress.com/415/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/scriptingmysql.wordpress.com/415/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/scriptingmysql.wordpress.com/415/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/scriptingmysql.wordpress.com/415/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/scriptingmysql.wordpress.com/415/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/scriptingmysql.wordpress.com/415/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/scriptingmysql.wordpress.com/415/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=415&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://scriptingmysql.wordpress.com/2011/11/02/checking-on-the-progress-of-large-dml-commands-in-mysql-using-perl-part-one/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4a7803de89b97b14df8a346d36a1b9a1?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tonydarnell</media:title>
		</media:content>

		<media:content url="http://www.scriptingmysql.com/scriptingmysql/tony.jpg" medium="image" />
	</item>
		<item>
		<title>Using MySQL, Perl and jQuery to Auto-Populate a Form Field on a Web Page</title>
		<link>http://scriptingmysql.wordpress.com/2011/10/28/using-mysql-perl-and-jquery-to-auto-populate-a-form-field-on-a-web-page/</link>
		<comments>http://scriptingmysql.wordpress.com/2011/10/28/using-mysql-perl-and-jquery-to-auto-populate-a-form-field-on-a-web-page/#comments</comments>
		<pubDate>Fri, 28 Oct 2011 11:10:58 +0000</pubDate>
		<dc:creator>Tony Darnell</dc:creator>
				<category><![CDATA[jQuery]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://scriptingmysql.wordpress.com/?p=355</guid>
		<description><![CDATA[If you have ever built a form on a web page, you might have used a drop-down menu to display the choices available for a particular field. With a drop-down menu, you restrict the choices a user may select so that the user doesn&#8217;t enter invalid data (among other reasons). If a user misspells an [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=355&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>If you have ever built a form on a web page, you might have used a drop-down menu to display the choices available for a particular field.  With a drop-down menu, you restrict the choices a user may select so that the user doesn&#8217;t enter invalid data (among other reasons).  If a user misspells an entry, then a subsequent search for that value would not produce a found result.</p>
<p>A friend of mine who runs an online forum sent me an email about a problem he was having.  He was trying to modify an existing registration web page using jQuery to auto-populate the state names, and then pass the state abbreviation back to his MySQL database.  Believe it or not, he was actually having problems with people knowing their own state abbreviation.  He had searched and found an example of what he wanted to do, but he couldn&#8217;t get it to work.  So, I took the <a target="new" href="http://www.jensbits.com/2011/05/09/jQuery-ui-autocomplete-widget-with-perl-and-mysql/" />example </a> that he found and figured out what he was doing wrong.</p>
<p>I had first suggested that he just hard-code the list of states and their abbreviations in the HTML code.  But, he said that if he figured out how to use jQuery with his state abbreviation problem, he would also use it on other parts of his web page where he had dynamic data.  With drop-down menus, it is fairly easy to create a list of static data to use in the HTML form.  But, in his case, what happens if the data is dynamic, or if there are too many items to list in a drop-down menu?  If you have ever had to include your country in a form (and you live in the US), it is always a pain to have to scroll down to the bottom of the long list to find &#8220;United States&#8221;.</p>
<p>An easy way to create a dynamic list (or even a long static list) is to use jQuery to access your data from a MySQL database, and to build an auto-populated field in your form.  When the user starts typing their entry, jQuery will search the MySQL database for a list of &#8220;like&#8221; matches, and then return a list of all of the matching results for that field.  </p>
<p>For this example, we will be using jQuery, Perl and a MySQL database to auto-populate a &#8220;state&#8221; field in a form.  Once a user has typed three characters in the state field box, a list of matching states will appear in a drop-down menu.  It will also return the state abbreviation and state id (code), which can then be saved in the MySQL database after the form has been submitted.  In this picture from our example, the user has typed &#8220;new&#8221;, and returned all states that match that string:</p>
<p><img src="http://tonydarnell.com/mysql_blog/jQuery_state_form.png"></p>
<p>First, let&#8217;s start by creating the MySQL database that we will use.  Here is the SQL code to create the database, which is named &#8220;states&#8221;.  The table will contain the state name, the state abbreviation, and an ID number.</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code>CREATE TABLE `states` (<br />
  `id` int(5) NOT NULL AUTO_INCREMENT,<br />
  `state` varchar(50) NOT NULL,<br />
  `abbrev` char(2) NOT NULL,<br />
  PRIMARY KEY (`id`)<br />
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1<br />
</code></td>
</tr>
</table>
<p>Next, you will want to import values into the database.  You could do this by importing a .csv file containing this information into MySQL, but to make it quicker for this example, here is the SQL:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code>insert into states (state, abbrev) values ('Alabama', 'AL');<br />
insert into states (state, abbrev) values ('Alaska', 'AK');<br />
insert into states (state, abbrev) values ('Arizona', 'AZ');<br />
insert into states (state, abbrev) values ('Arkansas', 'AR');<br />
insert into states (state, abbrev) values ('California', 'CA');<br />
insert into states (state, abbrev) values ('Colorado', 'CO');<br />
insert into states (state, abbrev) values ('Connecticut', 'CT');<br />
insert into states (state, abbrev) values ('Delaware', 'DE');<br />
insert into states (state, abbrev) values ('District of Columbia', 'DC');<br />
insert into states (state, abbrev) values ('Florida', 'FL');<br />
insert into states (state, abbrev) values ('Georgia', 'GA');<br />
insert into states (state, abbrev) values ('Hawaii', 'HI');<br />
insert into states (state, abbrev) values ('Idaho', 'ID');<br />
insert into states (state, abbrev) values ('Illinois', 'IL');<br />
insert into states (state, abbrev) values ('Indiana', 'IN');<br />
insert into states (state, abbrev) values ('Iowa', 'IA');<br />
insert into states (state, abbrev) values ('Kansas', 'KS');<br />
insert into states (state, abbrev) values ('Kentucky', 'KY');<br />
insert into states (state, abbrev) values ('Louisiana', 'LA');<br />
insert into states (state, abbrev) values ('Maine', 'ME');<br />
insert into states (state, abbrev) values ('Maryland', 'MD');<br />
insert into states (state, abbrev) values ('Massachusetts', 'MA');<br />
insert into states (state, abbrev) values ('Michigan', 'MI');<br />
insert into states (state, abbrev) values ('Minnesota', 'MN');<br />
insert into states (state, abbrev) values ('Mississippi', 'MS');<br />
insert into states (state, abbrev) values ('Missouri', 'MO');<br />
insert into states (state, abbrev) values ('Montana', 'MT');<br />
insert into states (state, abbrev) values ('Nebraska', 'NE');<br />
insert into states (state, abbrev) values ('Nevada', 'NV');<br />
insert into states (state, abbrev) values ('New Hampshire', 'NH');<br />
insert into states (state, abbrev) values ('New Jersey', 'NJ');<br />
insert into states (state, abbrev) values ('New Mexico', 'NM');<br />
insert into states (state, abbrev) values ('New York', 'NY');<br />
insert into states (state, abbrev) values ('North Carolina', 'NC');<br />
insert into states (state, abbrev) values ('North Dakota', 'ND');<br />
insert into states (state, abbrev) values ('Ohio', 'OH');<br />
insert into states (state, abbrev) values ('Oklahoma', 'OK');<br />
insert into states (state, abbrev) values ('Oregon', 'OR');<br />
insert into states (state, abbrev) values ('Pennsylvania', 'PA');<br />
insert into states (state, abbrev) values ('Rhode Island', 'RI');<br />
insert into states (state, abbrev) values ('South Carolina', 'SC');<br />
insert into states (state, abbrev) values ('South Dakota', 'SD');<br />
insert into states (state, abbrev) values ('Tennessee', 'TN');<br />
insert into states (state, abbrev) values ('Texas', 'TX');<br />
insert into states (state, abbrev) values ('Utah', 'UT');<br />
insert into states (state, abbrev) values ('Vermont', 'VT');<br />
insert into states (state, abbrev) values ('Virginia', 'VA');<br />
insert into states (state, abbrev) values ('Washington', 'WA');<br />
insert into states (state, abbrev) values ('West Virginia', 'WV');<br />
insert into states (state, abbrev) values ('Wisconsin', 'WI');<br />
insert into states (state, abbrev) values ('Wyoming', 'WY');<br />
insert into states (state, abbrev) values ('American Samoa');<br />
insert into states (state, abbrev) values ('Guam', 'GU');<br />
insert into states (state, abbrev) values ('Northern Mariana Islands', 'MP');<br />
insert into states (state, abbrev) values ('Puerto Rico', 'PR');<br />
</code></td>
</tr>
</table>
<p>Now that we have the database, we will need to create the Perl script.  Here is the Perl script, and you will need to change the database variables to match your system:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code>#!/usr/bin/perl -w<br />
use CGI;<br />
use DBI;<br />
use DBD::mysql;<br />
use JSON;</p>
<p># print the http header specifically for json<br />
print "Content-type: application/json; charset=iso-8859-1\n\n"; </p>
<p># your database variables<br />
my $database = "scripting_mysql";<br />
my $host = "192.168.1.2";<br />
my $port = "3306";<br />
my $tablename = "states";<br />
my $user = "root";<br />
my $pass = "root_password";<br />
my $cgi = CGI-&gt;new();<br />
my $term = $cgi-&gt;param('term');</p>
<p># mysql connection information<br />
$dsn = "dbi:mysql:$database:$host:$port";</p>
<p># open the database connection<br />
$connect = DBI-&gt;connect($dsn, $user, $pass) || die print "Can't connect - error...";</p>
<p># prepare the query<br />
$query = $connect-&gt;prepare(qq{select id, state AS value, abbrev FROM states where state like ?;});</p>
<p># execute the query<br />
$query-&gt;execute('%'.$term.'%');</p>
<p># obtain the results<br />
while ( my $row = $query-&gt;fetchrow_hashref ){<br />
    push @query_output, $row;<br />
}</p>
<p># close the database connection<br />
$connect-&gt;disconnect();</p>
<p># print the json output to be returned to the HTML page<br />
print JSON::to_json(\@query_output);<br />
</code></td>
</tr>
</table>
<p>For this example, the Perl script should be named states.pl.  When executed from the jQuery script in the web page, it will perform a search on the database where the search criteria is in a &#8220;like&#8221; statement, with a percent sign on both sides of the search term, like this:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code># execute the query<br />
$query-&gt;execute('%'.$term.'%');<br />
</code></td>
</tr>
</table>
<p>You might want to change this query if you have a long data set where entering a few letters would bring up a result that isn&#8217;t what the user would probably want.  Here is an example of the same form where we are asking the user to enter their state name, and they enter &#8220;min&#8221; for Minnesota, but it also brings up Wyoming:</p>
<p><img src="http://tonydarnell.com/mysql_blog/jQuery_state_form2.png"></p>
<p>If you want to only search for the beginning of the word, remove the first percent sign, like this:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code># execute the query<br />
$query-&gt;execute($term.'%');<br />
</code></td>
</tr>
</table>
<p>This would remove Wyoming from being populated as a choice:</p>
<p><img src="http://tonydarnell.com/mysql_blog/jQuery_state_form3.png"></p>
<p>Lastly, here is a simple web page that uses jQuery.  We are using the jQuery hosted by Google, and we are using one of their css templates.  You may delete their css template and use your own.  Also, you will need to change the path of your Perl script on this line:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code>source: "http://192.168.1.2/cgi-bin/mysql/jquery/state.pl"<br />
</code></td>
</tr>
</table>
<p>And here is the HTML:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code>&lt;html&gt;</p>
<p>&lt;link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jQueryui/1.8.16/themes/base/jQuery-ui.css"&gt;</p>
<p>&lt;!-- source = http://code.google.com/apis/libraries/devguide.html#jQuery  --&gt;<br />
&lt;script src="https://ajax.googleapis.com/ajax/libs/jQuery/1.6.4/jQuery.min.js"&gt;&lt;/script&gt;<br />
&lt;script src="https://ajax.googleapis.com/ajax/libs/jQueryui/1.8.16/jQuery-ui.min.js"&gt;&lt;/script&gt;</p>
<p>&lt;!--  Here is the jQuery code  --&gt;<br />
&lt;script&gt;<br />
&nbsp;&nbsp;&nbsp;$(function(get_states) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;$('#abbrev').val("");<br />
&nbsp;&nbsp;&nbsp;&nbsp;$("#state").autocomplete({<br />
&nbsp;&nbsp;&nbsp;&nbsp;source: "http://192.168.1.2/cgi-bin/mysql/jQuery/state.pl",<br />
&nbsp;&nbsp;&nbsp;&nbsp;minLength: 3,<br />
&nbsp;&nbsp;&nbsp;&nbsp;select: function(event, ui) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$('#state_id').val(ui.item.id);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$('#abbrev').val(ui.item.abbrev);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;});<br />
&nbsp;&nbsp;&nbsp;});<br />
&lt;/script&gt;</p>
<p>&lt;!--  The HTML is simplistic for the example:  --&gt;<br />
&lt;form  method="post"&gt;<br />
&lt;table&gt;<br />
&lt;tr&gt;&lt;td&gt;&lt;p class="ui-widget" &gt;&lt;label for="state"/&gt;State: &lt;/label&gt;&lt;/td&gt;<br />
&lt;td&gt;&lt;input type="text" id="state"  name="state" size=30/&gt; &lt;/td&gt;<br />
&lt;td&gt;&lt;input readonly="readonly" type="text" id="abbrev" name="abbrev" maxlength="2" size="2"/&gt;&lt;/td&gt;&lt;/tr&gt;<br />
&lt;/table&gt;<br />
&lt;input type="hidden" id="id" name="id" /&gt;<br />
&lt;p&gt;&lt;input type="submit" name="submit" value="Submit" /&gt;&lt;/p&gt;<br />
&lt;/form&gt;</p>
<p>&lt;!--  This section will populate the form field with a list of matching states  --&gt;<br />
&lt;script&gt;<br />
&nbsp;&nbsp;$("#auto_populate_field").submit(function(get_states){<br />
&nbsp;&nbsp;&nbsp;$("#submitted").html("State: " + $("#state").val() + "&lt;br /&gt;State Abbreviation: " + $("#abbrev").val() + "&lt;br /&gt;State ID: " + $("#state_id").val());<br />
&nbsp;&nbsp;&nbsp;return false;<br />
&nbsp;&nbsp;});<br />
&lt;/script&gt;</p>
<p></code></td>
</tr>
</table>
<p>In this example, once the user starts typing past three characters, a drop-down menu will appear with choices that match the letters being typed.  You can decrease/increase the total number of characters that the user will need to type before it queries the database.  This is done via this line in the jQuery code:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code>minLength: 3,<br />
</code></td>
</tr>
</table>
<p>Every time that the person types a character past the initial three characters, the jQuery script will query the MySQL database.  This needs to be taken into consideration if you will have a lot of traffic on the pages where you are using jQuery.</p>
<p>The Perl script returns three values in json output &#8211; the id, state and abbreviation fields.  The values of these fields are place in the text boxes by the autocomplete jQuery function.</p>
<p>In this example, the abbreviation for the state field is returned and placed in the &#8220;abbrev&#8221; field in the form.  The value for the state id is also returned, but since the id field is a hidden field in the form, you won&#8217;t see the output/value &#8211; but it will be stored in the form.</p>
<p>If you want to see the value of the state id, simply change your web form to look like this:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code>&lt;form  method="post"&gt;<br />
&lt;table&gt;<br />
&lt;tr&gt;&lt;td&gt;&lt;p class="ui-widget" style="textalign:right;"&gt;&lt;label for="state"/&gt;State: &lt;/label&gt;&lt;/td&gt;<br />
&lt;td&gt;&lt;input type="text" id="state"  name="state" size=30/&gt; &lt;/td&gt;<br />
&lt;td&gt;&lt;input readonly="readonly" type="text" id="abbrev" name="abbrev" maxlength="2" size="2"/&gt;&lt;/td&gt;<br />
&lt;td&gt;&lt;input type="text" size=4 id="state_id" name="state_id" /&gt;&lt;/td&gt;<br />
&lt;/tr&gt;<br />
&lt;/table&gt;<br />
&lt;p&gt;&lt;input type="submit" name="submit" value="Submit" /&gt;&lt;/p&gt;<br />
&lt;/form&gt;<br />
</code></td>
</tr>
</table>
<p>You can now see the third field which will contain the state id:</p>
<p><img src="http://tonydarnell.com/mysql_blog/jQuery_state_form4.png"></p>
<p>When you enter &#8220;min&#8221; and then click on Minnesota, you will see the state ID (24) in the third field:</p>
<p><img src="http://tonydarnell.com/mysql_blog/jQuery_state_form5.png"></p>
<p>You could also use this to auto-populate city and state fields after someone enters their zip code.  Or you could even use this to auto-populate the shipping costs for an online order (I might tackle this one in a future post).  Hopefully you will be able to copy and paste this example and have a working jQuery form web page example in just a few minutes.</p>
<p>&nbsp;
<p>
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<table width="100%">
<tr>
<td><img border="0" src="http://www.scriptingmysql.com/scriptingmysql/tony.jpg">
</td>
<td>
Tony Darnell is a Principal Sales Consultant for <a href="http://mysql.com/" />MySQL</a>, a division of <a href="http://oracle.com">Oracle</a>, Inc.  MySQL is the world&#8217;s most popular open-source database program.<br />
<br />Tony may be reached at info [at] ScriptingMySQL.com and on <a href="http://www.linkedin.com/in/tonydarnell">LinkedIn</a>.
</td>
</tr>
</table>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/scriptingmysql.wordpress.com/355/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/scriptingmysql.wordpress.com/355/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/scriptingmysql.wordpress.com/355/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/scriptingmysql.wordpress.com/355/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/scriptingmysql.wordpress.com/355/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/scriptingmysql.wordpress.com/355/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/scriptingmysql.wordpress.com/355/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/scriptingmysql.wordpress.com/355/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/scriptingmysql.wordpress.com/355/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/scriptingmysql.wordpress.com/355/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/scriptingmysql.wordpress.com/355/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/scriptingmysql.wordpress.com/355/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/scriptingmysql.wordpress.com/355/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/scriptingmysql.wordpress.com/355/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=355&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://scriptingmysql.wordpress.com/2011/10/28/using-mysql-perl-and-jquery-to-auto-populate-a-form-field-on-a-web-page/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4a7803de89b97b14df8a346d36a1b9a1?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tonydarnell</media:title>
		</media:content>

		<media:content url="http://tonydarnell.com/mysql_blog/jQuery_state_form.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/jQuery_state_form2.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/jQuery_state_form3.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/jQuery_state_form4.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/jQuery_state_form5.png" medium="image" />

		<media:content url="http://www.scriptingmysql.com/scriptingmysql/tony.jpg" medium="image" />
	</item>
		<item>
		<title>Using Perl, Cookies and MySQL to Record Web Site Visitor&#8217;s Data</title>
		<link>http://scriptingmysql.wordpress.com/2011/10/21/using-perl-cookies-and-mysql-to-record-web-site-visitors-data/</link>
		<comments>http://scriptingmysql.wordpress.com/2011/10/21/using-perl-cookies-and-mysql-to-record-web-site-visitors-data/#comments</comments>
		<pubDate>Fri, 21 Oct 2011 18:26:29 +0000</pubDate>
		<dc:creator>Tony Darnell</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://scriptingmysql.wordpress.com/?p=314</guid>
		<description><![CDATA[I have built several web sites and applications in the past, and I have to admit that I am a data junkie. If there is user data or any other data to be captured when someone uses my application or visits a web page, then I like to capture it (I can always delete it [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=314&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I have built several web sites and applications in the past, and I have to admit that I am a data junkie.  If there is user data or any other data to be captured when someone uses my application or visits a web page, then I like to capture it (I can always delete it later).  Of course, you can use a third-party Javascript plug-in for web site analytics (which I also use), but I like to gather information myself.</p>
<p>Most of the pages that I have written use Perl &#8211; even for the home page when possible (yes, I am &#8220;old school&#8221;, and my lack of using modern Perl code is evident).  Each time a user clicks to go to another page, I like to capture as much information as possible about their visit.</p>
<p>Perl, PHP and other scripting languages have ways for you to capture the information about your web page visitor.  For Perl, this simple script will tell you a lot of information the visitor and your server.  In order for this script to work, you have to call it from a web browser.</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code><br />
#!/usr/bin/perl -w<br />
use strict;<br />
use CGI qw(:standard);<br />
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);</p>
<p>print header;<br />
print start_html("Environment");</p>
<p>foreach my $key (sort(keys(%ENV))) {<br />
    print "$key = $ENV{$key}<br />\n";<br />
}</p>
<p>print end_html;<br />
</code>
</td>
</tr>
</table>
<p>I took the above script and placed it in my webserver&#8217;s cgi-bin directory, made it executable, and opened it in my browser.  I added a &#8220;?test=1234567&#8243; at the end of the script so that you could see the value of the REQUEST_URI variable.</p>
<p>Here is the web output:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code><br />
DOCUMENT_ROOT = /Library/WebServer/Documents<br />
GATEWAY_INTERFACE = CGI/1.1<br />
HTTP_ACCEPT = text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<br />
HTTP_ACCEPT_CHARSET = ISO-8859-1,utf-8;q=0.7,*;q=0.7<br />
HTTP_ACCEPT_ENCODING = gzip, deflate<br />
HTTP_ACCEPT_LANGUAGE = en-us,en;q=0.5<br />
HTTP_CONNECTION = keep-alive<br />
HTTP_COOKIE =<br />
HTTP_HOST = 192.168.1.2<br />
HTTP_USER_AGENT = Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1<br />
PATH = /usr/bin:/bin:/usr/sbin:/sbin<br />
QUERY_STRING = test=1234567<br />
REMOTE_ADDR = 192.168.1.5<br />
REMOTE_PORT = 60398<br />
REQUEST_METHOD = GET<br />
REQUEST_URI = /cgi-bin/mysql/perl_env.pl?test=1234567<br />
SCRIPT_FILENAME = /Library/WebServer/cgi-bin/mysql/perl_env.pl<br />
SCRIPT_NAME = /cgi-bin/mysql/perl_env.pl<br />
SERVER_ADDR = 192.168.1.2<br />
SERVER_ADMIN = email_address@scriptingmysql.com<br />
SERVER_NAME = 192.168.1.2<br />
SERVER_PORT = 80<br />
SERVER_PROTOCOL = HTTP/1.1<br />
SERVER_SIGNATURE =<br />
SERVER_SOFTWARE = Apache/2.2.17 (Unix) mod_ssl/2.2.17 OpenSSL/0.9.7l DAV/2 PHP/5.2.15</p>
<p></code>
</td>
</tr>
</table>
<p></code></p>
<p>This is a lot of information, and you probably don't need or want most of it.  You will want to select information that you can actually or potentially use.  For example, if you want to capture their computer info, HTTP referral and remote IP address, in your Perl script. you would create variables in your Perl script like this:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code><br />
$HTTP_USER_AGENT = $ENV{'HTTP_USER_AGENT'};<br />
$REMOTE_ADDR = $ENV{'REMOTE_ADDR'};<br />
$HTTP_REFERER = $ENV{'HTTP_REFERER'};
</td>
</tr>
</table>
<p></code></p>
<p>You can then insert this information into your MySQL database, along with an "action" of what they are doing on the page.  I create an activity table to record what the user is doing on various web pages.  If they are visiting your dashboard page, you might set their "activity" to "Dashboard Visit".  I also include a date and time stamp.  A sample activity table might look like this:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code><br />
CREATE TABLE `activity` (<br />
  `Customer_Serial_Number` varchar(15) NOT NULL,<br />
  `Action` varchar(50) NOT NULL,<br />
  `Date_Time` datetime NOT NULL,<br />
  `Info` varchar(50) NOT NULL,<br />
  `Notes` varchar(100) NOT NULL,<br />
  `HTTP_USER_AGENT` varchar(150) NOT NULL<br />
  `REMOTE_ADDR` varchar(15) NOT NULL<br />
  `HTTP_REFERER` varchar(300) NOT NULL<br />
) ENGINE=InnoDB DEFAULT CHARSET=utf8
</td>
</tr>
</table>
<p></code></p>
<p>If the web site requires a user name and password to login, I also use cookies - which is usually how I retrieve the Customer_Serial_Number and/or any other personal information that they have provided to me.  Or, if they fill out a "contact us" form, you can save their name and information in a cookie to be retrieved when they visit your web site later.  Just be sure to set the cookie expiration date to a date in the future, or to have the cookie never expire.</p>
<p>Here is a quick way to create a cookie in Perl.  In this example, we are creating two cookies, Customer Serial Number and Customer Email, both of which we have retrieved from MySQL after they logged into the site:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code><br />
&nbsp;&nbsp;&nbsp;# ===========<br />
&nbsp;&nbsp;&nbsp;# set cookie for Customer Serial Number<br />
&nbsp;&nbsp;&nbsp;# ===========<br />
&nbsp;&nbsp;&nbsp;$customer_serial_number = CGI::Cookie-&gt;new(-name =&gt; "CustSN",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-value =&gt; $Customer_Serial_Number,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-expires   =&gt; "+15m",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-domain    =&gt; ".mydomain.com",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-path      =&gt; "/"<br />
&nbsp;&nbsp;&nbsp;);</p>
<p>&nbsp;&nbsp;&nbsp;# ===========<br />
&nbsp;&nbsp;&nbsp;# set cookie for Customer Email<br />
&nbsp;&nbsp;&nbsp;# ===========<br />
&nbsp;&nbsp;&nbsp;$Email = CGI::Cookie-&gt;new(-name =&gt; "CustE",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-value =&gt; "$Customer_Email_Address",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-expires   =&gt; "+1y",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-domain    =&gt; ".mydomain.com",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;-path      =&gt; "/"<br />
&nbsp;&nbsp;&nbsp;);</p>
<p># create the cookie for Customer Serial Number and Customer Email<br />
$q = new CGI;<br />
print $q-&gt;header(-cookie =&gt; [$customer_serial_number, $Email] );<br />
</code>
</td>
</tr>
</table>
<p></code></p>
<p>Here are the definitions for the cookie variables (information from <a href="http://perldoc.perl.org/CGI/Cookie.html">http://perldoc.perl.org/CGI/Cookie.html</a>.</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code><br />
CSN - the name of the cookie.  You will use this name to retrieve the cookie later.<br />
value - the value of the cookie - the value can be a scalar, an array reference, or a hash reference.<br />
expires - how long you want the cookie to be available.  Here are some settings:<br />
&nbsp;&nbsp;&nbsp;- Cookie expires 10 seconds from now +10s<br />
&nbsp;&nbsp;&nbsp;- Cookie expires 10 minutes from now +10m<br />
&nbsp;&nbsp;&nbsp;- Cookie expires 10 hours from now +10h<br />
&nbsp;&nbsp;&nbsp;- Cookie expires 10 days from now +10d<br />
&nbsp;&nbsp;&nbsp;- Cookie expires 10 months from now +10M<br />
&nbsp;&nbsp;&nbsp;- Cookie expires 10 years from now +10y<br />
&nbsp;&nbsp;&nbsp;- to make it expire immediately, set it to a negative number, such as: -10M<br />
domain - points to a domain name or to a fully qualified host name. If not specified, the cookie will be returned only to the web server that created it.<br />
path - points to a partial URL on the current server. The cookie will be returned to all URLs beginning with the specified path. If not specified, it defaults to '/', which returns the cookie to all pages at your site.
</td>
</tr>
</table>
<p></code></p>
<p>There are a couple of other variables that you can use, so refer to the <a href="http://perldoc.perl.org/CGI/Cookie.html">Perl cookie</a> page for more information.</p>
<p>Deciding which information that you want to keep is up to you.  Then, you can simply create a MySQL table to store this information.  When a user registers on your site, you can store their email address in a cookie that never expires, so the next time they login, you can auto-populate the login form with their email address.</p>
<p>You can also redirect mobile users to a web page that is specific to their screen size.  For example, when I connect to this script with my iPhone, I can tell that the connection is from an iPhone via the HTTP_USER_AGENT:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code><br />
HTTP_USER_AGENT = Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_10 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8E600 Safari/6533.18.5
</td>
</tr>
</table>
<p></code><br />
However, my iPhone's remote IP address is almost useless:</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code><br />
REMOTE_ADDR = 10.1.10.10
</td>
</tr>
</table>
<p></code><br />
So, your Perl script can then detect that this user is on an iPhone, and then it can redirect them with a <a href="http://webdesign.about.com/od/metataglibraries/a/aa080300a.htm">meta refresh tag</a> to a version of the web page specifically designed for the iPhone screen resolution.</p>
<p>One web site that I designed required a user to login to get past the home screen.  Once they logged in, I would grab their serial number from the MySQL database, and then create a cookie with the serial number value.  With each page they visited, I would send a few bits of information to my MySQL visitor database.</p>
<p>Here is part of the Perl script that I would use to record customer information:  (information on inserting data into MySQL via Perl may be found <a href="http://scriptingmysql.wordpress.com/2011/08/05/inserting-data-into-mysql-with-perl/">in an earlier post</a>).</p>
<table cellpadding="10">
<tr>
<td bgcolor="white"><code><br />
#!/usr/bin/perl -w<br />
use CGI qw(:standard);<br />
use CGI::Carp qw(warningsToBrowser fatalsToBrowser);</p>
<p># ----------------------------------------------------------------------------------<br />
# grab the environment variables<br />
# ----------------------------------------------------------------------------------</p>
<p>$HTTP_USER_AGENT = $ENV{'HTTP_USER_AGENT'};<br />
$REMOTE_ADDR = $ENV{'REMOTE_ADDR'};</p>
<p># ----------------------------------------------------------------------------------<br />
# fetch the cookie for the Customer Serial Number<br />
# ----------------------------------------------------------------------------------</p>
<p>%cookies = CGI::Cookie-&gt;fetch;<br />
if ($cookies{CustSN}) {<br />
        $Customer_Serial_Name = $cookies{CustSN}-&gt;value;<br />
}</p>
<p># ----------------------------------------------------------------------------------<br />
# grab date and time<br />
# ----------------------------------------------------------------------------------</p>
<p>my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime time;</p>
<p>$year = $year + 1900;<br />
$mon = $mon + 1;</p>
<p># add a zero if the value is less than 10</p>
<p>if ($sec &lt; 10) { $sec = &quot;0$sec&quot;; }<br />
if ($min &lt; 10) { $min = &quot;0$min&quot;; }<br />
if ($hour &lt; 10) { $hour = &quot;0$hour&quot;; }<br />
if ($mday &lt; 10) { $mday = &quot;0$mday&quot;; }<br />
if ($mon &lt; 10) { $mon = &quot;0$mon&quot;; }<br />
if ($year &lt; 10) { $year = &quot;0$year&quot;; }</p>
<p>$DateTime = "$year-$mon-$mday $hour:$min:$sec";</p>
<p># ---------------------------------------------------------------------------------<br />
# insert customer activity into database<br />
# ---------------------------------------------------------------------------------</p>
<p>	$Action = "Dashboard Visit";</p>
<p>	$dbh = ConnectToMySql($Database);</p>
<p>	$query = "insert into Activity (Customer_Serial_Number, Action, Date_Time, HTTP_USER_AGENT, REMOTE_ADDR) values (?,?,?,?,?)";</p>
<p>	$sth = $dbh-&gt;prepare($query);</p>
<p>	$sth-&gt;execute('$Customer_Serial_Number', '$Action', '$DateTime', '$HTTP_USER_AGENT', '$REMOTE_ADDR');</p>
<p># ---------------------------------------------------------------------------------<br />
# ---------------------------------------------------------------------------------<br />
</code>
</td>
</tr>
</table>
<p></code></p>
<p>Once you have enough customer data, you can figure out the paths that your customers are taking when visiting your site.  Do they login and go straight to the forum page?  Or if you have a web store, do they go straight to the clearance page?  Or are they logging in and then doing nothing?  If a customer never visits a certain page, what can you do to drive them to visit that page?  Third-party tools can provide good overall web site analytical information, but nothing beats being able to see one particular customer's activity on your own.</p>
<p>&nbsp;
<p>
-----------------------------------------<br />
<table width="100%">
<tr>
<td><img border="0" src="http://www.scriptingmysql.com/scriptingmysql/tony.jpg">
</td>
<td>
Tony Darnell is a Principal Sales Consultant for <a href="http://mysql.com/" />MySQL</a>, a division of <a href="http://oracle.com">Oracle</a>, Inc.  MySQL is the world's most popular open-source database program.<br />
<br />Tony may be reached at info [at] ScriptingMySQL.com and on <a href="http://www.linkedin.com/in/tonydarnell">LinkedIn</a>.
</td>
</tr>
</table>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/scriptingmysql.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/scriptingmysql.wordpress.com/314/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/scriptingmysql.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/scriptingmysql.wordpress.com/314/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/scriptingmysql.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/scriptingmysql.wordpress.com/314/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/scriptingmysql.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/scriptingmysql.wordpress.com/314/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/scriptingmysql.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/scriptingmysql.wordpress.com/314/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/scriptingmysql.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/scriptingmysql.wordpress.com/314/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/scriptingmysql.wordpress.com/314/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/scriptingmysql.wordpress.com/314/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=314&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://scriptingmysql.wordpress.com/2011/10/21/using-perl-cookies-and-mysql-to-record-web-site-visitors-data/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4a7803de89b97b14df8a346d36a1b9a1?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tonydarnell</media:title>
		</media:content>

		<media:content url="http://www.scriptingmysql.com/scriptingmysql/tony.jpg" medium="image" />
	</item>
		<item>
		<title>Using Java to Connect to MySQL Enterprise Monitor with Plugin for Connector/J</title>
		<link>http://scriptingmysql.wordpress.com/2011/10/14/using-java-to-connect-to-mysql-enterprise-monitor-with-plugin-for-connectorj/</link>
		<comments>http://scriptingmysql.wordpress.com/2011/10/14/using-java-to-connect-to-mysql-enterprise-monitor-with-plugin-for-connectorj/#comments</comments>
		<pubDate>Fri, 14 Oct 2011 19:15:00 +0000</pubDate>
		<dc:creator>Tony Darnell</dc:creator>
				<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://scriptingmysql.wordpress.com/?p=292</guid>
		<description><![CDATA[If you use MySQL for any number of databases, and if you are not using the MySQL Enterprise Monitor (MEM) to manage your databases, then you are missing out on a great DBA tool. From http://dev.mysql.com/doc/mysql-monitor/2.3/en/mem-introduction.html: &#8220;MySQL Enterprise Monitor is a companion product for MySQL Server that monitors your MySQL instances, notifies you of potential [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=292&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>If you use MySQL for any number of databases, and if you are not using the MySQL Enterprise Monitor (MEM) to manage your databases, then you are missing out on a great DBA tool.</p>
<p>From <a href="http://dev.mysql.com/doc/mysql-monitor/2.3/en/mem-introduction.html">http://dev.mysql.com/doc/mysql-monitor/2.3/en/mem-introduction.html</a>:</p>
<p><i>&#8220;MySQL Enterprise Monitor is a companion product for MySQL Server that monitors your MySQL instances, notifies you of potential issues and problems, and advises you how to fix the issues. MySQL Enterprise Monitor can monitor all kinds of configurations, from a single MySQL instance that is important to your business, all the way up to a huge farm of database server machines powering a busy web site. &#8220;</i></p>
<p>The query analyzer function of the Enterprise Monitor helps you to analyze/tune your queries.  It can tell you which queries are being run the most often, which ones are taking the longest to run, it can even help you find queries that are returning a zero result set, and other query &#8220;violators&#8221;.</p>
<p>But the caveat is that in order to use the query analyzer function, you have to redirect your MySQL traffic through a proxy server (configured during the MEM installation).  Using the proxy server is an additional step that might be acceptible for testing on development servers, but it might not be a great idea in a production environment.</p>
<p>However, if you are using Java for your database connections, you can bypass the proxy server and send your query information directly to the MEM Service Manager.  This is accomplished with the <a href="http://dev.mysql.com/doc/mysql-monitor/2.3/en/mem-qanal-using-cj.html">MySQL Enterprise Plugin for Connector/J</a>.</p>
<p>From <a href="http://dev.mysql.com/doc/mysql-monitor/2.3/en/mem-qanal-using-cj.html">http://dev.mysql.com/doc/mysql-monitor/2.3/en/mem-qanal-using-cj.html</a>:</p>
<p><i>&#8220;The MySQL Enterprise Plugin for Connector/J lets you use the Query Analyzer to monitor MySQL queries from any application using the Connector/J JDBC driver. As described in Section 3.2, &#8220;<a href="http://dev.mysql.com/doc/mysql-monitor/2.3/en/mem-qanal-using-ui.html">Query Analyzer User Interface</a>&#8220;, the Query Analyzer can help you locate queries that are inefficient or slow. Tuning such queries helps to shorten load times for web pages, and improves overall system responsiveness and scalability.&#8221;</i></p>
<p>As stated, the information about the queries is sent directly to the MySQL Enterprise Service Manager. Once you install the MySQL Enterprise Plugin for Connector/J and tweak your Java database connection string, query analysis becomes available for your Java applications.  And, the Enterprise Monitor can show you the location of the &#8220;offensive&#8221; Java code.  Here is an example, with the code location highlighted in blue:</p>
<p><img src="http://tonydarnell.com/mysql_blog/java_bad_query_location.png"></p>
<p>There are a few things that you need to do before you can use this plugin.  The prerequisites are:</p>
<p> - MySQL Connector/J version 5.1.12 or later.<br />
 - JDK-1.5.0 or later.<br />
 - MySQL Enterprise Service Manager version 2.2 or later.<br />
 - The MySQL instance that the application uses must be monitored by a MySQL Enterprise monitoring agent. The mysql.inventory table must be accessible to the configured user for the Connector/J connection to get the UUID of the monitored server.<br />
 - Apache Commons logging in the CLASSPATH of the application being analyzed. If you are not already using Commons Logging, modify the application&#8217;s CLASSPATH as described in the following section to point to the JAR file bundled with the MySQL Enterprise Monitor product.</p>
<p>I don&#8217;t write Java code, but I wanted to be able to test this functionality.  I found an example script on <a href="http://dev.mysql.com/doc/mysql-monitor/2.3/en/mem-qanal-using-cj.html">MySQL&#8217;s web site</a>, and so I was able to modify it to send a test query to my installation of MEM.</p>
<p>I did run into one problem &#8211; I wasn&#8217;t setting my CLASSPATH variable correctly.  To solve this problem, I edited my .profile file for the root user, and added the following JAR file locations to my CLASSPATH:  (the colors are added for clarity)</p>
<table cellpadding="10">
<tr>
<td bgcolor="white">
<code><br />
export set CLASSPATH=<font color="blue">/Applications/mysql/enterprise/monitor/apache-tomcat/webapps/ROOT/WEB-INF/lib/mysql-connector-java-commercial-5.1.17-bin.jar:<font color="black">/Applications/mysql/enterprise/monitor/apache-tomcat/webapps/ROOT/WEB-INF/lib/c-java-mysql-enterprise-plugin-1.0.0.61.jar:<font color="blue">/Applications/mysql/enterprise/monitor/apache-tomcat/webapps/ROOT/WEB-INF/lib/required/commons-logging-1.1.1.jar:<font color="black"><br />
</code></p>
</td>
</tr>
</table>
<p>I am running MySQL on a Mac Pro Server, so you will need to modify the file paths in your CLASSPATH to match your system.</p>
<p>After you have completed the prerequisites, you are ready to see if you can connect to the Service Manager with a query via Java.  Here is a sample script that you can use (you will need to modify it your system parameters):</p>
<table cellpadding="10">
<tr>
<td bgcolor="white">
<code><br />
import java.io.IOException;<br />
import java.sql.*;</p>
<p>// Notice, do not import com.mysql.jdbc.*<br />
// or you will have problems!</p>
<p>public class LoadDriver {<br />
&nbsp;&nbsp;&nbsp;public static void main(String[] args) {</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// The newInstance() call is a work around for some<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// broken Java implementations</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class.forName("com.mysql.jdbc.Driver").newInstance();</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Connection conn = DriverManager.getConnection("jdbc:mysql://192.168.1.2/database_name?"+<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"user=root&amp;password=root_password"+<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&amp;statementInterceptors=com.mysql.etools.jdbc.StatementPerformanceCounters"+<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&amp;serviceManagerUrl=http://192.168.1.2:18080/"+<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&amp;serviceManagerUser=agent"+<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&amp;serviceManagerPassword=agent_password");</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//Get a Statement object<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Statement stmt = conn.createStatement();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ResultSet rs = stmt.executeQuery("SELECT sleep(120)");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("Closing connection");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;conn.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (Exception ex) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// handle the error<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ex.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</code>
</td>
</tr>
</table>
<p>You will need to compile the script before running it.  Here are the results from compiling and then executing the script:  (since you are doing a SELECT SLEEP(120), the script will &#8220;sleep&#8221; for 120 seconds before finishing.)</p>
<table cellpadding="10">
<tr>
<td bgcolor="white">
<code><br />
macserver01:java root# javac LoadDriver.java<br />
macserver01:java root# java LoadDriver<br />
Fri Oct 14 14:08:57 EDT 2011 DEBUG: Using direct result set size methods.<br />
Fri Oct 14 14:08:57 EDT 2011 DEBUG: Using batch-aware prepared sql extractor.<br />
Fri Oct 14 14:08:57 EDT 2011 INFO: MySQL Enterprise Plugin for Connector/J version 1.0.0.61 started for MySQL instance 53e71576-026c-4798-961b-0025efc37db2.<br />
Fri Oct 14 14:08:57 EDT 2011 DEBUG: GET http://192.168.1.2:18080/v2/rest/instance/mysql/StatementAnalysisSupport/53e71576-026c-4798-961b-0025efc37db2<br />
HTTP/1.1 200 OK<br />
Server: Apache-Coyote/1.1<br />
Content-Type: application/json<br />
Transfer-Encoding: chunked<br />
Date: Fri, 14 Oct 2011 18:08:57 GMT</p>
<p>{<font color="red"><br />
&nbsp;&nbsp;&nbsp;&nbsp;"name": "53e71576-026c-4798-961b-0025efc37db2",<br />
&nbsp;&nbsp;&nbsp;&nbsp;"parent": "/instance/mysql/Server/53e71576-026c-4798-961b-0025efc37db2",<br />
&nbsp;&nbsp;&nbsp;&nbsp;"values":&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="black">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</font><font color="red">"auto_explain_min_exec_time_ms": 1,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"capture_examples": "true",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"capture_explain": "true",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"enabled": "true",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"frequency": </font><font color="blue">null</font><font color="black"><br />
    }<br />
}<br />
Fri Oct 14 14:08:57 EDT 2011 DEBUG: Configuration is: com.mysql.etools.jdbc.StatementAnalysisConfiguration@a14e84[captureExamples=true,captureExplains=true,enabled=true,explainPlanThresholdMicros=1000,usingDefaults=false]<br />
Fri Oct 14 14:08:57 EDT 2011 DEBUG: GET http://192.168.1.2:18080/v2/rest/instance/mysql/StatementAnalysisSupport/53e71576-026c-4798-961b-0025efc37db2<br />
HTTP/1.1 200 OK<br />
Server: Apache-Coyote/1.1<br />
Content-Type: application/json<br />
Transfer-Encoding: chunked<br />
Date: Fri, 14 Oct 2011 18:08:57 GMT</p>
<p>{<font color="red"><br />
&nbsp;&nbsp;&nbsp;&nbsp;"name": "53e71576-026c-4798-961b-0025efc37db2",<br />
&nbsp;&nbsp;&nbsp;&nbsp;"parent": "/instance/mysql/Server/53e71576-026c-4798-961b-0025efc37db2",<br />
&nbsp;&nbsp;&nbsp;&nbsp;"values":     </font><font color="black">{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"auto_explain_min_exec_time_ms": 1,<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"capture_examples": "true",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"capture_explain": "true",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"enabled": "true",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"frequency": </font><font color="blue">null</font><font color="black"><br />
    }<br />
}<br />
Fri Oct 14 14:08:57 EDT 2011 DEBUG: Configuration is: com.mysql.etools.jdbc.StatementAnalysisConfiguration@a14e84[captureExamples=true,captureExplains=true,enabled=true,explainPlanThresholdMicros=1000,usingDefaults=false]<br />
</code></td>
</tr>
</table>
<p>And here are the results as show in the Query Analyzer tab of MySQL Enterprise Monitor:</p>
<p><img src="http://tonydarnell.com/mysql_blog/java_connector_MEM_sample_image.png"></p>
<p>By clicking on the <font color="blue">SELECT sleep(?)</font><font color="black"> link, I can then take a look at the query information:</p>
<p><img src="http://tonydarnell.com/mysql_blog/java_query_information.png"></p>
<p>For more complex queries, this tool really provides a wealth of information to help you tune your queries and increase the performance of your MySQL databases.  MySQL Enterprise Monitor has a wealth of great features.  For more information, see <a href="http://dev.mysql.com/doc/mysql-monitor/2.3/en/index.html">http://dev.mysql.com/doc/mysql-monitor/2.3/en/index.html</a>.</p>
<p>&nbsp;
<p>
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<table width="100%">
<tr>
<td><img border="0" src="http://www.scriptingmysql.com/scriptingmysql/tony.jpg">
</td>
<td>
Tony Darnell is a Principal Sales Consultant for <a href="http://mysql.com/" />MySQL</a>, a division of <a href="http://oracle.com">Oracle</a>, Inc.  MySQL is the world&#8217;s most popular open-source database program.<br />
<br />Tony may be reached at info [at] ScriptingMySQL.com and on <a href="http://www.linkedin.com/in/tonydarnell">LinkedIn</a>.
</td>
</tr>
</table>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/scriptingmysql.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/scriptingmysql.wordpress.com/292/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/scriptingmysql.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/scriptingmysql.wordpress.com/292/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/scriptingmysql.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/scriptingmysql.wordpress.com/292/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/scriptingmysql.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/scriptingmysql.wordpress.com/292/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/scriptingmysql.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/scriptingmysql.wordpress.com/292/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/scriptingmysql.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/scriptingmysql.wordpress.com/292/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/scriptingmysql.wordpress.com/292/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/scriptingmysql.wordpress.com/292/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=292&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://scriptingmysql.wordpress.com/2011/10/14/using-java-to-connect-to-mysql-enterprise-monitor-with-plugin-for-connectorj/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4a7803de89b97b14df8a346d36a1b9a1?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tonydarnell</media:title>
		</media:content>

		<media:content url="http://tonydarnell.com/mysql_blog/java_bad_query_location.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/java_connector_MEM_sample_image.png" medium="image" />

		<media:content url="http://tonydarnell.com/mysql_blog/java_query_information.png" medium="image" />

		<media:content url="http://www.scriptingmysql.com/scriptingmysql/tony.jpg" medium="image" />
	</item>
		<item>
		<title>Steve Jobs, you will be missed. Greatly.</title>
		<link>http://scriptingmysql.wordpress.com/2011/10/06/steve-jobs-you-will-be-missed-greatly/</link>
		<comments>http://scriptingmysql.wordpress.com/2011/10/06/steve-jobs-you-will-be-missed-greatly/#comments</comments>
		<pubDate>Thu, 06 Oct 2011 12:00:24 +0000</pubDate>
		<dc:creator>Tony Darnell</dc:creator>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Scripting]]></category>
		<category><![CDATA[Steve Jobs]]></category>
		<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://scriptingmysql.wordpress.com/?p=286</guid>
		<description><![CDATA[I remember my first computer. It was a TI-99/4A. I bought it back in 1982 (I think), and it cost around $300. The entire computer fit inside what looked like a really thick keyboard. It had a slot on the right for cartridges, and I had a cassette tape drive that I used for backing [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=286&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I remember my first computer.  It was a TI-99/4A.  I bought it back in 1982 (I think), and it cost around $300.  The entire computer fit inside what looked like a really thick keyboard.  It had a slot on the right for cartridges, and I had a cassette tape drive that I used for backing up the BASIC computer programs that I wrote.  I thought that it was a great computer at the time, but I really didn&#8217;t have anything to compare it to.  The games were the best part of the computer (really the only fun part &#8211; my BASIC skills were lacking).  And even though the games were fairly lame by even 1982 standards, but they were still plenty of fun to play.</p>
<p>I also remember when I saw a Macintosh for the first time.  I had followed Apple for some time, but I had never had the opportunity to actually see a Macintosh.  I think it was in 1987 or 1988, when I was a student at the University of Georgia.  I believe it was a Mac SE, and it had one megabyte of RAM and a twenty-megabyte hard drive.  Up to that point, I had only played around with MS-DOS, and that was on a computer at work.  I was amazed at the graphical interface.  The mouse was definitely cool.  I had to have one, but at that time, they were a couple thousand dollars (at least), and I was a &#8220;poor college student&#8221;.  I spent a lot of time at the computer lab, and I waited.</p>
<p>In 1989, I landed my first job out of college, and one of the first things on my &#8220;to-buy&#8221; list was a Mac.  I just didn&#8217;t WANT a Mac &#8211; I NEEDED a Mac.  So, with a loan from the bank (yes, we took out a loan), my brother and I bought two Mac SE&#8217;s, and an HP Deskwriter dot-matrix printer that cost $1,195 (we had to share the printer).  I remember opening the box and putting the computer on my desk &#8211; and I was thrilled and amazed.   With my 2400-baud modem, I could connect to the Unix computers at work.  Life was grand. The first major improvement that I made was to upgrade the RAM to four megabytes.  I think the upgrade was a whopping $400.  And then, about a year later, the hard drive died (one of the only problems that I have ever had with a Mac).  So, I upgraded to a forty-megabyte drive for $500.  I remember thinking that I will wouldn&#8217;t need any more additional hard drive space for a really long time.  Besides, I had several hundred 3.5 inch floppies.  I later upgraded to a faster processor and bought an internal video card that let me use a huge monitor at the same time (I think it was a 19&#8243; monitor &#8211; but it was a grayscale monitor).  But having two monitors was cool &#8211; very cool &#8211; even though a color monitor still eluded me.</p>
<p>And then, about every year or two, I would upgrade to a newer model.  I had an SE/30, LC, IIsi, Quadra 840 AV (which I used to edit my first videos), a Power Mac G3, G4 and then several iMac&#8217;s.  I remember staying up all night playing SIM City on the LC and playing on Prodigy.  I had other computers in the house &#8211; a Windows machine and a couple of Unix boxes.  But I was all-Mac.  I remember my first web cam, which I set up to record people driving my the house.  The motion-detection software would record a few grayscale photos when cars would drive by.  I found out when the trash was picked up and when the mail was delivered.  Technology was amazing.</p>
<p>I followed all of the Apple news.  Even before I bought my first Mac, I remember when Steve was booted from Apple.  I winced as I remember watching Scully and Amelio take Apple to the brink of bankruptcy.  When I traveled to the San Francisco area in the mid-1990&#8242;s on a business trip, I took some time to drive to Cupertino to the Apple Campus.  While I would have loved to have been an Apple employee back then, moving to California was pretty much out of the question.  But, I wanted to at least state that I had applied for a job there &#8211; which I did.  I wasn&#8217;t hired, but at least I tried, at least I did that.  And I remember when Steve Jobs returned.  Mac lovers now had hope.  The love affair was rekindled &#8211; and it had the opportunity to be much, much stronger than before.  Steve would fix it. He had to fix it.  And he did. </p>
<p>When I started a company a few years ago, the office was filled with Intel iMac&#8217;s and a Mac Pro Server (running MySQL of course!). My wife has a MacBook Pro, my kids have Mac Mini&#8217;s, and I just recently purchased a MacBook Pro.  We even have an iMac in the kitchen.  My Mom has an iMac and my Dad has my Mom&#8217;s old G4 (when she upgrades, he gets the hand-me-downs).  My sister recently &#8220;upgraded&#8221; from Windows to an iMac.  I gave my niece a MacBook when she started graphics arts school.  (My brother is the only current hold-out, but he is on the way to converting back to the Mac).  I think you get my point &#8211; I really love Macintosh computers and I enjoy &#8220;converting people&#8221; to the cause.</p>
<p>Needless to say, my life has been touched in some way throughout the past 20-plus years by the Macintosh.  I have done everything from creating proposals, creating and listening to music, to editing my youngest son&#8217;s birth video (yes, it is rated G) &#8211; all on a Macintosh.  It is even where I store my tens of thousands of digital photos.  I have designed web sites, created software products and ran a business on Macintosh computers. My wife produced a video for my 40th birthday party on her Mac.  And, I can&#8217;t forget my first iPod, my first iPod Touch, and my iPhones &#8211; versions 3 and 4 (I am holding out for the iPad 3).  Heck, I even still use the old AppleWorks application every once in a while.</p>
<p>Even though the Mac isn&#8217;t and has never been the most dominant &#8220;PC&#8221; in the marketplace &#8211; if you ask anyone that uses a Mac if they would ever use anything else, the vast majority of them would answer with a strong and resounding &#8220;no&#8221; (or even HELL NO).  Even when Apple stock was trading at less than five bucks per share, and it seemed like it was going out of business, I remember telling friends that Apple would pull through (heck &#8211; it HAD to pull through).  I couldn&#8217;t imagine having to use a Windows machine.</p>
<p>And so, I owe a lot of my memories over the past twenty years to Apple Computer, and of course, to Steve Jobs.  Steve wouldn&#8217;t just manufacture a computer, he would design a work of art (albeit a more expensive work of art).  And the operating system was, well, extremely easy to use.  Having an Apple computer is tantamount to having a love affair &#8211; a comment that I usually don&#8217;t hear from users of that other operating system.  Steve&#8217;s vision for what a computer should do for the user and how the user interacts with the computer was pure genius.  And being an ex-Unix admin, once the Mac OS switched to a Unix-based OS, I was even more smitten.</p>
<p>When I had heard the Steve Jobs had passed, I was sad.  Well, maybe a bit more than sad.  I was never really a big fan of Steve Jobs as a person, mainly because I really didn&#8217;t know a lot about him personally &#8211; I just loved his products, his vision.  When he would announce a new product, you could tell that he was really, really proud of what he had achieved.  He wasn&#8217;t just up on stage hawking widgets, he was introducing something truly historic.  Something that would cause other companies to scurry and to try and play catch-up (they rarely succeeded).  I can only hope that the team that he has placed at Apple will continue his legacy of producing innovation at the same level of genius that he has cultivated over the years.  If not, then I will also be sad for my two kids, as they won&#8217;t get to experience the joy of using a Macintosh as I have.  Steve Jobs, you will be missed.  Greatly.</p>
<p>&nbsp;
<p>
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<table width="100%">
<tr>
<td><img border="0" src="http://www.scriptingmysql.com/scriptingmysql/tony.jpg">
</td>
<td>
Tony Darnell is a Principal Sales Consultant for <a href="http://mysql.com/" />MySQL</a>, a division of <a href="http://oracle.com">Oracle</a>, Inc.  MySQL is the world&#8217;s most popular open-source database program.<br />
<br />Tony may be reached at info [at] ScriptingMySQL.com and on <a href="http://www.linkedin.com/in/tonydarnell">LinkedIn</a>.
</td>
</tr>
</table>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/scriptingmysql.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/scriptingmysql.wordpress.com/286/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/scriptingmysql.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/scriptingmysql.wordpress.com/286/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/scriptingmysql.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/scriptingmysql.wordpress.com/286/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/scriptingmysql.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/scriptingmysql.wordpress.com/286/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/scriptingmysql.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/scriptingmysql.wordpress.com/286/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/scriptingmysql.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/scriptingmysql.wordpress.com/286/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/scriptingmysql.wordpress.com/286/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/scriptingmysql.wordpress.com/286/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=286&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://scriptingmysql.wordpress.com/2011/10/06/steve-jobs-you-will-be-missed-greatly/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4a7803de89b97b14df8a346d36a1b9a1?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tonydarnell</media:title>
		</media:content>

		<media:content url="http://www.scriptingmysql.com/scriptingmysql/tony.jpg" medium="image" />
	</item>
		<item>
		<title>Sending and Managing Email Accounts in a MySQL Database using Perl</title>
		<link>http://scriptingmysql.wordpress.com/2011/09/30/sending-and-managing-email-accounts-in-a-mysql-database-using-perl/</link>
		<comments>http://scriptingmysql.wordpress.com/2011/09/30/sending-and-managing-email-accounts-in-a-mysql-database-using-perl/#comments</comments>
		<pubDate>Fri, 30 Sep 2011 16:19:04 +0000</pubDate>
		<dc:creator>Tony Darnell</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://scriptingmysql.wordpress.com/?p=273</guid>
		<description><![CDATA[A friend of mine has a small newsletter that he sends via email once a month. Initially, he was just blind-copying everyone on his list, but as the list grew, it was a pain for him to keep manually editing his BCC list. Also, some people weren&#8217;t receiving the newsletter as they had email filters [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=273&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>A friend of mine has a small newsletter that he sends via email once a month.  Initially, he was just blind-copying everyone on his list, but as the list grew, it was a pain for him to keep manually editing his BCC list.  Also, some people weren&#8217;t receiving the newsletter as they had email filters that would block emails that didn&#8217;t have their name in the &#8220;To&#8221; field.  And, he needed a way to allow people to opt-out of his newsletter without having to contact him directly.  His solution was that he wanted to use a MySQL database to send the email and manage his list, so that he could easily bypass the subscribers that had opted out. </p>
<p>We started by creating a MySQL table with just a few fields &#8211; ID, email_address and news_and_events.  The &#8220;news_and_events&#8221; field would be set to &#8220;yes&#8221; for those that wanted to receive the newsletter, and could be set to &#8220;no&#8221; if they wanted to opt-out.  Here is the database:<br />
<code><br />
CREATE TABLE `email_address_test` (<br />
  `id` int(5) NOT NULL AUTO_INCREMENT,<br />
  `email_address` varchar(50) NOT NULL,<br />
  `news_and_events` varchar(3) NOT NULL,<br />
  PRIMARY KEY (`id`)<br />
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1<br />
</code><br />
After he had imported all of the email addresses into the database (including setting the news_and_events column value to &#8220;yes&#8221;), we were ready to go.  We are using a Perl script to connect to the MySQL database and to retrieve all of the email addresses that have a value of &#8220;news_and_events = yes&#8221;.  We can then send each one an email with their email address in the &#8220;To&#8221; field.  We also create a log file to store the results.  To manage new subscribers, he modified his web site so that new email addresses would also be stored in the database.  An earlier post shows you how to insert information into a MySQL database via <a href="http://scriptingmysql.wordpress.com/2011/08/05/inserting-data-into-mysql-with-perl/" />Perl</a>.</p>
<p>This script uses a text file to store the database connectivity information.  (See this <a href="http://scriptingmysql.wordpress.com/2011/07/27/connecting-to-mysql-with-perl/" />earlier post</a> for instructions on how to use this text file).</p>
<p>This script also includes a &#8220;remove me&#8221; link (using a Perl script named remove_me.pl) in the email to allow people to opt-out of receiving future emails.  I include the remove_me.pl script below the main script.</p>
<p>Here is the main script to send email.  There are comments in the script to help you figure out how to modify the script for your use.<br />
<code><br />
#!/usr/bin/perl -w use strict;<br />
use DBI;</p>
<p>my $database;</p>
<p># create a log file to store the results<br />
open LOG, "&gt;filename.txt" or die "Cannot create output file: $!";</p>
<p>my $id;<br />
my $CurrentLine = 0;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# connect to database</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dbh = ConnectToMySql($database);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$query = "select email_address, id from email_address_test where news_and_events = \'yes\'";</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth = $dbh-&gt;prepare($query);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth-&gt;execute();</p>
<p>   while (@data = $sth-&gt;fetchrow_array()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  $email_address = $data[0];<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  $id = $data[1];</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# count the number of emails that we send<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$CurrentLine++;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
# edit this line to match the location of your sendmail program<br />
$sendmail = "/usr/sbin/sendmail -t";</p>
<p># you will need to modify this information<br />
$reply_to = "From: Scripting MySQL Blog &lt;info\@return_email.com&gt;\n";<br />
$from = "From: Scripting MySQL Blog &lt;info\@return_email.com&gt;\n";<br />
$subject = "Subject: Test email from MySQL\n";<br />
$to = "To: $email_address\n";</p>
<p># this is the body of the email - along with the unsubscribe script - remove_me.pl<br />
$content = "&lt;html&gt;&lt;body&gt;This is a test email.&lt;p&gt;" .</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"&lt;a href=\"http:\/\/cgi-bin/remove_me.pl?id=$id&amp;email_address=$email_address\"&gt;Remove me.&lt;\/a&gt;";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;open(SENDMAIL, "|$sendmail") or die "Cannot open $sendmail: $!";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print SENDMAIL $reply_to;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print SENDMAIL $from;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print SENDMAIL $subject;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print SENDMAIL $to;<br />
# use this line if you want to send a plain text email<br />
#&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print SENDMAIL "Content-type: text/plain\n\n";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print SENDMAIL "Content-type: text/html\n\n";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print SENDMAIL $content;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(SENDMAIL);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# comment these line if you don't want output to your monitor<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print "$CurrentLine Email sent to $email_address - $subject";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# comment this line if you don't want output to your log file<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print LOG "$CurrentLine Email sent to $email_address - $subject";</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# sleep X seconds after each email is sent<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep 1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
}</p>
<p>print "\nFinished...$CurrentLine emails were sent.\n";<br />
print LOG "\nFinished...$CurrentLine emails were sent.\n";</p>
<p>close(LOG);</p>
<p># for more information on this sub-routine and the use of the file accessBLOG, visit<br />
# http://scriptingmysql.wordpress.com/2011/07/27/connecting-to-mysql-with-perl/</p>
<p>#----------------------------------------------------------------------<br />
sub ConnectToMySql {<br />
#----------------------------------------------------------------------</p>
<p>   open(ACCESS_INFO, "&lt;..\/accessBLOG") || die "Can't access login credentials";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$database = &lt;ACCESS_INFO&gt;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$host = &lt;ACCESS_INFO&gt;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$userid = &lt;ACCESS_INFO&gt;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$passwd = &lt;ACCESS_INFO&gt;;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# the chomp() function will remove any newline character from the end of a string<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chomp ($database, $host, $userid, $passwd);</p>
<p>   my $connectionInfo="dbi:mysql:$database;$host";<br />
   close(ACCESS_INFO);</p>
<p>   # make connection to database<br />
   my $l_dbh = DBI-&gt;connect($connectionInfo,$userid,$passwd);<br />
   return $l_dbh;</p>
<p>}<br />
</code><br />
And here is the remove_me.pl script.  I don&#8217;t provide any error-checking to make sure that the news_and_events value is equal to &#8220;yes&#8221;, so you will need to edit the script if you want this functionality.<br />
<code><br />
#! /usr/bin/perl</p>
<p># DBI is the standard database interface for Perl<br />
# DBD is the Perl module that we use to connect to the MySQL database<br />
use DBI;<br />
use DBD::mysql;<br />
# use CGI for forms<br />
use CGI qw(:standard);</p>
<p>my $database;</p>
<p>$query = new CGI;</p>
<p>$id = $query-&gt;param("id");<br />
$email_address = $query-&gt;param("email_address");</p>
<p>print header;</p>
<p># connect to the database and update news_and_events to "no"</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dbh = ConnectToMySql($database);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$query = "update email_address_test set news_and_events = 'no' where id = '$id'";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth = $dbh-&gt;prepare($query);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth-&gt;execute();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$sth-&gt;finish;</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$dbh-&gt;disconnect;</p>
<p>print "Your email address $email_address has been removed.";</p>
<p>#----------------------------------------------------------------------<br />
sub ConnectToMySql {<br />
#----------------------------------------------------------------------</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;open(ACCESS_INFO, "&lt;..\/accessBLOG") || die "Can't access login credentials";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $database = &lt;ACCESS_INFO&gt;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $host = &lt;ACCESS_INFO&gt;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $userid = &lt;ACCESS_INFO&gt;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $passwd = &lt;ACCESS_INFO&gt;;</p>
<p># the chomp() function will remove any newline character from the end of a string<br />
chomp ($database, $host, $userid, $passwd);<br />
#print "&lt;br&gt;$database $host $userid $passwd &lt;br&gt;";</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $connectionInfo="dbi:mysql:$database;$host";<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;close(ACCESS_INFO);</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chomp($userid);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chomp($passwd);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;# make connection to database<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my $l_dbh = DBI-&gt;connect($connectionInfo,$userid,$passwd);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return $l_dbh;</p>
<p>}</p>
<p>exit;<br />
</code></p>
<p>&nbsp;
<p>
&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8211;<br />
<table width="100%">
<tr>
<td><img border="0" src="http://www.scriptingmysql.com/scriptingmysql/tony.jpg">
</td>
<td>
Tony Darnell is a Principal Sales Consultant for <a href="http://mysql.com/" />MySQL</a>, a division of <a href="http://oracle.com">Oracle</a>, Inc.  MySQL is the world&#8217;s most popular open-source database program.<br />
<br />Tony may be reached at info [at] ScriptingMySQL.com and on <a href="http://www.linkedin.com/in/tonydarnell">LinkedIn</a>.
</td>
</tr>
</table>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/scriptingmysql.wordpress.com/273/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/scriptingmysql.wordpress.com/273/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/scriptingmysql.wordpress.com/273/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/scriptingmysql.wordpress.com/273/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/scriptingmysql.wordpress.com/273/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/scriptingmysql.wordpress.com/273/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/scriptingmysql.wordpress.com/273/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/scriptingmysql.wordpress.com/273/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/scriptingmysql.wordpress.com/273/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/scriptingmysql.wordpress.com/273/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/scriptingmysql.wordpress.com/273/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/scriptingmysql.wordpress.com/273/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/scriptingmysql.wordpress.com/273/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/scriptingmysql.wordpress.com/273/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=scriptingmysql.wordpress.com&amp;blog=25354808&amp;post=273&amp;subd=scriptingmysql&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://scriptingmysql.wordpress.com/2011/09/30/sending-and-managing-email-accounts-in-a-mysql-database-using-perl/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://0.gravatar.com/avatar/4a7803de89b97b14df8a346d36a1b9a1?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">tonydarnell</media:title>
		</media:content>

		<media:content url="http://www.scriptingmysql.com/scriptingmysql/tony.jpg" medium="image" />
	</item>
	</channel>
</rss>
