diff --git a/core/Database.cpp b/core/Database.cpp
index 40b182d8..1a778a9c 100644
--- a/core/Database.cpp
+++ b/core/Database.cpp
@@ -14,6 +14,7 @@
 
 #include "Database.h"
 #include "HandleSys.h"
+#include "ShareSys.h"
 #include "sourcemod.h"
 
 DBManager g_DBMan;
@@ -28,6 +29,8 @@ void DBManager::OnSourceModAllInitialized()
 	
 	m_DriverType = g_HandleSys.CreateType("IDriver", this, 0, NULL, &sec, g_pCoreIdent, NULL);
 	m_DatabaseType = g_HandleSys.CreateType("IDatabase", this, 0, NULL, NULL, g_pCoreIdent, NULL);
+
+	g_ShareSys.AddInterface(NULL, this);
 }
 
 void DBManager::OnSourceModShutdown()
diff --git a/extensions/mysql/Makefile b/extensions/mysql/Makefile
new file mode 100644
index 00000000..8c735d7d
--- /dev/null
+++ b/extensions/mysql/Makefile
@@ -0,0 +1,87 @@
+#(C)2004-2006 SourceMM Development Team
+# Makefile written by David "BAILOPAN" Anderson
+
+SMSDK = ../..
+SRCDS = ~/srcds
+SOURCEMM = ../../../../sourcemm
+
+#####################################
+### EDIT BELOW FOR OTHER PROJECTS ###
+#####################################
+
+PROJECT = sample
+
+#Uncomment for SourceMM-enabled extensions
+#LINK_HL2 = $(HL2LIB)/tier1_i486.a vstdlib_i486.so tier0_i486.so 
+
+OBJECTS = sdk/smsdk_ext.cpp extension.cpp
+
+##############################################
+### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###
+##############################################
+
+C_OPT_FLAGS = -O3 -funroll-loops -s -pipe -fno-strict-aliasing
+C_DEBUG_FLAGS = -g -ggdb3
+CPP_GCC4_FLAGS = -fvisibility=hidden -fvisibility-inlines-hidden
+CPP = gcc-4.1
+
+HL2PUB = $(HL2SDK)/public
+HL2LIB = $(HL2SDK)/linux_sdk
+HL2SDK = $(SOURCEMM)/hl2sdk
+SMM_TRUNK = $(SOURCEMM)/trunk
+
+LINK = $(LINK_HL2) -static-libgcc
+
+INCLUDE = -I. -I.. -Isdk -I$(HL2PUB) -I$(HL2PUB)/dlls -I$(HL2PUB)/engine -I$(HL2PUB)/tier0 -I$(HL2PUB)/tier1 \
+          -I$(HL2PUB)/vstdlib -I$(HL2SDK)/tier1 -I$(SMM_TRUNK) -I$(SMM_TRUNK)/sourcehook -I$(SMM_TRUNK)/sourcemm \
+	  -I$(SMSDK)/public -I$(SMSDK)/public/sourcepawn -I$(SMSDK)/public/extensions \
+
+CFLAGS = -D_LINUX -DNDEBUG -Dstricmp=strcasecmp -D_stricmp=strcasecmp -D_strnicmp=strncasecmp -Dstrnicmp=strncasecmp -D_snprintf=snprintf -D_vsnprintf=vsnprintf -D_alloca=alloca -Dstrcmpi=strcasecmp -Wall -Werror -fPIC -msse -DSOURCEMOD_BUILD -DHAVE_STDINT_H
+CPPFLAGS = -Wno-non-virtual-dtor -fno-exceptions -fno-rtti
+
+################################################
+### DO NOT EDIT BELOW HERE FOR MOST PROJECTS ###
+################################################
+
+ifeq "$(DEBUG)" "true"
+	BIN_DIR = Debug
+	CFLAGS += $(C_DEBUG_FLAGS)
+else
+	BIN_DIR = Release
+	CFLAGS += $(C_OPT_FLAGS)
+endif
+
+
+GCC_VERSION := $(shell $(CPP) -dumpversion >&1 | cut -b1)
+ifeq "$(GCC_VERSION)" "4"
+	CPPFLAGS += $(CPP_GCC4_FLAGS)
+endif
+
+BINARY = $(PROJECT).ext.so
+
+OBJ_LINUX := $(OBJECTS:%.cpp=$(BIN_DIR)/%.o)
+
+$(BIN_DIR)/%.o: %.cpp
+	$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) -o $@ -c $<
+
+all:
+	mkdir -p $(BIN_DIR)/sdk
+	ln -sf $(SRCDS)/bin/vstdlib_i486.so vstdlib_i486.so
+	ln -sf $(SRCDS)/bin/tier0_i486.so tier0_i486.so
+	$(MAKE) extension
+
+extension: $(OBJ_LINUX)
+	$(CPP) $(INCLUDE) $(CFLAGS) $(CPPFLAGS) $(OBJ_LINUX) $(LINK) -shared -ldl -lm -o$(BIN_DIR)/$(BINARY)
+
+debug:	
+	$(MAKE) all DEBUG=true
+
+default: all
+
+clean:
+	rm -rf Release/*.o
+	rm -rf Release/sdk/*.o
+	rm -rf Release/$(BINARY)
+	rm -rf Debug/*.o
+	rm -rf Debug/sdk/*.o
+	rm -rf Debug/$(BINARY)
diff --git a/extensions/mysql/extension.cpp b/extensions/mysql/extension.cpp
new file mode 100644
index 00000000..fe0de158
--- /dev/null
+++ b/extensions/mysql/extension.cpp
@@ -0,0 +1,48 @@
+/**
+ * vim: set ts=4 :
+ * ===============================================================
+ * Sample SourceMod Extension
+ * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
+ * ===============================================================
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Version: $Id: extension.cpp 763 2007-05-09 05:20:03Z damagedsoul $
+ */
+
+#include "extension.h"
+#include "mysql/MyDriver.h"
+#include <assert.h>
+#include <stdlib.h>
+
+/**
+ * @file extension.cpp
+ * @brief Implement extension code here.
+ */
+
+DBI_MySQL g_MySqlDBI;		/**< Global singleton for extension's main interface */
+
+SMEXT_LINK(&g_MySqlDBI);
+
+bool DBI_MySQL::SDK_OnLoad(char *error, size_t maxlength, bool late)
+{
+	dbi->AddDriver(&g_MyDriver);
+
+	return true;
+}
+
+void DBI_MySQL::SDK_OnUnload()
+{
+	dbi->RemoveDriver(&g_MyDriver);
+}
diff --git a/extensions/mysql/extension.h b/extensions/mysql/extension.h
new file mode 100644
index 00000000..37888837
--- /dev/null
+++ b/extensions/mysql/extension.h
@@ -0,0 +1,111 @@
+/**
+ * vim: set ts=4 :
+ * ===============================================================
+ * Sample SourceMod Extension
+ * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
+ * ===============================================================
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ *
+ * Version: $Id: extension.h 763 2007-05-09 05:20:03Z damagedsoul $
+ */
+
+#ifndef _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
+#define _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
+
+/**
+ * @file extension.h
+ * @brief Sample extension code header.
+ */
+
+#include "smsdk_ext.h"
+
+
+/**
+ * @brief Sample implementation of the SDK Extension.
+ * Note: Uncomment one of the pre-defined virtual functions in order to use it.
+ */
+class DBI_MySQL : public SDKExtension
+{
+public:
+	/**
+	 * @brief This is called after the initial loading sequence has been processed.
+	 *
+	 * @param error		Error message buffer.
+	 * @param maxlength	Size of error message buffer.
+	 * @param late		Whether or not the module was loaded after map load.
+	 * @return			True to succeed loading, false to fail.
+	 */
+	virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
+	
+	/**
+	 * @brief This is called right before the extension is unloaded.
+	 */
+	virtual void SDK_OnUnload();
+
+	/**
+	 * @brief This is called once all known extensions have been loaded.
+	 * Note: It is is a good idea to add natives here, if any are provided.
+	 */
+	//virtual void SDK_OnAllLoaded();
+
+	/**
+	 * @brief Called when the pause state is changed.
+	 */
+	//virtual void SDK_OnPauseChange(bool paused);
+
+	/**
+	 * @brief this is called when Core wants to know if your extension is working.
+	 *
+	 * @param error		Error message buffer.
+	 * @param maxlength	Size of error message buffer.
+	 * @return			True if working, false otherwise.
+	 */
+	//virtual bool QueryRunning(char *error, size_t maxlength);
+public:
+#if defined SMEXT_CONF_METAMOD
+	/**
+	 * @brief Called when Metamod is attached, before the extension version is called.
+	 *
+	 * @param error			Error buffer.
+	 * @param maxlength		Maximum size of error buffer.
+	 * @param late			Whether or not Metamod considers this a late load.
+	 * @return				True to succeed, false to fail.
+	 */
+	//virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late);
+
+	/**
+	 * @brief Called when Metamod is detaching, after the extension version is called.
+	 * NOTE: By default this is blocked unless sent from SourceMod.
+	 *
+	 * @param error			Error buffer.
+	 * @param maxlength		Maximum size of error buffer.
+	 * @return				True to succeed, false to fail.
+	 */
+	//virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength);
+
+	/**
+	 * @brief Called when Metamod's pause state is changing.
+	 * NOTE: By default this is blocked unless sent from SourceMod.
+	 *
+	 * @param paused		Pause state being set.
+	 * @param error			Error buffer.
+	 * @param maxlength		Maximum size of error buffer.
+	 * @return				True to succeed, false to fail.
+	 */
+	//virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength);
+#endif
+};
+
+#endif // _INCLUDE_SOURCEMOD_EXTENSION_PROPER_H_
diff --git a/extensions/mysql/msvc8/sm_mysql.sln b/extensions/mysql/msvc8/sm_mysql.sln
new file mode 100644
index 00000000..25736ce5
--- /dev/null
+++ b/extensions/mysql/msvc8/sm_mysql.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "sm_mysql", "sm_mysql.vcproj", "{B3E797CF-4E77-4C9D-B8A8-7589B6902206}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Win32 = Debug|Win32
+		Release|Win32 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.ActiveCfg = Debug|Win32
+		{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Debug|Win32.Build.0 = Debug|Win32
+		{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.ActiveCfg = Release|Win32
+		{B3E797CF-4E77-4C9D-B8A8-7589B6902206}.Release|Win32.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/extensions/mysql/msvc8/sm_mysql.vcproj b/extensions/mysql/msvc8/sm_mysql.vcproj
new file mode 100644
index 00000000..efe81320
--- /dev/null
+++ b/extensions/mysql/msvc8/sm_mysql.vcproj
@@ -0,0 +1,279 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="sm_mysql"
+	ProjectGUID="{B3E797CF-4E77-4C9D-B8A8-7589B6902206}"
+	RootNamespace="sm_mysql"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="..;..\sdk;..\..\..\public;..\..\..\public\sourcepawn"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SOURCEMOD_BUILD"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				StructMemberAlignment="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="wsock32.lib mysqlclient.lib zlib.lib"
+				OutputFile="$(OutDir)\dbi.mysql.ext.dll"
+				LinkIncremental="2"
+				IgnoreDefaultLibraryNames="LIBCMT"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+			IntermediateDirectory="$(ConfigurationName)"
+			ConfigurationType="2"
+			CharacterSet="2"
+			WholeProgramOptimization="1"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="..;..\sdk;..\..\..\public;..\..\..\public\sourcepawn"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;SDK_EXPORTS;_CRT_SECURE_NO_DEPRECATE;SOURCEMOD_BUILD"
+				RuntimeLibrary="0"
+				StructMemberAlignment="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="false"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="wsock32.lib mysqlclient.lib"
+				OutputFile="$(OutDir)\dbi.mysql.ext.dll"
+				LinkIncremental="1"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath="..\extension.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath="..\extension.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+		<Filter
+			Name="SourceMod SDK"
+			UniqueIdentifier="{31958233-BB2D-4e41-A8F9-CE8A4684F436}"
+			>
+			<File
+				RelativePath="..\sdk\smsdk_config.h"
+				>
+			</File>
+			<File
+				RelativePath="..\sdk\smsdk_ext.cpp"
+				>
+			</File>
+			<File
+				RelativePath="..\sdk\smsdk_ext.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="MySQL Driver"
+			>
+			<Filter
+				Name="Headers"
+				>
+				<File
+					RelativePath="..\mysql\MyBasicResults.h"
+					>
+				</File>
+				<File
+					RelativePath="..\mysql\MyBoundResults.h"
+					>
+				</File>
+				<File
+					RelativePath="..\mysql\MyDatabase.h"
+					>
+				</File>
+				<File
+					RelativePath="..\mysql\MyDriver.h"
+					>
+				</File>
+				<File
+					RelativePath="..\mysql\MyStatement.h"
+					>
+				</File>
+			</Filter>
+			<Filter
+				Name="Source"
+				>
+				<File
+					RelativePath="..\mysql\MyBasicResults.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\mysql\MyBoundResults.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\mysql\MyDatabase.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\mysql\MyDriver.cpp"
+					>
+				</File>
+				<File
+					RelativePath="..\mysql\MyStatement.cpp"
+					>
+				</File>
+			</Filter>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
diff --git a/extensions/mysql/mysql/MyBasicResults.cpp b/extensions/mysql/mysql/MyBasicResults.cpp
new file mode 100644
index 00000000..96d75c5e
--- /dev/null
+++ b/extensions/mysql/mysql/MyBasicResults.cpp
@@ -0,0 +1,337 @@
+#include <stdlib.h>
+#include "MyBasicResults.h"
+
+MyBasicResults::MyBasicResults(MYSQL_RES *res)
+: m_pRes(res)
+{
+	Update();
+}
+
+MyBasicResults::~MyBasicResults()
+{
+}
+
+void MyBasicResults::Update()
+{
+	if (m_pRes)
+	{
+		m_ColCount = (unsigned int)mysql_num_fields(m_pRes);
+		m_RowCount = (unsigned int)mysql_num_rows(m_pRes);
+		m_CurRow = 0;
+		m_Row = NULL;
+	}
+}
+
+unsigned int MyBasicResults::GetRowCount()
+{
+	return m_RowCount;
+}
+
+unsigned int MyBasicResults::GetFieldCount()
+{
+	return m_ColCount;
+}
+
+bool MyBasicResults::FieldNameToNum(const char *name, unsigned int *columnId)
+{
+	unsigned int total = GetFieldCount();
+
+	for (unsigned int i=0; i<total; i++)
+	{
+		if (strcmp(FieldNumToName(i), name) == 0)
+		{
+			*columnId = i;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+const char *MyBasicResults::FieldNumToName(unsigned int colId)
+{
+	if (colId >= GetFieldCount())
+	{
+		return NULL;
+	}
+
+	MYSQL_FIELD *field = mysql_fetch_field_direct(m_pRes, colId);
+	return field ? (field->name ? field->name : "") : "";
+}
+
+bool MyBasicResults::MoreRows()
+{
+	return (m_CurRow < m_RowCount);
+}
+
+IResultRow *MyBasicResults::FetchRow()
+{
+	if (m_CurRow >= m_RowCount)
+	{
+		/* Put us one after so we know to block CurrentRow() */
+		m_CurRow = m_RowCount + 1;
+		return NULL;
+	}
+	m_Row = mysql_fetch_row(m_pRes);
+	m_Lengths = mysql_fetch_lengths(m_pRes);
+	m_CurRow++;
+	return this;
+}
+
+IResultRow *MyBasicResults::CurrentRow()
+{
+	if (!m_pRes
+		|| !m_CurRow
+		|| m_CurRow > m_RowCount)
+	{
+		return NULL;
+	}
+	
+	return this;
+}
+
+bool MyBasicResults::Rewind()
+{
+	mysql_data_seek(m_pRes, 0);
+	m_CurRow = 0;
+	return true;
+}
+
+DBType MyBasicResults::GetFieldType(unsigned int field)
+{
+	if (field >= m_ColCount)
+	{
+		return DBType_Unknown;
+	}
+
+	MYSQL_FIELD *fld = mysql_fetch_field_direct(m_pRes, field);
+	if (!fld)
+	{
+		return DBType_Unknown;
+	}
+
+	return GetOurType(fld->type);
+}
+
+DBType MyBasicResults::GetFieldDataType(unsigned int field)
+{
+	DBType type = GetFieldType(field);
+	if (type == DBType_Blob)
+	{
+		return DBType_Blob;
+	} else {
+		return DBType_String;
+	}
+}
+
+bool MyBasicResults::IsNull(unsigned int columnId)
+{
+	if (columnId >= m_ColCount)
+	{
+		return true;
+	}
+
+	return (m_Row[columnId] == NULL);
+}
+
+DBResult MyBasicResults::GetString(unsigned int columnId, const char **pString, size_t *length)
+{
+	if (columnId >= m_ColCount)
+	{
+		return DBVal_Error;
+	} else if (m_Row[columnId] == NULL) {
+		*pString = "";
+		if (length)
+		{
+			*length = 0;
+		}
+		return DBVal_Null;
+	}
+
+	*pString = m_Row[columnId];
+
+	if (length)
+	{
+		*length = (size_t)m_Lengths[columnId];
+	}
+
+	return DBVal_Data;
+}
+
+DBResult MyBasicResults::CopyString(unsigned int columnId, 
+									char *buffer, 
+									size_t maxlength, 
+									size_t *written)
+{
+	DBResult res;
+	const char *str;
+	if ((res=GetString(columnId, &str, NULL)) == DBVal_Error)
+	{
+		return DBVal_Error;
+	}
+
+	size_t wr = strncopy(buffer, str, maxlength);
+	if (written)
+	{
+		*written = wr;
+	}
+
+	return res;
+}
+
+size_t MyBasicResults::GetDataSize(unsigned int columnId)
+{
+	if (columnId >= m_ColCount)
+	{
+		return 0;
+	}
+
+	return (size_t)m_Lengths[columnId];
+}
+
+DBResult MyBasicResults::GetFloat(unsigned int col, float *fval)
+{
+	if (col >= m_ColCount)
+	{
+		return DBVal_Error;
+	} else if (m_Row[col] == NULL) {
+		*fval = 0.0f;
+		return DBVal_Null;
+	}
+
+	*fval = (float)atof(m_Row[col]);
+
+	return DBVal_Data;
+}
+
+DBResult MyBasicResults::GetInt(unsigned int col, int *val)
+{
+	if (col >= m_ColCount)
+	{
+		return DBVal_Error;
+	} else if (m_Row[col] == NULL) {
+		*val = 0;
+		return DBVal_Null;
+	}
+
+	*val = atoi(m_Row[col]);
+
+	return DBVal_Data;
+}
+
+DBResult MyBasicResults::GetBlob(unsigned int col, const void **pData, size_t *length)
+{
+	if (col >= m_ColCount)
+	{
+		return DBVal_Error;
+	} else if (m_Row[col] == NULL) {
+		*pData = NULL;
+		if (length)
+		{
+			*length = 0;
+		}
+		return DBVal_Null;
+	}
+
+	*pData = m_Row[col];
+
+	if (length)
+	{
+		*length = (size_t)m_Lengths[col];
+	}
+
+	return DBVal_Data;
+}
+
+DBResult MyBasicResults::CopyBlob(unsigned int columnId, void *buffer, size_t maxlength, size_t *written)
+{
+	const void *addr;
+	size_t length;
+	DBResult res;
+
+	if ((res=GetBlob(columnId, &addr, &length)) == DBVal_Error)
+	{
+		return DBVal_Error;
+	}
+
+	if (addr == NULL)
+	{
+		return DBVal_Null;
+	}
+
+	if (length > maxlength)
+	{
+		length = maxlength;
+	}
+
+	memcpy(buffer, addr, length);
+	if (written)
+	{
+		*written = length;
+	}
+
+	return res;
+}
+
+MyQuery::MyQuery(MyDatabase *db, MYSQL_RES *res)
+: m_pParent(db), m_rs(res)
+{
+	m_pParent->IncRefCount();
+}
+
+IResultSet *MyQuery::GetResultSet()
+{
+	if (m_rs.m_pRes == NULL)
+	{
+		return NULL;
+	}
+
+	return &m_rs;
+}
+
+bool MyQuery::FetchMoreResults()
+{
+	if (m_rs.m_pRes == NULL)
+	{
+		return false;
+	} else if (!mysql_more_results(m_pParent->m_mysql)) {
+		return false;
+	}
+
+	mysql_free_result(m_rs.m_pRes);
+	m_rs.m_pRes = NULL;
+
+	if (mysql_next_result(m_pParent->m_mysql) != 0)
+	{
+		return false;
+	}
+
+	m_rs.m_pRes = mysql_store_result(m_pParent->m_mysql);
+	m_rs.Update();
+
+	return (m_rs.m_pRes != NULL);
+}
+
+void MyQuery::Destroy()
+{
+	/* :TODO: All this rot should be moved into the destructor,
+	 * and the Update() function needs to not be so stupid.
+	 */
+
+	while (FetchMoreResults())
+	{
+		/* Spin until all are gone */
+	}
+
+	/* Free the last, if any */
+	if (m_rs.m_pRes != NULL)
+	{
+		mysql_free_result(m_rs.m_pRes);
+	}
+
+	/* Tell our parent we're done */
+	m_pParent->Close();
+
+	/* Self destruct */
+	delete this;
+}
diff --git a/extensions/mysql/mysql/MyBasicResults.h b/extensions/mysql/mysql/MyBasicResults.h
new file mode 100644
index 00000000..ea5be32c
--- /dev/null
+++ b/extensions/mysql/mysql/MyBasicResults.h
@@ -0,0 +1,64 @@
+#ifndef _INCLUDE_SM_MYSQL_BASIC_RESULTS_H_
+#define _INCLUDE_SM_MYSQL_BASIC_RESULTS_H_
+
+#include "MyDatabase.h"
+
+class MyQuery;
+
+class MyBasicResults : 
+	public IResultSet,
+	public IResultRow
+{
+	friend class MyQuery;
+public:
+	MyBasicResults(MYSQL_RES *res);
+	~MyBasicResults();
+public: //IResultSet
+	unsigned int GetRowCount();
+	unsigned int GetFieldCount();
+	const char *FieldNumToName(unsigned int columnId);
+	bool FieldNameToNum(const char *name, unsigned int *columnId);
+	bool MoreRows();
+	IResultRow *FetchRow();
+	bool Rewind();
+	DBType GetFieldType(unsigned int field);
+	DBType GetFieldDataType(unsigned int field);
+	IResultRow *CurrentRow();
+public: //IResultRow
+	DBResult GetString(unsigned int columnId, const char **pString, size_t *length);
+	DBResult GetFloat(unsigned int columnId, float *pFloat);
+	DBResult GetInt(unsigned int columnId, int *pInt);
+	bool IsNull(unsigned int columnId);
+	DBResult GetBlob(unsigned int columnId, const void **pData, size_t *length);
+	DBResult CopyBlob(unsigned int columnId, void *buffer, size_t maxlength, size_t *written);
+	DBResult CopyString(unsigned int columnId, 
+						char *buffer, 
+						size_t maxlength, 
+						size_t *written);
+	size_t GetDataSize(unsigned int columnId);
+protected:
+	void Update();
+private:
+	MYSQL_RES *m_pRes;
+	unsigned int m_CurRow;
+	MYSQL_ROW m_Row;
+	unsigned long *m_Lengths;
+	unsigned int m_ColCount;
+	unsigned int m_RowCount;
+};
+
+class MyQuery : public IQuery
+{
+	friend class MyBasicResults;
+public:
+	MyQuery(MyDatabase *db, MYSQL_RES *res);
+public:
+	IResultSet *GetResultSet();
+	bool FetchMoreResults();
+	void Destroy();
+private:
+	MyDatabase *m_pParent;
+	MyBasicResults m_rs;
+};
+
+#endif //_INCLUDE_SM_MYSQL_BASIC_RESULTS_H_
diff --git a/extensions/mysql/mysql/MyBoundResults.cpp b/extensions/mysql/mysql/MyBoundResults.cpp
new file mode 100644
index 00000000..d1a54c99
--- /dev/null
+++ b/extensions/mysql/mysql/MyBoundResults.cpp
@@ -0,0 +1,633 @@
+#include "MyBoundResults.h"
+
+#define DEFAULT_BUFFER_SIZE		5
+
+/* :IDEA: When we have to refetch a buffer to do type changes, should we rebind
+ * the buffer so the next fetch will predict the proper cast?  Probably yes since
+ * these things are done in standard iterations, but maybe users should be punished
+ * for not using the API as it was intended?  Maybe it should be an option set to 
+ * on by default to catch the bad users?
+ */
+
+enum_field_types GetTheirType(DBType type)
+{
+	switch (type)
+	{
+	case DBType_Float:
+		{
+			return MYSQL_TYPE_FLOAT;
+		}
+	case DBType_Integer:
+		{
+			return MYSQL_TYPE_LONG;
+		}
+	case DBType_String:
+		{
+			return MYSQL_TYPE_STRING;
+		}
+	case DBType_Blob:
+		{
+			return MYSQL_TYPE_BLOB;
+		}
+	}
+
+	return MYSQL_TYPE_STRING;
+}
+
+MyBoundResults::MyBoundResults(MYSQL_STMT *stmt, MYSQL_RES *res)
+: m_stmt(stmt), m_pRes(res), m_Initialized(false), m_RowCount(0), m_CurRow(0)
+{
+	/**
+	 * Important things to note here: 
+	 * 1) We're guaranteed at least one field.
+	 * 2) The field information should never change, and thus we
+	 *    never rebuild it.  If someone ALTERs the table during
+	 *    a prepared query's lifetime, it's their own death.
+	 */
+
+	m_ColCount = (unsigned int)mysql_num_fields(m_pRes);
+
+	/* Allocate buffers */
+	m_bind = (MYSQL_BIND *)malloc(sizeof(MYSQL_BIND) * m_ColCount);
+	m_pull = (ResultBind *)malloc(sizeof(ResultBind) * m_ColCount);
+
+	/* Zero data */
+	memset(m_bind, 0, sizeof(MYSQL_BIND) * m_ColCount);
+	memset(m_pull, 0, sizeof(ResultBind) * m_ColCount);
+}
+
+MyBoundResults::~MyBoundResults()
+{
+	if (m_Initialized)
+	{
+		/* Make sure we free our internal buffers */
+		for (unsigned int i=0; i<m_ColCount; i++)
+		{
+			delete [] m_pull[i].blob;
+		}
+	}
+
+	free(m_pull);
+	free(m_bind);
+}
+
+void MyBoundResults::Update()
+{
+	m_RowCount = (unsigned int)mysql_stmt_num_rows(m_stmt);
+	m_CurRow = 0;
+}
+
+bool MyBoundResults::Initialize()
+{
+	/* Check if we need to build our result binding information */
+	if (!m_Initialized)
+	{
+		for (unsigned int i=0; i<m_ColCount; i++)
+		{
+			MYSQL_FIELD *field = mysql_fetch_field_direct(m_pRes, i);
+			DBType type = GetOurType(field->type);
+
+			m_bind[i].length = &(m_pull[i].my_length);
+			m_bind[i].is_null = &(m_pull[i].my_null);
+
+			if (type == DBType_Integer)
+			{
+				m_bind[i].buffer_type = MYSQL_TYPE_LONG;
+				m_bind[i].buffer = &(m_pull[i].data.ival);
+			} else if (type == DBType_Float) {
+				m_bind[i].buffer_type = MYSQL_TYPE_FLOAT;
+				m_bind[i].buffer = &(m_pull[i].data.ival);
+			} else if (type == DBType_String || type == DBType_Blob) {
+				m_bind[i].buffer_type = GetTheirType(type);
+
+				/* We bound this to 2048 bytes.  Otherwise a MEDIUMBLOB
+				 * or something could allocate horrible amounts of memory
+				 * because MySQL is incompetent.  
+				 */
+				size_t creat_length = (size_t)field->length;
+				if (!creat_length || creat_length > DEFAULT_BUFFER_SIZE)
+				{
+					creat_length = DEFAULT_BUFFER_SIZE;
+				}
+				m_pull[i].blob = new unsigned char[creat_length];
+				m_pull[i].length = creat_length;
+
+				m_bind[i].buffer = m_pull[i].blob;
+				m_bind[i].buffer_length = (unsigned long)creat_length;
+			} else {
+				return false;
+			}
+		}
+		m_Initialized = true;
+	}
+
+	/* Do the actual bind */
+	return (mysql_stmt_bind_result(m_stmt, m_bind) == 0);
+}
+
+unsigned int MyBoundResults::GetRowCount()
+{
+	return m_RowCount;
+}
+
+unsigned int MyBoundResults::GetFieldCount()
+{
+	return m_ColCount;
+}
+
+const char *MyBoundResults::FieldNumToName(unsigned int columnId)
+{
+	if (columnId >= m_ColCount)
+	{
+		return NULL;
+	}
+
+	MYSQL_FIELD *field = mysql_fetch_field_direct(m_pRes, columnId);
+
+	return field ? (field->name ? field->name : "") : "";
+}
+
+bool MyBoundResults::FieldNameToNum(const char *name, unsigned int *columnId)
+{
+	for (unsigned int i=0; i<m_ColCount; i++)
+	{
+		if (strcmp(name, FieldNumToName(i)) == 0)
+		{
+			*columnId = i;
+			return true;
+		}
+	}
+
+	return false;
+}
+
+bool MyBoundResults::MoreRows()
+{
+	return (m_CurRow < m_RowCount);
+}
+
+IResultRow *MyBoundResults::FetchRow()
+{
+	if (!MoreRows())
+	{
+		m_CurRow = m_RowCount + 1;
+		NULL;
+	}
+
+	m_CurRow++;
+
+	/* We should be able to get another row */
+	int err = mysql_stmt_fetch(m_stmt);
+	if (err == 0 || err == MYSQL_DATA_TRUNCATED)
+	{
+		return this;
+	}
+
+	if (err == MYSQL_NO_DATA && m_CurRow == m_RowCount)
+	{
+		return this;
+	}
+
+	/* Some sort of error occurred */
+	return NULL;
+}
+
+IResultRow *MyBoundResults::CurrentRow()
+{
+	if (!m_CurRow || m_CurRow > m_RowCount)
+	{
+		return NULL;
+	}
+
+	return this;
+}
+
+bool MyBoundResults::Rewind()
+{
+	mysql_stmt_data_seek(m_stmt, 0);
+	m_CurRow = 0;
+	return true;
+}
+
+DBType MyBoundResults::GetFieldType(unsigned int field)
+{
+	if (field >= m_ColCount)
+	{
+		return DBType_Unknown;
+	}
+
+	MYSQL_FIELD *fld = mysql_fetch_field_direct(m_pRes, field);
+	return GetOurType(fld->type);
+}
+
+DBType MyBoundResults::GetFieldDataType(unsigned int field)
+{
+	return GetFieldType(field);
+}
+
+void ResizeBuffer(ResultBind *bind, size_t len)
+{
+	if (!bind->blob)
+	{
+		bind->blob = new unsigned char[len];
+		bind->length = len;
+	} else if (bind->length < len) {
+		delete [] bind->blob;
+		bind->blob = new unsigned char[len];
+		bind->length = len;
+	}
+}
+
+bool RefetchField(MYSQL_STMT *stmt, 
+				  ResultBind *rbind, 
+				  unsigned int id,
+				  size_t initSize,
+				  enum_field_types type)
+{
+	/* Make sure there is a buffer to pull into */
+	ResizeBuffer(rbind, initSize);
+
+	MYSQL_BIND bind;
+
+	/* Initialize bind info */
+	memset(&bind, 0, sizeof(MYSQL_BIND));
+	bind.buffer = rbind->blob;
+	bind.buffer_type = type;
+	bind.buffer_length = (unsigned long)rbind->length;
+	bind.length = &(rbind->my_length);
+	bind.is_null = &(rbind->my_null);
+
+	/* Attempt to fetch */
+	return (mysql_stmt_fetch_column(stmt, &bind, id, 0) == 0);
+}
+
+DBResult RefetchSize4Field(MYSQL_STMT *stmt,
+						unsigned int id,
+						void *buffer,
+						enum_field_types type)
+{
+	MYSQL_BIND bind;
+	my_bool is_null;
+
+	/* Initialize bind info  */
+	memset(&bind, 0, sizeof(MYSQL_BIND));
+	bind.buffer = buffer;
+	bind.buffer_type = type;
+	bind.is_null = &is_null;
+
+	/* Attempt to fetch */
+	if (mysql_stmt_fetch_column(stmt, &bind, id, 0) != 0)
+	{
+		return DBVal_TypeMismatch;
+	}
+
+	return is_null ? DBVal_Null : DBVal_Data;
+}
+
+
+bool RefetchUserField(MYSQL_STMT *stmt,
+					  unsigned int id,
+					  void *userbuf,
+					  size_t userlen,
+					  enum_field_types type,
+					  my_bool &is_null,
+					  size_t *written)
+{
+	MYSQL_BIND bind;
+	unsigned long length;
+
+	/* Initialize bind info */
+	memset(&bind, 0, sizeof(MYSQL_BIND));
+	bind.buffer = userbuf;
+	bind.buffer_type = type;
+	bind.length = &length;
+	bind.is_null = &is_null;
+	bind.buffer_length = (unsigned long)userlen;
+
+	if (mysql_stmt_fetch_column(stmt, &bind, id, 0) != 0)
+	{
+		return false;
+	}
+
+	if (is_null)
+	{
+		return true;
+	}
+
+	if (type == MYSQL_TYPE_STRING && (size_t)length == userlen)
+	{
+		/* Enforce null termination in case MySQL forgot.
+		 * Note we subtract one from the length (which must be >= 1)
+		 * so we can pass the number of bytes written below.
+		 */
+		char *data = (char *)userbuf;
+		data[--userlen] = '\0';
+	}
+
+	if (written)
+	{
+		/* In the case of strings, they will never be equal */
+		*written = (userlen < length) ? userlen : length;
+	}
+
+	return true;
+}
+
+#define BAD_COL_CHECK() \
+	if (id >= m_ColCount) \
+		return DBVal_Error;
+
+#define STR_NULL_CHECK_0(var) \
+	if (var) { \
+		*pString = NULL; \
+		if (length) \
+			*length = 0; \
+		return DBVal_Null; \
+	}
+
+DBResult MyBoundResults::GetString(unsigned int id, const char **pString, size_t *length)
+{
+	BAD_COL_CHECK();
+
+	STR_NULL_CHECK_0(m_pull[id].my_null);
+
+	if (m_bind[id].buffer_type != MYSQL_TYPE_STRING)
+	{
+		/* Ugh, we have to re-get this as a string.  Sigh, stupid user.
+		 * We're going to disallow conversions from blobs.
+		 */
+		if (m_bind[id].buffer_type == MYSQL_TYPE_BLOB)
+		{
+			return DBVal_TypeMismatch;
+		}
+
+		/* Attempt to refetch the string */
+		if (!RefetchField(m_stmt, &m_pull[id], id, 128, MYSQL_TYPE_STRING))
+		{
+			return DBVal_TypeMismatch;
+		}
+
+		/* Check if we have a new null */
+		STR_NULL_CHECK_0(m_pull[id].my_null);
+	}
+
+	/* Okay, we should now have a blob type whether we originally wanted one or not. */
+
+	/* Check if the size is too small.  Note that MySQL will not null terminate small buffers,
+	 * and it returns the size without the null terminator.  This means we need to add an extra
+	 * byte onto the end to accept the terminator until there is a workaround.
+	 *
+	 * Note that we do an >= check because MySQL appears to want the null terminator included,
+	 * so just to be safe and avoid its inconsistencies, we make sure we'll always have room.
+	 */
+	if ((size_t)(m_pull[id].my_length) >= m_pull[id].length)
+	{
+		/* Yes, we need to refetch. */
+		if (!RefetchField(m_stmt, &m_pull[id], id, m_pull[id].my_length + 1, MYSQL_TYPE_STRING))
+		{
+			return DBVal_Error;
+		}
+	}
+
+	/* Finally, we can return.  We're guaranteed to have a properly NULL-terminated string
+	 * here because we have refetched the string to a bigger length.
+	 */
+	*pString = (const char *)m_pull[id].blob;
+	if (length)
+	{
+		*length = (size_t)m_pull[id].my_length;
+	}
+
+	return DBVal_Data;
+}
+
+#define STR_NULL_CHECK_1(var) \
+	if (var) { \
+		buffer[0] = '\0'; \
+		if (written) \
+			*written = 0; \
+		return DBVal_Null; \
+	} 
+
+DBResult MyBoundResults::CopyString(unsigned int id, char *buffer, size_t maxlength, size_t *written)
+{
+	BAD_COL_CHECK();
+
+	STR_NULL_CHECK_1(m_pull[id].my_null);
+
+	if (!buffer || !maxlength)
+	{
+		return DBVal_Error;
+	}
+
+	if (m_bind[id].buffer_type != MYSQL_TYPE_STRING)
+	{
+		/* We're going to disallow conversions from blobs. */
+		if (m_bind[id].buffer_type == MYSQL_TYPE_BLOB)
+		{
+			return DBVal_TypeMismatch;
+		}
+
+		/* Re-fetch this for the user.  This call will guarantee NULL termination. */
+		my_bool is_null;
+		if (!RefetchUserField(m_stmt, id, buffer, maxlength, MYSQL_TYPE_STRING, is_null, written))
+		{
+			return DBVal_TypeMismatch;
+		}
+
+		STR_NULL_CHECK_1(is_null);
+
+		return DBVal_Data;
+	}
+
+	size_t pull_length = (size_t)m_pull[id].my_length;
+	size_t orig_length = m_pull[id].length;
+
+	/* If there's more data in the buffer, we have to look at two cases. */
+	if (pull_length >= orig_length)
+	{
+		/* If the user supplied a bigger buffer, just refetch for them. */
+		if (maxlength > orig_length)
+		{
+			my_bool is_null;
+			RefetchUserField(m_stmt, id, buffer, maxlength, MYSQL_TYPE_STRING, is_null, written);
+			STR_NULL_CHECK_1(is_null);
+			return DBVal_Data;
+		}
+		/* Otherwise, we should enforce null termination from MySQL. */
+		else if (pull_length == orig_length)
+		{
+			char *data = (char *)m_pull[id].blob;
+			data[pull_length] = '\0';
+		}
+	}
+
+	/* If we got here, we need to copy the resultant string to the user and be done with it.
+	 * Null termination is guaranteed from the pulled string.
+	 */
+	size_t wr = strncopy(buffer, (const char *)m_pull[id].blob, maxlength);
+	if (written)
+	{
+		*written = wr;
+	}
+
+	return DBVal_Data;
+}
+
+DBResult MyBoundResults::GetFloat(unsigned int id, float *pFloat)
+{
+	BAD_COL_CHECK();
+
+	if (m_pull[id].my_null)
+	{
+		*pFloat = 0.0f;
+		return DBVal_Null;
+	}
+
+	if (m_bind[id].buffer_type != MYSQL_TYPE_FLOAT)
+	{
+		if (m_bind[id].buffer_type == MYSQL_TYPE_BLOB)
+		{
+			return DBVal_TypeMismatch;
+		}
+		/* We have to convert... */
+		return RefetchSize4Field(m_stmt, id, pFloat, MYSQL_TYPE_FLOAT);
+	}
+
+	*pFloat = m_pull[id].data.fval;
+
+	return DBVal_Data;
+}
+
+DBResult MyBoundResults::GetInt(unsigned int id, int *pInt)
+{
+	BAD_COL_CHECK();
+
+	if (m_pull[id].my_null)
+	{
+		*pInt = 0;
+		return DBVal_Null;
+	}
+
+	if (m_bind[id].buffer_type != MYSQL_TYPE_LONG)
+	{
+		if (m_bind[id].buffer_type == MYSQL_TYPE_BLOB)
+		{
+			return DBVal_TypeMismatch;
+		}
+		/* We have to convert... */
+		return RefetchSize4Field(m_stmt, id, pInt, MYSQL_TYPE_LONG);
+	}
+
+	*pInt = m_pull[id].data.ival;
+
+	return DBVal_Data;
+}
+
+bool MyBoundResults::IsNull(unsigned int id)
+{
+	if (id >= m_ColCount)
+	{
+		return true;
+	}
+
+	return m_pull[id].my_null ? true : false;
+}
+
+#define BLOB_CHECK_NULL_0() \
+	if (m_pull[id].my_null) { \
+		*pData = NULL; \
+		if (length) \
+			*length = 0; \
+		return DBVal_Null; \
+	}
+
+DBResult MyBoundResults::GetBlob(unsigned int id, const void **pData, size_t *length)
+{
+	BAD_COL_CHECK();
+
+	BLOB_CHECK_NULL_0();
+
+	/* We only want blobs to be read as blobs */
+	if (m_bind[id].buffer_type != MYSQL_TYPE_BLOB)
+	{
+		return DBVal_TypeMismatch;
+	}
+
+	if ((size_t)m_pull[id].my_length > m_pull[id].length)
+	{
+		if (!RefetchField(m_stmt, &m_pull[id], id, m_pull[id].my_length, MYSQL_TYPE_BLOB))
+		{
+			return DBVal_TypeMismatch;
+		}
+		BLOB_CHECK_NULL_0();
+	}
+
+	*pData = m_pull[id].blob;
+	if (length)
+	{
+		*length = (size_t)m_pull[id].my_length;
+	}
+
+	return DBVal_Data;
+}
+
+#define BLOB_CHECK_NULL_1(var) \
+	if (var) { \
+		if (written) \
+			*written = 0; \
+		return DBVal_Null; \
+	}
+
+DBResult MyBoundResults::CopyBlob(unsigned int id, void *buffer, size_t maxlength, size_t *written)
+{
+	BAD_COL_CHECK();
+
+	/* We only want blobs to be read as blobs */
+	if (m_bind[id].buffer_type != MYSQL_TYPE_BLOB)
+	{
+		return DBVal_TypeMismatch;
+	}
+
+	BLOB_CHECK_NULL_1(m_pull[id].my_null);
+
+	size_t pull_size = (size_t)m_pull[id].my_length;
+	size_t push_size = m_pull[id].length;
+
+	/* Check if we can do a resize and copy in one step */
+	if (pull_size > push_size
+		&& maxlength > push_size)
+	{
+		my_bool is_null;
+		if (!RefetchUserField(m_stmt, id, buffer, maxlength, MYSQL_TYPE_BLOB, is_null, written))
+		{
+			return DBVal_TypeMismatch;
+		}
+		BLOB_CHECK_NULL_1(is_null);
+		return DBVal_Data;
+	}
+
+	/* If we got here, either there is no more data to refetch,
+	 * or our buffer is too small to receive the refetched data.
+	 */
+	size_t buf_bytes = pull_size > push_size ? push_size : pull_size;
+	size_t to_copy = buf_bytes > maxlength ? maxlength : buf_bytes;
+
+	memcpy(buffer, m_pull[id].blob, to_copy);
+	if (written)
+	{
+		*written = to_copy;
+	}
+
+	return DBVal_Data;
+}
+
+size_t MyBoundResults::GetDataSize(unsigned int id)
+{
+	if (id >= m_ColCount)
+	{
+		return 0;
+	}
+
+	return (size_t)m_pull[id].my_length;
+}
diff --git a/extensions/mysql/mysql/MyBoundResults.h b/extensions/mysql/mysql/MyBoundResults.h
new file mode 100644
index 00000000..74772668
--- /dev/null
+++ b/extensions/mysql/mysql/MyBoundResults.h
@@ -0,0 +1,66 @@
+#ifndef _INCLUDE_SM_MYSQL_BOUND_RESULTS_H_
+#define _INCLUDE_SM_MYSQL_BOUND_RESULTS_H_
+
+#include "MyDatabase.h"
+
+class MyStatement;
+
+struct ResultBind
+{
+	my_bool my_null;
+	unsigned long my_length;
+	union
+	{
+		int ival;
+		float fval;
+	} data;
+	unsigned char *blob;
+	size_t length;
+};
+
+class MyBoundResults : 
+	public IResultSet,
+	public IResultRow
+{
+	friend class MyStatement;
+public:
+	MyBoundResults(MYSQL_STMT *stmt, MYSQL_RES *res);
+	~MyBoundResults();
+public: //IResultSet
+	unsigned int GetRowCount();
+	unsigned int GetFieldCount();
+	const char *FieldNumToName(unsigned int columnId);
+	bool FieldNameToNum(const char *name, unsigned int *columnId);
+	bool MoreRows();
+	IResultRow *FetchRow();
+	bool Rewind();
+	DBType GetFieldType(unsigned int field);
+	DBType GetFieldDataType(unsigned int field);
+	IResultRow *CurrentRow();
+public: //IResultRow
+	DBResult GetString(unsigned int id, const char **pString, size_t *length);
+	DBResult CopyString(unsigned int id, 
+		char *buffer, 
+		size_t maxlength, 
+		size_t *written);
+	DBResult GetFloat(unsigned int id, float *pFloat);
+	DBResult GetInt(unsigned int id, int *pInt);
+	bool IsNull(unsigned int id);
+	size_t GetDataSize(unsigned int id);
+	DBResult GetBlob(unsigned int id, const void **pData, size_t *length);
+	DBResult CopyBlob(unsigned int id, void *buffer, size_t maxlength, size_t *written);
+public:
+	bool Initialize();
+	void Update();
+private:
+	MYSQL_STMT *m_stmt;
+	MYSQL_RES *m_pRes;
+	MYSQL_BIND *m_bind;
+	ResultBind *m_pull;
+	unsigned int m_ColCount;
+	bool m_Initialized;
+	unsigned int m_RowCount;
+	unsigned int m_CurRow;
+};
+
+#endif //_INCLUDE_SM_MYSQL_BOUND_RESULTS_H_
diff --git a/extensions/mysql/mysql/MyDatabase.cpp b/extensions/mysql/mysql/MyDatabase.cpp
new file mode 100644
index 00000000..500eacef
--- /dev/null
+++ b/extensions/mysql/mysql/MyDatabase.cpp
@@ -0,0 +1,244 @@
+#include "MyDatabase.h"
+#include "smsdk_ext.h"
+#include "MyBasicResults.h"
+#include "MyStatement.h"
+
+DBType GetOurType(enum_field_types type)
+{
+	switch (type)
+	{
+	case MYSQL_TYPE_DOUBLE:
+	case MYSQL_TYPE_FLOAT:
+		{
+			return DBType_Float;
+		}
+	case MYSQL_TYPE_TINY:
+	case MYSQL_TYPE_SHORT:
+	case MYSQL_TYPE_LONG:
+	case MYSQL_TYPE_INT24:
+	case MYSQL_TYPE_YEAR:
+	case MYSQL_TYPE_BIT:
+		{
+			return DBType_Integer;
+		}
+	case MYSQL_TYPE_LONGLONG:
+	case MYSQL_TYPE_DATE:
+	case MYSQL_TYPE_TIME:
+	case MYSQL_TYPE_DATETIME:
+	case MYSQL_TYPE_TIMESTAMP:
+	case MYSQL_TYPE_NEWDATE:
+	case MYSQL_TYPE_VAR_STRING:
+	case MYSQL_TYPE_VARCHAR:
+	case MYSQL_TYPE_STRING:
+	case MYSQL_TYPE_NEWDECIMAL:
+	case MYSQL_TYPE_DECIMAL:
+	case MYSQL_TYPE_ENUM:
+	case MYSQL_TYPE_SET:
+		{
+			return DBType_String;
+		}
+
+	case MYSQL_TYPE_TINY_BLOB:
+	case MYSQL_TYPE_MEDIUM_BLOB:
+	case MYSQL_TYPE_LONG_BLOB:
+	case MYSQL_TYPE_BLOB:
+	case MYSQL_TYPE_GEOMETRY:
+		{
+			return DBType_Blob;
+		}
+	default:
+		{
+			return DBType_String;
+		}
+	}
+
+	return DBType_Unknown;
+}
+
+MyDatabase::MyDatabase(MYSQL *mysql, const DatabaseInfo *info, bool persistent)
+: m_mysql(mysql), m_refcount(1), m_handle(BAD_HANDLE), m_bPersistent(persistent)
+{
+	m_Host.assign(info->host);
+	m_Database.assign(info->database);
+	m_User.assign(info->user);
+	m_Pass.assign(info->pass);
+
+	m_Info.database = m_Database.c_str();
+	m_Info.host = m_Host.c_str();
+	m_Info.user = m_User.c_str();
+	m_Info.pass = m_Pass.c_str();
+	m_Info.driver = NULL;
+	m_Info.maxTimeout = info->maxTimeout;
+	m_Info.port = info->port;
+}
+
+MyDatabase::~MyDatabase()
+{
+	mysql_close(m_mysql);
+	m_mysql = NULL;
+}
+
+void MyDatabase::IncRefCount()
+{
+	m_refcount++;
+}
+
+bool MyDatabase::Close(bool fromHndlSys)
+{
+	if (m_refcount > 1)
+	{
+		m_refcount--;
+		return false;
+	}
+
+	/* If we don't have a Handle and the Handle is
+	 * is from the Handle System, it means we need
+	 * to block a re-entrant call from our own 
+	 * FreeHandle().
+	 */
+	if (fromHndlSys && (m_handle == BAD_HANDLE))
+	{
+		return false;
+	}
+
+	/* Remove us from the search list */
+	if (m_bPersistent)
+	{
+		g_MyDriver.RemoveFromList(this, true);
+	}
+
+	/* If we're not from the Handle system, and
+	 * we have a Handle, we need to free it first.
+	 */
+	if (!fromHndlSys && m_handle != BAD_HANDLE)
+	{
+		Handle_t hndl = m_handle;
+		m_handle = BAD_HANDLE;
+		dbi->ReleaseHandle(hndl, DBHandle_Database, myself->GetIdentity());
+	}
+
+	/* Finally, free our resource(s) */
+	delete this;
+
+	return true;
+}
+
+Handle_t MyDatabase::GetHandle()
+{
+	if (m_handle == BAD_HANDLE)
+	{
+		m_handle = dbi->CreateHandle(DBHandle_Database, this, myself->GetIdentity());
+	}
+
+	return m_handle;
+}
+
+const DatabaseInfo &MyDatabase::GetInfo()
+{
+	return m_Info;
+}
+
+unsigned int MyDatabase::GetInsertID()
+{
+	return (unsigned int)mysql_insert_id(m_mysql);
+}
+
+unsigned int MyDatabase::GetAffectedRows()
+{
+	return (unsigned int)mysql_affected_rows(m_mysql);
+}
+
+const char *MyDatabase::GetError(int *errCode)
+{
+	if (errCode)
+	{
+		*errCode = mysql_errno(m_mysql);
+	}
+
+	return mysql_error(m_mysql);
+}
+
+bool MyDatabase::QuoteString(const char *str, char buffer[], size_t maxlength, size_t *newSize)
+{
+	unsigned long size = static_cast<unsigned long>(strlen(str));
+	unsigned long needed = size * 2 + 1;
+
+	if (maxlength < needed)
+	{
+		if (newSize)
+		{
+			*newSize = (size_t)needed;
+		}
+		return false;
+	}
+
+	needed = mysql_real_escape_string(m_mysql, buffer, str, size);
+	if (newSize)
+	{
+		*newSize = (size_t)needed;
+	}
+
+	return true;
+}
+
+bool MyDatabase::DoSimpleQuery(const char *query)
+{
+	IQuery *pQuery = DoQuery(query);
+	if (!pQuery)
+	{
+		return false;
+	}
+	pQuery->Destroy();
+	return true;
+}
+
+IQuery *MyDatabase::DoQuery(const char *query)
+{
+	if (mysql_real_query(m_mysql, query, strlen(query)) != 0)
+	{
+		return NULL;
+	}
+
+	MYSQL_RES *res = NULL;
+	if (mysql_field_count(m_mysql))
+	{
+		res = mysql_store_result(m_mysql);
+		if (!res)
+		{
+			return NULL;
+		}
+	}
+
+	return new MyQuery(this, res);
+}
+
+IPreparedQuery *MyDatabase::PrepareQuery(const char *query, char *error, size_t maxlength, int *errCode)
+{
+	MYSQL_STMT *stmt = mysql_stmt_init(m_mysql);
+	if (!stmt)
+	{
+		if (error)
+		{
+			strncopy(error, GetError(errCode), maxlength);
+		} else if (errCode) {
+			*errCode = mysql_errno(m_mysql);
+		}
+		return NULL;
+	}
+
+	if (mysql_stmt_prepare(stmt, query, strlen(query)) != 0)
+	{
+		if (error)
+		{
+			strncopy(error, mysql_stmt_error(stmt), maxlength);
+		}
+		if (errCode)
+		{
+			*errCode = mysql_stmt_errno(stmt);
+		}
+		mysql_stmt_close(stmt);
+		return NULL;
+	}
+
+	return new MyStatement(this, stmt);
+}
diff --git a/extensions/mysql/mysql/MyDatabase.h b/extensions/mysql/mysql/MyDatabase.h
new file mode 100644
index 00000000..d45a00be
--- /dev/null
+++ b/extensions/mysql/mysql/MyDatabase.h
@@ -0,0 +1,45 @@
+#ifndef _INCLUDE_SM_MYSQL_DATABASE_H_
+#define _INCLUDE_SM_MYSQL_DATABASE_H_
+
+#include "MyDriver.h"
+
+class MyQuery;
+class MyStatement;
+
+class MyDatabase : public IDatabase
+{
+	friend class MyQuery;
+	friend class MyStatement;
+public:
+	MyDatabase(MYSQL *mysql, const DatabaseInfo *info, bool persistent);
+	~MyDatabase();
+public: //IDatabase
+	bool Close(bool fromHndlSys=false);
+	const char *GetError(int *errorCode=NULL);
+	bool DoSimpleQuery(const char *query);
+	IQuery *DoQuery(const char *query);
+	IPreparedQuery *PrepareQuery(const char *query, char *error, size_t maxlength, int *errCode=NULL);
+	bool QuoteString(const char *str, char buffer[], size_t maxlen, size_t *newSize);
+	unsigned int GetAffectedRows();
+	unsigned int GetInsertID();
+	Handle_t GetHandle();
+public:
+	const DatabaseInfo &GetInfo();
+	void IncRefCount();
+private:
+	MYSQL *m_mysql;
+	unsigned int m_refcount;
+	Handle_t m_handle;
+
+	/* ---------- */
+	DatabaseInfo m_Info;
+	String m_Host;
+	String m_Database;
+	String m_User;
+	String m_Pass;
+	bool m_bPersistent;
+};
+
+DBType GetOurType(enum_field_types type);
+
+#endif //_INCLUDE_SM_MYSQL_DATABASE_H_
diff --git a/extensions/mysql/mysql/MyDriver.cpp b/extensions/mysql/mysql/MyDriver.cpp
new file mode 100644
index 00000000..7f006c67
--- /dev/null
+++ b/extensions/mysql/mysql/MyDriver.cpp
@@ -0,0 +1,169 @@
+#include "MyDriver.h"
+#include "MyDatabase.h"
+#include "sdk/smsdk_ext.h"
+
+MyDriver g_MyDriver;
+
+MyDriver::MyDriver()
+{
+	m_MyHandle = BAD_HANDLE;
+}
+
+void CloseDBList(List<MyDatabase *> &l)
+{
+	List<MyDatabase *>::iterator iter;
+	for (iter=l.begin(); iter!=l.end(); iter++)
+	{
+		MyDatabase *db = (*iter);
+		while (!db->Close())
+		{
+			/* Spool until it closes  */
+		}
+	}
+	l.clear();
+}
+
+void MyDriver::Shutdown()
+{
+	List<MyDatabase *>::iterator iter;
+	CloseDBList(m_PermDbs);
+
+	if (m_MyHandle != BAD_HANDLE)
+	{
+		dbi->ReleaseHandle(m_MyHandle, DBHandle_Driver, myself->GetIdentity());
+		m_MyHandle = BAD_HANDLE;
+	}
+}
+
+const char *MyDriver::GetIdentifier()
+{
+	return "mysql";
+}
+
+Handle_t MyDriver::GetHandle()
+{
+	if (m_MyHandle == BAD_HANDLE)
+	{
+		m_MyHandle = dbi->CreateHandle(DBHandle_Driver, this, myself->GetIdentity());
+	}
+
+	return m_MyHandle;
+}
+
+IdentityToken_t *MyDriver::GetIdentity()
+{
+	return myself->GetIdentity();
+}
+
+const char *MyDriver::GetProductName()
+{
+	return "MySQL";
+}
+
+MYSQL *Connect(const DatabaseInfo *info, char *error, size_t maxlength)
+{
+	MYSQL *mysql = mysql_init(NULL);
+
+	if (info->maxTimeout > 0)
+	{
+		mysql_options(mysql, MYSQL_OPT_CONNECT_TIMEOUT, (const char *)&(info->maxTimeout));
+	}
+
+	if (!mysql_real_connect(mysql,
+		info->host,
+		info->user, 
+		info->pass,
+		info->database,
+		info->port,
+		NULL,
+		M_CLIENT_MULTI_RESULTS))
+	{
+		/* :TODO: expose UTIL_Format from smutil! */
+		snprintf(error, maxlength, "[%d]: %s", mysql_errno(mysql), mysql_error(mysql));
+		mysql_close(mysql);
+		return NULL;
+	}
+
+	return mysql;
+}
+
+bool CompareField(const char *str1, const char *str2)
+{
+	if ((str1 == NULL && str2 != NULL)
+		|| (str1 != NULL && str2 == NULL))
+	{
+		return false;
+	}
+
+	if (str1 == NULL && str2 == NULL)
+	{
+		return true;
+	}
+
+	return (strcmp(str1, str2) == NULL);
+}
+
+IDatabase *MyDriver::Connect(const DatabaseInfo *info, bool persistent, char *error, size_t maxlength)
+{
+	if (persistent)
+	{
+		/* Try to find a matching persistent connection */
+		List<MyDatabase *>::iterator iter;
+		for (iter=m_PermDbs.begin();
+			 iter!=m_PermDbs.end();
+			 iter++)
+		{
+			MyDatabase *db = (*iter);
+			const DatabaseInfo &other = db->GetInfo();
+			if (CompareField(info->host, other.host)
+				&& CompareField(info->user, other.user)
+				&& CompareField(info->pass, other.pass)
+				&& CompareField(info->database, other.database)
+				&& (info->port == other.port))
+			{
+				db->IncRefCount();
+				return db;
+			}
+		}
+	}
+
+	MYSQL *mysql = ::Connect(info, error, maxlength);
+	if (!mysql)
+	{
+		return NULL;
+	}
+
+	MyDatabase *db = new MyDatabase(mysql, info, persistent);
+
+	if (persistent)
+	{
+		m_PermDbs.push_back(db);
+	}
+	
+	return db;
+}
+
+void MyDriver::RemoveFromList(MyDatabase *pdb, bool persistent)
+{
+	if (persistent)
+	{
+		m_PermDbs.remove(pdb);
+	}
+}
+
+unsigned int strncopy(char *dest, const char *src, size_t count)
+{
+	if (!count)
+	{
+		return 0;
+	}
+
+	char *start = dest;
+	while ((*src) && (--count))
+	{
+		*dest++ = *src++;
+	}
+	*dest = '\0';
+
+	return (dest - start);
+}
diff --git a/extensions/mysql/mysql/MyDriver.h b/extensions/mysql/mysql/MyDriver.h
new file mode 100644
index 00000000..6a41cf24
--- /dev/null
+++ b/extensions/mysql/mysql/MyDriver.h
@@ -0,0 +1,45 @@
+#ifndef _INCLUDE_SM_MYSQL_DRIVER_H_
+#define _INCLUDE_SM_MYSQL_DRIVER_H_
+
+#include <IDBDriver.h>
+#include <sm_platform.h>
+#if defined PLATFORM_WINDOWS
+#include <winsock.h>
+#endif
+
+#include <mysql.h>
+
+#include <sh_string.h>
+#include <sh_list.h>
+
+using namespace SourceMod;
+using namespace SourceHook;
+
+#define M_CLIENT_MULTI_RESULTS    ((1) << 17)  /* Enable/disable multi-results */
+
+class MyDatabase;
+
+class MyDriver : public IDBDriver
+{
+public:
+	MyDriver();
+public: //IDBDriver
+	IDatabase *Connect(const DatabaseInfo *info, bool persistent, char *error, size_t maxlength);
+	const char *GetIdentifier();
+	const char *GetProductName();
+	Handle_t GetHandle();
+	IdentityToken_t *GetIdentity();
+public:
+	void Shutdown();
+	void RemoveFromList(MyDatabase *pdb, bool persistent);
+private:
+	Handle_t m_MyHandle;
+	List<MyDatabase *> m_TempDbs;
+	List<MyDatabase *> m_PermDbs;
+};
+
+extern MyDriver g_MyDriver;
+
+unsigned int strncopy(char *dest, const char *src, size_t count);
+
+#endif //_INCLUDE_SM_MYSQL_DRIVER_H_
diff --git a/extensions/mysql/mysql/MyQuery.cpp b/extensions/mysql/mysql/MyQuery.cpp
new file mode 100644
index 00000000..bf42682d
--- /dev/null
+++ b/extensions/mysql/mysql/MyQuery.cpp
@@ -0,0 +1,7 @@
+#include "MyQuery.h"
+
+MyQuery::MyQuery(MyDatabase *db, MYSQL_RES *res)
+: m_pParent(db)
+{
+	
+}
diff --git a/extensions/mysql/mysql/MyQuery.h b/extensions/mysql/mysql/MyQuery.h
new file mode 100644
index 00000000..b3aa45e1
--- /dev/null
+++ b/extensions/mysql/mysql/MyQuery.h
@@ -0,0 +1,26 @@
+#ifndef _INCLUDE_SM_MYSQL_QUERY_H_
+#define _INCLUDE_SM_MYSQL_QUERY_H_
+
+#include "MyDriver.h"
+#include "MyDatabase.h"
+
+class MyResultSet :
+	public IResultSet,
+	public IResultRow
+{
+public:
+
+};
+
+class MyQuery : public IQuery
+{
+public:
+	MyQuery(MyDatabase *db, MYSQL_RES *res);
+public:
+	IResultSet *GetResults();
+	void Destroy();
+private:
+	MyDatabase *m_pParent;
+};
+
+#endif //_INCLUDE_SM_MYSQL_QUERY_H_
diff --git a/extensions/mysql/mysql/MyStatement.cpp b/extensions/mysql/mysql/MyStatement.cpp
new file mode 100644
index 00000000..b1038abd
--- /dev/null
+++ b/extensions/mysql/mysql/MyStatement.cpp
@@ -0,0 +1,257 @@
+#include "MyStatement.h"
+#include "MyBoundResults.h"
+
+MyStatement::MyStatement(MyDatabase *db, MYSQL_STMT *stmt)
+: m_mysql(db->m_mysql), m_pParent(db), m_stmt(stmt), m_rs(NULL), m_Results(false)
+{
+	m_Params = (unsigned int)mysql_stmt_param_count(m_stmt);
+
+	if (m_Params)
+	{
+		m_pushinfo = (ParamBind *)malloc(sizeof(ParamBind) * m_Params);
+		memset(m_pushinfo, 0, sizeof(ParamBind) * m_Params);
+		m_bind = (MYSQL_BIND *)malloc(sizeof(MYSQL_BIND) * m_Params);
+		memset(m_bind, 0, sizeof(MYSQL_BIND) * m_Params);
+	} else {
+		m_pushinfo = NULL;
+		m_bind = NULL;
+	}
+
+	m_pParent->IncRefCount();
+
+	m_pRes = mysql_stmt_result_metadata(stmt);
+	m_Results = false;
+}
+
+MyStatement::~MyStatement()
+{
+	/* Free result set structures */
+	delete m_rs;
+
+	/* Free old blobs */
+	for (unsigned int i=0; i<m_Params; i++)
+	{
+		free(m_pushinfo[i].blob);
+	}
+
+	/* Free our allocated arrays */
+	free(m_pushinfo);
+	free(m_bind);
+	
+	/* Close our mysql handles */
+	if (m_pRes)
+	{
+		mysql_free_result(m_pRes);
+	}
+	mysql_stmt_close(m_stmt);
+
+	/* Tell the parent database that we're done referencing it */
+	m_pParent->Close();
+}
+
+void MyStatement::Destroy()
+{
+	delete this;
+}
+
+bool MyStatement::FetchMoreResults()
+{
+	/* Multiple result sets are not supported by statements,
+	 * thank god.
+	 */
+	return false;
+}
+
+void *MyStatement::CopyBlob(unsigned int param, const void *blobptr, size_t length)
+{
+	void *copy_ptr = NULL;
+
+	if (m_pushinfo[param].blob != NULL)
+	{
+		if (m_pushinfo[param].length < length)
+		{
+			free(m_pushinfo[param].blob);
+		} else {
+			copy_ptr = m_pushinfo[param].blob;
+		}
+	}
+
+	if (copy_ptr == NULL)
+	{
+		copy_ptr = malloc(length);
+		m_pushinfo[param].blob = copy_ptr;
+		m_pushinfo[param].length = length;
+	}
+
+	memcpy(copy_ptr, blobptr, length);
+
+	return copy_ptr;
+}
+
+bool MyStatement::BindParamInt(unsigned int param, int num, bool signd)
+{
+	if (param >= m_Params)
+	{
+		return false;
+	}
+
+	m_pushinfo[param].data.ival = num;
+	m_bind[param].buffer_type = MYSQL_TYPE_LONG;
+	m_bind[param].buffer = &(m_pushinfo[param].data.ival);
+	m_bind[param].is_unsigned = signd ? 0 : 1;
+	m_bind[param].length = NULL;
+
+	return true;
+}
+
+bool MyStatement::BindParamFloat(unsigned int param, float f)
+{
+	if (param >= m_Params)
+	{
+		return false;
+	}
+
+	m_pushinfo[param].data.fval = f;
+	m_bind[param].buffer_type = MYSQL_TYPE_FLOAT;
+	m_bind[param].buffer = &(m_pushinfo[param].data.fval);
+	m_bind[param].length = NULL;
+
+	return true;
+}
+
+bool MyStatement::BindParamString(unsigned int param, const char *text, bool copy)
+{
+	if (param >= m_Params)
+	{
+		return false;
+	}
+
+	const void *final_ptr;
+	size_t len;
+
+	if (copy)
+	{
+		len = strlen(text);
+		final_ptr = CopyBlob(param, text, len+1);
+	} else {
+		len = strlen(text);
+		final_ptr = text;
+	}
+
+	m_bind[param].buffer_type = MYSQL_TYPE_STRING;
+	m_bind[param].buffer = (void *)final_ptr;
+	m_bind[param].buffer_length = (unsigned long)len;
+	m_bind[param].length = &(m_bind[param].buffer_length);
+
+	return true;
+}
+
+bool MyStatement::BindParamBlob(unsigned int param, const void *data, size_t length, bool copy)
+{
+	if (param >= m_Params)
+	{
+		return false;
+	}
+
+	const void *final_ptr;
+	
+	if (copy)
+	{
+		final_ptr = CopyBlob(param, data, length);
+	} else {
+		final_ptr = data;
+	}
+
+	m_bind[param].buffer_type = MYSQL_TYPE_BLOB;
+	m_bind[param].buffer = (void *)final_ptr;
+	m_bind[param].buffer_length = (unsigned long)length;
+	m_bind[param].length = &(m_bind[param].buffer_length);
+
+	return true;
+}
+
+bool MyStatement::BindParamNull(unsigned int param)
+{
+	if (param >= m_Params)
+	{
+		return false;
+	}
+
+	m_bind[param].buffer_type = MYSQL_TYPE_NULL;
+
+	return true;
+}
+
+bool MyStatement::Execute()
+{
+	/* Clear any past result first! */
+	m_Results = false;
+
+	/* Bind the parameters */
+	if (m_Params)
+	{
+		if (mysql_stmt_bind_param(m_stmt, m_bind) != 0)
+		{
+			return false;
+		}
+	}
+
+	if (mysql_stmt_execute(m_stmt) != 0)
+	{
+		return false;
+	}
+
+	/* Skip away if we don't have data */
+	if (!m_pRes)
+	{
+		return true;
+	}
+
+	/* If we don't have a result manager, create one. */
+	if (!m_rs)
+	{
+		m_rs = new MyBoundResults(m_stmt, m_pRes);
+	}
+
+	/* Tell the result set to update its bind info,
+	 * and initialize itself if necessary.
+	 */
+	if (!(m_Results = m_rs->Initialize()))
+	{
+		return false;
+	}
+
+	/* Try precaching the results. */
+	m_Results = (mysql_stmt_store_result(m_stmt) == 0);
+
+	/* Update now that the data is known. */
+	m_rs->Update();
+
+	/* Return indicator */
+	return m_Results;
+}
+
+const char *MyStatement::GetError(int *errCode/* =NULL */)
+{
+	if (errCode)
+	{
+		*errCode = mysql_stmt_errno(m_stmt);
+	}
+
+	return mysql_stmt_error(m_stmt);
+}
+
+unsigned int MyStatement::GetAffectedRows()
+{
+	return (unsigned int)mysql_stmt_affected_rows(m_stmt);
+}
+
+unsigned int MyStatement::GetInsertID()
+{
+	return (unsigned int)mysql_stmt_insert_id(m_stmt);
+}
+
+IResultSet *MyStatement::GetResultSet()
+{
+	return (m_Results ? m_rs : NULL);
+}
diff --git a/extensions/mysql/mysql/MyStatement.h b/extensions/mysql/mysql/MyStatement.h
new file mode 100644
index 00000000..8d2f9f98
--- /dev/null
+++ b/extensions/mysql/mysql/MyStatement.h
@@ -0,0 +1,51 @@
+#ifndef _INCLUDE_SM_MYSQL_STATEMENT_H_
+#define _INCLUDE_SM_MYSQL_STATEMENT_H_
+
+#include "MyDatabase.h"
+#include "MyBoundResults.h"
+
+struct ParamBind
+{
+	union
+	{
+		float fval;
+		int ival;
+	} data;
+	void *blob;
+	size_t length;
+};
+
+class MyStatement : public IPreparedQuery
+{
+public:
+	MyStatement(MyDatabase *db, MYSQL_STMT *stmt);
+	~MyStatement();
+public: //IQuery
+	IResultSet *GetResultSet();
+	bool FetchMoreResults();
+	void Destroy();
+public: //IPreparedQuery
+	bool BindParamInt(unsigned int param, int num, bool signd=true);
+	bool BindParamFloat(unsigned int param, float f);
+	bool BindParamNull(unsigned int param);
+	bool BindParamString(unsigned int param, const char *text, bool copy);
+	bool BindParamBlob(unsigned int param, const void *data, size_t length, bool copy);
+	bool Execute();
+	const char *GetError(int *errCode=NULL);
+	unsigned int GetAffectedRows();
+	unsigned int GetInsertID();
+private:
+	void *CopyBlob(unsigned int param, const void *blobptr, size_t length);
+private:
+	MYSQL *m_mysql;
+	MYSQL_STMT *m_stmt;
+	MYSQL_BIND *m_bind;
+	MYSQL_RES *m_pRes;
+	MyDatabase *m_pParent;
+	ParamBind *m_pushinfo;
+	unsigned int m_Params;
+	MyBoundResults *m_rs;
+	bool m_Results;
+};
+
+#endif //_INCLUDE_SM_MYSQL_STATEMENT_H_
diff --git a/extensions/mysql/sdk/smsdk_config.h b/extensions/mysql/sdk/smsdk_config.h
new file mode 100644
index 00000000..f52dfaf6
--- /dev/null
+++ b/extensions/mysql/sdk/smsdk_config.h
@@ -0,0 +1,54 @@
+/**
+ * vim: set ts=4 :
+ * ===============================================================
+ * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. 
+ * All rights reserved.
+ * ===============================================================
+ *
+ *  This file is part of the SourceMod/SourcePawn SDK.  This file may only be 
+ * used or modified under the Terms and Conditions of its License Agreement, 
+ * which is found in public/licenses/LICENSE.txt.  As of this notice, derivative 
+ * works must be licensed under the GNU General Public License (version 2 or 
+ * greater).  A copy of the GPL is included under public/licenses/GPL.txt.
+ * 
+ * To view the latest information, see: http://www.sourcemod.net/license.php
+ *
+ * Version: $Id: smsdk_config.h 763 2007-05-09 05:20:03Z damagedsoul $
+ */
+
+#ifndef _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
+#define _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
+
+/**
+ * @file smsdk_config.h
+ * @brief Contains macros for configuring basic extension information.
+ */
+
+/* Basic information exposed publicly */
+#define SMEXT_CONF_NAME			"MySQL-DBI"
+#define SMEXT_CONF_DESCRIPTION	"MySQL driver implementation for DBI"
+#define SMEXT_CONF_VERSION		"1.0.0.0"
+#define SMEXT_CONF_AUTHOR		"AlliedModders"
+#define SMEXT_CONF_URL			"http://www.sourcemod.net/"
+#define SMEXT_CONF_LOGTAG		"MYSQL"
+#define SMEXT_CONF_LICENSE		"GPL"
+#define SMEXT_CONF_DATESTRING	__DATE__
+
+/** 
+ * @brief Exposes plugin's main interface.
+ */
+#define SMEXT_LINK(name) SDKExtension *g_pExtensionIface = name;
+
+/**
+ * @brief Sets whether or not this plugin required Metamod.
+ * NOTE: Uncomment to enable, comment to disable.
+ */
+//#define SMEXT_CONF_METAMOD		
+
+/** Enable interfaces you want to use here by uncommenting lines */
+//#define SMEXT_ENABLE_FORWARDSYS
+//#define SMEXT_ENABLE_HANDLESYS
+//#define SMEXT_ENABLE_PLAYERHELPERS
+#define SMEXT_ENABLE_DBMANAGER
+
+#endif // _INCLUDE_SOURCEMOD_EXTENSION_CONFIG_H_
diff --git a/extensions/mysql/sdk/smsdk_ext.cpp b/extensions/mysql/sdk/smsdk_ext.cpp
new file mode 100644
index 00000000..9d6c8cca
--- /dev/null
+++ b/extensions/mysql/sdk/smsdk_ext.cpp
@@ -0,0 +1,361 @@
+/**
+ * vim: set ts=4 :
+ * ===============================================================
+ * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. 
+ * All rights reserved.
+ * ===============================================================
+ *
+ *  This file is part of the SourceMod/SourcePawn SDK.  This file may only be 
+ * used or modified under the Terms and Conditions of its License Agreement, 
+ * which is found in public/licenses/LICENSE.txt.  As of this notice, derivative 
+ * works must be licensed under the GNU General Public License (version 2 or 
+ * greater).  A copy of the GPL is included under public/licenses/GPL.txt.
+ * 
+ * To view the latest information, see: http://www.sourcemod.net/license.php
+ *
+ * Version: $Id: smsdk_ext.cpp 763 2007-05-09 05:20:03Z damagedsoul $
+ */
+
+#include <stdio.h>
+#include <malloc.h>
+#include "smsdk_ext.h"
+
+/**
+ * @file smsdk_ext.cpp
+ * @brief Contains wrappers for making Extensions easier to write.
+ */
+
+IExtension *myself = NULL;				/**< Ourself */
+IShareSys *g_pShareSys = NULL;			/**< Share system */
+IShareSys *sharesys = NULL;				/**< Share system */
+ISourceMod *g_pSM = NULL;				/**< SourceMod helpers */
+ISourceMod *smutils = NULL;				/**< SourceMod helpers */
+
+#if defined SMEXT_ENABLE_FORWARDSYS
+IForwardManager *g_pForwards = NULL;	/**< Forward system */
+IForwardManager *forwards = NULL;		/**< Forward system */
+#endif
+#if defined SMEXT_ENABLE_HANDLESYS
+IHandleSys *g_pHandleSys = NULL;		/**< Handle system */
+IHandleSys *handlesys = NULL;			/**< Handle system */
+#endif
+#if defined SMEXT_ENABLE_PLAYERHELPERS
+IPlayerHelpers *playerhelpers = NULL;	/**< Player helpers */
+#endif //SMEXT_ENABLE_PLAYERHELPERS
+#if defined SMEXT_ENABLE_DBMANAGER
+IDBManager *dbi = NULL;					/**< DB Manager */
+#endif //SMEXT_ENABLE_DBMANAGER
+
+/** Exports the main interface */
+PLATFORM_EXTERN_C IExtensionInterface *GetSMExtAPI()
+{
+	return g_pExtensionIface;
+}
+
+SDKExtension::SDKExtension()
+{
+#if defined SMEXT_CONF_METAMOD
+	m_SourceMMLoaded = false;
+	m_WeAreUnloaded = false;
+	m_WeGotPauseChange = false;
+#endif
+}
+
+bool SDKExtension::OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late)
+{
+	g_pShareSys = sharesys = sys;
+	myself = me;
+
+#if defined SMEXT_CONF_METAMOD
+	m_WeAreUnloaded = true;
+
+	if (!m_SourceMMLoaded)
+	{
+		if (error)
+		{
+			snprintf(error, maxlength, "Metamod attach failed");
+		}
+		return false;
+	}
+#endif
+	SM_GET_IFACE(SOURCEMOD, g_pSM);
+	smutils = g_pSM;
+#if defined SMEXT_ENABLE_HANDLESYS
+	SM_GET_IFACE(HANDLESYSTEM, g_pHandleSys);
+	handlesys = g_pHandleSys;
+#endif
+#if defined SMEXT_ENABLE_FORWARDSYS
+	SM_GET_IFACE(FORWARDMANAGER, g_pForwards);
+	forwards = g_pForwards;
+#endif
+#if defined SMEXT_ENABLE_PLAYERHELPERS
+	SM_GET_IFACE(PLAYERMANAGER, playerhelpers);
+#endif
+#if defined SMEXT_ENABLE_DBMANAGER
+	SM_GET_IFACE(DBI, dbi);
+#endif
+
+	if (SDK_OnLoad(error, maxlength, late))
+	{
+#if defined SMEXT_CONF_METAMOD
+		m_WeAreUnloaded = true;
+#endif
+		return true;
+	}
+
+	return false;
+}
+
+bool SDKExtension::IsMetamodExtension()
+{
+#if defined SMEXT_CONF_METAMOD
+	return true;
+#else
+	return false;
+#endif
+}
+
+void SDKExtension::OnExtensionPauseChange(bool state)
+{
+#if defined SMEXT_CONF_METAMOD
+	m_WeGotPauseChange = true;
+#endif
+	SDK_OnPauseChange(state);
+}
+
+void SDKExtension::OnExtensionsAllLoaded()
+{
+	SDK_OnAllLoaded();
+}
+
+void SDKExtension::OnExtensionUnload()
+{
+#if defined SMEXT_CONF_METAMOD
+	m_WeAreUnloaded = true;
+#endif
+	SDK_OnUnload();
+}
+
+const char *SDKExtension::GetExtensionAuthor()
+{
+	return SMEXT_CONF_AUTHOR;
+}
+
+const char *SDKExtension::GetExtensionDateString()
+{
+	return SMEXT_CONF_DATESTRING;
+}
+
+const char *SDKExtension::GetExtensionDescription()
+{
+	return SMEXT_CONF_DESCRIPTION;
+}
+
+const char *SDKExtension::GetExtensionVerString()
+{
+	return SMEXT_CONF_VERSION;
+}
+
+const char *SDKExtension::GetExtensionName()
+{
+	return SMEXT_CONF_NAME;
+}
+
+const char *SDKExtension::GetExtensionTag()
+{
+	return SMEXT_CONF_LOGTAG;
+}
+
+const char *SDKExtension::GetExtensionURL()
+{
+	return SMEXT_CONF_URL;
+}
+
+bool SDKExtension::SDK_OnLoad(char *error, size_t maxlength, bool late)
+{
+	return true;
+}
+
+void SDKExtension::SDK_OnUnload()
+{
+}
+
+void SDKExtension::SDK_OnPauseChange(bool paused)
+{
+}
+
+void SDKExtension::SDK_OnAllLoaded()
+{
+}
+
+#if defined SMEXT_CONF_METAMOD
+
+PluginId g_PLID = 0;						/**< Metamod plugin ID */
+ISmmPlugin *g_PLAPI = NULL;					/**< Metamod plugin API */
+SourceHook::ISourceHook *g_SHPtr = NULL;	/**< SourceHook pointer */
+ISmmAPI *g_SMAPI = NULL;					/**< SourceMM API pointer */
+
+IVEngineServer *engine = NULL;				/**< IVEngineServer pointer */
+IServerGameDLL *gamedll = NULL;				/**< IServerGameDLL pointer */
+
+/** Exposes the extension to Metamod */
+SMM_API void *PL_EXPOSURE(const char *name, int *code)
+{
+	if (name && !strcmp(name, PLAPI_NAME))
+	{
+		if (code)
+		{
+			*code = IFACE_OK;
+		}
+		return static_cast<void *>(g_pExtensionIface);
+	}
+
+	if (code)
+	{
+		*code = IFACE_FAILED;
+	}
+
+	return NULL;
+}
+
+bool SDKExtension::Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlen, bool late)
+{
+	PLUGIN_SAVEVARS();
+
+	GET_V_IFACE_ANY(serverFactory, gamedll, IServerGameDLL, INTERFACEVERSION_SERVERGAMEDLL);
+	GET_V_IFACE_CURRENT(engineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
+
+	m_SourceMMLoaded = true;
+
+	return SDK_OnMetamodLoad(ismm, error, maxlen, late);
+}
+
+bool SDKExtension::Unload(char *error, size_t maxlen)
+{
+	if (!m_WeAreUnloaded)
+	{
+		if (error)
+		{
+			snprintf(error, maxlen, "This extension must be unloaded by SourceMod.");
+		}
+		return false;
+	}
+
+	return SDK_OnMetamodUnload(error, maxlen);
+}
+
+bool SDKExtension::Pause(char *error, size_t maxlen)
+{
+	if (!m_WeGotPauseChange)
+	{
+		if (error)
+		{
+			snprintf(error, maxlen, "This extension must be paused by SourceMod.");
+		}
+		return false;
+	}
+
+	m_WeGotPauseChange = false;
+
+	return SDK_OnMetamodPauseChange(true, error, maxlen);
+}
+
+bool SDKExtension::Unpause(char *error, size_t maxlen)
+{
+	if (!m_WeGotPauseChange)
+	{
+		if (error)
+		{
+			snprintf(error, maxlen, "This extension must be unpaused by SourceMod.");
+		}
+		return false;
+	}
+
+	m_WeGotPauseChange = false;
+
+	return SDK_OnMetamodPauseChange(false, error, maxlen);
+}
+
+const char *SDKExtension::GetAuthor()
+{
+	return GetExtensionAuthor();
+}
+
+const char *SDKExtension::GetDate()
+{
+	return GetExtensionDateString();
+}
+
+const char *SDKExtension::GetDescription()
+{
+	return GetExtensionDescription();
+}
+
+const char *SDKExtension::GetLicense()
+{
+	return SMEXT_CONF_LICENSE;
+}
+
+const char *SDKExtension::GetLogTag()
+{
+	return GetExtensionTag();
+}
+
+const char *SDKExtension::GetName()
+{
+	return GetExtensionName();
+}
+
+const char *SDKExtension::GetURL()
+{
+	return GetExtensionURL();
+}
+
+const char *SDKExtension::GetVersion()
+{
+	return GetExtensionVerString();
+}
+
+bool SDKExtension::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late)
+{
+	return true;
+}
+
+bool SDKExtension::SDK_OnMetamodUnload(char *error, size_t maxlength)
+{
+	return true;
+}
+
+bool SDKExtension::SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength)
+{
+	return true;
+}
+
+#endif
+
+/* Overload a few things to prevent libstdc++ linking */
+#if defined __linux__
+extern "C" void __cxa_pure_virtual(void)
+{
+}
+
+void *operator new(size_t size)
+{
+	return malloc(size);
+}
+
+void *operator new[](size_t size) 
+{
+	return malloc(size);
+}
+
+void operator delete(void *ptr) 
+{
+	free(ptr);
+}
+
+void operator delete[](void * ptr)
+{
+	free(ptr);
+}
+#endif
diff --git a/extensions/mysql/sdk/smsdk_ext.h b/extensions/mysql/sdk/smsdk_ext.h
new file mode 100644
index 00000000..d5877cdd
--- /dev/null
+++ b/extensions/mysql/sdk/smsdk_ext.h
@@ -0,0 +1,237 @@
+/**
+ * vim: set ts=4 :
+ * ===============================================================
+ * SourceMod, Copyright (C) 2004-2007 AlliedModders LLC. 
+ * All rights reserved.
+ * ===============================================================
+ *
+ *  This file is part of the SourceMod/SourcePawn SDK.  This file may only be 
+ * used or modified under the Terms and Conditions of its License Agreement, 
+ * which is found in public/licenses/LICENSE.txt.  As of this notice, derivative 
+ * works must be licensed under the GNU General Public License (version 2 or 
+ * greater).  A copy of the GPL is included under public/licenses/GPL.txt.
+ * 
+ * To view the latest information, see: http://www.sourcemod.net/license.php
+ *
+ * Version: $Id: smsdk_ext.h 763 2007-05-09 05:20:03Z damagedsoul $
+ */
+
+#ifndef _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_
+#define _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_
+
+/**
+ * @file smsdk_ext.h
+ * @brief Contains wrappers for making Extensions easier to write.
+ */
+
+#include "smsdk_config.h"
+#include <IExtensionSys.h>
+#include <IHandleSys.h>
+#include <sp_vm_api.h>
+#include <sm_platform.h>
+#include <ISourceMod.h>
+#if defined SMEXT_ENABLE_FORWARDSYS
+#include <IForwardSys.h>
+#endif //SMEXT_ENABLE_FORWARDSYS
+#if defined SMEXT_ENABLE_PLAYERHELPERS
+#include <IPlayerHelpers.h>
+#endif //SMEXT_ENABLE_PlAYERHELPERS
+#if defined SMEXT_ENABLE_DBMANAGER
+#include <IDBDriver.h>
+#endif //SMEXT_ENABLE_DBMANAGER
+
+#if defined SMEXT_CONF_METAMOD
+#include <ISmmPlugin.h>
+#include <eiface.h>
+#endif
+
+using namespace SourceMod;
+using namespace SourcePawn;
+
+class SDKExtension : 
+#if defined SMEXT_CONF_METAMOD
+	public ISmmPlugin,
+#endif
+	public IExtensionInterface
+{
+public:
+	/** Constructor */
+	SDKExtension();
+public:
+	/**
+	 * @brief This is called after the initial loading sequence has been processed.
+	 *
+	 * @param error		Error message buffer.
+	 * @param maxlength	Size of error message buffer.
+	 * @param late		Whether or not the module was loaded after map load.
+	 * @return			True to succeed loading, false to fail.
+	 */
+	virtual bool SDK_OnLoad(char *error, size_t maxlength, bool late);
+	
+	/**
+	 * @brief This is called right before the extension is unloaded.
+	 */
+	virtual void SDK_OnUnload();
+
+	/**
+	 * @brief This is called once all known extensions have been loaded.
+	 */
+	virtual void SDK_OnAllLoaded();
+
+	/**
+	 * @brief Called when the pause state is changed.
+	 */
+	virtual void SDK_OnPauseChange(bool paused);
+
+#if defined SMEXT_CONF_METAMOD
+	/**
+	 * @brief Called when Metamod is attached, before the extension version is called.
+	 *
+	 * @param error			Error buffer.
+	 * @param maxlength		Maximum size of error buffer.
+	 * @param late			Whether or not Metamod considers this a late load.
+	 * @return				True to succeed, false to fail.
+	 */
+	virtual bool SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlength, bool late);
+
+	/**
+	 * @brief Called when Metamod is detaching, after the extension version is called.
+	 * NOTE: By default this is blocked unless sent from SourceMod.
+	 *
+	 * @param error			Error buffer.
+	 * @param maxlength		Maximum size of error buffer.
+	 * @return				True to succeed, false to fail.
+	 */
+	virtual bool SDK_OnMetamodUnload(char *error, size_t maxlength);
+
+	/**
+	 * @brief Called when Metamod's pause state is changing.
+	 * NOTE: By default this is blocked unless sent from SourceMod.
+	 *
+	 * @param paused		Pause state being set.
+	 * @param error			Error buffer.
+	 * @param maxlength		Maximum size of error buffer.
+	 * @return				True to succeed, false to fail.
+	 */
+	virtual bool SDK_OnMetamodPauseChange(bool paused, char *error, size_t maxlength);
+#endif
+
+public: //IExtensionInterface
+	virtual bool OnExtensionLoad(IExtension *me, IShareSys *sys, char *error, size_t maxlength, bool late);
+	virtual void OnExtensionUnload();
+	virtual void OnExtensionsAllLoaded();
+
+	/** Returns whether or not this is a Metamod-based extension */
+	virtual bool IsMetamodExtension();
+
+	/**
+	 * @brief Called when the pause state changes.
+	 * 
+	 * @param state			True if being paused, false if being unpaused.
+	 */
+	virtual void OnExtensionPauseChange(bool state);
+
+	/** Returns name */
+	virtual const char *GetExtensionName();
+	/** Returns URL */
+	virtual const char *GetExtensionURL();
+	/** Returns log tag */
+	virtual const char *GetExtensionTag();
+	/** Returns author */
+	virtual const char *GetExtensionAuthor();
+	/** Returns version string */
+	virtual const char *GetExtensionVerString();
+	/** Returns description string */
+	virtual const char *GetExtensionDescription();
+	/** Returns date string */
+	virtual const char *GetExtensionDateString();
+#if defined SMEXT_CONF_METAMOD
+public: //ISmmPlugin
+	/** Called when the extension is attached to Metamod. */
+	virtual bool Load(PluginId id, ISmmAPI *ismm, char *error, size_t maxlength, bool late);
+	/** Returns the author to MM */
+	virtual const char *GetAuthor();
+	/** Returns the name to MM */
+	virtual const char *GetName();
+	/** Returns the description to MM */
+	virtual const char *GetDescription();
+	/** Returns the URL to MM */
+	virtual const char *GetURL();
+	/** Returns the license to MM */
+	virtual const char *GetLicense();
+	/** Returns the version string to MM */
+	virtual const char *GetVersion();
+	/** Returns the date string to MM */
+	virtual const char *GetDate();
+	/** Returns the logtag to MM */
+	virtual const char *GetLogTag();
+	/** Called on unload */
+	virtual bool Unload(char *error, size_t maxlength);
+	/** Called on pause */
+	virtual bool Pause(char *error, size_t maxlength);
+	/** Called on unpause */
+	virtual bool Unpause(char *error, size_t maxlength);
+private:
+	bool m_SourceMMLoaded;
+	bool m_WeAreUnloaded;
+	bool m_WeGotPauseChange;
+#endif
+};
+
+extern SDKExtension *g_pExtensionIface;
+extern IExtension *myself;
+
+extern IShareSys *g_pShareSys;
+extern IShareSys *sharesys;				/* Note: Newer name */
+extern ISourceMod *g_pSM;
+extern ISourceMod *smutils;				/* Note: Newer name */
+
+/* Optional interfaces are below */
+#if defined SMEXT_ENABLE_FORWARDSYS
+extern IForwardManager *g_pForwards;
+extern IForwardManager *forwards;		/* Note: Newer name */
+#endif //SMEXT_ENABLE_FORWARDSYS
+#if defined SMEXT_ENABLE_HANDLESYS
+extern IHandleSys *g_pHandleSys;
+extern IHandleSys *handlesys;			/* Note: Newer name */
+#endif //SMEXT_ENABLE_HANDLESYS
+#if defined SMEXT_ENABLE_PLAYERHELPERS
+extern IPlayerHelpers *playerhelpers;
+#endif //SMEXT_ENABLE_PLAYERHELPERS
+#if defined SMEXT_ENABLE_DBMANAGER
+extern IDBManager *dbi;
+#endif //SMEXT_ENABLE_DBMANAGER
+
+#if defined SMEXT_CONF_METAMOD
+PLUGIN_GLOBALVARS();
+extern IVEngineServer *engine;
+extern IServerGameDLL *gamedll;
+#endif
+
+/** Creates a SourceMod interface macro pair */
+#define SM_MKIFACE(name) SMINTERFACE_##name##_NAME, SMINTERFACE_##name##_VERSION
+/** Automates retrieving SourceMod interfaces */
+#define SM_GET_IFACE(prefix, addr) \
+	if (!g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)) \
+	{ \
+		if (error) \
+		{ \
+			snprintf(error, maxlength, "Could not find interface: %s (version: %d)", SMINTERFACE_##prefix##_NAME, SMINTERFACE_##prefix##_VERSION); \
+			return false; \
+		} \
+	}
+/** Automates retrieving SourceMod interfaces when needed outside of SDK_OnLoad() */
+#define SM_GET_LATE_IFACE(prefix, addr) \
+	g_pShareSys->RequestInterface(SM_MKIFACE(prefix), myself, (SMInterface **)&addr)
+/** Validates a SourceMod interface pointer */
+#define SM_CHECK_IFACE(prefix, addr) \
+	if (!addr) \
+	{ \
+		if (error) \
+		{ \
+			snprintf(error, maxlength, "Could not find interface: %s", SMINTERFACE_##prefix##_NAME); \
+			return false; \
+		} \
+	}
+
+#endif // _INCLUDE_SOURCEMOD_EXTENSION_BASESDK_H_
diff --git a/public/IDBDriver.h b/public/IDBDriver.h
index 130ea6d1..88d3a31f 100644
--- a/public/IDBDriver.h
+++ b/public/IDBDriver.h
@@ -224,6 +224,14 @@ namespace SourceMod
 		 */
 		virtual IResultRow *FetchRow() =0;
 
+		/**
+		 * @brief Returns a pointer to the current row.
+		 *
+		 * @return				IResultRow pointer to the current row,
+		 *						or NULL if the current row is invalid.
+		 */
+		virtual IResultRow *CurrentRow() =0;
+
 		/**
 		 * @brief Rewinds back to the beginning of the row iteration.
 		 *