The Software Workshop inc. - software that fits! ™                  ExtSQL - Extended SQL
.
 
. Home   Contact Us    login
.
 
 
 

    Home

    Documentation

    Downloads

    FAQ

    News & Events

    Privacy Policy

    Report Problem

    Support

    Terms & Conditions


Quick Feedback!
This is a new project,
feedback is welcome
(and will be read!)

Source for PostgreSQL patch set

--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/backend/utils/misc/Makefile	2008-02-19 05:30:09.000000000 -0500
+++ src/backend/utils/misc/Makefile	2009-11-28 09:57:35.000000000 -0500
@@ -15,5 +15,7 @@
 override CPPFLAGS := -I$(srcdir) $(CPPFLAGS)
 
-OBJS = guc.o help_config.o pg_rusage.o ps_status.o superuser.o tzparser.o
+# EXTSQL START
+OBJS = guc.o help_config.o pg_rusage.o ps_status.o superuser.o tzparser.o extsql.o
+# EXTSQL END
 
 # This location might depend on the installation directories. Therefore
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/backend/nodes/copyfuncs.c	2009-06-17 21:27:02.000000000 -0400
+++ src/backend/nodes/copyfuncs.c	2009-11-28 10:01:07.000000000 -0500
@@ -2926,4 +2926,65 @@
 }
 
+// EXTSQL START
+static VariableShowStatsStmt *
+_copyVariableShowStatsStmt(VariableShowStatsStmt *from)
+{
+	VariableShowStatsStmt *newnode = makeNode(VariableShowStatsStmt);
+
+	COPY_NODE_FIELD(stats_vars);
+        COPY_STRING_FIELD(stats_class);
+        COPY_STRING_FIELD(wild);
+        COPY_STRING_FIELD(stats_order_var);
+        COPY_STRING_FIELD(stats_where_var);
+        COPY_SCALAR_FIELD(stats_order_dir);
+        COPY_SCALAR_FIELD(stats_order_limit);
+        COPY_SCALAR_FIELD(stats_hourly);
+        COPY_SCALAR_FIELD(stats_where_num);
+        COPY_SCALAR_FIELD(stats_where_char);
+
+	return newnode;
+}
+
+static VariableStatisticsUsage *
+_copyVariableStatisticsUsage(VariableStatisticsUsage *from)
+{
+        VariableStatisticsUsage *newnode = makeNode(VariableStatisticsUsage);
+
+        return newnode;
+}
+
+static VariableStatisticsEnable *
+_copyVariableStatisticsEnable(VariableStatisticsEnable *from)
+{
+        VariableStatisticsEnable *newnode = makeNode(VariableStatisticsEnable);
+
+        COPY_SCALAR_FIELD(stats_status);
+  
+        return newnode;
+}
+
+static VariableStatisticsReset *
+_copyVariableStatisticsReset(VariableStatisticsReset *from)
+{
+        VariableStatisticsReset *newnode = makeNode(VariableStatisticsReset);
+
+        COPY_STRING_FIELD(config_file);
+
+        return newnode;
+}
+
+static VariableStatisticsFileIO *
+_copyVariableStatisticsFileIO(VariableStatisticsFileIO *from)
+{
+        VariableStatisticsFileIO *newnode = makeNode(VariableStatisticsFileIO);
+
+        COPY_SCALAR_FIELD(stats_io_mode);
+        COPY_SCALAR_FIELD(stats_confirm);
+        COPY_STRING_FIELD(stats_reload_file);
+
+        return newnode;
+}
+// EXTSQL END
+
 static DiscardStmt *
 _copyDiscardStmt(DiscardStmt *from)
@@ -3892,4 +3953,21 @@
 			retval = _copyVariableShowStmt(from);
 			break;
+                // EXTSQL START
+		case T_VariableShowStatsStmt:
+			retval = _copyVariableShowStatsStmt(from);
+			break;
+                case T_VariableStatisticsUsage:
+                        retval = _copyVariableStatisticsUsage(from);
+                        break;
+                case T_VariableStatisticsEnable:
+                        retval = _copyVariableStatisticsEnable(from);
+                        break;
+                case T_VariableStatisticsReset:
+                        retval = _copyVariableStatisticsReset(from);
+                        break;
+                case T_VariableStatisticsFileIO:
+                        retval = _copyVariableStatisticsFileIO(from);
+                        break;
+                // EXTSQL END
 		case T_DiscardStmt:
 			retval = _copyDiscardStmt(from);
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/backend/nodes/equalfuncs.c	2009-06-17 21:27:02.000000000 -0400
+++ src/backend/nodes/equalfuncs.c	2009-11-28 10:04:00.000000000 -0500
@@ -1510,4 +1510,54 @@
 }
 
+// EXTSQL START
+static bool
+_equalVariableShowStatsStmt(VariableShowStatsStmt *a, VariableShowStatsStmt *b)
+{
+	COMPARE_NODE_FIELD(stats_vars);
+        COMPARE_STRING_FIELD(stats_class);
+        COMPARE_STRING_FIELD(wild);
+        COMPARE_STRING_FIELD(stats_order_var);
+        COMPARE_STRING_FIELD(stats_where_var);
+        COMPARE_SCALAR_FIELD(stats_order_dir);
+        COMPARE_SCALAR_FIELD(stats_order_limit);
+        COMPARE_SCALAR_FIELD(stats_where_num);
+        COMPARE_SCALAR_FIELD(stats_where_char);
+
+	return true;
+}
+
+static bool
+_equalVariableStatisticsUsage(VariableStatisticsUsage *a, VariableStatisticsUsage *b)
+{
+        return true;
+}
+
+static bool
+_equalVariableStatisticsEnable(VariableStatisticsEnable *a, VariableStatisticsEnable *b)
+{
+        COMPARE_SCALAR_FIELD(stats_status);
+  
+        return true;
+}
+
+static bool
+_equalVariableStatisticsReset(VariableStatisticsReset *a, VariableStatisticsReset *b)
+{
+        COMPARE_STRING_FIELD(config_file);
+
+        return true;
+}
+
+static bool
+_equalVariableStatisticsFileIO(VariableStatisticsFileIO *a, VariableStatisticsFileIO *b)
+{
+        COMPARE_SCALAR_FIELD(stats_io_mode);
+        COMPARE_SCALAR_FIELD(stats_confirm);
+        COMPARE_STRING_FIELD(stats_reload_file);
+
+        return true;
+}
+// EXTSQL END
+
 static bool
 _equalDiscardStmt(DiscardStmt *a, DiscardStmt *b)
@@ -2669,4 +2719,21 @@
 			retval = _equalVariableShowStmt(a, b);
 			break;
+                // EXTSQL START
+		case T_VariableShowStatsStmt:
+			retval = _equalVariableShowStatsStmt(a, b);
+			break;
+                case T_VariableStatisticsUsage:
+                        retval = _equalVariableStatisticsUsage(a, b);
+                        break;
+                case T_VariableStatisticsEnable:
+                        retval = _equalVariableStatisticsEnable(a, b);
+                        break;
+                case T_VariableStatisticsReset:
+                        retval = _equalVariableStatisticsReset(a, b);
+                        break;
+                case T_VariableStatisticsFileIO:
+                        retval = _equalVariableStatisticsFileIO(a, b);
+                        break;
+                // EXTSQL END
 		case T_DiscardStmt:
 			retval = _equalDiscardStmt(a, b);
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/backend/parser/gram.y	2009-07-05 22:58:48.000000000 -0400
+++ src/backend/parser/gram.y	2009-11-28 10:10:19.000000000 -0500
@@ -391,4 +391,13 @@
 %type 	TableLikeOptionList
 %type 	TableLikeOption
+
+/* EXTSQL START */
+ %type     stats_order_dir stats_compare stats_hourly stats_limit_clause
+                 maybe_confirm
+ %type     wild  stats_class stats_var maybe_file_name
+ %type    stats_var_list
+ %type    stats_where_clause stats_order_clause StatisticsStmt
+/* EXTSQL END */
+
 %type 	ColQualList
 %type 	ColConstraint ColConstraintElem ConstraintAttr
@@ -456,4 +465,9 @@
 	HANDLER HAVING HEADER_P HOLD HOUR_P
 
+        /* EXTSQL START */
+        CONFIRM
+        HISTORY
+        /* EXTSQL END */
+
 	IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P
 	INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY
@@ -690,4 +704,7 @@
 			| RuleStmt
 			| SelectStmt
+                        // EXTSQL START
+                        | StatisticsStmt
+                        // EXTSQL END
 			| TransactionStmt
 			| TruncateStmt
@@ -1400,4 +1417,38 @@
 					$$ = (Node *) n;
 				}
+                        /* EXTSQL START */   
+                        | SHOW STATISTICS
+                                {
+                                        VariableShowStatsStmt *n = makeNode(VariableShowStatsStmt);
+					n->stats_vars = NULL;
+                                        n->stats_class = NULL;
+                                        n->wild = NULL;
+                                        n->stats_where_var = NULL;
+                                        n->stats_where_num = 0;
+                                        n->stats_where_char = '0';
+                                        n->stats_order_var = NULL;
+                                        n->stats_order_dir = 0;
+                                        n->stats_hourly = 0;
+                                        n->stats_order_limit = 0;
+					$$ = (Node *) n;
+                                }
+                                        
+                                           /*  3           4      5          6          7                   8               9            10 */
+			| SHOW STATISTICS stats_var_list  FROM stats_class  wild stats_where_clause stats_order_clause stats_hourly stats_limit_clause
+				{
+					VariableShowStatsStmt *n = makeNode(VariableShowStatsStmt);
+					n->stats_vars = $3;
+                                        n->stats_class = $5;
+                                        n->wild = $6;
+                                        n->stats_where_var = ((VariableShowStatsStmt *) $7)->stats_where_var;
+                                        n->stats_where_num = ((VariableShowStatsStmt *) $7)->stats_where_num;
+                                        n->stats_where_char = ((VariableShowStatsStmt *) $7)->stats_where_char;
+                                        n->stats_order_var = ((VariableShowStatsStmt *) $8)->stats_order_var;
+                                        n->stats_order_dir = ((VariableShowStatsStmt *) $8)->stats_order_dir;
+                                        n->stats_hourly = $9;
+                                        n->stats_order_limit = $10;
+					$$ = (Node *) n;
+				}
+                        /* EXTSQL END */
 			| SHOW TIME ZONE
 				{
@@ -1426,4 +1477,152 @@
 		;
 
+/* EXTSQL START */
+
+stats_class: 
+        '*' { $$ = "*"; }
+        | ColId ;
+
+stats_compare:
+        '='      { $$ = '='; }
+        | '<'   { $$ = '<'; }
+        | '>' { $$ = '>'; };
+       
+stats_hourly :
+	/* empty */         { $$=0; }
+	| HISTORY	    { $$=1; };
+
+stats_limit_clause:
+        /* empty */	
+           { 
+              $$ = 0; 
+           }
+       
+	| LIMIT ICONST
+           { 
+              $$ = $2;
+           }
+        ;
+
+stats_order_clause:
+          /* empty */
+        { 
+          VariableShowStatsStmt *n = makeNode(VariableShowStatsStmt);
+          n->stats_order_var =  NULL;
+          n->stats_order_dir =  0 ;
+          $$ = (Node *) n; 
+        }
+
+        | ORDER BY stats_var stats_order_dir
+        { 
+
+          VariableShowStatsStmt *n = makeNode(VariableShowStatsStmt);
+          n->stats_order_var =  $3;
+          n->stats_order_dir =  $4 ;
+          $$ = (Node *) n; 
+        }
+        ;
+
+stats_order_dir:
+	/* empty */ { $$ =  1; }
+	| ASC  { $$ =1; }
+	| DESC { $$ =0; };
+
+stats_var:  '*' 
+        | ColId ;
+
+stats_var_list:  
+         stats_var_list ',' stats_var    { $$ = lappend($1, makeString($3)); }
+			| stats_var	{ $$ = list_make1(makeString($1)); }
+		;
+
+stats_where_clause:
+          /* empty */ 
+          {
+          VariableShowStatsStmt *n = makeNode(VariableShowStatsStmt);
+          n->stats_where_var = NULL;
+          n->stats_where_char = 0;
+          n->stats_where_num = 0; 
+          $$ = (Node *) n; 
+         }
+
+          | WHERE stats_var stats_compare ICONST 
+          {
+          VariableShowStatsStmt *n = makeNode(VariableShowStatsStmt);
+          n->stats_where_var = $2;
+          n->stats_where_char = $3;
+          n->stats_where_num = $4; 
+          $$ = (Node *) n; 
+          }
+          ;
+
+wild:
+       LIKE SCONST { $$ = $2; }
+| /* empty */{ $$ = NULL;}  ;
+
+
+StatisticsStmt:
+          STATISTICS
+          {
+            VariableStatisticsUsage *n = makeNode(VariableStatisticsUsage);
+            $$ = (Node *) n;
+          }
+          | STATISTICS ON
+          {
+            VariableStatisticsEnable *n = makeNode(VariableStatisticsEnable);
+            n->stats_status = 1;
+            $$ = (Node *) n;
+          }
+          | STATISTICS OFF
+          {
+            VariableStatisticsEnable *n = makeNode(VariableStatisticsEnable);
+            n->stats_status = 0;
+            $$ = (Node *) n;
+          }
+          | STATISTICS RESET maybe_file_name
+          {
+            VariableStatisticsReset *n = makeNode(VariableStatisticsReset);
+            n->config_file = $3;
+            $$ = (Node *) n;
+          }
+          | STATISTICS READ maybe_confirm file_name
+          {
+            VariableStatisticsFileIO *n = makeNode(VariableStatisticsFileIO);
+            n->stats_io_mode = 0;
+            n->stats_confirm = $3;
+            n->stats_reload_file = $4;
+            $$ = (Node *) n;
+          }
+          | STATISTICS WRITE file_name
+          {
+            VariableStatisticsFileIO *n = makeNode(VariableStatisticsFileIO);
+            n->stats_io_mode = 1;
+            n->stats_confirm = 0;
+            n->stats_reload_file = $3;
+            $$ = (Node *) n;
+          }
+          ;
+
+maybe_file_name:
+          /* nothing */
+          {
+            $$ = NULL;
+          }
+          | file_name
+          {
+            $$ = $1;
+          }
+          ;
+
+maybe_confirm:
+          /* nothing */
+          {
+            $$ = 0;
+          }
+          | CONFIRM
+          {
+            $$ = 1;
+          }
+          ;
+/* EXTSQL END */
 
 ConstraintsSetStmt:
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/backend/postmaster/postmaster.c	2009-08-24 16:08:40.000000000 -0400
+++ src/backend/postmaster/postmaster.c	2009-11-28 13:50:13.000000000 -0500
@@ -1024,4 +1024,21 @@
 	load_ident();
 
+        // EXTSQL START
+        int startType = 0;
+          
+        // if the default config params contain a non null
+        // extsql_reload_file and its contents look valid, we will set
+        // startType to STATS_INIT_RELOAD, otherwise STATS_INIT_NORMAL
+        elog(LOG, "ExtSQL(postmaster): ready to call extsql_prep and extsql_init");
+        extsql_prep(&startType, NULL, extsql_reload_file);
+         
+        // if reload fails here, just do a regular startup
+        if (startType == STATS_INIT_FAILURE) { 
+          startType = STATS_INIT_NORMAL; 
+        }
+
+        extsql_init(Shared->extsql_class_list, startType, Shared->extsql_reload_file);
+        // EXTSQL END
+
 	/*
 	 * Remember postmaster startup time
@@ -4034,4 +4051,9 @@
 ExitPostmaster(int status)
 {
+        // EXTSQL START
+        if (*extsql_reload_file)
+          if (extsql_reload(STATS_WRITE_RELOAD, extsql_reload_file))
+            sql_print_error("ExtSQL: Error encountered during reload WRITE");
+        // EXTSQL END
 	/* should cleanup shared memory and kill all backends */
 
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/backend/tcop/pquery.c	2009-06-11 10:49:02.000000000 -0400
+++ src/backend/tcop/pquery.c	2009-11-28 13:59:56.000000000 -0500
@@ -1176,4 +1176,11 @@
 		  IsA(utilityStmt, VariableSetStmt) ||
 		  IsA(utilityStmt, VariableShowStmt) ||
+                  // EXTSQL START
+                  IsA(utilityStmt, VariableShowStatsStmt) ||
+                  IsA(utilityStmt, VariableStatisticsUsage) ||
+                  IsA(utilityStmt, VariableStatisticsEnable) ||
+                  IsA(utilityStmt, VariableStatisticsReset) ||
+                  IsA(utilityStmt, VariableStatisticsFileIO) ||
+                  // EXTSQL END 
 		  IsA(utilityStmt, ConstraintsSetStmt) ||
 	/* efficiency hacks from here down */
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/backend/tcop/utility.c	2009-06-11 16:46:11.000000000 -0400
+++ src/backend/tcop/utility.c	2009-11-28 13:58:22.000000000 -0500
@@ -58,4 +58,9 @@
 #include "utils/syscache.h"
 
+// EXTSQL START
+#ifndef EXTSQL_H
+#include "utils/extsql.h"
+#endif
+// EXTSQL END
 
 /*
@@ -924,4 +929,62 @@
 			break;
 
+                // EXTSQL START
+		case T_VariableShowStatsStmt:
+			{
+                                char varList[100] = {'\0'};
+                                VariableShowStatsStmt *n = (VariableShowStatsStmt *) parsetree;
+
+                                if (0) {
+                                elog(LOG, "ExtSQL: internal variables (%s) class %s, \
+  hourly %d, wild %s, ORDER BY %s, direction %d, LIMIT %d,              \
+  WHERE  var %s, compare %d, value %d", 
+                                     varList, n->stats_class, n->stats_hourly, n->wild,
+                                     n->stats_order_var,
+                                     n->stats_order_dir, n->stats_order_limit,
+                                     n->stats_where_var, 
+                                     n->stats_where_char, n->stats_where_num);
+                                
+                                }
+                                
+                                mysql_show_extsql(MyProc, n->stats_class, dest, n->stats_vars,
+                                                  n->stats_hourly, n->wild, n->stats_order_var,
+                                                  n->stats_order_dir, n->stats_order_limit,
+                                                  n->stats_where_var, n->stats_where_num,
+                                                  n->stats_where_char);
+                        }
+			break;
+
+                case T_VariableStatisticsUsage:
+                        {
+                                extsql_usage(MyProc, dest);
+                        }
+                        break;
+
+                case T_VariableStatisticsEnable:
+                        {
+                                VariableStatisticsEnable *n = (VariableStatisticsEnable *) parsetree;
+                                
+                                extsql_enable(MyProc, dest, n->stats_status);
+                        }
+                        break;
+
+                case T_VariableStatisticsReset:
+                        {
+                                VariableStatisticsReset *n = (VariableStatisticsReset *) parsetree;
+
+                                extsql_reset(MyProc, dest, n->config_file);
+                        }
+                        break;
+
+                case T_VariableStatisticsFileIO:
+                        {
+                                VariableStatisticsFileIO *n = (VariableStatisticsFileIO *) parsetree;
+
+                                extsql_file_io(MyProc, dest, n->stats_io_mode,
+                                               n->stats_confirm, n->stats_reload_file);
+                        }
+                        break;
+                // EXTSQL END
+
 		case T_DiscardStmt:
 			DiscardCommand((DiscardStmt *) parsetree, isTopLevel);
@@ -1151,4 +1214,21 @@
 			return true;
 
+                // EXTSQL START
+                case T_VariableShowStatsStmt:
+ 			return false;
+
+                case T_VariableStatisticsUsage:
+                        return false;
+
+                case T_VariableStatisticsEnable:
+                        return false;
+
+                case T_VariableStatisticsReset:
+                        return false;
+                        
+                case T_VariableStatisticsFileIO:
+                        return false;
+                // EXTSQL END
+
 		default:
 			return false;
@@ -1205,4 +1285,38 @@
 			}
 
+                // EXTSQL START
+		case T_VariableShowStatsStmt:
+			{
+				VariableShowStatsStmt *n = (VariableShowStatsStmt *) parsetree;
+
+				return GetPGVariableResultDesc(n->stats_class); 
+			}
+                        
+                case T_VariableStatisticsUsage:
+			{
+                                return NULL;
+			}
+
+                case T_VariableStatisticsEnable:
+			{
+				VariableStatisticsEnable *n = (VariableStatisticsEnable *) parsetree;
+
+				return GetPGVariableResultDesc(n->stats_status); 
+			}
+
+                case T_VariableStatisticsReset:
+			{
+				VariableStatisticsReset *n = (VariableStatisticsReset *) parsetree;
+
+				return GetPGVariableResultDesc(n->config_file); 
+			}
+                case T_VariableStatisticsFileIO:
+			{
+				VariableStatisticsFileIO *n = (VariableStatisticsFileIO *) parsetree;
+
+				return GetPGVariableResultDesc(n->stats_reload_file); 
+			}
+                // EXTSQL END
+
 		default:
 			return NULL;
@@ -1262,4 +1376,8 @@
 	const char *tag;
 
+        // EXTSQL START  ZZ - put a function call here to capture all
+        extsql_inc(&Questions, 1);
+        // EXTSQL END
+
 	switch (nodeTag(parsetree))
 	{
@@ -1267,16 +1385,28 @@
 		case T_InsertStmt:
 			tag = "INSERT";
+                        // EXTSQL START
+                        extsql_inc(&Com_insert, 1);
+                        // EXTSQL END
 			break;
 
 		case T_DeleteStmt:
 			tag = "DELETE";
+                        // EXTSQL START
+                        extsql_inc(&Com_delete, 1);
+                        // EXTSQL END
 			break;
 
 		case T_UpdateStmt:
 			tag = "UPDATE";
+                        // EXTSQL START
+                        extsql_inc(&Com_update, 1);
+                        // EXTSQL END
 			break;
 
 		case T_SelectStmt:
 			tag = "SELECT";
+                        // EXTSQL START
+                        extsql_inc(&Com_select, 1);
+                        // EXTSQL END
 			break;
 
@@ -1290,4 +1420,7 @@
 					case TRANS_STMT_BEGIN:
 						tag = "BEGIN";
+                                               // EXTSQL START
+                                                extsql_inc(&Com_begin, 1);
+                                                // EXTSQL END
 						break;
 
@@ -1298,4 +1431,7 @@
 					case TRANS_STMT_COMMIT:
 						tag = "COMMIT";
+                                               // EXTSQL START
+                                                extsql_inc(&Com_commit, 1);
+                                                // EXTSQL END
 						break;
 
@@ -1303,4 +1439,7 @@
 					case TRANS_STMT_ROLLBACK_TO:
 						tag = "ROLLBACK";
+                                                // EXTSQL START
+                                                extsql_inc(&Com_rollback, 1);
+                                                // EXTSQL END
 						break;
 
@@ -1365,4 +1504,7 @@
 		case T_CreateStmt:
 			tag = "CREATE TABLE";
+                        // EXTSQL START
+                        extsql_inc(&Com_create_table, 1);
+                        // EXTSQL END
 			break;
 
@@ -1416,4 +1558,7 @@
 				case OBJECT_TABLE:
 					tag = "DROP TABLE";
+					// EXTSQL START
+					extsql_inc(&Com_drop_table, 1);
+					// EXTSQL END
 					break;
 				case OBJECT_SEQUENCE:
@@ -1828,4 +1973,26 @@
 			break;
 
+                // EXTSQL START
+		case T_VariableShowStatsStmt:
+			tag = "SHOW STATISTICS";
+			break;
+
+                case T_VariableStatisticsUsage:
+                        tag = "STATISTICS";
+                        break;
+
+                case T_VariableStatisticsEnable:
+                        tag = "STATISTICS";
+                        break;
+                        
+                case T_VariableStatisticsReset:
+                        tag = "STATISTICS";
+                        break;
+                        
+                case T_VariableStatisticsFileIO:
+                        tag = "STATISTICS";
+                        break;
+                // EXTSQL END
+
 		case T_DiscardStmt:
 			switch (((DiscardStmt *) parsetree)->target)
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/backend/utils/init/postinit.c	2009-07-08 13:53:32.000000000 -0400
+++ src/backend/utils/init/postinit.c	2009-11-28 14:02:41.000000000 -0500
@@ -652,4 +652,27 @@
 		pgstat_bestart();
 
+        // EXTSQL START
+        if (bootstrap) {
+          int startType = 0;
+          
+          // if the default config params contain a non null
+          // extsql_reload_file and its contents look valid, we will set
+          // startType to STATS_INIT_RELOAD, otherwise STATS_INIT_NORMAL
+          // elog(LOG, "ExtSQL(postinit-1): ready to call extsql_prep and extsql_init");
+          extsql_prep(&startType, NULL, extsql_reload_file);
+
+          // if reload fails here, just do a regular startup
+          if (startType == STATS_INIT_FAILURE) { 
+            startType = STATS_INIT_NORMAL; 
+          }
+          extsql_init(Shared->extsql_class_list, startType, Shared->extsql_reload_file);
+
+        } else {
+          // elog(LOG, "ExtSQL(postinit-2): skip extsql_prep, ready to call extsql_thread_init");
+          extsql_thread_init(MyProc, STATS_THD_INIT_NORM);
+          
+        }
+        // EXTSQL END
+
 	/* close the transaction we started above */
 	if (!bootstrap)
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/backend/utils/misc/guc.c	2009-09-03 18:08:14.000000000 -0400
+++ src/backend/utils/misc/guc.c	2009-11-29 09:09:33.000000000 -0500
@@ -1641,4 +1641,33 @@
 	},
 
+        // EXTSQL START
+        {
+          {"extsql_active", PGC_POSTMASTER, DEVELOPER_OPTIONS,
+           gettext_noop("Set the Extended Statistics internal debug level for output to error log. Use with caution!"),
+           NULL
+          },
+          (int *)&extsql_active,
+          0, 0, INT_MAX, NULL, NULL
+        },
+
+        {
+          {"extsql_counter", PGC_POSTMASTER, DEVELOPER_OPTIONS,
+           gettext_noop("Set the Extended Statistics internal counter. Use with caution!"),
+           NULL
+          },
+          (int *)&extsql_counter,
+          0, 0, INT_MAX, NULL, NULL
+        },
+
+        {
+          {"extsql_debug", PGC_POSTMASTER, DEVELOPER_OPTIONS,
+           gettext_noop("Set the Extended Statistics debug level for output to error log. Use with caution!"),
+           NULL
+          },
+          (int *)&extsql_debug,
+          0, 0, INT_MAX, NULL, NULL
+        },
+        // EXTSQL END
+
 	{
 		{"commit_delay", PGC_USERSET, WAL_SETTINGS,
@@ -2301,4 +2330,42 @@
 	},
 
+        // EXTSQL START
+        {
+          {"extsql_class_list", PGC_POSTMASTER, DEVELOPER_OPTIONS,
+           gettext_noop("This is a specially formatted list of class definitions that define what statistics are collected."),
+           NULL
+          },
+          &extsql_class_list,
+          "", NULL, NULL
+        },
+
+        {
+          {"extsql_key", PGC_POSTMASTER, DEVELOPER_OPTIONS,
+           gettext_noop("This is a license key used with a binary distribution of ExtSQL."),
+           NULL
+          },
+          &extsql_key,
+          "", NULL, NULL
+        },
+
+        {
+          {"extsql_users", PGC_POSTMASTER, DEVELOPER_OPTIONS,
+           gettext_noop("This contains an additional list of userids allowed to run statistics (root always can)."),
+           NULL
+          },
+          &extsql_users,
+          "", NULL, NULL
+        },
+
+        {
+          {"extsql_reload_file", PGC_POSTMASTER, DEVELOPER_OPTIONS,
+           gettext_noop("Allow the server to record statistics data in the specified file and reload upon restart."),
+           NULL
+          },
+          &extsql_reload_file,
+          "", NULL, NULL
+        },
+        // EXTSQL END
+
 	{
 		/* Not for general use --- used by SET ROLE */
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/include/nodes/nodes.h	2009-06-11 10:49:11.000000000 -0400
+++ src/include/nodes/nodes.h	2009-11-28 14:08:32.000000000 -0500
@@ -291,4 +291,11 @@
 	T_VariableSetStmt,
 	T_VariableShowStmt,
+        /* EXTSQL START */
+	T_VariableShowStatsStmt, 
+        T_VariableStatisticsUsage,
+        T_VariableStatisticsEnable,
+        T_VariableStatisticsReset,
+        T_VariableStatisticsFileIO,
+        /* EXTSQL END */
 	T_DiscardStmt,
 	T_CreateTrigStmt,
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/include/nodes/parsenodes.h	2009-06-17 21:27:02.000000000 -0400
+++ src/include/nodes/parsenodes.h	2009-11-28 14:11:34.000000000 -0500
@@ -1314,4 +1314,69 @@
 } VariableShowStmt;
 
+/* EXTSQL START */
+/* ----------------------
+ * Show Statistics Statement
+ * ----------------------
+ */
+
+typedef struct VariableShowStatsStmt
+{
+  NodeTag		type;
+  List	     *stats_vars;
+  char       *stats_class;
+  char       *wild;
+  char       *stats_order_var;
+  char       *stats_where_var;
+  int        stats_order_dir;
+  int        stats_order_limit;
+  int        stats_hourly;
+  int        stats_where_num;
+  int        stats_where_char;
+} VariableShowStatsStmt;
+
+/* ----------------------
+ * Statistics Statement
+ * ----------------------
+ */
+
+typedef struct VariableStatisticsUsage
+{
+  NodeTag    type;
+} VariableStatisticsUsage;
+
+/* ----------------------
+ * Statistics ON|OFF Statement
+ * ----------------------
+ */
+
+typedef struct VariableStatisticsEnable
+{
+  NodeTag    type;
+  int        stats_status;
+} VariableStatisticsEnable;
+
+/* ----------------------
+ * Statistics RESET Statement
+ * ----------------------
+ */
+
+typedef struct VariableStatisticsReset
+{
+  NodeTag    type;
+  char       *config_file;
+} VariableStatisticsReset;
+
+/* ----------------------
+ * Statistics READ|WRITE Statement
+ * ----------------------
+ */
+typedef struct VariableStatisticsFileIO
+{
+  NodeTag    type;
+  int        stats_io_mode, stats_confirm;
+  char       *stats_reload_file;
+} VariableStatisticsFileIO;
+/* EXTSQL END */
+
 /* ----------------------
  *		Create Table Statement
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/include/storage/proc.h	2009-02-23 04:28:50.000000000 -0500
+++ src/include/storage/proc.h	2009-11-28 14:13:14.000000000 -0500
@@ -99,4 +99,12 @@
 	struct PGPROC *lwWaitLink;	/* next waiter for same LW lock */
 
+        // EXTSQL START
+        #define STATS_MAX_CLASSES 7
+        int     statIndex[STATS_MAX_CLASSES]; // ZZ - stores the indexes to use when incrementing 
+                                              // quick lookup into statsData
+
+        int     statVerify; // store the magic here to verify a good set
+        // EXTSQL END
+
 	/* Info about lock the process is currently waiting for, if any. */
 	/* waitLock and waitProcLock are NULL if not currently waiting. */
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/include/tcop/dest.h	2009-06-11 10:49:12.000000000 -0400
+++ src/include/tcop/dest.h	2009-11-28 14:14:46.000000000 -0500
@@ -123,4 +123,7 @@
 	CommandDest mydest;
 	/* Private fields might appear beyond this point... */
+        // EXTSQL START
+        int verify;
+        // EXTSQL END
 };
 
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/include/utils/guc.h	2009-09-03 18:08:14.000000000 -0400
+++ src/include/utils/guc.h	2009-11-28 14:15:42.000000000 -0500
@@ -18,4 +18,7 @@
 #include "utils/array.h"
 
+// EXTSQL START
+#include "utils/extsql.h"
+// EXTSQL END
 
 /*
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/include/parser/kwlist.h	2009-04-06 04:42:53.000000000 -0400
+++ src/include/parser/kwlist.h	2009-11-28 10:14:27.000000000 -0500
@@ -85,4 +85,7 @@
 PG_KEYWORD("concurrently", CONCURRENTLY, UNRESERVED_KEYWORD)
 PG_KEYWORD("configuration", CONFIGURATION, UNRESERVED_KEYWORD)
+// EXTSQL START
+PG_KEYWORD("confirm", CONFIRM, UNRESERVED_KEYWORD)
+// EXTSQL END 
 PG_KEYWORD("connection", CONNECTION, UNRESERVED_KEYWORD)
 PG_KEYWORD("constraint", CONSTRAINT, RESERVED_KEYWORD)
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/backend/utils/misc/extsql.c	1969-12-31 19:00:00.000000000 -0500
+++ src/backend/utils/misc/extsql.c	2009-12-01 08:13:40.000000000 -0500
@@ -0,0 +1,4437 @@
+/* Copyright (C) 2006, 2007, 2008, 2009, 2010 Software Workshop Incorporated
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#define PGSQL 1
+
+#ifdef PGSQL
+#include "utils/extsql.h"
+
+#else // MYSQL
+
+#include "mysql_priv.h"
+#include "stacktrace.h"
+
+#endif  // PGSQL or MYSQL
+
+//  DEBUG FLAGS  -- we show decimal, has to be used in SET GLOBAL extsql_debug= val
+#define STATS_DUMP           1    // dump stats internal data on every SHOW command
+#define STATS_DUMP_ONCE      2    // just dump it once and clear stats_debug ZZ
+#define STATS_SHOW_PARAMS    4    // show parameters to SHOW STATISTICS
+#define STATS_INC_PARAMS     8    // print warning on bad param to extsql_inc
+#define STATS_ADMIN          16   // allow write/read/reset commands
+#define STATS_TEST_TWO       32   // testing
+#define STATS_INC_VAR        64   // show details on stats increment
+#define STATS_THD_INIT_PARAMS  128  // show parameters on thread init
+#define STATS_THD_INIT_LOOP    256  // show search for matching/new instance of class
+#define STATS_DISABLE_INC      512  // disable extsql_inc processing
+#define STATS_THREAD_CHK      1024  // do a check of the thread on each inc, only print errors
+#define STATS_DUMP_START      2048  // dump all tracking info at server start 
+#define STATS_TIME_DETAIL     4096  // show start secs/minutes if min/hour are units
+#define STATS_EXTRA_VARS      8192  // allow user to select untested vars for tracking
+#define STATS_MEM_ALLOC      16384  // show startup mem allocs
+#define STATS_TIME_CHANGE    32768  // show start of time roll over processing
+#define STATS_RELOAD         65536  // show reload processing
+#define STATS_TEST_ONE      131072  // testing
+#define STATS_PID           262144  // show server pid as part of show statistics, for gdb
+
+#define PROG_POINT(x,y)   sql_print_information("ExtSQL: PROGRESS POINT %s (0x%x)", x, y)
+
+// LIMITS
+#define STATS_MAX_TIME_LABEL   20
+#define STATS_WARNING_LIMIT 10
+
+#define MAX_BUFF_SIZE 2048  // used for temporary buffs of user input (product of next two)
+#define MAX_VAR_SIZE 45     // max length we allows for a Var name that is tracked.
+#define MAX_VARS_IN_CLASS 50  // max number of vars in single class def & row of output
+#define DATE_SIZE 30
+
+// MISC
+#define ARRAY_INDEX(i,j,size_j,k,size_k) ( (i * size_j +j) * size_k + k)
+
+
+// just testing
+
+time_t StartTime;
+
+// GLOBAL's defined in GLOBAL struct, extsql.h, 
+//  few vars here where compiler needs static addresses. Set global in extsql_init_globals
+
+// these are globals initially set in postgresql.conf -- extsql_init has not been called yet,
+// need to have a static address allocated, extsql_init_globals will then copy to Shared.
+ulong extsql_active=0, extsql_counter=0, extsql_debug=0, queries=0, connects=0;
+char  *extsql_class_list=NULL, *extsql_reload_file=NULL;
+
+
+#ifdef PGSQL
+
+pGLOBAL Shared; // Used for shared memory/globals - only dynamic allocation at start.
+
+#else // MYSQL
+
+GLOBAL GShared;  // can be static, shared between threads
+pGLOBAL Shared = &GShared;
+
+#endif
+
+
+// CONSTANT GLOBALS HERE 
+
+char *extsqlClassesSupported[STATS_MAX_CLASSES] = {"condb", "conuser", "db", "host", "server", "user", NULL};
+char *extsql_key, *extsql_users; 
+static char *extsql_version = "\nExtSQL version: __STATS_VERSION__\n"; // keep \n at start and end!
+
+
+// vars we have tested and confirmed with, they can set STATS_EXTRA_VARS to override.
+static  char *allowedVarsArray[MAX_VARS] = {"Com_begin", "Com_commit", "Com_create_table", 
+            "Com_delete", "Com_drop_table", "Com_insert", "Com_lock_tables", "Com_replace", 
+            "Com_rollback", "Com_select", "Com_set_option", "Com_show_fields", "Com_stmt_execute", 
+            "Com_stmt_prepare", "Com_update", "Connections", "Created_tmp_tables", 
+            "Created_tmp_disk_tables", "Handler_read_rnd", "Handler_read_rnd_next", 
+            "Qcache_hits", "Questions", "Select_full_join", "Select_range_check", 
+            "Select_scan", "Slow_queries", NULL };
+
+static  char *startTypeName[] = { "FAILURE", "NORMAL", "RESET", "RELOAD" };
+
+char **allowedVars = allowedVarsArray;
+
+static char *adminDisabled = "ExtSQL: In this release STATISTICS RESET/READ/WRITE are disabled by default due \
+to incomplete testing. If you wish to use these commands you must added the following to the server \
+config file and restart the server:   extsql_debug = 16";
+
+
+// FUNCTION prototypes
+
+int extsql_init_globals(void);
+static void extsql_stats_dump(void);
+static void extsql_thread_dump(THD *thd, int doDump);
+static int extsql_store_var_addr(char *varAddr);
+static void extsql_init_proc_vars(int *threadID, int *command, char **user, char **db, char **host,
+                                  char **proc_info, int **indexPtr, int **statVerify);
+
+
+#ifdef PGSQL
+
+ulong Com_begin, Com_commit, Com_create_table, Com_delete, 
+  Com_drop_table, Com_insert, Com_rollback, Com_select, Com_update, Connections, Questions;
+
+char *ShmemPtr = NULL;  // for shared memory
+static slock_t  *MemLock = NULL; // spin lock needs to be in shared mem region.
+char **NextFree = NULL;  // for shared memory!
+
+struct show_var_st status_vars[] = {
+  {"Com_begin", &Com_begin},
+  {"Com_commit", &Com_commit},
+  {"Com_create_table", &Com_create_table},
+  {"Com_delete", &Com_delete},
+  {"Com_drop_table", &Com_drop_table},
+  {"Com_insert", &Com_insert},
+  {"Com_rollback", &Com_rollback},
+  {"Com_select", &Com_select},
+  {"Com_update", &Com_update},
+  {"Connections", &Connections},
+  {"Questions", &Questions},
+  {NullS, (ulong *) 0}
+};
+char *command_name[] = {"n/a for pgsql", "n/a for pgsql", NULL};
+
+// change in number of args from 7.4.19 -> 8.4
+#ifdef PGSQL_8
+#define TupleDescInitEntry(a,b,c,d,e,f,g)  TupleDescInitEntry(a,b,c,d,e,f)
+#endif
+
+int mysql_show_extsql(THD *thd, const char *stats_class, DestReceiver *dest, List *stats_vars,
+                      uint stats_hourly, const char *wild, char *stats_order_var,
+                      const uint stats_order_dir, const uint stats_order_limit, char *stats_where_var,
+                      const uint stats_where_num, const uint stats_where_char);
+
+#define SHMEM_SIZE    1000000   // ZZ - need to predict based on class list for pgsql
+#define SHMEM_RESERVE  100000
+
+// need our own my_malloc to zero alloc'd memory
+// NOTE - this allocs from our limited shared memory area, we don't FREE. This should
+// only be used for extsql data
+// Temporary buffers used for i/o should be alloced with just "malloc/free"
+char * extsql_malloc(int, uint);
+char * extsql_malloc(int size, uint flags) {  // from our shared memory segment, pointed at by ShmemPtr;
+
+  char 	   *newStart; // similiar code in shmem.c
+  char 	   *newFree;
+  char	   *addr;
+
+
+  if (ShmemPtr == NULL || NextFree == NULL) { // not allocated yet
+    sql_print_error("ExtSQL extsql_malloc failure, shared memory not allocated!");
+    return(NULL);
+  }
+
+  size = MAXALIGN(size);
+
+  SpinLockAcquire(MemLock);
+  
+  newStart = *NextFree;
+  
+   /* extra alignment for large requests, since they are probably buffers */
+  if (size >= BLCKSZ) {
+    newStart = (char *) BUFFERALIGN(newStart);
+  }
+  
+  newFree = newStart + size;
+  if (newFree <= SHMEM_SIZE + ShmemPtr) {
+    addr = newStart;
+    *NextFree = newFree;
+
+  } else {
+    addr = NULL;
+  }
+  
+  SpinLockRelease(MemLock);
+  
+  if (!addr)
+    ereport(WARNING,
+            (errcode(ERRCODE_OUT_OF_MEMORY),
+             errmsg("ExtSQL - out of shared memory")));
+
+  bzero(addr, size);
+ 
+  if STATS_DEBUG(STATS_MEM_ALLOC ) {
+    sql_print_information("ExtSQL: alloc at 0x%x, of %d bytes",
+                          (uint)addr, size);
+  }
+
+  return(addr);
+  
+} // end my_malloc for PGSQL
+
+// need our own strdup for pgsql
+// NOTE - this allocs from our limited shared memory area, we don't FREE. This should
+// only be used for extsql data
+// Temporary buffers used for i/o should be alloced with just "strdup"
+char * extsql_strdup(char *, uint flags);
+char * extsql_strdup(char *srcStr, uint flags) {
+
+  int size = strlen(srcStr);
+  char *newStr = NULL;
+
+  newStr = extsql_malloc(size+1, 0);  // second param doesn't matter for PGSQL
+
+  if (!newStr) {
+    sql_print_error("ExtSQL my_strdup: failed to allocate size (%d)", size);
+    return(NULL);
+  } else {
+    strcpy(newStr, srcStr);
+
+  }
+
+  return(newStr);
+
+} // end my_strdup for PGSQL
+
+
+static void my_datetime_to_str(time_t *, char *);
+static void my_datetime_to_str(time_t *secsNow, char *date) {
+
+  struct tm *timeNow;
+  timeNow=localtime(secsNow);
+
+  strftime(date, DATE_SIZE , "%m/%d/%y %H:%M:%S", timeNow);
+
+}
+
+// wild_case_compare -- from MySQL source, not ours.  We don't use
+// charset info for PGSQL.
+int wild_case_compare(int cs, const char *str,const char *wildstr);
+int wild_case_compare(int cs, const char *str,const char *wildstr)
+{
+  char wild_many='%', wild_one='_', wild_prefix='\\'; 
+  int flag;
+
+  while (*wildstr) {
+
+    while (*wildstr && *wildstr != wild_many && *wildstr != wild_one) {
+
+      if (*wildstr == wild_prefix && wildstr[1])
+        wildstr++;
+      
+      if (toupper(*wildstr++) !=
+          toupper(*str++)) 
+        return(1);
+    }
+
+    if (! *wildstr ) return(*str != 0);
+
+    if (*wildstr++ == wild_one) {
+      if (! *str++) 
+        return(1);    /* One char; skip */
+      
+    } else {                                           /* Found '*' */
+      if (!*wildstr) 
+        return(0);            /* '*' as last char: OK */
+
+      flag=(*wildstr != wild_many && *wildstr != wild_one);
+      do {
+
+        if (flag) {
+          char cmp;
+            if ((cmp= *wildstr) == wild_prefix && wildstr[1])
+              cmp=wildstr[1];
+            cmp=toupper(cmp);
+            while (*str && toupper(*str) != cmp)
+              str++;
+            if (!*str) 
+              return(1);
+        }
+
+        if (wild_case_compare(0, str,wildstr) == 0) 
+          return(0);
+        
+      } while (*str++);
+      return(1);
+    }
+  }
+  return(*str != '\0');
+} // end wild_case_compare
+
+
+#else  // MYSQL
+
+
+// for mysql we just use what they have
+#define extsql_malloc(a,b)  my_malloc(a,b)
+#define extsql_strdup(a,b)  my_strdup(a,b)
+
+static int extsql_output_prep_2_col(char *col1, char *col2, Protocol *protocol,
+                             List field_list, char *fill2);
+static int extsql_output_2_col(char *col1Str, int col1Int, char *col2Str,
+                               int col2Int, Protocol *protocol, char *fill1);
+
+#endif // PGSQL or MYSQL build
+
+
+
+#ifdef EXTSQL_50
+#define net_printf  net_printf_error
+#define PROTOCOL    Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF
+#else
+#define PROTOCOL    1
+#endif
+
+
+// remove this define if you are building from source, will skip license checks.
+// #define EXTSQL_BINARY
+
+
+#ifndef DBUG_RETURN
+#define DBUG_RETURN(x) return(x)
+#endif
+
+//
+// START ACTUAL EXTSQL FUNCTION DEFINITIONS
+//
+
+#ifdef PGSQL
+int extsql_usage(THD* thd, DestReceiver *protocol) {
+
+#ifdef NEVER__
+}
+#endif
+
+#else
+int extsql_usage(THD* thd) {
+#endif
+
+#ifdef PGSQL
+  TupOutputState *tstate;
+  TupleDesc tupdesc = NULL;
+#else
+  Item* item;
+  List field_list;
+  Protocol *protocol = thd->protocol;
+  char *tstate = NULL, *tupdesc = '\0';
+#endif
+
+  char* enableHelp  = "Turn statistics on or off";
+  char* enableUsage = "STATISTICS ON|OFF";
+  char* resetHelp   = "Reset statistics [reread conf file]";
+  char* resetUsage  = "STATISTICS RESET ['conf file']";
+  char* readHelp    = "Read saved statistics data";
+  char* readUsage   = "STATISTICS READ [CONFIRM] 'data file'";
+  char* writeHelp   = "Write out statistics data";
+  char* writeUsage  = "STATISTICS WRITE 'data file'";
+
+  DBUG_ENTER("extsql_usage");
+
+  // return if not authorized, disabled or inactive
+  if (extsql_check(thd, 1)) DBUG_RETURN(1);
+
+#ifdef PGSQL
+  if (extsql_output_prep_2_col("Function", "Usage", protocol, &tstate,
+                               tupdesc)) {
+    DBUG_RETURN(1);
+  }
+#else
+  if (extsql_output_prep_2_col("Function", "Usage", protocol, field_list,
+                               tupdesc)) {
+    DBUG_RETURN(1);
+  }
+#endif
+
+  if (extsql_output_2_col(enableHelp, 0, enableUsage, 0, protocol, tstate)) {
+    DBUG_RETURN(1);
+  }
+
+  if (extsql_output_2_col(resetHelp, 0, resetUsage, 0, protocol, tstate)) {
+    DBUG_RETURN(1);
+  }
+
+  if (extsql_output_2_col(readHelp, 0, readUsage, 0, protocol, tstate)) {
+    DBUG_RETURN(1);
+  }
+
+  if (extsql_output_2_col(writeHelp, 0, writeUsage, 0, protocol, tstate)) {
+    DBUG_RETURN(1);
+  }
+
+  extsql_output_complete(thd, tstate);
+
+  DBUG_RETURN(0);
+}
+
+// simple routine to turn extsql on or off using "STATISTICS ON|OFF"
+// grammer
+#ifdef PGSQL
+int extsql_enable(THD* thd, DestReceiver *protocol, uint status) {
+
+#ifdef NEVER__
+}
+#endif
+
+#else
+int extsql_enable(THD* thd, uint status) {
+#endif
+  
+#ifdef PGSQL
+  TupOutputState *tstate;
+  TupleDesc tupdesc = NULL;
+#else
+  Item* item;
+  List field_list;
+  Protocol *protocol = thd->protocol;
+  char *tstate = NULL, *tupdesc = '\0';
+#endif
+  DBUG_ENTER("extsql_enable");
+
+  // return if not authorized, disabled or inactive
+  if (extsql_check(thd, 1)) DBUG_RETURN(1);
+
+  // accept any positive integer
+  if (status > 0) { status = 1; }
+
+  Shared->extsql_active = status;
+
+#ifdef PGSQL
+  if (extsql_output_prep_2_col("extsql_active", "status", protocol, &tstate,
+                               tupdesc)) {
+    DBUG_RETURN(1);
+  }
+#else
+  if (extsql_output_prep_2_col("extsql_active", "status", protocol, field_list,
+                              tupdesc)) {
+    DBUG_RETURN(1);
+  }
+#endif
+
+  if (extsql_output_2_col(NULL, Shared->extsql_active, NULL, 1, protocol, tstate)) {
+    DBUG_RETURN(1);
+  }
+
+  extsql_output_complete(thd, tstate);
+
+  DBUG_RETURN(0);
+}
+
+// handler for "STATISTICS RESET"
+#ifdef PGSQL
+int extsql_reset(THD* thd, DestReceiver *protocol, const char* conf) {
+
+#ifdef NEVER__
+}
+#endif
+
+#else
+int extsql_reset(THD* thd, const char* conf) {
+#endif
+
+#ifdef PGSQL
+  TupOutputState *tstate;
+  TupleDesc tupdesc = NULL;
+#else
+  Item* item;
+  List field_list;
+  Protocol *protocol = thd->protocol;
+  char *tstate = NULL, *tupdesc = '\0';
+#endif
+
+  int startType = STATS_INIT_RESET;
+
+  DBUG_ENTER("extsql_reset");
+
+  if (! STATS_DEBUG(STATS_ADMIN)) { // disabled
+    net_printf(thd, 0, adminDisabled);
+    return(0);
+  }
+
+  // return if not authorized, disabled or inactive
+  if (extsql_check(thd, 0)) DBUG_RETURN(1);
+
+  // in this case, extsql_prep will parse and process the conf
+  // file.
+  if (conf != NULL) {
+    extsql_prep(&startType, conf, NULL);
+    if (startType == STATS_INIT_FAILURE) {
+      net_printf(thd, 0, "ExtSQL: Error reading config file");
+      DBUG_RETURN(1);
+    }
+  }
+
+  if (extsql_init(Shared->extsql_class_list, startType, Shared->extsql_reload_file)) {
+    net_printf(thd, 0, "ExtSQL: Reset failed");
+    DBUG_RETURN(1);
+  }
+
+#ifdef PGSQL
+  if (extsql_output_prep_2_col("message", "status", protocol, &tstate,
+                               tupdesc)) {
+    DBUG_RETURN(1);
+  }
+#else
+  if (extsql_output_prep_2_col("message", "status", protocol, field_list,
+                              tupdesc)) {
+    DBUG_RETURN(1);
+  }
+#endif
+
+  if (extsql_output_2_col("Statistics reset", 0, NULL, 1, protocol, tstate)) {
+    DBUG_RETURN(1);
+  }
+
+  extsql_output_complete(thd, tstate);
+
+  return 0;
+}
+
+// handler for "STATISTICS READ|WRITE"
+#ifdef PGSQL
+int extsql_file_io(THD* thd, DestReceiver *protocol, uint io_mode, uint confirm,
+                   char* reload_file) {
+
+#ifdef NEVER__
+}
+#endif
+
+#else
+int extsql_file_io(THD* thd, uint io_mode, uint confirm,
+                   char* reload_file) {
+#endif
+
+#ifdef PGSQL
+  TupOutputState *tstate;
+  TupleDesc tupdesc = NULL;
+#else
+  Item* item;
+  List field_list;
+  Protocol *protocol = thd->protocol;
+  char *tstate = NULL, *tupdesc = '\0';
+#endif
+
+  int startType = STATS_INIT_RELOAD;
+  int prevState = Shared->extsql_active;
+
+  char* reloadFileCopy = extsql_strdup(reload_file, MYF(MY_WME));
+  char* message = extsql_strdup((io_mode ? "Reload file written successfully." :
+                             "Reload file read successfully. Statistics are disabled. "), 
+                            MYF(MY_WME));
+
+  DBUG_ENTER("extsql_file-io");
+
+  if (! STATS_DEBUG(STATS_ADMIN)) { // disabled
+    net_printf(thd, 0, adminDisabled);
+    return(0);
+  }
+
+  // return if not authorized, disabled or inactive
+  if (extsql_check(thd, 0)) DBUG_RETURN(1);
+
+  Shared->extsql_active = 0;
+
+
+  // writing file
+  if (io_mode) {
+
+    if (extsql_reload(STATS_WRITE_RELOAD, reloadFileCopy)) {
+      net_printf(thd, 0, "ExtSQL: Error encountered during reload WRITE");
+      Shared->extsql_active = prevState;
+      DBUG_RETURN(1);
+    }
+
+    Shared->extsql_active = 1;
+    
+  // reading file
+  } else {
+
+    extsql_prep(&startType, NULL, reloadFileCopy);
+
+    if (startType == STATS_INIT_FAILURE) {
+      net_printf(thd, 0, "Error reading reload file or version incompatibility.");
+      Shared->extsql_active = prevState;
+      DBUG_RETURN(1);
+    }
+
+    if (startType == STATS_INIT_CONFIRM && !confirm) {
+      net_printf(thd, 0,
+                 "Class data in reload file or hostname does not match.  Use STATISTICS READ CONFIRM '%s' to override.",
+                 reload_file);
+      Shared->extsql_active = prevState;
+      DBUG_RETURN(1);
+    }
+
+    if (extsql_init(Shared->extsql_class_list, STATS_INIT_RELOAD, reloadFileCopy)) {
+      net_printf(thd, 0, "ExtSQL: Read failed");
+      Shared->extsql_active = prevState;
+      DBUG_RETURN(1);
+    }
+
+    Shared->extsql_active = 0;
+  }
+
+
+#ifdef PGSQL
+  if (extsql_output_prep_2_col("message", "status", protocol, &tstate,
+                               tupdesc)) {
+    DBUG_RETURN(1);
+  }
+#else
+  if (extsql_output_prep_2_col("message", "status", protocol, field_list,
+                              tupdesc)) {
+    DBUG_RETURN(1);
+  }
+#endif
+
+  if (extsql_output_2_col(message, 0, NULL, 1, protocol, tstate)) {
+    DBUG_RETURN(1);
+  }
+
+  extsql_output_complete(thd, tstate);  
+
+  return 0;
+}
+
+// convenience function to check user authorization
+// checks to see if the specified 'user' is in the string containing
+// authorized users 'authUsers', set by admin with extsql_users=".."
+// return 1 if authorized, 0 otherwise
+static int extsql_user_auth(char *user, char *authUsers) {
+
+  char *tPtr, *token;
+  char tmpUser[STATS_TMP_BUFF_SIZE];
+  int found;
+
+  DBUG_ENTER("extsql_user_auth");
+
+  // we search allowed users each time in case list changes
+  if (strlen(authUsers) >= STATS_TMP_BUFF_SIZE-1) {
+    sql_print_error("ExtSQL: user list has exceeded storage limits");
+    return(0);
+  }
+
+  strcpy(tmpUser, authUsers);
+  tPtr = tmpUser;
+  found = 0;
+
+  while ( (token = strtok(tPtr, ", ")) ) {
+    
+    tPtr = NULL;
+    if (!strcmp(token, user) || !strcmp("root", user)) { // match
+      found = 1;
+      break;
+    }
+  } // end while - more user names
+
+  if (!found) {    
+    return(0);
+  }
+
+  return(1); // they are okay!
+
+} // end extsql_user_auth
+
+// Check for authorized user, enabled and active extsql
+int extsql_check(THD* thd, int overrideActive) {
+
+  char *user;
+
+  DBUG_ENTER("extsql_check");
+
+  if (Shared->extsql_disabled) { // just get out
+    net_printf(thd, 0, "ExtSQL: disabled");
+    DBUG_RETURN(1);
+  }
+  
+  if (!(Shared->extsql_active || overrideActive)) { // just get out
+    net_printf(thd, 0, "ExtSQL: deactivated");
+    DBUG_RETURN(1);
+  }
+
+#ifdef PGSQL
+  user = MyProcPort->user_name;
+#else
+
+#ifdef EXTSQL_50
+  user = thd->security_ctx->user;
+#else
+  user = thd->user;
+#endif
+
+#endif
+
+  // are they authorized
+  if (!extsql_user_auth(user, extsql_users)) {
+
+    // let the DBA know just in case.
+    sql_print_warning("ExtSQL: attempted access by user: %s", user);
+    net_printf(thd, 0, "ExtSQL: access not allowed to user: %s",
+               user);
+    DBUG_RETURN(1);
+  }
+
+  DBUG_RETURN(0);
+}
+
+// generic function to do output prep, identify column headers, types
+// INPUT: col1 and col2 (col2 can be NULL)
+// non-zero return on failure, one or two columns
+// NOTE dest,tstate, and tupdesc are declared in the calling function,
+// same vars will be used in call to extsql_output_2_col
+// fill1 and fill2 are placeholders to keep function calls the same
+int extsql_output_prep_2_col(char *col1, char *col2
+
+#ifdef PGSQL
+                             ,DestReceiver *dest, TupOutputState **tstate, TupleDesc tupdesc
+#else
+                             ,Protocol *protocol, List field_list,   char *fill2
+#endif
+
+) {
+
+  if (!col1) {
+    sql_print_error("ExtSQL: extsql_output_prep_2_col missing col1.");
+    return(1);
+  }
+  
+#ifdef PGSQL
+
+  // tuple descriptor for up to two cols
+  if (col2) {
+
+    tupdesc = CreateTemplateTupleDesc(2, false);
+
+    TupleDescInitEntry(tupdesc, (AttrNumber) 1, col1,
+                       TEXTOID, -1, 0, false);
+    TupleDescInitEntry(tupdesc, (AttrNumber) 2, col2,
+                       TEXTOID, -1, 0, false);
+  } else {
+    tupdesc = CreateTemplateTupleDesc(1, false);
+    TupleDescInitEntry(tupdesc, (AttrNumber) 1, col1,
+                       TEXTOID, -1, 0, false);
+  }
+
+  // prepare for projection of tuples
+  *tstate = begin_tup_output_tupdesc(dest, tupdesc);
+  
+#else
+  Item *item;
+  
+  // column headers
+  field_list.push_back(item = new Item_empty_string(col1, MAX_VAR_SIZE));
+  if (col2) {
+    field_list.push_back(item = new Item_empty_string(col2, MAX_VAR_SIZE));
+  }
+  
+  // output the column headers
+  if (protocol->send_fields(&field_list, PROTOCOL)) {
+    sql_print_error("ExtSQL: output_prep_2_col protocol write failed");
+    return(1);
+  }
+
+#endif
+
+  return(0);
+
+} // end extsql_output_prep_2_col
+
+
+// generic function to send output rows (up to 2 cols, char data)
+// INPUT: col1Str (value), col2Str maybe NULL
+// NOTE tstate is declared in the calling function,
+// same vars will be used in call to extsql_output_prep_2_col
+// null strings will result in using integer values
+int extsql_output_2_col(char *col1Str, int col1Int, char *col2Str, int col2Int
+
+#ifdef PGSQL
+                        ,DestReceiver *dest, TupOutputState *tstate
+#else
+                        ,Protocol *protocol, char *fill1
+#endif
+
+
+) {
+
+  bool cleanup1 = false;
+  bool cleanup2 = false;
+
+#ifdef PGSQL
+  char	   *values[2];
+#endif
+
+  // Convert ints to char*
+  if (col1Str == NULL) {
+    cleanup1 = true;
+    col1Str = (char*)my_malloc(8 * sizeof (char), MYF(MY_WME | MY_ZEROFILL));
+    sprintf(col1Str, "%d", col1Int);
+  }
+
+  if (col2Str == NULL) {
+    cleanup2 = true;
+    col2Str = (char*)my_malloc(8 * sizeof (char), MYF(MY_WME | MY_ZEROFILL));
+    sprintf(col2Str, "%d", col2Int);
+  }
+
+#ifdef PGSQL
+
+
+  // assign to the values array ZZ - not done
+  if (col1Str) {
+    values[0] = col1Str;
+  }
+
+  if (col2Str) {
+    values[1] = col2Str;
+  }
+
+  // send it to dest 
+  do_tup_output(tstate, values);
+ 
+
+#else
+  protocol->prepare_for_resend();
+  if (col1Str) {
+    protocol->store(col1Str, strlen(col1Str), system_charset_info);
+  } else { // must be int
+    protocol->store((longlong) col1Int);
+  }
+
+  if (col2Str) { 
+    protocol->store(col2Str, strlen(col2Str), system_charset_info);
+  } else { // must be int
+    protocol->store((longlong) col2Int);
+  }
+  
+  if (protocol->write()) {
+    sql_print_error("ExtSQL: output_2_col protocol write failed");
+    return(1);
+  }  
+#endif
+
+  // cleanup dynamic memory allocation
+  if (cleanup1) { my_free(col1Str, MYF(0)); }
+  if (cleanup2) { my_free(col2Str, MYF(0)); }
+  
+  return(0);
+  
+} // end extsql_output_2_col
+
+// generic function to handle transmission end
+void extsql_output_complete(
+
+#ifdef PGSQL
+             THD *thd, TupOutputState *tstate
+#else
+             THD *thd, char *tstate
+#endif
+
+             ) {
+
+#ifdef PGSQL
+  end_tup_output(tstate);
+#else
+  
+  send_eof(thd);
+
+#endif
+
+} // end extsql_output_complete
+
+
+// called from the parser in response to a SHOW STATISTICS command.
+// wild is what is given in the LIKE 'wild'
+int mysql_show_extsql(THD *thd, 
+                           const char *stats_class, 
+#ifdef PGSQL
+                           DestReceiver *protocol,
+                           List *stats_vars,
+#else
+                           List  &stats_vars,
+#endif
+                           uint stats_hourly,
+                           const char *wild, 
+#ifdef PGSQL
+                           char *stats_order_var,
+#else
+                           const char *stats_order_var,
+#endif
+                           const uint stats_order_dir,
+                           const uint stats_order_limit,
+#ifdef PGSQL
+                           char *stats_where_var,
+#else
+                           const char *stats_where_var,
+#endif
+                           const uint stats_where_num,
+                           const uint stats_where_char)  
+{
+#ifdef PGSQL
+
+#define VALUE_LIMIT 100
+  TupOutputState *tstate;
+  TupleDesc	tupdesc =  NULL;
+
+#ifdef PGSQL_8
+  ListCell *item;
+#else
+  List *item;
+#endif
+
+  int listCount;
+  char *values[MAX_VARS_IN_CLASS], *valuesPtr[VALUE_LIMIT], valueBuff[256]; // output
+  int ptrIndex = 0;
+  int system_charset_info = 0; // not used in PGSQL, just placeholder, call our func.
+
+#else
+
+  Item *item;
+  List field_list;  // has column headings, all strings.
+  List    check_vars; 
+  Protocol *protocol= thd->protocol;
+  LEX_COLUMN *column;
+  char *tstate = NULL; char *tupdesc = '\0'; // placeholders for tstate and tupdesc
+
+#endif
+
+  char *columnName; // used in output for MySQL PGSQL 
+  int res = 0;
+  int namedVars = 0;  // are they asking for specific vars
+  char listBuff[MAX_BUFF_SIZE], timeBuff[DATE_SIZE];  
+  char *varListPtr = listBuff;
+  int timeLimit = 0, currentTime = 0, indexTime = 0, varIndex = 0;
+  char *varName, *termChar;
+  int varNameLength = 0, timeCount = 0, rowCount = 0, whereVarAddedList = 0;
+
+  pSTATS_CLASS_DATA stats_class_data;
+  STAT_VAR **statPtr;
+  int i, maxVar, maxTime, instance, maxInstance, var, found=0, value = 0, skip = 0,
+    rowHasData;
+  char *user;
+  MYSQL_TIME mysql_time;
+
+#ifdef EXTSQL_50
+  user = thd->security_ctx->user;
+#else
+
+#ifdef PGSQL
+  user = MyProcPort->user_name; 
+#else
+  user = thd->user;
+#endif
+#endif
+
+  DBUG_ENTER("mysql_show_extsql");
+
+  // CHECK FOR DATA DUMPS OR TESTS
+  if STATS_DEBUG(STATS_DUMP) {
+    extsql_stats_dump();
+    extsql_thread_dump(thd, 1);
+
+  } else if STATS_DEBUG(STATS_DUMP_ONCE) { // just once
+    extsql_stats_dump();
+    extsql_thread_dump(thd, 1);
+    Shared->extsql_debug -= STATS_DUMP_ONCE; // clear 
+
+  } 
+
+  if STATS_DEBUG(STATS_TEST_ONE) {
+    
+    Shared->extsql_active = 0;
+    Shared->extsql_debug -= STATS_TEST_ONE; // clear 
+    extsql_stats_dump();
+    if (extsql_reload(STATS_WRITE_RELOAD, Shared->extsql_reload_file)) {
+      sql_print_error("ExtSQL: Error encountered during reload WRITE");
+    }
+    extsql_stats_dump();
+    Shared->extsql_active = 1;
+    
+  } 
+  
+  if STATS_DEBUG(STATS_TEST_TWO) {
+    
+    Shared->extsql_debug -= STATS_TEST_TWO; // clear 
+    extsql_stats_dump();
+
+    if (0) {
+      extsql_init(Shared->extsql_class_list, STATS_INIT_RELOAD, Shared->extsql_reload_file);
+    } else {
+      extsql_init(Shared->extsql_class_list, STATS_INIT_RESET, Shared->extsql_reload_file);
+    }
+    
+    extsql_stats_dump();
+    
+  } // end if-else testing
+
+
+  // return if not authorized, disabled or inactive
+  if (extsql_check(thd, 0)) DBUG_RETURN(1);
+
+  // okay, statistics are active, prepare for output.  
+  if STATS_DEBUG(STATS_SHOW_PARAMS) {
+    sql_print_information("ExtSQL: internal variables class %s,\
+  hourly %d, wild %s, ORDER BY %s, direction %d, LIMIT %d, \
+  WHERE  var %s, compare %d, value %d",
+                          stats_class, stats_hourly, wild,
+                          stats_order_var,
+                              stats_order_dir, stats_order_limit,
+                          stats_where_var, 
+                          stats_where_char, stats_where_num);
+  }
+
+  if (stats_class == NULL) { // they want help/status
+    
+    pSTATS_CLASS_DATA stats_class_data;
+    STAT_VAR **statPtr;
+
+
+    char *Usage = "Usage";
+    char *Help  = "SHOW STATISTICS (* | Var[,Var]) FROM Class [LIKE 'Instance']";
+    char *Help2 = "     [WHERE Var ('<'|'>'|'=') num] [ORDER BY Var] [HISTORY] [LIMIT rows_or_time]";
+#ifdef EXTSQL_50
+    char *Help3 = "also available from INFORMATION_SCHEMA, SHOW TABLES FROM INFORMATION_SCHEMA for list.\
+ExtSQL reported as part of EXTSTATS_(Class) tables.";
+#endif 
+    char *Version = "Version";
+#ifdef EXTSQL_BINARY
+    char *Key   = "License Key";
+#endif
+    char *Users = "Stat Users";
+    char *Blank = " ";
+    int maxVar, maxTime, maxInstance, var, instance, classCount;
+
+#ifdef PGSQL
+    if (extsql_output_prep_2_col("Item", "Value", protocol, &tstate, tupdesc)) {
+      DBUG_RETURN(1);
+    }
+#else
+     if (extsql_output_prep_2_col("Item", "Value", protocol, field_list, tupdesc)) {
+      DBUG_RETURN(1);
+    }   
+#endif
+
+    if (extsql_output_2_col(Usage, 0, Help, 0, protocol, tstate)) {
+      DBUG_RETURN(1);
+    }  
+
+    if (extsql_output_2_col(Usage, 0, Help2, 0, protocol, tstate)) {
+      DBUG_RETURN(1);
+    }                   
+ 
+#ifdef EXTSQL_50
+    if (extsql_output_2_col(Usage, 0, Help3, 0, protocol, tstate)) {
+      DBUG_RETURN(1);
+    }                   
+#endif                 
+
+    if (extsql_output_2_col(Version, 0, Shared->extsql_version+1, 0, protocol, tstate)) {
+      DBUG_RETURN(1);
+    }  
+    
+#ifdef EXTSQL_BINARY
+    if (extsql_output_2_col(Key, 0, extsql_key, 0, protocol, tstate)) {
+      DBUG_RETURN(1);
+    }  
+#endif
+
+    if (extsql_output_2_col(Users, 0, extsql_users, 0, protocol, tstate)) {
+      DBUG_RETURN(1);
+    }  
+
+    if STATS_DEBUG(STATS_PID) { // show the pid of the server for gdb
+      sprintf(listBuff, "(%d)", getpid());
+      if (extsql_output_2_col("Server PID", 0, listBuff, 0, protocol, tstate)) {
+        DBUG_RETURN(1);
+      }  
+    }
+      
+    // now we show them the class list stuff
+    classCount = 0;
+    for (stats_class_data = Shared->statData; classCount < STATS_MAX_CLASSES && stats_class_data->maxInstance; 
+         stats_class_data++, classCount++) {
+      
+      maxVar = stats_class_data->maxVar; 
+      maxTime = stats_class_data->maxTime-1; 
+      maxInstance = stats_class_data->maxInstance;
+
+      if (extsql_output_2_col(Blank, 0, Blank, 0, protocol, tstate)) {
+        DBUG_RETURN(1);
+      }
+
+      // how many instances are in use
+      for (instance=0; 
+           instance < maxInstance && stats_class_data->instanceIndex[instance]; 
+           instance++) {
+      }
+
+      sprintf(listBuff, "Max instances/in use (%d/%d), Max vars (%d), Max time (%d), Time units(%c)",
+              maxInstance, instance, maxVar, maxTime, stats_class_data->timeUnits);
+
+      if (extsql_output_2_col(stats_class_data->name, 0, listBuff, 0, protocol, tstate)) {
+        DBUG_RETURN(1);
+      }  
+
+      strcpy(listBuff, " ");
+      
+      for (var=0, statPtr = stats_class_data->varIndex; 
+           (var < maxVar) && *statPtr ; 
+           var++, statPtr++) {
+        
+        sprintf(listBuff+strlen(listBuff),"%s ", (*statPtr)->name);
+      }
+      
+      if (extsql_output_2_col(stats_class_data->name, 0, listBuff, 0, protocol, tstate)) {
+        DBUG_RETURN(1);
+      }
+
+    } // end for - all clasees
+
+
+    extsql_output_complete(thd, tstate);
+    DBUG_RETURN(0);  
+
+  } // end if - just showing help
+  // NOTE - normal RETURN ONLY here!
+
+
+  // find the instance list for the class we are looking for
+  found = 0;
+  for (stats_class_data = Shared->statData; stats_class_data->maxInstance; 
+       stats_class_data++) {
+    if (!strcmp(stats_class_data->name, stats_class)) { // found it
+      found = 1;
+      break;
+    }
+  } // end for 
+  
+  if (!found) {
+    net_printf(thd, 0, "ExtSQL: can't find requested class %s, enter SHOW STATISTICS for usage.",
+               stats_class);
+    DBUG_RETURN(1);
+  }
+
+  // AT THIS POINT stats_class_data points to the requested class 
+  maxVar = stats_class_data->maxVar; 
+  maxTime = stats_class_data->maxTime; 
+  maxInstance = stats_class_data->maxInstance; // needed for array indexing
+
+
+  // NOTE - a LOT of checking first to make sure inputs make sense.
+
+  if (stats_order_var) { // they used ORDER BY
+    net_printf(thd, 0, "ExtSQL:  ORDER BY not supported in this version.");
+    DBUG_RETURN(1);
+  }
+  
+  // CHECK that the limit is NOT larger than allowed if done for time
+  if (stats_hourly && stats_order_limit >= maxTime) {
+    net_printf(thd, 0, "ExtSQL, limit of %d is greater than stored time for this class of %d.",
+               stats_order_limit, maxTime-1);
+    DBUG_RETURN(1);
+  }
+
+  // CHECK BLOCK - check the where character
+  if (stats_where_char) {
+
+    switch (stats_where_char) {
+      
+    case '>':
+    case '<':
+    case '=':
+      break;
+      
+    default:
+      net_printf(thd, 0, "ExtSQL: unsupported comparison (%c), enter SHOW_STATISTICS for usage.", stats_where_char);
+      DBUG_RETURN(1);
+      
+    } // end switch
+  }
+
+  // Set listCount to the number of Var column headings we will have
+#ifdef PGSQL
+
+  // For PGSQL we need to count the columns what we have ahead of time
+  listCount = 0; namedVars = 0;
+  foreach(item, stats_vars) {
+    
+    char *var1 = strVal(lfirst(item));
+
+    if (!strcmp(var1, "statistics") ) { // ZZ - not really best way to check, default list
+
+      // loop through for count
+      for (var=0, statPtr = stats_class_data->varIndex; 
+           (var < stats_class_data->maxVar) && *statPtr ; 
+           var++, statPtr++) {  
+        listCount++;
+      }
+      break;
+    }
+
+    listCount++;   
+    namedVars = 1; // redundant
+  } // end for - all vars in list
+
+#else
+
+  if (stats_vars.elements) {
+    namedVars = 1;
+  }
+
+#endif
+
+  // CHECK BLOCK - if they gave us specific columns (namedVars=1) to display, 
+  // check those vars are actually being tracked
+  if (namedVars) {
+
+
+
+#ifdef PGSQL
+
+    foreach(item, stats_vars) { // output the column heading
+
+      columnName = strVal(lfirst(item));
+#else
+
+    List_iterator  stats_column(stats_vars);
+    
+    while ((column=stats_column++)) { // search for a match in class
+
+      columnName = (char *)column->column.ptr();
+#endif
+
+      found = 0;
+      for (var = 0, statPtr = stats_class_data->varIndex;
+           (var < maxVar) && *statPtr ; 
+           var++, statPtr++) {
+
+        if (strlen(columnName) > MAX_VAR_SIZE - 5) {
+          net_printf(thd, 0, "ExtSQL: Var is too long");
+          DBUG_RETURN(1);
+        }
+
+        if (!strcasecmp((*statPtr)->name, columnName)) { // ZZ - low case input in postgres?
+          found = 1;
+          break;
+        }
+      } // end for - all vars
+      
+      if (!found) {
+        net_printf(thd, 0, "ExtSQL: can't find Var %s, SHOW STATISTICS for usage.",
+                   columnName);
+        DBUG_RETURN(1);
+      }
+
+    } // end while/for - more columns
+
+#ifdef NEVER__  
+    }  // to keep indent level correct in emacs
+#endif
+
+  } // end if - named vars are being tracked.
+
+
+  // CHECK BLOCK - if we have an ORDER by or WHERE clause variable, check those also
+  if (stats_where_var || stats_order_var) {
+
+#ifdef PGSQL
+
+    List *checkList;
+
+    if (stats_where_var && stats_order_var) {
+      checkList = (List *)list_make2(makeString(stats_where_var), makeString(stats_order_var));
+
+    } else if (stats_where_var) {
+      checkList = (List *)list_make1(makeString(stats_where_var));
+
+    } else {
+      checkList = (List *)list_make1(makeString(stats_order_var));
+    }
+
+    foreach(item, checkList) { // check the list
+      
+      columnName = strVal(lfirst(item));  
+
+#else
+    if (stats_where_var) {
+      String *tmpStr = new (thd->mem_root) String ((const char *)stats_where_var, strlen(stats_where_var), system_charset_info);
+      check_vars.push_back(new LEX_COLUMN (*tmpStr, 0));
+    }
+    
+    if (stats_order_var) {
+      String *tmpStr = new (thd->mem_root) String ((const char *)stats_order_var, strlen(stats_where_var), system_charset_info);
+      check_vars.push_back(new LEX_COLUMN (*tmpStr, 0));
+    }
+  
+    List_iterator  stats_column(stats_vars);
+    
+    while ((column=stats_column++)) { // search for a match in class
+      
+      columnName = (char *)column->column.ptr();
+
+#endif
+
+      found = 0;
+      for (var = 0, statPtr = stats_class_data->varIndex;
+           (var < stats_class_data->maxVar) && *statPtr ; 
+           var++, statPtr++) {
+        
+        // make sure the name isn't too long
+        if (strlen(columnName) > MAX_VAR_SIZE - 5) {
+          net_printf(thd, 0, "ExtSQL: Var (%s) is too long, check entry.",
+                     columnName);
+          DBUG_RETURN(1);
+        }
+        
+        if (!strcasecmp((*statPtr)->name, columnName)) {
+          found = 1;
+        break;
+        }
+
+      } // end for - all vars       
+    
+      if (!found) {
+        net_printf(thd, 0, "ExtSQL: can't find Var %s, enter SHOW STATISTICS for usage.",
+                   columnName);
+        DBUG_RETURN(1);
+      }
+    } // end while - more columns
+
+#ifdef NEVER__  
+    }  // to keep indent level correct in emacs
+#endif
+
+  } // end if - specified where or order by var
+  
+  // START OUTPUT - prepare and output the header columns
+  // The class name (always FIRST column)
+  // PGSQL uses a predefined array of column headers, need to keep count
+  // MYSQL uses a stack approach.
+
+#ifdef PGSQL
+  if (stats_hourly) {
+    listCount += 2;  // class name and time
+  } else {
+    listCount++; // add just one for the class name
+  }
+  i = 1;  // current param position
+
+  tupdesc = CreateTemplateTupleDesc(listCount, false);
+
+  TupleDescInitEntry(tupdesc, (AttrNumber) i++, stats_class, TEXTOID, -1, 0, false); 
+
+#else
+  field_list.push_back(item = new Item_empty_string(stats_class, STATS_MAX_NAME));
+#endif
+
+  // if HOURLY is asked for, it is always the SECOND column
+  if (stats_hourly) {
+    char *units;
+    switch (stats_class_data->timeUnits) {
+    case 'm':
+      units = "minutes";
+      break;
+    case 'h':
+      units = "hours";
+      break;
+    case 'd':
+      units = "days";
+      break;
+    default:
+      units = "UNKNOWN";
+    }
+
+#ifdef PGSQL
+    TupleDescInitEntry(tupdesc, (AttrNumber) i++, units, TEXTOID, -1, 0, false);
+#else
+    field_list.push_back(item = new Item_empty_string(units, 30)); // max size of 'minutes'
+#endif
+
+  }
+
+  // Then the variable list, this will either be what they specified, or
+  // the conf list.  We do a SPECIAL check to see if they have included a
+  // WHERE clause.  If they have, but it is not included in the column list
+  // we will add it, but it will not be displayed on output
+
+  // LARGE else block here depending on whether they specified list, or we use default!
+  strcpy(varListPtr,","); // init the list
+
+  if (namedVars) { // they identified the columns they want
+
+    char tempName[MAX_VAR_SIZE];   // ZZ
+
+#ifdef PGSQL
+    foreach(item, stats_vars) { // output the column heading
+
+      columnName = strVal(lfirst(item));
+#else
+
+    List_iterator  stats_column2(stats_vars);    
+    while ((column=stats_column2++)) { // search for a match in class
+
+      columnName = (char *)column->column.ptr();
+#endif
+
+      if (strlen(columnName) > MAX_VAR_SIZE - 5) {
+        net_printf(thd, 0, "ExtSQL: Var is too long");
+        DBUG_RETURN(1);
+      }
+     
+
+#ifdef PGSQL
+       TupleDescInitEntry(tupdesc, (AttrNumber) i++, columnName, TEXTOID, -1, 0, false);
+      
+#else
+      field_list.push_back(item = new Item_uint(columnName, MY_INT64_NUM_DECIMAL_DIGITS ));
+#endif
+
+      strcat(varListPtr, columnName);
+      strcat(varListPtr, ",");
+      
+    } // end while - more columns
+#ifdef NEVER__  
+    }  // to keep indent level correct in emacs
+#endif
+
+    // is the where var on the list
+    if (stats_where_var) {
+      if (strlen(stats_where_var) > MAX_VAR_SIZE - 5) {
+        net_printf(thd, 0, "ExtSQL: WHERE Var too long");
+        DBUG_RETURN(1);
+      }
+      strcpy(tempName, ",");
+      strcat(tempName, stats_where_var);
+      strcat(tempName, ",");
+      if (strstr(varListPtr,tempName)) {
+        whereVarAddedList = 0;
+      } else {
+        whereVarAddedList = 1;
+        strcat(varListPtr, stats_where_var);
+        strcat(varListPtr,",");
+      }
+    } // end if - where clause
+
+
+  } else  { //  we output default column headings and create varListPtr
+          
+    // loop through the var names for headings
+    for (var=0, statPtr = stats_class_data->varIndex; 
+         (var < stats_class_data->maxVar) && *statPtr ; 
+         var++, statPtr++) {      
+      
+#ifdef PGSQL
+      TupleDescInitEntry(tupdesc, (AttrNumber) i++, (*statPtr)->name, TEXTOID, -1, 0, false); 
+#else
+      field_list.push_back(item = new Item_uint((*statPtr)->name, MY_INT64_NUM_DECIMAL_DIGITS  ));
+      item->maybe_null=1;
+#endif
+      strcat(varListPtr,(*statPtr)->name );
+      strcat(varListPtr, ",");
+
+      // check to make sure we don't bust string
+      if (strlen(varListPtr) > MAX_BUFF_SIZE - 50) {
+        net_printf(thd, 0, "ExtSQL: Var list too long");
+        DBUG_RETURN(1);
+      }
+    } // end for - all instances
+  } // end if - use defaults
+
+  // output the column headers
+#ifdef PGSQL
+  tstate = begin_tup_output_tupdesc(protocol, tupdesc);
+#else
+  if (protocol->send_fields(&field_list, PROTOCOL)) {
+    DBUG_RETURN(1); 
+  }
+
+#endif
+
+  // AT THIS POINT the output columns are in varListPtr
+  // next, if they will be asking for hourly output, we prepare an array
+  // of hour indexes.
+  if STATS_DEBUG(STATS_SHOW_PARAMS) {
+    sql_print_information("ExtSQL: varListPtr is (%s), whereVarAddedList(%d)", 
+                          varListPtr, whereVarAddedList);
+  }
+
+  timeLimit = 1; // by default we only show one time.
+  currentTime = stats_class_data->time; // time we are currently logging to.
+
+  if (stats_hourly) { // reset the proper inner loop limits
+    if (stats_order_limit) {
+      timeLimit = stats_order_limit; // whatever thy wanted
+    } else {
+      timeLimit = maxTime-1; // they get it all
+    } // end if else - time limit
+  } // end if - user wants hours displayed.
+ 
+
+  // AT THIS POINT - we have the varListPtr area with the oolumns in the
+  // display order we want.  Remember, zero index holds the total. The
+  // currentTime has our present location and it is circular, i.e. if
+  // maxTime for the class is 4, we store current + 3.  If the currentTime
+  // is 2, the proper way to display all hours, starting with the most
+  // recent is to show 2(current),1(prior),3(more prior) - skip 0
+
+  // the currentTime has no correlation to actual clock time, it is just
+  // a position within a circular buffer of times, each class could have
+  // a different limit.
+  
+  // START outputing data for the every instance within the matching class  
+  // we now go through all the instances.
+  for (instance=0; instance < maxInstance && stats_class_data->instanceIndex[instance] ; 
+       instance++) {
+    
+    if (wild && wild_case_compare(system_charset_info,
+                                  stats_class_data->instanceIndex[instance], wild) ) {
+      
+      continue;  // skip this one
+    } // end if - wild match
+    
+    // are we over our output LIMIT
+    if (!stats_hourly && stats_order_limit) { // not doing times, put limit on general output
+      if (rowCount >= stats_order_limit) {
+        break;
+      }
+    }
+
+    // loop through the times, if stats_hourly is not set we just print the stuff for zero
+    // time, the grand totals
+    // if stats_timely is set we will output a number of hours starting at currentTime, and
+    // limited by timeLimit (starts at 1).
+    for (timeCount = 0, indexTime = stats_hourly ? currentTime : 0 ;
+         timeCount < timeLimit  && indexTime >= 0;
+         timeCount++, indexTime--  )  {
+      
+      // if we are outputing times, we have to adjust our indexTime
+      if (stats_hourly && !indexTime) { // we have gone back to the total 
+        indexTime = maxTime - 1; // pick the last
+      }
+
+      // prepare  the data row
+      skip = 0;
+
+#ifdef PGSQL
+      // nothing special required here
+      // NOTE, variable i keeps our index in values array
+      i = 0;
+#else
+      protocol->prepare_for_resend();
+#endif
+      res = 0;
+      rowHasData = 0;  // do we have anything to show, only on HISTORY (stats_hourly set)
+
+      // first column - instance name - always
+#ifdef PGSQL
+      values[i++] = stats_class_data->instanceIndex[instance];
+#else
+      protocol->store(stats_class_data->instanceIndex[instance], 
+                      strlen(stats_class_data->instanceIndex[instance]), system_charset_info);
+#endif
+
+      // if we are doing times, second column is times - always, we use indexTime
+      if (stats_hourly) {
+        value = (int) stats_class_data->timeLabels[indexTime];
+
+        // convert to local time and then to a string for output
+#ifdef PGSQL
+        // ZZ need time conversion/zone
+        mysql_time = value;
+#else
+        thd->variables.time_zone->gmt_sec_to_TIME(&mysql_time, (my_time_t) value);
+#endif
+
+        my_datetime_to_str(&mysql_time, timeBuff);
+        
+        // we normally chop seconds off the time, from: 2008-04-04 14:59:48  TO 2008-04-04 14:59
+        if (!STATS_DEBUG(STATS_TIME_DETAIL)) {
+          timeBuff[strlen(timeBuff) - 3] = '\0';
+        }
+#ifdef PGSQL
+        values[i++] = timeBuff; 
+#else
+        protocol->store(timeBuff, strlen(timeBuff), system_charset_info);
+#endif
+   
+      } // end if - hourly
+
+      // loop through varListPtr, output the vars in the proper order
+      // varListPtr = ",bytes,selects," varName will move through this
+      for ( varName = varListPtr; *varName ; varName = strstr(varName, ",")) {
+
+        varName++; // move off the comma
+        //sql_print_information("   target varName is (%s)", varName);
+
+        if (! *varName) { // we are done
+          break;
+        }
+
+        varNameLength = strchr(varName, ',') - varName;
+    
+        // okay, varName points at a name, lets go through the index looking
+        // for a match
+        found = 0;
+        value = 0;
+
+        for (varIndex=0, statPtr = stats_class_data->varIndex; 
+             varIndex < maxVar && *statPtr;
+             varIndex++, statPtr++) { 
+          
+          termChar = (*statPtr)->name + varNameLength +1; // point to end of the current var name
+
+          if (!strncasecmp( (*statPtr)->name, varName, varNameLength)) {
+            found = 1;
+            value = stats_class_data->data [ARRAY_INDEX(instance, varIndex, maxVar,
+                                                        indexTime, maxTime)]; 
+
+            // before we send, check the value if they have set a WHERE condition
+            if (stats_where_var && !strncasecmp((*statPtr)->name, stats_where_var, varNameLength)) { // match
+
+              switch (stats_where_char) {
+
+              case '>':
+                if (value <= stats_where_num) skip = 1;  // this row is no good
+                break;
+                
+              case '<':
+                if (value >= stats_where_num) skip = 1;  // this row is no good
+                break;
+
+              case '=':
+                if (value != stats_where_num) skip = 1;  // this row is no good
+                break;
+
+              default:
+
+                sql_print_warning("ExtSQL: unsupported comparison (%d)", stats_where_char);
+
+              } // end switch
+
+              rowHasData = 1;
+
+            } // end if - match using WHERE clause
+
+            if (skip) {
+              break;
+            }
+
+            if (whereVarAddedList && !strncasecmp((*statPtr)->name, stats_where_var, varNameLength)) {
+              break; // don't output the where column, they didn't ask for it
+            }
+
+#ifdef PGSQL
+            // convert to text, store ptr addr and then free
+            // after send
+            sprintf(valueBuff, "%d",  value);
+            values[i] = strdup(valueBuff);
+            valuesPtr[ptrIndex++] = values[i++]; // need to free after output
+            if (ptrIndex >= VALUE_LIMIT) {
+              sql_print_error("ExtSQL, output value limit reached");
+              DBUG_RETURN(1);
+            }
+#else
+            protocol->store((longlong) value);
+#endif
+
+            if (value) { // is it non-zero
+              rowHasData = 1;
+            }
+            break;
+          } // end if - matching
+
+        } // end for - a matching var in the list
+
+        if (skip) {
+          break;
+        }
+
+        if (!found) {
+
+#ifdef PGSQL
+          values[i++] = "n/a"; 
+#else
+          value=999999;
+          protocol->store((longlong) value);
+#endif
+
+        }
+
+      } // end for - requested values
+
+      if (skip || (stats_hourly && !rowHasData)) { // free it up!
+
+        // if PGSQL we allocate some value space above, make sure we free it in all situations.
+#ifdef PGSQL
+        if (ptrIndex) {
+          for (ptrIndex--; ptrIndex; ptrIndex--) {
+            if (valuesPtr[ptrIndex]) {
+              free(valuesPtr[ptrIndex]);
+            }
+          } 
+        }
+#endif   
+        continue;
+      }
+
+
+      // send the row to the user,
+
+#ifdef PGSQL
+      do_tup_output(tstate, values);
+
+      if (ptrIndex) {
+        for (ptrIndex--; ptrIndex; ptrIndex--) {
+          if (valuesPtr[ptrIndex]) {
+            free(valuesPtr[ptrIndex]);
+          }
+        }
+      }
+#else
+      if (protocol->write()) {
+        sql_print_error("ExtSQL, protocol write failed");
+        DBUG_RETURN(1);
+      }
+#endif
+
+      rowCount++; // keep track of the count if have a general LIMIT in effect.
+  
+    } // end for - all requested times
+
+  } // end for - all instances
+  
+
+  extsql_output_complete(thd, tstate);
+  DBUG_RETURN(0);
+
+} // end mysql_show_statistics
+
+
+// record a statistic_increment call
+void extsql_inc(ulong *V, ulong C)
+{
+
+#ifdef PGSQL
+  THD *thd = MyProc;
+  time_t log_sec, now_sec;
+#else
+  THD *thd = current_thd;
+  my_time_t log_sec, now_sec;
+#endif
+
+  pSTATS_CLASS_DATA stats_class_data;
+  STAT_VAR **var_ptr;
+    int i, var, offset, offsetLimit, classCount, found = 0, instance, maxVar, maxTime;
+  int threadID, command;
+  char *user = "", *host = "", *db = "", *proc_info = "";
+  int *statVerify = 0, *indexPtr = 0;
+
+  if (!Shared->extsql_active || Shared->extsql_disabled || STATS_DEBUG(STATS_DISABLE_INC)) {
+    return;
+  }
+
+#ifdef EXTSQL_50
+  // during init we stored just offsets from THD structure status_var to each stat
+  // for nonglobal items -- we got an address in V, need to determine if it is a real global
+  // or something incremented as part of a thread.  We check to see if it is in the 
+  // address range of the status_var structure of the current thread
+  char *off;
+  off = (char *) V;
+  if (off >= (char *)&(thd->status_var) && off < (char *)&(thd->status_var)+sizeof(thd->status_var)) {
+    V =  (ulong *)(off - (char *)&(thd->status_var)) ;
+    if STATS_DEBUG(STATS_INC_VAR) sql_print_information("         altered to: 0x%x, base: 0x%x", 
+                                                        V, &(thd->status_var));
+  }
+#endif
+
+  // check against the list of Vars we are tracking
+  for (i = 0; i < Shared->varAddrCount; i++) {
+    if (Shared->varAddrTrackArray[i] == (char *) V) { // one we are tracking
+      found = 1;
+      break;
+    }
+  } // end for - all tracked vars
+
+  if (!found) {
+    return;
+  }
+
+#ifndef PGSQL
+  // ZZ ignore slow_launch_threads and early byte counts - unstable at this point
+  if (V == (ulong *) &slow_launch_threads || thd->command == COM_CONNECT) {
+    return;
+  }
+#endif
+
+  // input checks 
+  if (!thd 
+#ifndef PGSQL 
+      || !thd->thread_id
+#endif
+      ) {  // don't do thread zero for now
+    if STATS_DEBUG(STATS_INC_PARAMS) {
+      sql_print_information("ExtSQL: Got null thread or thd 0");
+    }
+    return;
+  }
+
+  extsql_init_proc_vars(&threadID, &command, &user, &db, &host, &proc_info, &indexPtr, &statVerify);
+
+ // we need something for these values
+  if (!user) {
+    user="(null)";
+  }
+
+  if (!host) {
+    host="(null)";
+  }
+   
+  if (*statVerify != STATS_MAGIC_NUM) { 
+    Shared->extsql_counter++; // ZZ - how many do we get?
+    return;
+  } // end if - badmagic
+
+
+  // too many warnings, turn it off
+  if (Shared->extsql_counter > STATS_WARNING_LIMIT) {
+    Shared->extsql_active = 0;
+    sql_print_warning("ExtSQL: deactivated due to high internal warning count(%d), dumping internals",
+                      (int)Shared->extsql_counter);
+    extsql_stats_dump();
+    return;
+  } 
+
+  if STATS_DEBUG(STATS_THREAD_CHK) {
+    extsql_thread_dump(thd, 0); // do a check of indexes, no output unless error
+  }
+  
+  // we get time in seconds, for performance we only call localtime once/minute to do the min,hour,day conversions
+  // could use thd->start_time, always avail? ZZ
+  now_sec = time(NULL);
+  
+  if (Shared->lastMin != (int)(now_sec/60)) { // we rolled over
+
+    // let's try and get the lock, if we fail, someone else doing rollover
+    if  (pthread_mutex_trylock(&Shared->LOCK_stats_clock)) { 
+      // nothing to do
+ 
+    } else {
+      
+      struct tm now_date;
+      localtime_r(&now_sec, &now_date);
+
+      Shared->lastMin = (int)(now_sec/60);      
+      
+      // check all time for classes
+      classCount = 0;
+      for (stats_class_data = Shared->statData; 
+           classCount < STATS_MAX_CLASSES && stats_class_data->maxInstance; 
+           stats_class_data++, classCount++) {
+        
+        int now_time;
+        
+        switch (stats_class_data->timeUnits) {
+        case 'm':
+          now_time = now_date.tm_min;
+          break;
+      
+        case 'h':
+          now_time = now_date.tm_hour;
+          break;
+      
+        case 'd':
+          now_time = now_date.tm_mday;
+          break;
+      
+        default:
+          now_time = now_date.tm_hour;
+          Shared->extsql_active = 0;
+          sql_print_error("ExtSQL: deactivated, got invalid time unit (%d)", stats_class_data->timeUnits);
+
+#ifdef PGSQL
+          pthread_mutex_unlock(&Shared->LOCK_stats_clock);
+#else
+          VOID(pthread_mutex_unlock(&Shared->LOCK_stats_clock));
+#endif
+          return;
+        }
+      
+        if (now_time != stats_class_data->lastTime) { // rolled over
+          stats_class_data->lastTime = now_time;
+        
+          // increment time and do checks        
+          stats_class_data->time++;
+        
+          if (stats_class_data->time >= stats_class_data->maxTime) { // reset to start
+            stats_class_data->time = 1;   // zero index is used for totals  
+          }
+
+          // create label, MM/DD HH:MM
+        
+          if STATS_DEBUG(STATS_TIME_CHANGE) {
+            sql_print_information("ExtSQL, class %s, time change: cur clock time is %d, time index s %d",
+                                  stats_class_data->name, now_time, stats_class_data->time);
+          }
+        
+          // reset counters for that time to zero for all variables
+          for (instance=0, maxVar = stats_class_data->maxVar, maxTime = stats_class_data->maxTime; 
+               instance < stats_class_data->maxInstance; instance++) { 
+            for (var=0; var < maxVar; var++) {
+            
+              offset = ARRAY_INDEX(instance, var, maxVar, stats_class_data->time, maxTime);
+              offsetLimit = stats_class_data->dataEnd - stats_class_data->data;
+            
+
+              // check to make sure offset isn't out of limits
+              if (offset < 0 || offset >= offsetLimit ) {
+                sql_print_warning("ExtSQL: warning, TIME reset offset of 0x%x (%d,%d,%d,%d,%d) for 0x%x class %s of thd %d/%s exceeds bound of 0x%x(0x%x)",
+                                  offset, instance, var, maxVar, stats_class_data->time, maxTime, 
+                                  (uint)V, stats_class_data->name, threadID, command_name[command], offsetLimit, *statVerify);
+                Shared->extsql_counter++;
+                extsql_thread_dump(thd, 1);
+#ifdef PGSQL
+                pthread_mutex_unlock(&Shared->LOCK_stats_clock);
+#else
+                VOID(pthread_mutex_unlock(&Shared->LOCK_stats_clock));
+#endif
+                return;
+              }
+            
+              stats_class_data->data[offset] = 0;
+
+              // store unix time
+              // we normally round it off to minutes/hours/days depending on units
+              if (!STATS_DEBUG(STATS_TIME_DETAIL)) {
+
+                switch (stats_class_data->timeUnits) {
+                case 'm':
+                  log_sec = now_sec - (now_sec % 60);
+                  break;
+                  
+                case 'h':
+                  log_sec = now_sec - (now_sec % 3600);
+                  break;
+                  
+                case 'd':
+                  log_sec = now_sec - (now_sec % 3600);
+                  break;
+                  
+                default:
+                  now_time = now_date.tm_hour;
+                  Shared->extsql_active = 0;
+                  sql_print_error("ExtSQL: deactivated, got invalid time unit (%d)", stats_class_data->timeUnits);
+                  return;
+                }
+
+              } else {
+
+                log_sec = now_sec;
+
+              } // end if/else  - don't round off time
+                
+              stats_class_data->timeLabels[stats_class_data->time] = log_sec;            
+            
+            } // end for - vars
+          } // end for - instances
+        } // end if - new time 
+      
+      } // end for - all classes
+      
+#ifdef PGSQL
+      pthread_mutex_unlock(&Shared->LOCK_stats_clock);
+#else
+      VOID(pthread_mutex_unlock(&Shared->LOCK_stats_clock));
+#endif
+    } // end if-else - got the lock
+  } //end if - time rolled over
+  
+
+  // ready to increment value
+  if STATS_DEBUG(STATS_INC_VAR)   sql_print_information("ExtSQL: 0x%x by %d", (uint)V,(int)C);
+
+  // look for the value being tracked in all classes
+  classCount = 0;
+  for (stats_class_data = Shared->statData; 
+       classCount < STATS_MAX_CLASSES && stats_class_data->maxInstance; 
+       stats_class_data++, classCount++) {
+
+    var_ptr = stats_class_data->varIndex;
+    for (var = 0,  maxVar = stats_class_data->maxVar, maxTime = stats_class_data->maxTime
+           ; var < maxVar ; var_ptr++,var++) {
+      if ((*var_ptr)->addr == (char *)V) { // we are tracking it
+       
+        i = indexPtr[(int)classCount];
+
+        if (i < 0 || i >= stats_class_data->maxInstance) { // bound exceeded
+          sql_print_warning("ExtSQL: index (%d) bad value (0x%x/0x%x), V(0x%x), classCount(%d), thd(%d/%s/%s) user(%s), host(%s) db(%s) magic(0x%x)",
+                            classCount, i, stats_class_data->maxInstance, (uint) V, classCount, 
+                            threadID, proc_info, command_name[command],
+                            user, host, db, *statVerify);
+          Shared->extsql_counter++;
+          extsql_thread_dump(thd, 1);
+          return;
+        }
+
+        // increment it for the class for the 0 (summary time) and the current time
+        offset = ARRAY_INDEX(i, var, maxVar, stats_class_data->time, maxTime);
+        offsetLimit = stats_class_data->dataEnd - stats_class_data->data;
+
+        if STATS_DEBUG(STATS_INC_VAR) {
+          sql_print_information("ExtSQL, class %s, i (%d) incrementing %s by (%d), offset/Limit(%d/%d)", 
+                                stats_class_data->name, i, (*var_ptr)->name, (int) *V, offset, offsetLimit);
+        }
+        
+        // check to make sure offset isn't out of limits
+        if (offset < 0 || offset >= offsetLimit ) {
+           sql_print_warning("ExtSQL: warning, DATA inc offset of 0x%x (%d,%d,%d,%d,%d) for 0x%x class %s of thd %d/%s exceeds bound of 0x%x(0x%x)",
+                             offset, i, var, maxVar, stats_class_data->time, maxTime, 
+                             (uint)V, stats_class_data->name, threadID, command_name[command], offsetLimit, *statVerify);
+          Shared->extsql_counter++;
+          extsql_thread_dump(thd, 1);
+          return;
+        }
+
+        stats_class_data->data[offset] += C; 
+        
+        offset = ARRAY_INDEX(i, var, maxVar, 0, maxTime);
+        stats_class_data->data[offset] += C; 
+        break;  // check the next class
+      } // end if - match
+    } // end for - all vars
+
+  } // end for - all classes
+
+} // end function extsql_inc
+
+#ifdef EXTSQL_BINARY
+#include "../../../../../../../bin/checkParam.h"
+#endif
+
+
+// extsql_prep - invoked to set/confirm start type
+// OUTPUT: startType - STATS_INIT_FAILURE, _NORMAL, _RESET, _RELOAD
+//         it will log an error message on _FAILURE
+// INPUT:  confFile - may be NULL (startType = NORMAL).  If present the files is scanned
+//         for new global extsql vars: _class_list, _users, _reload_file, _debug, _license_key
+//         and the startType is set to _RESET.
+//         reload_file - may be NULL.  If present and contents is valid, startType
+//         set to _RELOAD, file is scanned to make sure hostname and class list matches.
+//         NO global vars are changed!!
+// NOTE:   At present only ONE of confFile and realodFile may be set, error otherwise.
+//         
+void extsql_prep(int *startType, const char *confFile, char *reloadFile) {
+
+  // if no extsql_reload_file is present:
+  //   mysql: reloadFile == 0
+  //   pgsql: reloadFile[0] == 0
+
+  extsql_init_globals();
+
+  if (! STATS_DEBUG(STATS_ADMIN) ) { // always normal
+    *startType = STATS_INIT_NORMAL;
+    return;
+  }
+
+#ifdef PGSQL
+  if (!*startType && *reloadFile) *startType = STATS_INIT_RELOAD;
+#else
+  if (!*startType && reloadFile) *startType = STATS_INIT_RELOAD;
+#endif
+
+  if (*startType == STATS_INIT_RELOAD && reloadFile != NULL) {
+
+    // read reload file
+    File reloadHandle;
+    char *memPtr = NULL, *srcPtr = NULL, *tmpPtr = NULL, *tmpPtr2 = NULL;
+    int size, i, fieldLength;
+    char *rfVersion = NULL, *rfClassList = NULL, *rfHostname = NULL;
+    char *extsql_class_listNoWS;    char hostname[FN_REFLEN];
+
+    if (gethostname(hostname, FN_REFLEN) < 0) {
+      strcpy(hostname, "localhost");
+    }
+
+    if ((reloadHandle = my_open(reloadFile, O_RDONLY|O_BINARY, MYF(0))) < 0 ) {
+      sql_print_information("ExtSQL: Specified reload_file could not be opened: %s", reloadFile);
+      *startType = STATS_INIT_FAILURE;
+      return;
+    }
+
+    if (!(size = extsql_read_section_bytes(reloadFile, reloadHandle, &memPtr, 
+                                           "RELOAD", 0))) {
+      sql_print_error("ExtSQL: Error reading from file %s", reloadFile);
+      *startType = STATS_INIT_FAILURE;
+      return;
+    }  
+
+    // find version, classlist and hostname
+    for (srcPtr = memPtr, i = 0; i < size; srcPtr++, i++) {
+ 
+      if (!strncmp(srcPtr, "host: ", 6)) { // found hostname
+        tmpPtr = srcPtr + strlen("host: ");
+        fieldLength = 0;
+        while (*tmpPtr != '\n') {
+          ++fieldLength;
+          ++tmpPtr;
+        }
+
+        rfHostname = strndup(srcPtr + strlen("host: "), fieldLength);
+      }
+
+      if (!strncmp(srcPtr, "EXT     version: ", 17)) { // found extsql version
+        tmpPtr = srcPtr + strlen("EXT     version: ");
+        fieldLength = 0;
+        while (*tmpPtr != '\n') {
+          ++fieldLength;
+          ++tmpPtr;
+        }
+
+        ++fieldLength; // we want the trailing '\n' here
+
+        rfVersion = strndup(srcPtr + strlen("EXT     version: "), fieldLength);
+      }
+
+      if (!strncmp(srcPtr, "extsql_class_list: ", 19)) { // found class list
+        tmpPtr = srcPtr + strlen("extsql_class_list: ");
+        fieldLength = 0;
+
+        while (*tmpPtr != '\n') {
+          ++fieldLength;
+          ++tmpPtr;
+        }
+
+        rfClassList = strndup(srcPtr + strlen("extsql_class_list: "),
+                              fieldLength);
+      }
+    }
+
+    // by here, all pointers should be set, or we've got a badly
+    // formatted reload file
+    if (!(rfVersion && rfClassList && rfHostname)) {
+      sql_print_error("ExtSQL: Malformatted reload file %s", reloadFile);
+      *startType = STATS_INIT_FAILURE;
+      return;
+    }
+
+    // check for mismatches that are okay, but require confirmation
+    if (strcmp(rfHostname, hostname)) {
+      sql_print_information("ExtSQL: hostname mismatch (file: %s, server: %s)",
+                            rfHostname, hostname);
+      *startType = STATS_INIT_CONFIRM;
+      return;
+    }
+
+    if (strcmp(rfVersion, Shared->extsql_version+1)) {
+      sql_print_information("ExtSQL: version mismatch (file: %s, server: %s)",
+                            rfVersion, Shared->extsql_version+1);
+      *startType = STATS_INIT_CONFIRM;
+      return;
+    }
+
+
+    // we need a duplicate of extsql_class_list without whitespace
+    extsql_class_listNoWS = extsql_strdup(Shared->extsql_class_list, MYF(MY_WME));
+    for (tmpPtr = Shared->extsql_class_list, tmpPtr2 = extsql_class_listNoWS;
+         *tmpPtr != '\0'; ++tmpPtr) {
+
+      if (!(*tmpPtr == ' ' || *tmpPtr == '\t'))
+        *tmpPtr2++ = *tmpPtr;       
+    }
+
+    *tmpPtr2 = '\0';
+
+    if (strcmp(rfClassList, extsql_class_listNoWS)) {
+      sql_print_information("ExtSQL: class list mismatch (file: %s, server: %s)",
+                            rfClassList, extsql_class_listNoWS);
+      *startType = STATS_INIT_CONFIRM;
+      return;
+    }
+
+    my_free(extsql_class_listNoWS, MYF(0));
+    my_free(rfHostname, MYF(0));
+    my_free(rfVersion, MYF(0));
+    my_free(rfClassList, MYF(0));
+    my_free(memPtr, MYF(0));
+    
+  } else if (*startType == STATS_INIT_RESET && confFile != NULL) {
+
+    char line[2048];
+    FILE* conf = fopen(confFile, "r");
+
+    // parse conf file
+    if (conf == NULL) {
+      sql_print_error("ExtSQL: Unable to open conf file %s", confFile);
+      *startType = STATS_INIT_FAILURE;
+      return;
+    }
+
+    while (fgets(line, 1024, conf) != NULL) {
+
+      // lowercase directive name and strip all whitespace
+      bool foundEqual = false;
+      int equalPos = 0, readPos = 0, writePos = 0;
+      char *directive, *data;
+
+      while (line[readPos] != '\0') {
+
+        if (line[readPos] == '=') {
+          foundEqual = true;
+          equalPos = writePos;
+        }
+
+        if (!foundEqual && line[readPos] > 64 && line[readPos] < 91)
+          line[readPos] += 32;
+
+        if (!(line[readPos] == '\t' || line[readPos] == ' ' ||
+              line[readPos] == '\n' || line[readPos] == '"' ||
+              line[readPos] == '\'')) {
+          line[writePos] = line[readPos];
+          ++writePos;
+        }
+
+        ++readPos;        
+      } // end while line
+
+      line[writePos] = '\0';
+
+      if (strncmp(line, "extsql_", 7)) continue;
+
+      directive = strndup(line, equalPos);
+      data = line + (equalPos + 1) * (sizeof(char));
+
+      // set the appropriate data member
+      if (!strcmp(directive, "extsql_class_list"))
+        Shared->extsql_class_list = extsql_strdup(data, MYF(MY_WME));
+      else if (!strcmp(directive, "extsql_users"))
+        extsql_users = extsql_strdup(data, MYF(MY_WME));
+      else if (!strcmp(directive, "extsql_reload_file"))
+        Shared->extsql_reload_file = extsql_strdup(data, MYF(MY_WME));
+      else if (!strcmp(directive, "extsql_debug"))
+        Shared->extsql_debug = atoi(extsql_strdup(data, MYF(MY_WME)));
+      else if (!strcmp(directive, "extsql_key")) {
+        extsql_key = extsql_strdup(data, MYF(MY_WME));
+        sql_print_information("ExtSQL: extsql_key %s", data);
+      }
+      else {
+        sql_print_error("ExtSQL: Unknown configuration directive: %s",
+                        directive);
+        *startType = STATS_INIT_FAILURE;
+      }
+      
+    } // end while read conf
+
+  } else {
+    *startType = STATS_INIT_NORMAL;
+  }
+}
+
+
+
+// extsql_init_globals - MySQL uses threads for each server, Postgres uses a separate process.
+// Shared memory is used to speed our operations, data seg is shared between threads in MySQL,
+// but separate in postgres.  To keep common code we need to alloc the area for our globals,
+// store in section //GLOBALS a top of this file.  Not really needed to MySQL, but doesn't hurt.
+// BIG code change, need to switch all refs to pointers!
+// my_malloc is ifdef'd for PGSQL to do the shared memory magic!
+// Return 1 on failure
+int extsql_init_globals() {
+
+#ifdef PGSQL   
+  // we allocate a big hunk of shared memory
+  bool memFound = false;
+
+  ShmemPtr = (char *) ShmemInitStruct("ExtSQL Data", SHMEM_SIZE, &memFound);
+
+  if (!ShmemPtr) {
+    sql_print_error("ExtSQL extsql_init_globals: can't init shared mem area of %d bytes", SHMEM_SIZE);
+    return(1);
+  }
+
+  if STATS_DEBUG(STATS_DUMP_START) {
+    sql_print_information("ExtSQL extsql_init_globals:  ShmemPtr at 0x%x, memFound(%d)", (uint)ShmemPtr, memFound);
+  }
+
+  if (memFound) { // issue warning, should have only been called once!
+
+    // set our two pointers again
+    MemLock = (slock_t *) ShmemPtr; // already initialized.
+    NextFree = (char **) ShmemPtr + sizeof(slock_t *); 
+    return(0);  // ZZ - not fatal?
+  }
+
+  // if we get here, FIRST and ONLY time through for original allocation.
+    
+  // our MemLock and NextFree live at the start of the region.
+  // this is needed for the PGSQL version of extsql_malloc
+  MemLock = (slock_t *) ShmemPtr;
+  SpinLockInit(MemLock);
+  NextFree = (char **)ShmemPtr + sizeof(slock_t *); 
+  *NextFree = (char *)NextFree + sizeof(NextFree);
+
+  // okay alloc the global space
+  Shared = (pGLOBAL) extsql_malloc(sizeof(GLOBAL), MYF(MY_WME | MY_ZEROFILL) );
+  if (!Shared) {
+    sql_print_error("ExtSQL extsql_init_globals: can't alloc shared area.");
+    return(1);
+  }
+
+  Shared->extsql_class_list = extsql_strdup(extsql_class_list, MYF(MY_WME));
+  Shared->extsql_key = extsql_strdup(extsql_key, MYF(MY_WME));
+  Shared->extsql_users = extsql_strdup(extsql_users, MYF(MY_WME));
+  Shared->extsql_version = extsql_strdup(extsql_version, MYF(MY_WME));      
+  Shared->extsql_reload_file = extsql_strdup(extsql_reload_file, MYF(MY_WME));
+
+#else
+  static int didInit = 0;
+
+  if (!didInit) {
+    // THIS IS MYSQL, the Shared structure is static and already declared.
+    Shared->extsql_class_list = extsql_class_list;
+    Shared->extsql_key = extsql_key;
+    Shared->extsql_users = extsql_users;
+    Shared->extsql_version = extsql_version;      
+    Shared->extsql_reload_file = extsql_reload_file;
+    didInit = 1;
+  } else {
+    return(0);
+  }
+
+  (void) pthread_mutex_init(&Shared->LOCK_stats_clock,MY_MUTEX_INIT_FAST);
+#endif
+
+  // take care of copying some startup global values
+  Shared->extsql_active = extsql_active;
+  Shared->extsql_counter = extsql_counter;
+  Shared->extsql_debug = extsql_debug;
+
+
+  if STATS_DEBUG(STATS_DUMP_START) {
+    sql_print_information("ExtSQL: Globals are active(%d), debug(%d), extsql_class_list(%s), extsql_version(%s), extsql_users(%s), extsql_reload_file(%s)",
+                          (int)Shared->extsql_active, (int)Shared->extsql_debug, Shared->extsql_class_list,
+                          Shared->extsql_version, Shared->extsql_users, Shared->extsql_reload_file);
+  }
+
+
+  return(0);
+
+} // end extsql_init_globals
+
+
+// Called to initialize tracking data structures, potentially reload with prior data.
+// We may be here from a NORMAL init, first time, or a RESET in the middle of a server run 
+// or a RELOAD from a start or the middle of server run.
+// extsql_prep has already been invoked, so global extsql_ vars are set
+int extsql_init(char *extsql_classlist, int startType, char *reloadFile) 
+{
+  int extsql_willbe_active = 1; // track state during init process, global extsql_active is
+                                // always set to off during init.
+  int reloadFail = 0;
+  
+  //extsql_class_list is a comma separated list of which define what we will
+  // be tracking, number of instances, times of data, and which variables
+  //     "db,max-5,time-10,units-d(Com_show_tables,Com_show_variables),
+  //      user,max-50,time-24,units-m(Bytes_sent,Bytes_received)"
+  //   class_name, max-instance_limit, max-time_limit, units-(min|day|hour) (var_list)
+  char *parse_string, *malloc_addr;
+  char *token, *tmpPtr;
+  pSTATS_CLASS_DATA stats_class_data;
+  STAT_VAR **var_ptr = 0;
+  struct show_var_st *status_var_ptr = status_vars;
+  int found = 0, skip = 0, foundParen = 0, num = 0, i = 0, j = 0, size = 0, classCount = 0, totalSize = 0;
+  int thisDebug = 0; char timeUnit;
+  
+  sql_print_information("ExtSQL start type(%s): %s",  startTypeName[startType], Shared->extsql_version+1);
+
+  // allocate our global area
+  if (extsql_init_globals()) {
+    sql_print_error("ExtSQL: start aborted.  Failed to alloc global shared mem.");
+    return(1);
+  }
+
+  // Shared->extsql_class_list = my_strdup(extsql_class_list, MYF(MY_WME));
+  // Shared->extsql_reload_file = my_strdup(extsql_reload_file, MYF(MY_WME));
+
+
+  Shared->extsql_active = 0; // will be set at end of this function if returned to active
+
+
+  if (startType == STATS_INIT_FAILURE) {
+    sql_print_error("ExtSQL: disabled.  Start aborted due to prior errors");
+
+    // We do not set Shared->extsql_disabled, may just be a failed reload/reset, okay to try again.
+    return(1);
+  }
+
+
+#ifdef EXTSQL_BINARY
+
+  int status, days;
+
+  // license sequence is ONLY area for returns before end of function!
+  if (!extsql_key) {
+    sql_print_error("ExtSQL: disabled. No license key found for binary build, make sure to define ExtSQL_key in /etc/my.cnf.");
+    Shared->extsql_active = 0;  // turn it all off
+    Shared->extsql_disabled = 1;
+    return(1);
+  }
+
+  if (status = checkParam(Shared->extsql_version+1, extsql_key, &days)) {
+    sql_print_error("ExtSQL: disabled.  Improper license key found(%s), code %d.", 
+                    Shared->extsql_version+1, status);
+    Shared->extsql_active = 0;  // turn it all off
+    Shared->extsql_disabled = 1;  // turn it all off
+    return(1);
+  }
+    
+  if (days == 99999) { 
+    sql_print_information("ExtSQL: Permanent license verified.");
+    
+  } else if (days < 31) {
+
+    // limited time
+    sql_print_warning("ExtSQL: Evaluation license good for server startup only %d more days.", days);
+
+  } else {
+
+    // expired
+    sql_print_error("ExtSQL: disabled.  Evaluation period has expired.");
+    Shared->extsql_disabled = 1;  // turn it all off
+    Shared->extsql_active = 0;  // turn it all off
+    return(1);
+
+  }    
+
+#endif
+
+  if (!extsql_users) {
+    sql_print_information("ExtSQL: no defined user list, only root user allowed");
+    extsql_users="root";
+  } else {
+    sql_print_information("ExtSQL: access allowed only to users: %s", extsql_users);
+  }
+
+  if (!extsql_class_list) {
+    extsql_willbe_active = 0;  // turn it all off
+    Shared->extsql_disabled = 1;  // turn it all off
+    Shared->extsql_active = 0;  // turn it all off
+    sql_print_information("ExtSQL: deactivated by user, no extsql_class_list defined");
+    return(1);
+
+  } else {
+    extsql_willbe_active = 1;
+  }
+  
+  //init our var addr tracking array to unstored
+  bzero((char *) Shared->varAddrTrackArray, sizeof(Shared->varAddrTrackArray));
+  Shared->varAddrCount = 0;
+
+  // if we are here because of a RESET, there should be something in the statAllocArray
+  // from prior - check to make sure -- if _NORMAL, we zero the whole thing.
+  if (startType != STATS_INIT_NORMAL) {   // _RELOAD or _RESET
+    
+    // wait just a bit for all threads to know we've stopped
+    Shared->extsql_reload_in_progress = 1;
+    sleep(2);
+   
+    if (startType == STATS_INIT_RESET && ( ! Shared->statsAllocArray[0] || ! Shared->allocIndex) ) { // empty!
+      sql_print_error("ExtSQL: deactivated, RESET request failed, no prior data found.");
+      extsql_willbe_active = 0;
+      
+    } else { // free up any existing for RELOAD or RESET
+      
+      char *addr;
+      for (i = 0, addr = Shared->statsAllocArray[i]; (addr = Shared->statsAllocArray[i]) && i < STATS_MAX_NUM_ALLOC; i++) {
+        my_free(addr, MYF(0)); 
+      }
+    } // end if - memory clear necessary
+
+  } else {
+
+    Shared->extsql_reload_in_progress = 0;
+
+  } // end if-else startType other than NORMAL
+
+
+  bzero((char *) Shared->statsAllocArray, sizeof(Shared->statsAllocArray));
+  Shared->allocIndex = 0; // for recording mem allocations
+  bzero((char *) &Shared->statData, sizeof(Shared->statData)); // zero out all the contents, support restart - reload
+  
+  if STATS_DEBUG(STATS_DUMP_START) sql_print_information("ExtSQL tracking classes: %s", extsql_class_list); //DEBUG
+  
+  if (!(parse_string = extsql_strdup(extsql_class_list, MYF(MY_WME)))) {
+    Shared->extsql_active = 0;
+    Shared->extsql_disabled = 1;
+    Shared->extsql_reload_in_progress = 0;
+    sql_print_error( "ExtSQL: disabled, unable to dup extsql_class_list(%s)",
+                     extsql_class_list);
+    return(1);
+    
+  } 
+    
+  if (startType == STATS_INIT_NORMAL || startType == STATS_INIT_RESET) { // init structures on RESET/NORMAL starts, skip on RELOAD
+      
+    int i = 0; // track our position in statVars
+    Shared->statsAllocArray[Shared->allocIndex++] = parse_string;
+    malloc_addr = parse_string;
+    
+    
+    while ( (token = strtok(parse_string, ", ")) ) { // start new loop on each class name
+      
+      char **tPtr;
+      parse_string = NULL;
+      found = 0; num = 0;
+      
+      // should have a class name
+      if (thisDebug) sql_print_information("ExtSQL, Class token is (%s)", token);
+      
+        
+      // is it allowable
+      for (tPtr = extsqlClassesSupported; *tPtr; tPtr++) {
+        if (!strcmp(token, *tPtr)) {
+          found = 1;
+          break;
+        }
+      } // end for - allowable class names
+
+      if (! found) {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, bad class name (%s)", token);
+        break;
+      }
+
+      // we have a valid class name, make sure it is not a dup
+      found = 0;
+      for (stats_class_data = Shared->statData; stats_class_data->name[0]; stats_class_data++) {
+        if (!strcmp(token, stats_class_data->name)) {
+          found = 1;
+          break;
+        }
+      } // end for - existing classes
+
+      if (found) {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, duplicate class name (%s)", token);
+        break;
+      }
+
+      // okay we have a good name, start loading the structure
+      strncpy(stats_class_data->name, token, STATS_MAX_NAME-1);
+
+      // set our starting time
+      stats_class_data->time = 0;
+
+
+      // get the next token, should be instance limit
+      if (! (token = strtok(parse_string, ", "))) {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, incomplete class definitions, started with (%s)", 
+                        extsql_class_list);
+        break;
+      }
+
+      // should start with max-
+      if (strncmp(token, "max-", 4)) {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, missing max instance amount, got (%s)", 
+                        token);
+        break;
+      }
+
+      // get the number for max instances and allocate space
+      num = atoi(token+4);
+      if (!num) {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, missing valid instance amount, got (%s)", 
+                        token);
+        break;
+      }
+      stats_class_data->maxInstance = num;
+
+      // we null term it by getting one more than required
+      if (!(stats_class_data->instanceIndex =  (char **)extsql_malloc( ((num+1) * sizeof(char *)),
+                                                                   MYF(MY_WME | MY_ZEROFILL)) )) {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, can't allocate class instance memory");
+        break;
+      }
+      Shared->statsAllocArray[Shared->allocIndex++] = (char *)stats_class_data->instanceIndex;
+
+
+      // good instance limit, now get time limit
+      if (! (token = strtok(parse_string, ", "))) {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, incomplete class definitions, missing time limit, started with (%s)", 
+                        extsql_class_list);
+        break;
+      }
+
+      // should start with time-
+      if (strncmp(token, "time-", 5)) {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, missing max time amount, got (%s)", 
+                        token);
+        break;
+      }
+
+      // get the number for max times
+      num = atoi(token+5);
+      num += 1; // always the zero hour - totals
+      if (!num || num < 2) {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, missing valid time amount, got (%s)", 
+                        token);
+        break;
+      }
+      stats_class_data->maxTime = num;
+
+      // allocate space  ZZ add to size count reported
+      if (!(stats_class_data->timeLabels = (my_time_t *)extsql_malloc( ((num+1) *  sizeof(my_time_t)),
+                                                                   MYF(MY_WME | MY_ZEROFILL)) )) {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, can't allocate class time label memory");
+        break;
+      }
+      Shared->statsAllocArray[Shared->allocIndex++] = (char *) stats_class_data->timeLabels;
+
+      // get the time Units, m - minutes, h - hours, d - days
+      if (! (token = strtok(parse_string, ", "))) {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, incomplete class definitions, missing timeUnits started with (%s)", 
+                        token);
+        break;
+      }
+        
+      // should start with units-
+      if (strncmp(token, "units-", 6)) {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, missing units amount, got (%s)", 
+                        token);
+        break;
+      }
+
+      // get the time units
+      timeUnit = *(token+6);
+      if (timeUnit == 'm') {
+        stats_class_data->timeUnits = 'm';
+      } else if (timeUnit == 'h') {
+        stats_class_data->timeUnits = 'h';
+      } else if (timeUnit == 'd') {
+        stats_class_data->timeUnits = 'd';
+      } else {
+        extsql_willbe_active = 0;
+        sql_print_error("ExtSQL: deactivated, missing valid time unit amount, got (%c)", 
+                        timeUnit);
+        break;
+      }
+
+      // set remaining vars
+      stats_class_data->maxVar = 0;
+      stats_class_data->lastTime = 0;
+          
+      // okay, next token is var list like: (Com_show_tables,Com_show_variables) OR
+      //                                    (  Com_....  )
+      // first and last token have parens
+      // clear out tmp storage
+      j = 0;  // keep track of var tokens
+      i = 0;
+      foundParen = 0;  // haven't seen closing paren
+      while (!foundParen && (token = strtok(parse_string, ", ")) ) {
+
+        if (thisDebug) sql_print_information("ExtSQL, variable token is (%s)", token);
+
+        // none of the tokens should be close to MAX_VAR_SIZE
+        if (strlen(token) > MAX_VAR_SIZE - 5) {
+          extsql_willbe_active = 0;
+          sql_print_error("ExtSQL, var name too long in var list (%s)", 
+                          token);
+          break;
+        }
+
+        // if we got a closing paren by itself, we're done
+        if (!strcmp(")", token)) {
+          break;
+        }
+
+        // should have a paren( on first one, move past that
+        if (!j) {
+          if (token[0] != '(') {
+            extsql_willbe_active = 0;
+            sql_print_error("ExtSQL, bad format in var list, missing ( in %s", 
+                            token);
+            break;
+          }
+            
+          // okay, now we count the , from opening to closing paren, need to know
+          // how many vars there are so we can allocate space for pointer array to them
+          for (i = 0, num = 1, tmpPtr = token; *tmpPtr != ')'; tmpPtr++) {
+            if (*tmpPtr == ',') {
+              num++;
+            }
+          } // end for - token string
+            
+            // we null term pointer array by alloc of one extra
+          if (!(stats_class_data->varIndex =  (STAT_VAR **)extsql_malloc( ((num+1) * sizeof(pSTAT_VAR)),
+                                                                      MYF(MY_WME | MY_ZEROFILL)) )) {
+            extsql_willbe_active = 0;
+            sql_print_error("ExtSQL: deactivated, can't allocate class varIndex memory");
+            break;
+          }
+            
+          Shared->statsAllocArray[Shared->allocIndex++] = (char *) stats_class_data->varIndex;
+          var_ptr = stats_class_data->varIndex; // pointer to array of pointer to each var we find below
+
+          // check to see if got just a ')', in that case we get the next
+          if (!strcmp(token, "(")) {
+            token = strtok(parse_string, ", ");
+          } else {
+            token++; // move off paren
+          }
+
+          if (thisDebug) sql_print_information("ExtSQL, FIRST variable token is (%s)", token);
+
+        } // end if - starting paren
+
+        if (token[strlen(token) - 1] == ')') { // last one
+          token[strlen(token) - 1] = '\0'; // null it out early
+          foundParen = 1;
+          if (thisDebug) sql_print_information("ExtSQL, LAST variable token is (%s)", token);
+        }
+
+        // unless the debug flag is set, check to see if allowed
+        if (!STATS_DEBUG(STATS_EXTRA_VARS)) {
+          char **varPtr; extsql_willbe_active = 0;
+          for (varPtr = allowedVars; *varPtr; varPtr++) {
+            if (!strcmp(*varPtr, token)) {
+              extsql_willbe_active = 1;
+              break;
+            } // end if
+          } // end for - all allowed
+            
+          if (!extsql_willbe_active) {
+            sql_print_error("ExtSQL, requested tracking var (%s) not on approved list.  Please check spelling and documenation.  This setting can be overridden via debug flag (STATS_EXTRA_VARS)",
+                            token);
+            break;
+          }
+        } // end if - check approved vars
+
+
+        j++;   // token count
+          
+        // we should now have a token, look for match in status_vars
+        found = 0; skip = 0;
+        for (status_var_ptr = status_vars;  status_var_ptr->name; status_var_ptr++) {
+            
+          if (thisDebug) sql_print_information("ExtSQL, status_var is %s(0x%x)", 
+                                               status_var_ptr->name, (uint)status_var_ptr->value );
+
+          if (!strcmp(token, status_var_ptr->name)) { // match
+              
+            if (!status_var_ptr->value && strcmp(token, "Questions")) { // no address assigned, not tracking this 
+              // okay if Questions, we will fix below
+                                           
+
+#ifdef EXTSQL_50
+              // okay if Bytes_received - first item
+              if (strcmp(token,"Bytes_received")) { // only okay for Bytes_received
+#endif
+                sql_print_error("ExtSQL, variable (%s) has no address, can not be tracked",
+                                status_var_ptr->name);
+                extsql_willbe_active = 0;
+                break;
+#ifdef EXTSQL_50
+              }
+#endif
+            } // end if - no address
+            
+            // allocate room for the structure itself, put the address in the pointer array
+            if (!(*var_ptr =  (STAT_VAR *)extsql_malloc( (sizeof(STAT_VAR)),
+                                                     MYF(MY_WME | MY_ZEROFILL)) )) {
+              extsql_willbe_active = 0;
+              skip = 1;
+              sql_print_error("ExtSQL: deactivated, can't allocate class var memory");
+              break;
+            }
+              
+            Shared->statsAllocArray[Shared->allocIndex++] = (char *) *var_ptr;
+
+            if (!((*var_ptr)->name = extsql_strdup(status_var_ptr->name, MYF(MY_WME)))) {
+              extsql_willbe_active = 0;
+              sql_print_error( "ExtSQL: deactivated, unable to alloc for (%s)",
+                               status_var_ptr->name);
+              break;
+            } // end if - malloc
+
+            Shared->statsAllocArray[Shared->allocIndex++] = (*var_ptr)->name;
+
+#ifdef PGSQL
+            (*var_ptr)->addr = (char *)status_var_ptr->value;
+#else
+
+            // SPECIAL here, if the value is Connections or Questions, we override with our internal
+            // tracking variable address (connects or queries) -- special case for them.
+            if (!strcmp(token, "Questions")) {
+              (*var_ptr)->addr = (char *)&Shared->queries;
+            } else if (!strcmp(token, "Connections")) {
+              (*var_ptr)->addr = (char *)&Shared->connects;
+            } else { // regular
+              (*var_ptr)->addr = (char *)status_var_ptr->value;
+            }
+#endif
+              
+            found = 1;
+            if (thisDebug) sql_print_information("ExtSQL: tracking varIndex[%d] var(%s), addr(0x%x)\n",
+                                                 i, (*var_ptr)->name, (uint)(*var_ptr)->addr);
+            (uint)stats_class_data->maxVar++;
+            i++; 
+
+            // store the addr in our quick look up array, only if its not already there
+            if (extsql_store_var_addr((*var_ptr)->addr)) {
+              extsql_willbe_active = 0;
+              break;
+            }
+            
+            break ; // look for next one
+              
+          } // end if - match
+            
+        } // end for - more status vars
+          
+        if (skip) { // we missed a variable that had a zero address, that is okay.
+          continue;
+        }
+            
+        if (! found ) { // could not complete match on one of their variables
+          extsql_willbe_active = 0;
+          sql_print_error( "ExtSQL: deactivated, could not complete variable match for (%s)",
+                           token);
+        }
+          
+        if (! extsql_willbe_active || ! stats_class_data->maxVar) { // had failure somewhere above
+          extsql_willbe_active = 0;
+          break;
+        }
+        var_ptr++;
+ 
+      } // end while -  more tokens in var list
+        
+      if (! extsql_willbe_active) { // had a failure above
+        break;
+      }
+      
+    } // end while - more token in class definitions
+      
+  } else if (startType == STATS_INIT_RELOAD) {
+    
+    // make copy of class list in the event of failure
+    char* oldClassList = extsql_strdup(extsql_class_list, MYF(MY_WME));
+
+    if (extsql_reload(STATS_READ_RELOAD, reloadFile)) { // reload failed 
+      
+      sql_print_error("ExtSQL: Reload FAIL--resetting class list OLD(%s), NEW(%s)",
+                            oldClassList, extsql_class_list);
+      
+      // restore old class list
+      extsql_class_list = oldClassList;
+      
+      // reset
+      startType = STATS_INIT_RESET;
+      extsql_willbe_active = 1; // reload should log error 
+      reloadFail = 1; // flag to return error status      
+    }
+ 
+  } // end if-else startType (NORMAL, RESET or RELOAD
+  
+  
+  if (extsql_willbe_active) { // calculate data sizes for each class and print what we got
+      size = 0;
+      
+      for (stats_class_data = Shared->statData, classCount = 0; 
+           classCount < STATS_MAX_CLASSES && stats_class_data->maxInstance; 
+           stats_class_data++, classCount++) {
+        
+        if STATS_DEBUG(STATS_DUMP_START) sql_print_information("ExtSQL, class %s, max inst %d, max vars %d, max time %d %d", 
+                                                               stats_class_data->name, stats_class_data->maxInstance,
+                                                               stats_class_data->maxVar, stats_class_data->maxTime,
+                                                               stats_class_data->timeUnits);
+        
+        // loop through all vars
+        for (var_ptr = stats_class_data->varIndex, i = 0; i < stats_class_data->maxVar;
+             var_ptr++, i++) {
+          if STATS_DEBUG(STATS_DUMP_START) sql_print_information("   Var %s at addr 0x%x", (*var_ptr)->name, (uint)(*var_ptr)->addr);
+        } // end for all vars defined
+        
+        size = stats_class_data->maxInstance * stats_class_data->maxVar *
+          stats_class_data->maxTime * sizeof(ulong);
+        
+        // if NOT RELOAD (a NORMAL OR RESET start) allocate data space
+        if (startType != STATS_INIT_RELOAD) {
+          if (!(stats_class_data->data  = (ulong *)extsql_malloc(size, MYF(MY_WME | MY_ZEROFILL)) )) {
+            extsql_willbe_active = 0;
+            sql_print_error("ExtSQL: deactivated, failed to alloc %d bytes for class %s data",
+                            size, stats_class_data->name);
+            break;
+          }
+        
+          Shared->statsAllocArray[Shared->allocIndex++] = (char *)stats_class_data->data;
+          stats_class_data->dataEnd = stats_class_data->data + size/sizeof(ulong);
+        }
+        
+        // set end marker
+        if STATS_DEBUG(STATS_DUMP_START) sql_print_information("   Data allocated %d bytes, data start at 0x%x, end at 0x%x", 
+                                                               size, (uint)stats_class_data->data, (uint)stats_class_data->dataEnd);
+        totalSize += size;
+
+#ifdef PGSQL
+        if (totalSize + SHMEM_RESERVE > SHMEM_SIZE) {
+          extsql_willbe_active = 0;
+          sql_print_error("ExtSQL: deactivated, projected mem usage (%d) too close to limit of %d",
+                            size, SHMEM_SIZE);
+        }
+#endif
+
+      } // end for - all classes
+  } // end if - stats will be active
+  
+  if (startType != STATS_INIT_NORMAL) { // RELOAD or RESET, clear any stored thread instance info
+
+#ifndef PGSQL
+   
+    // loop through ALL threads and zero indexes
+    i = 1;
+    while (pthread_mutex_trylock(&LOCK_thread_count)) { // didn't get it, do UNLOCK!!!!
+      sleep(i++);
+      sql_print_information("ExtSQL: Trying to completed RELOAD/RESET, can't get lock, sleeping for (%d)",i);
+      if (i > 5) {
+        extsql_willbe_active = 0;
+
+        VOID(pthread_mutex_unlock(&LOCK_thread_count));
+        break;
+      }
+    } // end while - get thread lock
+    
+
+    if (extsql_willbe_active) { // loop through all threads
+
+        I_List_iterator it(threads);
+        THD *tmp;
+        int *indexPtr, *statVerify;
+      
+        while ((tmp=it++)) {
+          extsql_thread_init(tmp, STATS_THD_INIT_ALL);
+        } // end while - more threads
+
+      } // end if - extsqlwillbeactive
+
+      VOID(pthread_mutex_unlock(&LOCK_thread_count));
+#endif
+      
+#ifdef NEVER__
+    }
+#endif
+
+  } // end if - RELOAD or RESET
+  
+  if (extsql_willbe_active) {
+    Shared->extsql_active = 1;
+    sql_print_information("ExtSQL ACTIVE allocated memory: %d bytes for %d classes", 
+                          totalSize, classCount); 
+  }  else {
+    sql_print_information("ExtSQL NOT ACTIVE");
+    Shared->extsql_active = 0;
+  }// end if - stats active
+
+  Shared->extsql_reload_in_progress = 0; // in all cases.
+
+  if (Shared->extsql_active && !reloadFail) {
+    return(0);
+  } else {
+    return(1);
+  }
+  
+} // end extsql_init
+
+
+// extsql_init_proc_vars - is used to abstract the different locations in which both
+// MySQL and Postgres store process/status info
+// this is always with respect to the current thread -- not all are available for both!
+static void extsql_init_proc_vars(int *threadID, int *command, char **user, char **db, char **host, 
+                                  char **proc_info, int **indexPtr, int **statVerify) {
+
+#ifdef PGSQL
+  THD *thd = MyProc;
+#else
+  THD *thd = current_thd;
+#endif
+  
+#ifdef PGSQL
+  *user = MyProcPort->user_name;
+  *statVerify = &thd->statVerify;
+  *indexPtr = thd->statIndex;
+  *proc_info = "n/a";
+  *host = "n/a";
+  *command = 1;
+  *threadID = getpid();
+#else
+
+#ifdef EXTSQL_50
+  *user = thd->security_ctx->user;
+  *host = thd->security_ctx->host;
+  *statVerify = &thd->security_ctx->statVerify;
+  *indexPtr = thd->security_ctx->statIndex;
+#else
+  *user = thd->user;
+  *host = thd->host;
+  *statVerify = &thd->statVerify;
+  *indexPtr = thd->statIndex;
+#endif
+
+  // more just MySQL
+  *command = thd->command;
+  *proc_info = (char *)thd->proc_info;
+  *threadID = thd->thread_id;
+#endif
+
+#ifdef PGSQL
+  *db = MyProcPort->database_name;
+#else
+  *db = thd->db;
+#endif
+
+
+} // end extsql_init_proc_vars 
+
+// this function prints hex bytes from the startAddr for size
+static void extsql_print_bytes(char *startAddr, int size) {
+
+  char *tmpPtr;
+  int i;
+  char buff[120] = {'\0'};
+
+  for (i = 0, tmpPtr=startAddr; i < size; tmpPtr++, i++) {
+
+    if (!(i%8) && strlen(buff)) {
+      sql_print_information("ExtSQL: 0x%x - %s", (uint)startAddr+i, buff);
+      buff[0] = '\0';
+    }
+    sprintf(buff+strlen(buff), "0x%x (0x%x) / ", i, *tmpPtr);
+
+  } // end for - entire string
+
+  if (strlen(buff)) {
+    sql_print_information("ExtSQL: 0x%x - %s", (uint)startAddr+i, buff);
+  }
+
+} // end extsql_print_bytes
+    
+
+// this utility function reds a section header in a
+// RELOAD file and stores to address of memPtr, 
+// as input if memPtr is zero, this function allocates memory and it must be
+// freed by caller.  If memPtr is nonzero, we assume caller has allocated space!
+// returns 0 on error,  hdr is the name of the header we should be reading
+// num is context for an error.
+int extsql_read_section_bytes(char *fileName, File fileDes, char **memPtr,
+                                     char *hdr, int num) {
+
+  char buff[80];
+  int size;
+  
+
+  // read the section hdr
+  if (my_read(fileDes, buff, STATS_SECTION_HDR, MYF(MY_WME)) != STATS_SECTION_HDR) {
+    sql_print_error("ExtSQL: Section header byte count read failed on file %s, (%s/%d)",
+                    fileName, hdr, num);
+    return(0);
+  }
+  
+  if (!strstr(buff, hdr)) { // missing
+    sql_print_error("ExtSQL: Section header from file %s unexpected, got %s, wanted %s",
+                    fileName, buff, hdr);
+    return(0);
+  }
+
+  size = atoi(buff + STATS_SECTION_BYTES);
+
+  if (size <= 0) {
+    sql_print_error("ExtSQL: Section header bad size (%d) on file %s, (%s/%d)",
+                    size, fileName, hdr, num);
+    return(0);
+  }
+
+
+  if (*memPtr == NULL) { // alloc memory for the data
+    if (!(*memPtr = (char *)extsql_malloc(size, MYF(MY_WME | MY_ZEROFILL)))) {
+      sql_print_error("ExtSQL: Could not alloc %d bytes to read data  on file %s, (%s/%d)",
+                      size, fileName, hdr, num);
+      return(0);
+    }
+  }
+
+  if (my_read(fileDes, *memPtr, size, MYF(MY_WME)) != size) {
+    sql_print_error("ExtSQL: Section header data read failed on file %s for %d bytes, (%s/%d)",
+                    fileName, size, hdr, num);
+    return(0);
+  }
+  
+  return(size);
+} // end extsql_read_section_bytes
+  
+
+// extsql_write_section_hdr - writes the header for a section to the RELOAD
+// file.  The hdr should curretnly be 6 chars in length.  The size is the
+// size of the data to be stored in that section.
+// Returns non zero on error, puts msg in error log.
+static int extsql_write_section_hdr(char *loadFileName, File reloadFile, char *hdr, int size) {
+
+  char buff[60];
+
+  if (strlen(hdr) != 6) {
+    sql_print_error("ExtSQL: Bad header length for %s", hdr);
+    return(1);
+  }
+
+  sprintf(buff, "\nEXT %s: %09d\n", hdr, size);
+
+  if (strlen(buff) != STATS_SECTION_HDR) { // sanity check
+    sql_print_error("ExtSQL: Bad length for %s section hdr,  %d/%d", 
+                    hdr, STATS_SECTION_HDR, strlen(buff));
+    return(1);
+  }
+
+  
+  if (my_write(reloadFile, (byte*) buff, STATS_SECTION_HDR, MYF(MY_WME)) != STATS_SECTION_HDR) {
+    sql_print_error("ExtSQL: Could not write %s header section to RELOAD file %s (%d/%d)", 
+                    hdr, loadFileName, size, reloadFile);
+    return(1);
+  }
+ 
+  return(0);
+
+} // end - extsql_write_section_hdr
+
+
+// manage reload data - this function take care of reading/write reload data. 
+// WRITE_RELOAD: It creates the file used for the RELOAD command, most of it 
+// consists of binary data, but the first few lines are in ASCII so that a 'head' can
+// be done on the file to extract general info
+// READ_RELOAD: Reads in file, sets globa statData and extsql_class_list to what is found
+// in the file.
+// IN: action (STATS_WRITE_RELOAD, STATS_READ_RELOAD)
+// IN: loadFileName (name of reload file to read/write)
+// GLOBALS: will read/write extsql_class_list and statData
+int extsql_reload(int action, char *loadFileName) {
+
+  File reloadFile;  // a file descriptor
+  char buff[STATS_TMP_BUFF_SIZE];
+  char *memPtr; // memPtr holds dynamic alloc, needs to be freed!
+  my_time_t now_sec;
+  MYSQL_TIME mysql_time;
+
+#ifndef PGSQL
+  THD *thd =  _current_thd();
+#endif
+
+  char dateBuff[80];
+#define CLASS_SIZE 8192
+  char classBuff[CLASS_SIZE];
+  char *srcPtr, *destPtr, *actionStr, *className, **ptrPtr;
+
+  pSTATS_CLASS_DATA stats_class_data;
+  int maxVar, maxTime, maxInstance, var, found, instance, classCount, size, size2, mode, i;
+  int numClasses;
+  char hostname[FN_REFLEN];  // defined in my_global.h
+ 
+  if (! STATS_DEBUG(STATS_ADMIN)) { // disabled
+    sql_print_information(adminDisabled);
+    return(0);
+  }
+
+  if (gethostname(hostname, FN_REFLEN) < 0) { // failed
+    strcpy(hostname, "localhost");
+  }
+
+  // Shared->extsql_debug |= STATS_RELOAD;
+
+  if (action == STATS_WRITE_RELOAD) { // set some params
+    mode = O_WRONLY|O_CREAT|O_BINARY;
+    actionStr = "write/store";
+  } else if (action == STATS_READ_RELOAD) {
+    mode = O_RDONLY|O_BINARY;
+    actionStr = "read/restore";
+  } else {
+    sql_print_error("ExtSQL: unexpected reload request (%d)", action);
+    return(1);
+  }
+
+  if (strlen(Shared->extsql_class_list) >= CLASS_SIZE) {
+    sql_print_error("ExtSQL: extsql_class_list too long for configured limit, can't save RELOAD data.");
+    return(1);
+  }
+
+  // open the file
+  if ((reloadFile= my_open(loadFileName, mode, MYF(0))) < 0 ) {
+    sql_print_error("ExtSQL: Unable to open %s for %s of RELOAD data, aborted (%d).", 
+                    loadFileName, actionStr, errno);
+    return(1);
+  }
+  sql_print_information("ExtSQL: (%s) Reload file is %s, Current active extsql_class_list is %s",
+                        actionStr, loadFileName, Shared->extsql_class_list);
+
+  // get the current date/time, do any conversions
+  now_sec = time(NULL);
+
+#ifdef PGSQL
+        // need time convesion ZZ
+  mysql_time = now_sec;
+#else
+  thd->variables.time_zone->gmt_sec_to_TIME(&mysql_time, (my_time_t) now_sec);
+#endif
+
+  my_datetime_to_str(&mysql_time, dateBuff);
+
+  // strip ALL blanks from current class_list, count classes
+  numClasses = 0;
+  for (srcPtr=Shared->extsql_class_list, destPtr=classBuff; *srcPtr; srcPtr++) {
+    
+    if (*srcPtr != ' ' && *srcPtr != '\t') {
+      *destPtr++ = *srcPtr;
+    }
+
+    if (*srcPtr == ')') {
+      numClasses++;
+    }
+  } // end for - all chars
+
+  // null term
+  *destPtr = '\0';
+  
+  // write/read the header lines first, following format, designed to allow grep "EXT" to show
+  //  useful info:
+  //
+  // line 0 - "\nEXT RELOAD: 000000025\n   (ALL section headers, 12 char prefix, 9 char size
+  // line 1 - "EXT data stored on:  date/time\n"
+  // line 2 - "EXT      From host:  bit.bongo.com\n"
+  // line 3 - "EXT extsql version:  version\n"
+  // line 4 - "EXT\n"
+  // line 3 - "EXT ExtSQL extsql_class_list: db,max-130,time-100,units-m,(Binlog_cache_disk_use,Binlog_cache_use...\n"
+  // line 5 - "EXT\n";
+
+  if (action == STATS_WRITE_RELOAD) {
+
+    sprintf(buff, "\
+EXT data stored: %s\n\
+EXT   from host: %s\n\
+EXT     version: %s\n\
+EXT num classes: %d\n\
+EXT\n\
+EXT extsql_class_list: %s\n\
+EXT\n", dateBuff, hostname, Shared->extsql_version+1, numClasses, classBuff);
+    
+ 
+    if (extsql_write_section_hdr(loadFileName, reloadFile, "RELOAD", strlen(buff))) {
+      return(1);
+    }
+  
+    if (my_write(reloadFile, (byte*) buff, strlen(buff), MYF(MY_WME)) != strlen(buff)) {
+      sql_print_error("ExtSQL: Could not %s header data to RELOAD file %s", actionStr, loadFileName);
+      return(1);
+    }
+    
+  } else { // READ
+
+    char *classListStart;
+    
+    memPtr = NULL; // read_section_bytes will alloc space
+    if (!(size = extsql_read_section_bytes(loadFileName, reloadFile, &memPtr, 
+                                           "RELOAD", 0))) {
+      return(1);
+    } 
+
+    // find the stored class list.
+    found = 0;
+    for (srcPtr = memPtr, i = 0; i < size; srcPtr++, i++) {
+      if (!strncmp(srcPtr, "extsql_class_list:", 18)) { // found it
+        found = 1;
+        classListStart = srcPtr + strlen("extsql_class_list: ");
+        break;
+      }
+      
+    } // end for - all chars in header
+    
+    if (!found) {
+      sql_print_error("ExtSQL: Could not find class info in %s, section size (%d) (%s)", 
+                      loadFileName, size, memPtr);
+      my_free(memPtr, MYF(0));
+      return(1);
+    }
+
+    // NULL term the class list
+    for (i = 0; *(srcPtr+i) != '\n'; i++) ;      
+    *(srcPtr+i) = '\0'; // null term
+
+    // check for new class list
+    if (strncmp(classListStart, classBuff, strlen(classBuff)) ||
+        strlen(classListStart) != strlen(classBuff)) {
+
+      char *numClassPtr;
+      
+      if (!(Shared->extsql_class_list = extsql_strdup(srcPtr, MYF(MY_WME)))) {
+        sql_print_error("ExtSQL: reload failed, unable to alloc space for new class list");
+        return(1);
+      }
+
+      // check the number of classes present
+      numClasses = 0;
+      if (!(numClassPtr = strstr(memPtr, "num classes: "))) {
+        sql_print_error("ExtSQL: failed to find class count in reload file");
+        return(1);
+      }
+      numClasses = atoi(numClassPtr + strlen("num classes: "));
+      
+
+      sql_print_information("ExtSQL: %d classes found, new class list will be loaded: %s", 
+                            numClasses, Shared->extsql_class_list);
+ 
+    } // end if - new class list
+    
+    my_free(memPtr, MYF(0));
+
+  } // end if - else (first section)
+
+  if STATS_DEBUG(STATS_RELOAD) {
+    sql_print_information("ExtSQL: during %s on %s, completed section RELOAD", actionStr, hostname);
+  }
+    
+  // loop and read/write each class data to/from the RELOAD file  
+  classCount = 0;
+  for (stats_class_data = Shared->statData; classCount < STATS_MAX_CLASSES && classCount < numClasses; 
+       stats_class_data++, classCount++) {
+
+    STAT_VAR **statPtr;
+      
+    
+    // -- below section repeated for each class
+    // -- write the binary data in sections, each unique section preceded by byte count that follows
+    // line 6 - "\nEXT CLAS n: 000000000\n"   (class number, 0..n
+    //        -  structure STATS_CLASS_DATA
+
+    sprintf(buff, "CLAS %1d", classCount);
+
+    if (action == STATS_WRITE_RELOAD) { 
+
+      if (extsql_write_section_hdr(loadFileName, reloadFile, buff, sizeof(STATS_CLASS_DATA))) {
+        return(1);
+      }
+
+      if (my_write(reloadFile, (byte*) stats_class_data, sizeof(STATS_CLASS_DATA), 
+                   MYF(MY_WME)) != sizeof(STATS_CLASS_DATA)) {
+        sql_print_error("ExtSQL: Could not %s class %d header data to RELOAD file %s", actionStr, 
+                        classCount, loadFileName);
+        return(1);
+      }
+      
+    } else { // READ
+      
+      memPtr = (char *) stats_class_data;
+      if (!extsql_read_section_bytes(loadFileName, reloadFile, &memPtr, 
+                                    buff, classCount)) {
+        return(1);
+      }
+      
+    }
+    
+    className = stats_class_data->name;
+    maxVar = stats_class_data->maxVar; 
+    maxTime = stats_class_data->maxTime; 
+    maxInstance = stats_class_data->maxInstance;
+
+
+    // sanity check, make sure the className is on our supported list
+    for (i = 0, ptrPtr=extsqlClassesSupported; i < STATS_MAX_CLASSES; i++, ptrPtr++) {
+
+      found = 0;
+      if (! strcmp(className, *ptrPtr)) {
+        found = 1;
+        break;
+      }
+    } // end for - all supported classes
+    
+    if (!found) {
+      sql_print_error("ExtSQL: Bad class name found (%s)", className);
+      return(1);
+    }
+
+    // print out summary info on the CLASS
+    if STATS_DEBUG(STATS_RELOAD) {
+      sql_print_information("ExtSQL: During reload (%s), starting section %s", actionStr, buff);
+      sql_print_information("CLASS is %s, maxInstance(%d), maxVar(%d), maxTime(%d), time(%d), \
+timeUnits(%c), lastTime(%d)",
+                            stats_class_data->name, maxInstance, maxVar, maxTime,
+                            stats_class_data->time, stats_class_data->timeUnits,
+                            stats_class_data->lastTime);
+    }
+
+    //        - "\nEXT INSTNC: 3400\n"
+    //        - instanceNames 1..n from char **instanceIndex
+
+    if (action == STATS_WRITE_RELOAD) {
+
+      // count the size of what we have
+      size = 0;
+      for (instance = 0; instance < maxInstance  && stats_class_data->instanceIndex[instance];
+         instance++) {
+        size += strlen(stats_class_data->instanceIndex[instance]) + 1; // don't forget the NULL!
+      } // end for - all class instances
+      
+      if (!(memPtr = (char *)extsql_malloc(size, MYF(MY_WME | MY_ZEROFILL)))) {
+        sql_print_error("ExtSQL: Could not alloc %d bytes to write instance data for class %d",
+                        size, classCount);
+        return(1);
+      }
+
+      // write the data to memPtr
+      size = 0;
+      for (instance = 0; instance < maxInstance  && stats_class_data->instanceIndex[instance];
+           instance++) {
+        strcpy(memPtr + size, stats_class_data->instanceIndex[instance]);
+
+        if STATS_DEBUG(STATS_RELOAD) sql_print_information("ExtSQL: INSTNC (%d/%s)", 
+                                                             instance, memPtr+size);
+
+        size += strlen(stats_class_data->instanceIndex[instance]);
+        size++;  // don't forget the NULL!
+
+      } // end for - all class instances
+      
+      
+      if (extsql_write_section_hdr(loadFileName, reloadFile, "INSTNC", size)) {
+        my_free(memPtr, MYF(0));
+        return(1);
+      }
+
+      if (my_write(reloadFile, (byte*) memPtr, size, 
+                   MYF(MY_WME)) != size) {
+        sql_print_error("ExtSQL: Could write instance data to RELOAD file %s for %d", 
+                        loadFileName, classCount);
+        my_free(memPtr, MYF(0));
+        return(1);
+      }  
+
+      my_free(memPtr, MYF(0));
+
+    } else {  // READ
+
+      memPtr = NULL;
+      if (!(size2 = extsql_read_section_bytes(loadFileName, reloadFile, &memPtr, 
+                                              "INSTNC", classCount))) {
+        return(1);
+      }
+
+      // allocate memory to hold the instanceIndex array!
+      if (!(stats_class_data->instanceIndex =  (char **)extsql_malloc( ((maxInstance+1) * sizeof(char *)),
+                                                                   MYF(MY_WME | MY_ZEROFILL)) )) {
+        sql_print_error("ExtSQL: Could not alloc space for instanceIndex, RELOAD file %s for %d",
+                        loadFileName, classCount);
+        return(1);
+      }
+       
+
+      // move the data from buffer to memory, it is a long sequence of null
+      // terminated instance names.
+      // careful, we limit ourselves based not on the max supported, but how many
+      // instances we really had.
+      size = 0;
+      for (instance = 0, srcPtr = memPtr; instance < maxInstance && srcPtr - memPtr < size2; instance++) {
+
+        size = strlen(srcPtr) + 1; // don't forget the NULL
+          
+        if (!(destPtr = extsql_malloc(size, MYF(MY_WME | MY_ZEROFILL)))) {
+          sql_print_error("ExtSQL: Memory alloc failed on instance(%d), class(%d)",
+                          instance, classCount);
+          my_free(memPtr, MYF(0));
+          return(1);
+        }
+        
+        strcpy(destPtr, srcPtr);
+        stats_class_data->instanceIndex[instance] = destPtr;
+        srcPtr += size;
+
+        if STATS_DEBUG(STATS_RELOAD) sql_print_information("ExtSQL: INSTNC (%d/%s)", 
+                                                             instance, stats_class_data->instanceIndex[instance]);
+
+        // sql_print_information("ExtSQL: On read, instance(%d) at addr (0x%x), at (%s)", instance, destPtr, destPtr);
+      } // end for - all instance names
+
+      my_free(memPtr, MYF(0));
+
+    }
+
+    if STATS_DEBUG(STATS_RELOAD) {
+      sql_print_information("ExtSQL: during %s, completed section INSTNC, class (%d)", 
+                            actionStr, classCount);
+    }
+
+    //        - "\nEXT VAR___:  2343\n"
+    //        - structure STAT_VAR from STAT_VAR **varIndex
+
+    if (action == STATS_WRITE_RELOAD) {
+
+      // count the size of what we have, this is an array of pointers to structures, store
+      // the addr and the string
+      statPtr = stats_class_data->varIndex;
+      size = 0;
+      for (var = 0; var < maxVar; var++, statPtr++) {
+        size += sizeof(char *) + strlen((*statPtr)->name) + 1;
+      }
+      
+      if (!(memPtr = (char *)extsql_malloc(size, MYF(MY_WME | MY_ZEROFILL)))) {
+        sql_print_error("ExtSQL: Could not alloc %d bytes to write varIndex data for class %d",
+                        size, classCount);
+        return(1);
+      }
+      
+      // write the data to buffPtr (address, followed by null term name)
+      statPtr = stats_class_data->varIndex;
+      size = 0;
+      for (var = 0; var < maxVar; var++, statPtr++) {
+        ptrPtr = (char **)(memPtr+size);
+        *ptrPtr = (*statPtr)->addr; // ZZ - var addr may not match on restart?
+        size += sizeof (char *);
+        strcpy(memPtr+size, (*statPtr)->name);
+        size += strlen((*statPtr)->name);
+        if STATS_DEBUG(STATS_RELOAD) sql_print_information("ExtSQL: VAR (%d / %s / 0x%x)", 
+                                                             var, (*statPtr)->name, (uint)(*statPtr)->addr);
+        *(memPtr+size++) = '\0'; // don't forget the NULL
+      }
+
+      if (extsql_write_section_hdr(loadFileName, reloadFile, "VAR___", size)) {
+        my_free(memPtr, MYF(0));
+        return(1);
+      }
+       
+     
+      if (my_write(reloadFile, (byte*) memPtr, size, 
+                   MYF(MY_WME)) != size) {
+        sql_print_error("ExtSQL: Could write varIndexdata to RELOAD file %s for %d", 
+                        loadFileName, classCount);
+        my_free(memPtr, MYF(0));
+        return(1);
+      }  
+
+      my_free(memPtr, MYF(0));
+
+    } else { // READ
+
+      memPtr = NULL;
+      if (!(size2 = extsql_read_section_bytes(loadFileName, reloadFile, &memPtr, 
+                                              "VAR___", classCount))) {
+        return(1);
+      }
+
+      // alloc memory for the complete var index of pointers
+      if (!(stats_class_data->varIndex =  (STAT_VAR **)extsql_malloc( ((maxVar+1) * sizeof(pSTAT_VAR)),
+                                                                  MYF(MY_WME | MY_ZEROFILL)) )) {
+        sql_print_error("ExtSQL: Could not alloc space for varIndex, RELOAD file %s for %d",
+                        loadFileName, classCount);
+        return(1);
+      }
+
+
+      // move the data from buff to memory, careful that we don't exceed what
+      // we actually read in.
+      statPtr = stats_class_data->varIndex;
+      size = 0;
+      for (var = 0, srcPtr = memPtr; srcPtr - memPtr < size2; var++, statPtr++) {
+
+        // allocate room to the STAT_VAR structure we will point to and that will hold
+        // the name and addr
+        if (!(*statPtr =  (STAT_VAR *)extsql_malloc( (sizeof(STAT_VAR)),
+                                                 MYF(MY_WME | MY_ZEROFILL)) )) {
+          sql_print_error("ExtSQL: Could not alloc space for STAT_VAR structure, RELOAD file %s for %d",
+                        loadFileName, classCount); 
+          return(1);
+        }
+          
+        ptrPtr = (char **)srcPtr;
+        (*statPtr)->addr = *ptrPtr;
+  
+        // move to name
+        size = sizeof (char *);
+        srcPtr += size;       // start of name
+        size = strlen(srcPtr) + 1; // length
+        
+        if (!(destPtr = extsql_malloc(size, MYF(MY_WME | MY_ZEROFILL)))) {
+          sql_print_error("ExtSQL: Memory alloc failed on var(%d), class(%d)",
+                          var, classCount);
+          my_free(memPtr, MYF(0));
+          return(1);
+        }
+        
+        strcpy(destPtr, srcPtr);   // copy name to allocated memory
+        (*statPtr)->name = destPtr;  // set pointer
+
+        // need to store the address in our quick lookup array, it would have been cleared
+        // prior to the reload
+        if (extsql_store_var_addr((*statPtr)->addr )) {
+          return(1);
+        }
+        
+        if STATS_DEBUG(STATS_RELOAD) sql_print_information("ExtSQL: VAR (%d / %s / 0x%x)", 
+                                                             var, (*statPtr)->name, (uint)(*statPtr)->addr);
+        
+        srcPtr += size;  // move to next addr/name pair
+        
+      } // end for - all vars
+      
+      my_free(memPtr, MYF(0));
+      
+    } // end if - else
+
+    if STATS_DEBUG(STATS_RELOAD) {
+      sql_print_information("ExtSQL: during %s, completed section VAR___, class (%d)", 
+                            actionStr, classCount);
+    }
+
+    //        - "\nEXT TIME:  2123\n"
+    //        - my_time_t array of time entries for each data entry from my_time_t *timeLabels
+    
+
+    if (action == STATS_WRITE_RELOAD) {
+
+      // count the size of what we have, this is an array of time labels,
+      // just items of my_time_t all in a row
+      size = sizeof(my_time_t) * maxTime;
+
+      if (extsql_write_section_hdr(loadFileName, reloadFile, "TIME__", size)) {
+        return(1);
+      }
+    
+      if STATS_DEBUG(STATS_RELOAD) {
+
+        strcpy(buff, "ExtSQL: TIME ");
+        
+        // only the first 10!
+        for (i = 0; i < maxTime  && i < 10; i++) {
+          sprintf(buff+strlen(buff), "(%d / %d)", i, (int)stats_class_data->timeLabels[i]);
+        }
+
+        sql_print_information(buff);
+      }
+
+      if (my_write(reloadFile, (byte*) stats_class_data->timeLabels, size, 
+                   MYF(MY_WME)) != size) {
+        sql_print_error("ExtSQL: Could write timeLabels data to RELOAD file %s for %d", 
+                        loadFileName, classCount);
+        return(1);
+      }  
+
+      // just to satisfy compiler that extsql_print_bytes could be used!
+      if (!strcmp(loadFileName, "bongongongog")) {
+        extsql_print_bytes((char *)stats_class_data->timeLabels, size);
+      }
+      
+    } else { // READ
+
+      // this one is easy, just read it right in, space has already been allocated!
+      memPtr = NULL;
+      if (!extsql_read_section_bytes(loadFileName, reloadFile, &memPtr, 
+                                    "TIME__", classCount)) {
+        return(1);
+      }
+
+      // DON'T FREE memPtr here
+      stats_class_data->timeLabels = (my_time_t *) memPtr;
+ 
+      if STATS_DEBUG(STATS_RELOAD) {
+        
+        strcpy(buff, "ExtSQL: TIME ");
+        
+        // only the first 10!
+        for (i = 0; i < maxTime  && i < 10; i++) {
+          sprintf(buff+strlen(buff), "(%d / %d)", i, (int)stats_class_data->timeLabels[i]);
+        }
+        
+        sql_print_information(buff);
+      }
+      
+    } // end if - else
+
+    if STATS_DEBUG(STATS_RELOAD) {
+      sql_print_information("ExtSQL: during %s, completed section TIME__, class (%d)", 
+                            actionStr, classCount);
+    }
+
+    //        - "\nEXT DATA__: 000342432\n"
+    //        - ulong data (actual recorded data) from ulong *data
+ 
+    // get the size of the data section
+    size = stats_class_data->maxInstance * stats_class_data->maxVar *
+      stats_class_data->maxTime * sizeof(ulong);
+    
+    if (action == STATS_WRITE_RELOAD) {
+
+      
+      // sanity check, size should be same as diff, remember offset in dataEnd
+      // is as an index to ulong entries, size is in bytes!
+      size2 = (stats_class_data->dataEnd - stats_class_data->data) * sizeof(ulong);
+      if (size != size2) {
+        sql_print_error("ExtSQL: data size error (%d/%d) for class %d",
+                        size, size2, classCount);
+        return(1);
+      }
+      
+      if (extsql_write_section_hdr(loadFileName, reloadFile, "DATA__", size)) {
+        return(1);
+      }
+
+      if (my_write(reloadFile, (byte*) stats_class_data->data, size, 
+                   MYF(MY_WME)) != size) {
+        sql_print_error("ExtSQL: Could write ext data to RELOAD file %s for %d", 
+                        loadFileName, classCount);
+        return(1);
+      }
+      
+    } else { // READ
+
+      // this one is easy, just read it right in!
+      memPtr = NULL;
+      if (!(size2 = extsql_read_section_bytes(loadFileName, reloadFile, &memPtr, 
+                                              "DATA__", classCount)) ) {
+        return(1);
+      }
+
+      // sanity check, same size?
+      if (size != size2) {
+        sql_print_error("ExtSQL: data size error  (%d/%d) for class %d",
+                        size, size2, classCount);
+        
+        my_free(memPtr, MYF(0));
+        return(1);
+      }
+      
+      // DON'T FREE memPtr here
+      stats_class_data->data = (ulong *) memPtr;
+
+      // set dataEnd
+      stats_class_data->dataEnd = stats_class_data->data + size/sizeof(ulong);
+
+    } // end if -else
+    
+    
+   if STATS_DEBUG(STATS_RELOAD) {
+     sql_print_information("ExtSQL: during %s, completed section DATA__, class (%d)", 
+                           actionStr, classCount);
+   }
+    //        - "\nEXT CLASS n: 2\n"   (repeat part for each class)
+    
+  } // end for - all classes
+  
+  return(0);
+
+} // end extsql_write_reload
+
+// extsql_store_var_addr - stores just the address of a tracked var in a single array
+// this makes increment processing much quicker on the lookup to see if we are
+// tracking a variable
+static int extsql_store_var_addr(char *varAddr) {
+
+  int k, varAddrFound;
+
+  for (k = 0, varAddrFound = 0; k < Shared->varAddrCount; k++) {
+                
+    if (Shared->varAddrTrackArray[k] == varAddr) { // it's there
+      varAddrFound = 1;
+      break;
+    }
+  } // end for - existing array values
+              
+  if (!varAddrFound && k < MAX_VARS) { // not there and not at end, add it
+    Shared->varAddrTrackArray[k] =  varAddr;
+    Shared->varAddrCount++;
+    
+  } else if (!varAddrFound && k >= MAX_VARS) {
+    sql_print_error("ExtSQL: disabled, var tracking limit of %d exceeded",
+                    MAX_VARS);    
+    return(1);
+  }
+  
+  return(0);
+
+} // end extsql_store_var_addr
+
+
+// print out all the internal data structures
+static void extsql_stats_dump()  {
+
+  pSTATS_CLASS_DATA stats_class_data;
+  STAT_VAR **statPtr;
+  int i, time, maxVar, maxTime, maxInstance, var, value, instance, classCount;
+  char buff[STATS_TMP_BUFF_SIZE];
+ 
+
+  // DEBUG LOG TO FILE
+  // general info
+  sql_print_information("ExtSQL: DUMP START (%d)", (int)StartTime);
+  sql_print_information("    version (%s)", Shared->extsql_version+17); // don't reprint version
+  sql_print_information("    extsql_class_string (%s)", Shared->extsql_class_list);
+  sql_print_information("    extsql_users (%s)", extsql_users); 
+
+
+  // varAddrTrackArray
+  sprintf(buff,"   varAddrTrackArray (%d): ", Shared->varAddrCount);
+
+  for (i = 0; i < MAX_VARS && i < 40 && i < Shared->varAddrCount; i++) {
+    sprintf(buff + strlen(buff),"(0x%x) ", (uint) Shared->varAddrTrackArray[i]);
+  }
+
+  sql_print_information(buff);
+    
+  
+  // loop and print everything to the log file  
+  classCount = 0;
+  for (stats_class_data = Shared->statData; classCount < STATS_MAX_CLASSES && stats_class_data->maxInstance; 
+       stats_class_data++, classCount++) {
+    
+    maxVar = stats_class_data->maxVar; 
+    maxTime = stats_class_data->maxTime; 
+    maxInstance = stats_class_data->maxInstance;
+      
+    
+    // print out summary info on the CLASS
+    sql_print_information("CLASS is %s, maxInstance(%d), maxVar(%d), maxTime(%d), time(%d), \
+timeUnits(%c), lastTime(%d)",
+                          stats_class_data->name, maxInstance, maxVar, maxTime,
+                          stats_class_data->time, stats_class_data->timeUnits,
+                          stats_class_data->lastTime);
+    
+    sql_print_information("  Base of instanceIndex array at 0x%x", (uint)stats_class_data->instanceIndex);
+
+    for (instance=0; 
+         instance < maxInstance && stats_class_data->instanceIndex[instance]; 
+         instance++) {
+      sql_print_information("  instanceIndex[%d] = (%s), addr(0x%x)", 
+                            instance, stats_class_data->instanceIndex[instance],
+                            (uint) stats_class_data->instanceIndex[instance]);
+    } // end for -- all instances
+
+    for (var=0, statPtr = stats_class_data->varIndex; 
+         (var < stats_class_data->maxVar) && *statPtr ; 
+         var++, statPtr++) {
+      sql_print_information("    varIndex[0x%x] = name(%s), addr(0x%x)",
+                            var, (*statPtr)->name, (uint)(*statPtr)->addr);
+
+    } // end for - all vars
+    
+    for (instance=0; instance < maxInstance; instance++) {
+      for (var=0, statPtr = stats_class_data->varIndex; 
+           var < stats_class_data->maxVar && *statPtr; 
+           var++, statPtr++) {
+        for (time = 0; time < maxTime; time++) {
+            
+          value = stats_class_data->data [ARRAY_INDEX(instance, var, maxVar,
+                                                      time, maxTime)];
+          if (value) {
+            sql_print_information("      statData[%d-%s][%d-%s][%d](%d) = %d",
+                                  instance, stats_class_data->instanceIndex[instance], 
+                                  var, (*statPtr)->name, 
+                                  time, (int)stats_class_data->timeLabels[time],
+                                  value);
+            
+          } // end if - value
+        } // end for - all times    
+      } // end for - all variables
+    } // end for - all instances
+    
+  } // end for - log file write all classes
+  sql_print_information("ExtSQL: DUMP END ");
+
+} // end extsql_stats_dump
+
+
+
+// dump/check thread info
+// if doDump is set, then go ahead and dump all info on all threads;
+// otherwise just create output if there is an error.
+static void extsql_thread_dump(THD *thd, int doDump)
+{
+
+#ifndef PGSQL
+  if (pthread_mutex_trylock(&LOCK_thread_count)) { // forget about it!
+    return;
+  }; // For unlink from list
+#endif
+
+#ifdef PGSQL
+
+  // NEED this ZZ
+#else
+
+  I_List_iterator it(threads);
+  THD *tmp;
+  pthread_t my_id = pthread_self();
+  int foundError = 0;
+  char *user, *host;
+  int *statVerify, *indexPtr;
+
+  if (doDump) {
+    sql_print_information("ExtSQL: this thread id is %d", thd->thread_id);
+  }
+
+  
+
+  while ((tmp=it++))
+    {
+#ifdef EXTSQL_50
+      user = tmp->security_ctx->user;
+      host = tmp->security_ctx->host;
+      statVerify = &tmp->security_ctx->statVerify;
+      indexPtr = tmp->security_ctx->statIndex;
+#else
+      user = tmp->user;
+      host = tmp->host;
+      statVerify = &tmp->statVerify;
+      indexPtr = tmp->statIndex;
+#endif
+
+      if (doDump) {
+        sql_print_information("ExtSQL:   thd(%d/%s/%s) user(%s) host(%s) db(%s) magic(0x%x)",
+                              tmp->thread_id, tmp->proc_info, command_name[tmp->command], user, 
+                              host, tmp->db, *statVerify);
+      }
+
+      for (int i = 0; i < STATS_MAX_CLASSES; i++) {
+        if (indexPtr[i]) {
+
+          if ( (*statVerify == STATS_MAGIC_NUM) && 
+               ( (indexPtr[i] >= Shared->statData[i].maxInstance) || indexPtr[i] < 0) ) {
+            sql_print_warning("ExtSQL: special check failed: thd(%d/%s/%s) user(%s) host(%s) db(%s) magic(0x%x)",
+                              tmp->thread_id, tmp->proc_info, command_name[tmp->command], user, 
+                              host, tmp->db, *statVerify);
+            sql_print_warning("           index(%d), value(0x%x/0x%x)",
+                                  i, indexPtr[i], Shared->statData[i].maxInstance);  
+          }
+
+          if (doDump) {
+            sql_print_information("           index(%d), value(0x%x/0x%x)",
+                                  i, indexPtr[i], Shared->statData[i].maxInstance);
+          } // end if - dump value
+
+        } // end if - has value
+      } // end for - all entries in this thread
+    } // end while - still more threads
+
+#endif
+
+#ifndef PGSQL
+  VOID(pthread_mutex_unlock(&LOCK_thread_count));
+#endif
+
+} // end extsql_thread_dump
+
+
+
+// a new thread has been created, init the stat tracking structures
+// if (initType == STATS_THD_INIT_DB) is set, the thread exists, but a 'use' command was given to change DB's
+// we need to update the db index ONLY!
+// if initType == STATS_THD_INIT_ALL -- we reset everybody no matter what!
+int extsql_thread_init(THD *thd, int initType)
+
+{
+  int i, threadID, command;
+  char *tmpName = "", classStart;
+  int classCount = 0; 
+  int found = 0;
+  pSTATS_CLASS_DATA stats_class_data;
+  char *user = "", *host = "", *db = "", *proc_info = "", **instPtr;
+  int *statVerify = 0, *indexPtr = 0;
+  char tmpBuff[STATS_TMP_BUFF_SIZE];
+
+
+  if (initType != STATS_THD_INIT_ALL) { // normal
+    
+    if (!Shared->extsql_active || Shared->extsql_disabled) { // shouldn't normally even get here
+      return(0);
+    }
+    
+    if (initType == STATS_THD_INIT_DB) { // ZZ -return
+      // return(0);
+    }  
+  }
+
+  // attach to our shared memory!
+  if (extsql_init_globals()) {
+    return(1);
+  }
+  
+  if STATS_DEBUG(STATS_DUMP_START) {
+    extsql_stats_dump();
+  }  
+
+  StartTime = time(NULL);
+
+  extsql_init_proc_vars(&threadID, &command, &user, &db, &host, &proc_info, &indexPtr, &statVerify);
+
+
+  // OKAY, if (initType == STATS_THD_INIT_DB) is set we should already be tracking data on this thread, just
+  // need to change the db index - SO, we should have already done an init on this
+  // thread and the MAGIC should have been set, if not, get out!
+  if (initType == STATS_THD_INIT_DB) {
+    if (*statVerify != STATS_MAGIC_NUM) {
+      return(1);
+    }
+  }
+
+  // check that we have a host and db
+  if (! host || ! *host ||  *host == '\0') {
+    host = "(null)";
+  }
+
+  if (! db || ! *db ||  *db == '\0') {
+    db = "(null)";
+  }
+
+  // we don't do thread zero -- ZZ disabled temp
+  if (0 && ! threadID) {
+    sql_print_warning("ExtSQL: thread_init called for thread zero in error");
+    return(0);
+  }
+  
+  // for root stuff, i.e. phpMyAdmin, the db is (null).
+  if STATS_DEBUG(STATS_THD_INIT_PARAMS) {
+    sql_print_information("ExtSQL: thread (%d) started for db %s(0x%x), user %s(0x%x), host %s(0x%x)",
+                          threadID, db, (uint)db, user, (uint)user, host, (uint)host);
+  }
+
+  // for quick indexing on increment, we store the index values used to track the instances
+  // used by this thread within the thread itself
+  // see if user and db names are there already
+      
+  // check/add indexes depending on classes that we are collecting for;
+
+  // init the class index array to zero if this is a first time init or for ALL
+  if (!(initType == STATS_THD_INIT_DB)) {
+    for (i = 0; i< STATS_MAX_CLASSES; i++) {
+      indexPtr[i] = 0;
+    }
+    *statVerify = 0; // will be set below when we find match on anything.
+  }
+
+  for (stats_class_data = Shared->statData, classCount = 0; 
+        classCount < STATS_MAX_CLASSES && stats_class_data->maxInstance; 
+       stats_class_data++, classCount++) {
+
+    classStart = stats_class_data->name[0];
+
+    if ((initType == STATS_THD_INIT_DB) && classStart != 'd' && classStart != 'c') { // we just want the db or condb
+      continue;
+    }
+
+    switch (classStart) { // LIST should match extsqlClassesSupported[]
+          
+    case 'c':   // connect          
+
+      if ((initType == STATS_THD_INIT_DB) && stats_class_data->name[3] != 'd') { // not condb
+        continue;
+      }
+
+      if (stats_class_data->name[3] == 'd') { // condb - db@host
+         
+        strcpy(tmpBuff, db);
+
+      } else if (stats_class_data->name[3] == 'u') {   // conuser- user@host
+        strcpy(tmpBuff, user);
+
+      } else {
+        
+        sql_print_error("ExtSQL: disabled, unexpected connection class name %s", 
+                        stats_class_data->name);
+        Shared->extsql_disabled = 1;
+        break;
+      }
+
+      strcat(tmpBuff, "@");
+      strcat(tmpBuff, host);
+      tmpName = tmpBuff;
+          
+      break;
+          
+    case 'd':   // db          
+         
+      tmpName = db;          
+      break;
+          
+    case 'h':    // host
+          
+      tmpName = host;
+      break;
+          
+    case 's':    // server -- cum total of all on this server
+          
+      tmpName = "server";
+      break;
+          
+    case 'u':   // user
+          
+      tmpName = user;
+      break;
+          
+    default:
+          
+      sql_print_error("ExtSQL: disabled, unexpected class name %s", 
+                      stats_class_data->name);
+      Shared->extsql_disabled = 1;
+          
+    } // end switch
+        
+    // make sure we got something in tmpName
+    if (!tmpName) {
+      // sql_print_warning("ExtSQL: got null tmpName instance value for class %s, forcing to (null)", stats_class_data->name);
+      tmpName = "(null)";
+    }
+
+    if (Shared->extsql_disabled) {
+      break;
+    }
+ 
+    // now try to match or insert
+    // check for new or existing instance, LOCK statData during the search
+    found = 0;
+
+    i = 0;
+    for (instPtr = (char **)stats_class_data->instanceIndex; 
+         i <  stats_class_data->maxInstance; instPtr++, i++) {
+          
+      if STATS_DEBUG(STATS_THD_INIT_LOOP) { 
+        sql_print_information("   Looking for match of %s with %s", *instPtr, tmpName);
+      }
+              
+      if (!*instPtr) { // at a blank, fill it
+
+        // Grab the lock now, check to see if it is still NULL
+        //    if it is, fill it in
+        (void) pthread_mutex_lock(&Shared->LOCK_stats_load); // IMPORTANT, don't leave with unlock!
+        
+        if (!*instPtr) { // at a blank, fill it
+          if (!(*instPtr = extsql_strdup(tmpName, MYF(MY_WME)))) {
+            Shared->extsql_disabled = 1;
+            sql_print_error("ExtSQL: disabled, unable to alloc instance item %s",
+                            tmpName);
+            // UNLOCK statData
+            (void) pthread_mutex_unlock(&Shared->LOCK_stats_load); // IMPORTANT!
+            break;
+          } 
+          found = 1;
+
+          Shared->statsAllocArray[Shared->allocIndex] = *instPtr;
+  
+          // UNLOCK statData
+          (void) pthread_mutex_unlock(&Shared->LOCK_stats_load); // IMPORTANT!
+          
+          indexPtr[classCount] = i;
+
+          if  STATS_DEBUG(STATS_THD_INIT_LOOP) {
+            sql_print_information("ExtSQL, NEW statIndex[%d]->%d for %s in class %s stored as (%s)",
+                                  classCount, i, tmpName, stats_class_data->name,
+                                  Shared->statsAllocArray[Shared->allocIndex]);
+          }
+
+          Shared->allocIndex++;
+          break;
+
+        } // end if - was emtpy - fill in new values
+
+        //  if we get here it is not null, someone else got it ahead of us. May have filled in another value,
+        // or what we want. -- we release lock, we will fall throught to below and check for a match, and keep looping
+        // UNLOCK statData
+        (void) pthread_mutex_unlock(&Shared->LOCK_stats_load); // IMPORTANT!
+
+      } // end if - was empty - fill in new value
+          
+      if (!strcmp(*instPtr, tmpName)) { // match
+        indexPtr[classCount] = i;
+        found = 1;
+        break;
+      }   
+
+    } // end for - each instance
+ 
+
+   // check for max instances exceeded
+    if (! found) {
+      sql_print_warning("ExtSQL: disabled, instances exceed tracking limit for class %s with %s",
+                        stats_class_data->name, tmpName);
+      Shared->extsql_disabled = 1;
+      break;
+    }
+
+    // if we get here, something was found.
+    *statVerify = STATS_MAGIC_NUM;
+
+    if (Shared->extsql_disabled) {
+      break;
+    }
+        
+  } // end for - each class                     
+  if STATS_DEBUG(STATS_DUMP_START) {
+    extsql_stats_dump();
+  }
+
+#ifdef PGSQL
+  extsql_inc(&Connections, 1);
+#endif
+
+  return(0);
+  
+} // end extsql_thread_init
+
+#ifdef EXTSQL_50    
+// only for information schema, in 5 and above
+
+extern bool schema_table_store_record(THD *thd, TABLE *table);
+
+// We fill the table with our tracking data, depending on the name
+int fill_schema_extsql(THD *thd, TABLE_LIST *tables, COND *cond)
+{
+
+  const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
+  TABLE *table= tables->table;
+  CHARSET_INFO *scs= system_charset_info;
+
+  pSTATS_CLASS_DATA stats_class_data;
+  STAT_VAR **statPtr;
+  ST_SCHEMA_TABLE *schema_table= tables->schema_table;
+  int found, var, maxVar, maxTime, maxInstance, currentTime, timeLimit, timeCount, indexTime,
+    varNameLength, varIndex, value, stats_hourly, fieldIndex=0, rowHasData, doZeroTime=1;
+  char listBuff[MAX_BUFF_SIZE], className[STATS_MAX_NAME];  
+  char *varListPtr = listBuff, *stats_class = className, *varName, *termChar;  
+  MYSQL_TIME now_mysql_time;
+  char *user;
+
+  DBUG_ENTER("schema_table_store_record");
+
+  // are they authorized
+#ifdef EXTSQL_50
+  user = thd->security_ctx->user;
+#else
+  user = thd->user;
+#endif
+
+  // return if not authorized, disabled or inactive
+  if (extsql_check(thd, 0)) DBUG_RETURN(1);
+
+  // lets make sure this is one of our tables
+  if (!strncmp(schema_table->table_name, "EXTSTATS_", 9)) { // one of ours
+    
+    int found, var, maxVar;
+    
+    // lets get the class name off the end
+    strcpy(stats_class, schema_table->table_name + 9);
+    
+    // find the data for the Class we are interested in
+    found = 0;
+    for (stats_class_data = Shared->statData; stats_class_data->maxInstance; 
+         stats_class_data++) {
+      if (!strcmp(stats_class_data->name, stats_class)) { // found it
+        found = 1;
+        break;
+      }
+    } // end for 
+    
+    if (!found) {
+      net_printf_error(thd, 0, "ExtSQL: can't fill requested SCHEMA TABLE %s(%s).  The \
+most likely reason is that no data is being recorded for that class.  Use SHOW STATISTICS to see \
+what is being tracked.",
+
+                       schema_table->table_name, stats_class);
+      DBUG_RETURN(0);
+    } 
+ 
+  } else { // called by mistake
+    net_printf_error(thd, 0, "ExtSQL: schema called in error to fill table %s.",
+                     schema_table->table_name);
+    DBUG_RETURN(0);
+  }
+ 
+  // AT THIS POINT stats_class_data points to the requested class 
+  maxVar = stats_class_data->maxVar; 
+  maxTime = stats_class_data->maxTime; 
+  maxInstance = stats_class_data->maxInstance; // needed for array indexing
+  
+  currentTime = stats_class_data->time; // time we are currently logging to.
+  timeLimit = maxTime-1; // they get it all
+
+  // we need to now load the columns in the PROPER order, data is recorded as it
+  // occurs, but the Var name order is controlled by the user, we try to use
+  // that order.
+  strcpy(varListPtr,","); // init the list
+  // loop through the instance variables for names
+  for (var=0, statPtr = stats_class_data->varIndex; 
+       (var < stats_class_data->maxVar) && *statPtr ; 
+       var++, statPtr++) {      
+                                                            
+    strcat(varListPtr,(*statPtr)->name );
+    strcat(varListPtr, ",");
+
+    if (strlen(varListPtr) > MAX_BUFF_SIZE - 50) {
+      net_printf(thd, 0, "ExtSQL: List of Vars too long");
+      DBUG_RETURN(1);
+    }
+  } // end for - all instances
+
+ 
+  // Remember, zero index holds the total. The
+  // currentTime has our present location and it is circular, i.e. if
+  // maxTime for the class is 4, we store current + 3.  If the currentTime
+  // is 2, the proper way to display all hours, starting with the most
+  // recent is to show 2(current),1(prior),3(more prior) - skip 0
+  // we now go through all the instances, we will be loading the table 
+  // with instance_name, time, var, var, .....
+  for (int instance=0; instance < maxInstance && stats_class_data->instanceIndex[instance] ; 
+       instance++) {
+    
+    // loop through the times,
+    // if stats_timely is set we will output a number of hours starting at currentTime, and
+    // limited by timeLimit (starts at 1).
+    // For INFORMATION_SCHEMA we have a real problem, need to print the totals under
+    // time heading of 0000-00-00 00:00 (zero time), but then pick up and print the rest,
+    // have to really hack the loop control to make first output special, zero time.
+    // If doZeroTime = 1 -- we need to output the zero values(totals)
+    doZeroTime = 1;
+
+    for (timeCount = 0, indexTime = currentTime ;
+         timeCount < timeLimit  && indexTime >= 0;
+         timeCount++, indexTime--  )  {
+      
+      // we have to adjust our indexTime for wrap
+      if (!indexTime && !doZeroTime) { // we have gone back to the total 
+        indexTime = maxTime - 1; // pick the last
+      }
+      
+      restore_record(table, s->default_values);
+      fieldIndex = 0;
+      rowHasData = 0;  // do we have anything to show, only on HISTORY
+
+      // first column - instance name - always
+      table->field[fieldIndex++]->store(stats_class_data->instanceIndex[instance],
+                              strlen(stats_class_data->instanceIndex[instance]), scs);
+
+      // second column is times - always, we use indexTime
+      if (indexTime) {
+        thd->variables.time_zone->gmt_sec_to_TIME(&now_mysql_time,
+                                                  (my_time_t) stats_class_data->timeLabels[indexTime]);
+      } else {
+        char *zeroTime = "0000-00-00 00:00:00";
+        str_to_time_with_warn(zeroTime, strlen(zeroTime), &now_mysql_time);
+      }
+
+      table->field[fieldIndex++]->store_time(&now_mysql_time, MYSQL_TIMESTAMP_DATETIME);
+        
+      // loop through varListPtr, output the vars in the DEFAULT order
+      // varListPtr = ",bytes,selects," varName will move through this
+      for ( varName = varListPtr; *varName ; varName = strstr(varName, ",")) {
+        
+        varName++; // move off the comma
+        //sql_print_information("   target varName is (%s)", varName);
+
+        if (! *varName) { // we are done
+          break;
+        }
+
+        varNameLength = strchr(varName, ',') - varName;
+    
+        // okay, varName points at a name, lets go through the index looking
+        // for a match
+        found = 0;
+        for (varIndex=0, statPtr = stats_class_data->varIndex; 
+             varIndex < maxVar && *statPtr;
+             varIndex++, statPtr++) { 
+          
+          termChar = (*statPtr)->name + varNameLength +1; // point to end of the current var name
+
+          if (!strncmp( (*statPtr)->name, varName, varNameLength)) {
+            found = 1;
+            value = stats_class_data->data [ARRAY_INDEX(instance, varIndex, maxVar,
+                                                        indexTime, maxTime)]; 
+
+            table->field[fieldIndex++]->store((longlong) value, TRUE);
+            if (value) { // is it non-zero
+              rowHasData = 1;
+            }
+            break;
+          }
+          
+        } // end for - a matching var in the list
+               
+        if (!found) {
+          table->field[fieldIndex++]->store((longlong) 9999999, TRUE);
+        }
+        
+      } // end for - requested values
+            
+      if (!indexTime) { // it had hit zero and we have outputed totals
+        doZeroTime = 0; // don't do it again for this class
+        indexTime = 1; // we want it to zero again for wrap.
+        timeCount--;   // this row doesn't count
+      }
+
+      if (!rowHasData) {
+        continue;
+      }
+
+      // record the row
+      if (schema_table_store_record(thd, table)) {
+        sql_print_error("ExtSQL, protocol write failed");
+        DBUG_RETURN(1);
+      }
+    } // end for - all requested times
+    
+  } // end for - all instances
+  
+  return 0;
+}
+
+#endif
--- /export/mysql/extsql-build/builds/8.4.1/rhel4/x86/1/0.0/src/include/utils/extsql.h	1969-12-31 19:00:00.000000000 -0500
+++ src/include/utils/extsql.h	2009-11-29 17:01:47.000000000 -0500
@@ -0,0 +1,217 @@
+
+/* Copyright (C) 2006, 2007, 2008, 2009, 2010 Software Workshop Incorporated 
+
+  This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+
+#ifndef EXTSQL_H
+#define EXTSQL_H  1
+#endif
+
+#define PGSQL 1
+
+#ifdef PGSQL
+#define PGSQL_8 1        // only for 8.4 builds and above.
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "postgres.h"
+#include "libpq/pqcomm.h"
+#include "miscadmin.h" 
+#include "catalog/pg_type.h"
+#include "tcop/dest.h"
+#include "executor/executor.h"
+#include "storage/proc.h"
+#include "storage/backendid.h"
+#include "libpq/libpq-be.h"
+#include "libpq/hba.h"
+#include "storage/pg_shmem.h" // ZZ shared memory
+#include "storage/spin.h"
+#include "storage/fd.h"
+#include "nodes/pg_list.h"
+
+// need this stuff for PGSQL, mimics where stored in mysql (mysqld.cc)
+// by default we are set for MySQL 4.x, PGSQL set for any PGSQL build where
+// MySQL stuff will NOT apply
+
+// NOTE variadic macros below, invoke with either '...' or '__VA_ARGS__' compiler dependent!
+#define sql_print_information(str, ...)    elog(LOG, str, ##__VA_ARGS__)
+#define sql_print_warning(str, ...)    elog(LOG, str, ##__VA_ARGS__)
+#define sql_print_error(str, ...)    elog(LOG, str, ##__VA_ARGS__)
+
+#define net_printf(thd, x, str, ...) elog(ERROR, str, ##__VA_ARGS__)
+
+#define DBUG_RETURN(x)    return(x)
+#define DBUG_ENTER(x)
+
+#define NullS  (char *) 0
+
+#define MY_MUTEX_INIT_FAST &my_fast_mutexattr
+
+#define pthread_mutex_trylock(lock) pthread_mutex_lock(lock)
+#define my_free(x, y)    free(x)  
+#define my_malloc(a,b)  malloc(a)
+#define my_open(fileName, mode, flag)    open(fileName, mode)
+#define my_read(fd, buff, bytes, flags)  read(fd, buff, bytes)
+#define my_write(fd, buff, bytes, flags) write(fd, buff, bytes)
+#define MY_WME  1
+#define MY_NABP 1
+#define MY_ZEROFILL 1
+#define  MYF(a)           a
+#define O_BINARY 0     // ZZ
+
+
+#define FN_REFLEN  255
+
+
+typedef char byte;
+typedef time_t my_time_t;
+typedef time_t MYSQL_TIME;
+typedef struct PGPROC THD;
+typedef struct show_var_st {
+  char *name;
+  ulong *value;
+} SHOW_VAR;
+
+extern ulong Com_begin, Com_commit, Com_create_table, Com_delete, 
+  Com_drop_table, Com_insert, Com_rollback, Com_select, Com_update, Connections, Questions;
+extern int mysql_show_extsql(THD *thd, const char *stats_class, DestReceiver *dest, List *stats_vars,
+                      uint stats_hourly, const char *wild, char *stats_order_var,
+                      const uint stats_order_dir, const uint stats_order_limit, char *stats_where_var,
+                      const uint stats_where_num, const uint stats_where_char);
+
+#endif // PGSQL
+
+
+
+#define STATS_DEBUG(Val) (Val & extsql_debug ? 1 : 0)
+
+#define STATS_MAGIC_NUM  0x12345678
+#define STATS_MAX_NAME         20   // max size of a Class name
+#define STATS_TMP_BUFF_SIZE  2048
+
+#define STATS_INIT_FAILURE     0    // define the start types
+#define STATS_INIT_NORMAL      1
+#define STATS_INIT_RESET       2   
+#define STATS_INIT_RELOAD      3
+#define STATS_INIT_CONFIRM     4
+
+#define STATS_THD_INIT_NORM    5
+#define STATS_THD_INIT_DB      6
+#define STATS_THD_INIT_ALL     7
+
+#define STATS_WRITE_RELOAD     1    // actions taken with reload file
+#define STATS_READ_RELOAD      2
+#define STATS_SECTION_HDR      23   // characters in reload file section hdrs
+#define STATS_SECTION_BYTES    13   // offset to first digit in byte count
+
+#define STATS_MAX_NUM_ALLOC    200  // max independent mem allocs we track
+#define MAX_VARS  50        // the most unique Vars we can track
+
+// #define EXTSQL_50      1  -- external define set during build during configure.
+// #define EXTSQL_BINARY  1  -- external define set during build during configure.
+
+typedef struct stat_vars {
+  char *name;
+  char *addr;
+} STAT_VAR, *pSTAT_VAR;
+
+typedef struct stats_class_data { // keep this padded to 4 byte borders 
+  char name[STATS_MAX_NAME];   // class name
+  ulong *data;   // pointer to data area for that class
+                 // 3-d array [instance index][var index][hour index, 0-summary]
+  ulong *dataEnd;       // where does data end - limit check
+  int maxInstance;
+  char **instanceIndex; // indexes for named instances
+  int maxVar;
+  STAT_VAR **varIndex;  // indexes for vars, name & addr
+  int maxTime;
+  char *varList;        // NOT USED ZZ
+  int time;             // the current time unit we are logging to
+  char timeUnits;       // d - day, h - hour, m - minute
+  char padd[3];
+  my_time_t *timeLabels;     // absolute time for each time entry in data
+  int lastTime;         // the last clock time we saw for data logged
+} STATS_CLASS_DATA, *pSTATS_CLASS_DATA;
+
+
+// SHARED MEM -- all our global data
+typedef struct global_alloc { // in same order as declared in extsql.cc
+  STATS_CLASS_DATA statData[STATS_MAX_CLASSES];
+  char *extsql_class_list, *extsql_reload_file;
+
+  char *statsAllocArray[STATS_MAX_NUM_ALLOC]; // used to track mem allocs for reset/free
+  int allocIndex; // our position in the global statsAllocArray
+
+  pthread_mutex_t LOCK_stats_load, LOCK_stats_clock;
+
+  char *extsql_key, *extsql_users, *extsql_version;
+
+  ulong extsql_active, // temp stop extsql activity, can be user re-activated by SET
+    extsql_disabled,   // perm stop extsql activity, severe/license error, only cleared by server restart
+    extsql_reload_in_progress,  // temp stop extsql activity during startType reset/reload
+    extsql_debug, queries, connects, extsql_counter;
+
+  char *varAddrTrackArray[MAX_VARS]; // tracks addr of vars of interest, speeds up increment search. 
+  int   varAddrCount;  // how many do we have being tracked
+  int lastMin;   // top of minute processing 
+
+} GLOBAL, *pGLOBAL;
+
+extern pGLOBAL Shared;
+
+// FOLLOWING only used at startup, then referenced from Shared.
+extern ulong extsql_active, extsql_counter, extsql_debug, queries, connects;
+extern char *extsql_class_list, *extsql_key, *extsql_users, *extsql_reload_file;
+
+
+// FUNCTION PROTOTYPES
+int extsql_init_globals();
+int extsql_check(THD*, int);
+
+#ifdef PGSQL
+int extsql_output_prep_2_col(char *col1, char *col2,DestReceiver *dest, 
+                                    TupOutputState **tstate, TupleDesc tupdesc);
+int extsql_output_2_col(char *col1Str, int col1Int, char *col2Str, int col2Int,
+                               DestReceiver *dest, TupOutputState *tstate);
+void extsql_output_complete(THD *, TupOutputState *);
+int extsql_usage(THD*, DestReceiver*);
+int extsql_enable(THD*, DestReceiver*, uint);
+int extsql_reset(THD* thd, DestReceiver*, const char* conf);
+int extsql_file_io(THD* thd, DestReceiver*, uint io_mode, uint confirm, char* reload_file);
+#else
+static int extsql_output_prep_2_col(char *col1, char *col2, Protocol *protocol,
+                             List field_list, char *fill2);
+static int extsql_output_2_col(char *col1Str, int col1Int, char *col2Str,
+                               int col2Int, Protocol *protocol, char *fill1);
+void extsql_output_complete(THD* thd, char *tstate);
+int extsql_usage(THD*);
+int extsql_enable(THD*, uint);
+int extsql_reset(THD* thd, const char* conf);
+int extsql_file_io(THD* thd, uint io_mode, uint confirm, char* reload_file);
+#endif
+
+extern void extsql_inc(ulong *V, ulong C);
+extern int extsql_init(char *, int, char *);
+extern void extsql_prep(int *, const char *, char *);
+int extsql_thread_init(THD *thd, int initType);
+int extsql_read_section_bytes(char*, File, char**, char*, int);
+int extsql_reload(int action, char *loadFileName);
 

[Home]    [FAQ List]    [About Us]    [Contact Us]   
 

NOTE: MySQL® is a registered trademark of Sun Microsystems. 
ExtSQL® is registered trademark of Software Workshop Inc.
ExtSQL is a separate product and should not be confused with MySQL
or PostgreSQL. It contains independently developed additional features,
released under the GPL,v.2.

©Copyright 1996-2009 Software Workshop Inc. 
1