TestFramework:RegisterTest("[Prepared Query] have correct set... functions", function(test)
	local db = TestFramework:ConnectToDatabase()
	local qu = db:prepare("SELECT ? as a, ? as b, ? as c, ? as d, ? as e")
	qu:setNumber(1, 5.5)
	qu:setString(2, "test")
	qu:setBoolean(3, true)
	qu:setBoolean(4, false)
	qu:setString(5, "b")
	qu:setNull(5)
	qu:start()
	qu:wait()
	local data = qu:getData()
	test:shouldHaveLength(data, 1)
	test:shouldBeEqual(data[1].a, 5.5)
	test:shouldBeEqual(data[1].b, "test")
	test:shouldBeEqual(data[1].c, 1)
	test:shouldBeEqual(data[1].d, 0)
	test:shouldBeNil(data[1].e)
	test:Complete()
end)

TestFramework:RegisterTest("[Prepared Query] allow batching parameters correctly", function(test)
	local db = TestFramework:ConnectToDatabase()
	local qu = db:prepare("SELECT ? as a")
	qu:setNumber(1, 1)
	qu:putNewParameters()
	qu:setNumber(1, 2)
	qu:putNewParameters()
	qu:setNumber(1, 3)
	qu:start()
	qu:wait()
	test:shouldBeEqual(qu:hasMoreResults(), true)
	test:shouldBeEqual(qu:getData()[1].a, 1)
	qu:getNextResults()
	test:shouldBeEqual(qu:hasMoreResults(), true)
	test:shouldBeEqual(qu:getData()[1].a, 2)
	qu:getNextResults()
	test:shouldBeEqual(qu:hasMoreResults(), true)
	test:shouldBeEqual(qu:getData()[1].a, 3)
	qu:getNextResults()
	test:shouldBeEqual(qu:hasMoreResults(), false)
	test:Complete()
end)

TestFramework:RegisterTest("[Prepared Query] clear parameters correctly", function(test)
	local db = TestFramework:ConnectToDatabase()
	local qu = db:prepare("SELECT ? as a, ? as b")
	qu:setNumber(1, 1)
	qu:setString(2, "test")
	qu:clearParameters()
	qu:start()
	qu:wait()
	local data = qu:getData()
	test:shouldHaveLength(data, 1)
	test:shouldBeNil(data[1].a)
	test:shouldBeNil(data[1].b)
	test:Complete()
end)

TestFramework:RegisterTest("[Prepared Query] last insert should return correct values", function(test)
	local db = TestFramework:ConnectToDatabase()
	TestFramework:RunQuery(db, [[DROP TABLE IF EXISTS last_insert_test]])
	TestFramework:RunQuery(db, [[CREATE TABLE last_insert_test(id INT AUTO_INCREMENT PRIMARY KEY)]])

	local qu = db:prepare("INSERT INTO last_insert_test VALUES()")
	function qu:onSuccess()
		test:shouldBeEqual(qu:lastInsert(), 1)
	end
	qu:start()
	local qu2 = db:prepare("INSERT INTO last_insert_test VALUES()")
	function qu2:onSuccess()
		test:shouldBeEqual(qu2:lastInsert(), 2)
	end
	qu2:start()
	local qu3 = db:prepare("INSERT INTO last_insert_test VALUES()")
	function qu3:onSuccess()
		test:shouldBeEqual(qu3:lastInsert(), 3)
		function qu3:onSuccess()
			test:shouldBeEqual(qu3:lastInsert(), 4)
			qu3.onSuccess = nil
			qu3:start()
			qu3:wait()
			test:shouldBeEqual(qu3:lastInsert(), 5)
			test:Complete()
		end
		qu3:start()
	end
	qu3:start()
end)

TestFramework:RegisterTest("[Prepared Query] affected rows should return correct values", function(test)
	local db = TestFramework:ConnectToDatabase()
	TestFramework:RunQuery(db, [[DROP TABLE IF EXISTS affected_rows_test]])
	TestFramework:RunQuery(db, [[CREATE TABLE affected_rows_test(id INT AUTO_INCREMENT PRIMARY KEY)]])
	TestFramework:RunQuery(db, "INSERT INTO affected_rows_test VALUES()")
	TestFramework:RunQuery(db, "INSERT INTO affected_rows_test VALUES()")
	TestFramework:RunQuery(db, "INSERT INTO affected_rows_test VALUES()")
	TestFramework:RunQuery(db, "INSERT INTO affected_rows_test VALUES()")
	local qu = db:prepare("DELETE FROM affected_rows_test WHERE id = ?")
	qu:setNumber(1, 4)
	qu:start()
	qu:wait()
	test:shouldBeEqual(qu:affectedRows(), 1)
	qu:start()
	local qu2 = db:prepare("DELETE FROM affected_rows_test")
	function qu2:onSuccess()
		test:shouldBeEqual(qu2:affectedRows(), 3)
		function qu2:onSuccess()
			test:shouldBeEqual(qu2:affectedRows(), 0)
			test:Complete()
		end
		qu2:start()
	end
	qu2:start()
end)

TestFramework:RegisterTest("[Prepared Query] isRunning should return the correct value", function(test)
	local db = TestFramework:ConnectToDatabase()
	local qu = db:prepare("SELECT SLEEP(0.1)")
	test:shouldBeEqual(qu:isRunning(), false)
	function qu:onSuccess()
		test:shouldBeEqual(qu:isRunning(), true)
		timer.Simple(0.1, function()
			test:shouldBeEqual(qu:isRunning(), false)
			test:Complete()
		end)
	end
	qu:start()
	test:shouldBeEqual(qu:isRunning(), true)
end)

TestFramework:RegisterTest("[Prepared Query] should return correct data", function(test)
	local db = TestFramework:ConnectToDatabase()
	TestFramework:RunQuery(db, [[DROP TABLE IF EXISTS data_test]])
	TestFramework:RunQuery(db, [[CREATE TABLE data_test(id INT PRIMARY KEY, str VARCHAR(10), big BIGINT, bin BLOB, num DOUBLE, bool BIT)]])
	TestFramework:RunQuery(db, [[INSERT INTO data_test VALUES(1, '2', 8589934588, X'470047', 3.3, TRUE)]])
	TestFramework:RunQuery(db, [[INSERT INTO data_test VALUES(2, null, -8589930588, X'00AB', 10.1, FALSE)]])

	local qu = db:prepare("SELECT * FROM data_test")
	function qu:onSuccess(data)
		test:shouldBeEqual(data, qu:getData()) //Check that it is cached correctly
		test:shouldBeEqual(#data, 2)
		local row1 = data[1]
		test:shouldBeEqual(row1.id, 1)
		test:shouldBeEqual(row1.str, "2")
		test:shouldBeEqual(row1.big, 8589934588)
		test:shouldBeEqual(row1.bin, string.char(0x47,0x00,0x47))
		test:shouldBeEqual(row1.num, 3.3)
		test:shouldBeEqual(row1.bool, 1)
		local row2 = data[2]
		test:shouldBeEqual(row2.id, 2)
		test:shouldBeNil(row2.str)
		test:shouldBeEqual(row2.big, -8589930588)
		test:shouldBeEqual(row2.bin, string.char(0x00,0xAB))
		test:shouldBeEqual(row2.num, 10.1)
		test:shouldBeEqual(row2.bool, 0)
		test:Complete()
	end
	function qu:onError(err)
		print(err)
	end
	qu:start()
end)

TestFramework:RegisterTest("[Prepared Query] should return correct data if numeric is enabled", function(test)
	local db = TestFramework:ConnectToDatabase()
	local qu = db:prepare("SELECT 1, 2, 4")
	qu:setOption(mysqloo.OPTION_NUMERIC_FIELDS)
	function qu:onSuccess(data)
		test:shouldBeEqual(#data, 1)
		local row = data[1]
		test:shouldBeEqual(row[1], 1)
		test:shouldBeEqual(row[2], 2)
		test:shouldBeEqual(row[3], 4)
		test:shouldBeNil(row[4])
		test:Complete()
	end
	qu:start()
end)

TestFramework:RegisterTest("[Prepared Query] should return correct error", function(test)
	local db = TestFramework:ConnectToDatabase()
	local qu = db:prepare("SEsdg")
	function qu:onError(err, sql)
		test:shouldBeEqual(qu:error(), err)
		test:shouldBeGreaterThan(#qu:error(), 0)
		test:shouldBeEqual(sql, "SEsdg")
		test:Complete()
	end
	qu:start()
end)

TestFramework:RegisterTest("[Prepared Query] should return correct error", function(test)
	local db = TestFramework:ConnectToDatabase()
	local qu = db:prepare("SEsdg")
	function qu:onError(err)
		test:shouldBeEqual(qu:error(), err)
		test:shouldBeGreaterThan(#qu:error(), 0)
		timer.Simple(0.1, function()
			test:shouldBeEqual(qu:error(), err)
			test:Complete()
		end)
	end
	qu:start()
end)

TestFramework:RegisterTest("[Prepared Query] should return correct error if waiting", function(test)
	local db = TestFramework:ConnectToDatabase()
	local qu = db:prepare("SEsdg")
	qu:start()
	qu:wait()
	test:shouldBeGreaterThan(#qu:error(), 0)
	test:Complete()
end)

TestFramework:RegisterTest("[Prepared Query] prevent multiple statements if disabled", function(test)
	local db = mysqloo.connect(DatabaseSettings.Host, DatabaseSettings.Username, DatabaseSettings.Password, DatabaseSettings.Database, DatabaseSettings.Port)
	db:setMultiStatements(false)
	db:connect()
	db:wait()
	local qu = db:prepare("SELECT 1; SELECT 2;")
	function qu:onError()
		test:Complete()
	end
	function qu:onSuccess()
		test:Fail("Query should have failed but did not")
	end
	qu:start()
	qu:wait()
end)

TestFramework:RegisterTest("[Prepared Query]  prevent multiple statements even if enabled", function(test)
	local db = TestFramework:ConnectToDatabase()
	local qu = db:prepare("SELECT 1 as a; SELECT 2 as b;")
	function qu:onError()
		test:Complete()
	end
	qu:start()
end)

TestFramework:RegisterTest("[Prepared Query] call onData correctly", function(test)
	local db = TestFramework:ConnectToDatabase()
	local qu = db:prepare("SELECT ? as a UNION ALL SELECT ?")
	qu:setNumber(1, 1)
	qu:setNumber(2, 2)
	local callCount = 0
	local sum = 0
	function qu:onSuccess(data) //onData is called before onSuccess
		test:shouldHaveLength(data, 2)
		test:shouldBeEqual(callCount, 2)
		test:shouldBeEqual(sum, 3)
		test:Complete()
	end
	function qu:onData(row)
		callCount = callCount + 1
		sum = sum + row.a
	end
	qu:start()
end)

TestFramework:RegisterTest("[Prepared Query] abort query correctly", function(test)
	local db = TestFramework:ConnectToDatabase()
	local qu = db:prepare("SELECT SLEEP(1)") //This should block for a bit
	qu:start()
	local qu2 = db:prepare("SELECT 1")
	qu2:start()
	function qu2:onAborted()
		test:Complete()
	end
	test:shouldBeEqual(qu2:abort(), true)
	test:shouldBeEqual(qu:abort(), false)
end)

TestFramework:RegisterTest("[Prepared Query] Work with stored procedure correctly", function(test)
	local db = TestFramework:ConnectToDatabase()
	//db:setMultiStatements(false)
	TestFramework:RunQuery(db, "DROP PROCEDURE IF EXISTS test_procedure")
	TestFramework:RunQuery(db, [[
		CREATE PROCEDURE test_procedure (IN param INT)
		BEGIN
			SELECT param as a;
			SELECT 999 as b;
		END
	]])
	local qu = db:prepare("CALL test_procedure(?)")
	qu:setNumber(1, 5)
	qu:start()
	qu:wait()
	test:shouldBeEqual(qu:hasMoreResults(), true)
	local first = qu:getData()
	test:shouldBeEqual(first[1].a, 5)
	qu:getNextResults()
	test:shouldBeEqual(qu:hasMoreResults(), true)
	local second = qu:getData()
	test:shouldBeEqual(second[1].b, 999)
	qu:getNextResults()
	test:shouldBeEqual(qu:hasMoreResults(), true) //For some reason, stored procedures add extra result sets
	qu:getNextResults()
	test:shouldBeEqual(qu:hasMoreResults(), false)
	test:Complete()
end)