/*
Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.

The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.

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; version 2 of the License.

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 St, Fifth Floor, Boston, MA 02110-1301  USA
*/



#include <sstream>
#include <math.h>
#include <stdio.h>

#include "mysql_util.h"
#include "mysql_art_resultset.h"
#include "mysql_art_rset_metadata.h"
#include "mysql_debug.h"

#include <cppconn/exception.h>


namespace sql
{
namespace mysql
{

/* {{{ MyVal::MyVal() -I- */
MyVal::MyVal(const sql::SQLString & s)
  : val_type(typeString)
{
	val.str = new sql::SQLString(s);
}

/* }}} */


/* {{{ MyVal::MyVal() -I- */
MyVal::MyVal(const char * const s)
  : val_type(typeString)
{
	// Init it clearly
	val.str = new sql::SQLString(s);
}
/* }}} */


/* {{{ MyVal::getString() -I- */
sql::SQLString
MyVal::getString()
{
	switch (val_type) {
		case typeString:
			return *val.str;
		case typeDouble:
		{
			char buf[31];
			size_t len = snprintf(buf, sizeof(buf) - 1, "%14.14Lf", val.dval);
			return sql::SQLString(buf, len);
		}
		case typeInt:
		{
			char buf[20];
			size_t len = snprintf(buf, sizeof(buf) - 1, "%lld", (long long int)val.lval);
			return sql::SQLString(buf, len);
		}
		case typeUInt:
		{
			char buf[20];
			size_t len = snprintf(buf, sizeof(buf) - 1, "%llu", (long long unsigned int)val.ulval);
			return sql::SQLString(buf, len);
		}
		case typeBool:
		{
			char buf[3];
			size_t len = snprintf(buf, sizeof(buf) - 1, "%d", val.bval);
			return sql::SQLString(buf, len);
		}
		case typePtr:
			return "";
	}
	throw std::runtime_error("impossible");
}
/* }}} */


/* {{{ MyVal::getDouble() -I- */
long double
MyVal::getDouble()
{
	switch (val_type) {
		case typeString:
			return sql::mysql::util::strtold(val.str->c_str(), NULL);
		case typePtr:
			return .0;
		case typeDouble:
			return val.dval;
		case typeInt:
			return static_cast<long double>(val.lval);
		case typeUInt:
			return static_cast<long double>(val.ulval);
		case typeBool:
			return val.bval ? 1.0 : 0.0;

	}
	throw std::runtime_error("impossible");
}
/* }}} */


/* {{{ MyVal::getInt64() -I- */
int64_t
MyVal::getInt64()
{
	switch (val_type) {
		case typeString:
			return strtoll(val.str->c_str(), NULL, 10);
		case typePtr:
			return 0;
		case typeDouble:
			return static_cast<int64_t>(val.dval);
		case typeBool:
			return val.bval ? 1LL : 0LL;
		case typeInt:
		case typeUInt:
			return val.lval;

	}
	throw std::runtime_error("impossible");
}
/* }}} */


/* {{{ MyVal::getUInt64() -I- */
uint64_t
MyVal::getUInt64()
{
	switch (val_type) {
		case typeString:
			return strtoull(val.str->c_str(), NULL, 10);
		case typePtr:
			return 0;
		case typeDouble:
			return static_cast<uint64_t>(val.dval);
		case typeBool:
			return val.bval ? UL64(1) : UL64(0);
		case typeInt:
		case typeUInt:
			return val.ulval;

	}
	throw std::runtime_error("impossible");
}
/* }}} */


/* {{{ MyVal::getBool() -I- */
bool
MyVal::getBool()
{
	static const double delta= 0.000001;

	switch (val_type) {
		case typeString:
			return getInt64() != 0;
		case typeDouble:
			return !(val.dval < delta && val.dval > -delta);
		case typeInt:
		case typeUInt:
			return val.lval != 0;
		case typeBool:
			return val.bval;
		case typePtr:
			return val.pval != NULL;

	}
	throw std::runtime_error("impossible");
}
/* }}} */


/* {{{ MySQL_ArtResultSet::MySQL_ArtResultSet() -I- */
MySQL_ArtResultSet::MySQL_ArtResultSet(const StringList& fn, rset_t * const rs, boost::shared_ptr< MySQL_DebugLogger > & l)
  : num_fields(static_cast<int>(fn.size())), rset(rs), current_record(rset->begin()),
    started(false), field_index_to_name_map(new sql::SQLString[num_fields]),
	num_rows(rset->size()), row_position(0), is_closed(false), logger(l)
{
	CPP_ENTER("MySQL_ArtResultSet::MySQL_ArtResultSet");
	CPP_INFO_FMT("metadata.size=%d resultset.size=%d", fn.size(), rset->size());

//	field_index_to_name_map = new sql::SQLString[num_fields];

	unsigned int idx = 0;
	for (StringList::const_iterator it = fn.begin(), e = fn.end(); it != e; ++it, ++idx) {
		boost::scoped_array< char > upstring(sql::mysql::util::utf8_strup(it->c_str(), 0));
		field_name_to_index_map[sql::SQLString(upstring.get())] = idx;
		field_index_to_name_map[idx] = upstring.get();
	}

	meta.reset(new MySQL_ArtResultSetMetaData(this, logger));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::~MySQL_ArtResultSet() -I- */
MySQL_ArtResultSet::~MySQL_ArtResultSet()
{
	CPP_ENTER("MySQL_ArtResultSet::~MySQL_ArtResultSet");
	if (!isClosed()) {
		close();
	}
}
/* }}} */


/* {{{ MySQL_ArtResultSet::seek() -I- */
void MySQL_ArtResultSet::seek()
{
	CPP_ENTER("MySQL_ArtResultSet::seek");
	current_record = rset->begin();
	/* i should be signed, or when row_position is 0 `i` will overflow */
	for (long long i = row_position - 1; i > 0; --i) {
		++current_record;
	}
}
/* }}} */


/* {{{ MySQL_ArtResultSet::isBeforeFirstOrAfterLast() -I- */
bool
MySQL_ArtResultSet::isBeforeFirstOrAfterLast() const
{
	CPP_ENTER("MySQL_ArtResultSet::isBeforeFirstOrAfterLast");
	checkValid();
	return (row_position == 0) || (row_position == num_rows + 1);
}
/* }}} */


/* {{{ MySQL_ArtResultSet::absolute() -I- */
bool
MySQL_ArtResultSet::absolute(const int row)
{
	CPP_ENTER("MySQL_ArtResultSet::absolute");
	checkValid();
	if (row > 0) {
		if (row > (int) num_rows) {
			afterLast();
		} else {
			row_position = row;
			seek();
			return true;
		}
	} else if (row < 0) {
		if ((-row) > (int) num_rows) {
			beforeFirst();
		} else {
			row_position = num_rows - (-row)  + 1;
			seek();
			return true;
		}
	} else {
		/* According to the JDBC book, absolute(0) means before the result set */
		beforeFirst();
	}
	return (row_position > 0 && row_position < (num_rows + 1));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::afterLast() -I- */
void
MySQL_ArtResultSet::afterLast()
{
	CPP_ENTER("MySQL_ArtResultSet::afterLast");
	checkValid();
	row_position = num_rows + 1;
	seek();
}
/* }}} */


/* {{{ MySQL_ArtResultSet::beforeFirst() -I- */
void
MySQL_ArtResultSet::beforeFirst()
{
	CPP_ENTER("MySQL_ArtResultSet::beforeFirst");
	checkValid();
	row_position = 0;
	seek();
}
/* }}} */


/* {{{ MySQL_ArtResultSet::cancelRowUpdates() -U- */
void
MySQL_ArtResultSet::cancelRowUpdates()
{
	CPP_ENTER("MySQL_ArtResultSet::cancelRowUpdates");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::cancelRowUpdates()");
}
/* }}} */


/* {{{ MySQL_ArtResultSet::checkValid() -I- */
void
MySQL_ArtResultSet::checkValid() const
{
	CPP_ENTER("MySQL_ArtResultSet::checkValid");
	CPP_INFO_FMT("this=%p", this);
	if (isClosed()) {
		throw sql::InvalidInstanceException("ResultSet has been closed");
	}
}
/* }}} */


/* {{{ MySQL_ArtResultSet::clearWarnings() -U- */
void
MySQL_ArtResultSet::clearWarnings()
{
	CPP_ENTER("MySQL_ArtResultSet::clearWarnings");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::clearWarnings()");
}
/* }}} */


/* {{{ MySQL_ArtResultSet::close() -I- */
void
MySQL_ArtResultSet::close()
{
	CPP_ENTER("MySQL_ArtResultSet::close");
	checkValid();
//	delete [] field_index_to_name_map;
	is_closed = true;
}
/* }}} */


/* {{{ MySQL_ArtResultSet::findColumn() -I- */
uint32_t
MySQL_ArtResultSet::findColumn(const sql::SQLString& columnLabel) const
{
	CPP_ENTER("MySQL_ArtResultSet::columnLabel");
	checkValid();

	boost::scoped_array< char > upstring(sql::mysql::util::utf8_strup(columnLabel.c_str(), 0));

	FieldNameIndexMap::const_iterator iter = field_name_to_index_map.find(upstring.get());

	if (iter == field_name_to_index_map.end()) {
		return 0;
	}
	/* findColumn returns 1-based indexes */
	return iter->second + 1;
}
/* }}} */


/* {{{ MySQL_ArtResultSet::first() -I- */
bool
MySQL_ArtResultSet::first()
{
	CPP_ENTER("MySQL_ArtResultSet::first");
	checkValid();
	if (num_rows) {
		row_position = 1;
		seek();
	}
	return num_rows != 0;
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getBlob() -I- */
std::istream *
MySQL_ArtResultSet::getBlob(const uint32_t columnIndex) const
{
	CPP_ENTER("MySQL_ArtResultSet::getBlob(int)");

	/* isBeforeFirst checks for validity */
	if (isBeforeFirstOrAfterLast()) {
		throw sql::InvalidArgumentException("MySQL_ArtResultSet::getString: can't fetch because not on result set");
	}
	return new std::istringstream(getString(columnIndex));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getBlob() -I- */
std::istream *
MySQL_ArtResultSet::getBlob(const sql::SQLString& columnLabel) const
{
	CPP_ENTER("MySQL_ArtResultSet::getBlob(string)");
	return new std::istringstream(getString(columnLabel));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getBoolean() -I- */
bool
MySQL_ArtResultSet::getBoolean(const uint32_t columnIndex) const
{
	CPP_ENTER("MySQL_ArtResultSet::getBoolean(int)");

	/* isBeforeFirst checks for validity */
	if (isBeforeFirstOrAfterLast()) {
		throw sql::InvalidArgumentException("MySQL_ArtResultSet::getString: can't fetch because not on result set");
	}
	return getInt(columnIndex) != 0;
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getBoolean() -I- */
bool
MySQL_ArtResultSet::getBoolean(const sql::SQLString& columnLabel) const
{
	CPP_ENTER("MySQL_ArtResultSet::getBoolean(string)");
	return getInt(columnLabel) != 0;
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getConcurrency() -U- */
int
MySQL_ArtResultSet::getConcurrency()
{
	CPP_ENTER("MySQL_ArtResultSet::getConcurrency");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::getConcurrency()");
	return 0; // This will shut up compilers
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getCursorName() -U- */
SQLString
MySQL_ArtResultSet::getCursorName()
{
	CPP_ENTER("MySQL_ArtResultSet::getCursorName");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::getCursorName()");
	return 0; // This will shut up compilers
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getDouble() -I- */
long double
MySQL_ArtResultSet::getDouble(uint32_t columnIndex) const
{
	CPP_ENTER("MySQL_ArtResultSet::getDouble(int)");

	/* isBeforeFirst checks for validity */
	if (isBeforeFirstOrAfterLast()) {
		throw sql::InvalidArgumentException("MySQL_ArtResultSet::getDouble: can't fetch because not on result set");
	}

	if (columnIndex > num_fields || columnIndex == 0) {
		throw sql::InvalidArgumentException("MySQL_ArtResultSet::getDouble: invalid value of 'columnIndex'");
	}

	return (*current_record)[columnIndex - 1].getDouble();
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getDouble() -I- */
long double
MySQL_ArtResultSet::getDouble(const sql::SQLString& columnLabel) const
{
	CPP_ENTER("MySQL_ArtResultSet::getDouble(string)");
	return getDouble(findColumn(columnLabel));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getFetchDirection() -U- */
int
MySQL_ArtResultSet::getFetchDirection()
{
	CPP_ENTER("MySQL_ArtResultSet::getFetchDirection");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::getFetchDirection()");
	return 0; // This will shut up compilers
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getFetchSize() -U- */
size_t
MySQL_ArtResultSet::getFetchSize()
{
	CPP_ENTER("MySQL_ArtResultSet::getFetchSize");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::getFetchSize()");
	return 0; // This will shut up compilers
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getHoldability() -U- */
int
MySQL_ArtResultSet::getHoldability()
{
	CPP_ENTER("MySQL_ArtResultSet::getHoldability");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::getHoldability()");
	return 0; // This will shut up compilers
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getInt() -I- */
int32_t
MySQL_ArtResultSet::getInt(uint32_t columnIndex) const
{
	CPP_ENTER("MySQL_ArtResultSet::getInt(int)");
	return static_cast<int32_t>(getInt64(columnIndex));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getInt() -I- */
int32_t
MySQL_ArtResultSet::getInt(const sql::SQLString& columnLabel) const
{
	CPP_ENTER("MySQL_ArtResultSet::getInt(string)");
	return getInt(findColumn(columnLabel));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getUInt() -I- */
uint32_t
MySQL_ArtResultSet::getUInt(uint32_t columnIndex) const
{
	CPP_ENTER("MySQL_ArtResultSet::getUInt(int)");
	return static_cast<uint32_t>(getUInt64(columnIndex));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getUInt() -I- */
uint32_t
MySQL_ArtResultSet::getUInt(const sql::SQLString& columnLabel) const
{
	CPP_ENTER("MySQL_ArtResultSet::getUInt(string)");
	return getUInt(findColumn(columnLabel));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getInt64() -I- */
int64_t
MySQL_ArtResultSet::getInt64(const uint32_t columnIndex) const
{
	CPP_ENTER("MySQL_ArtResultSet::getInt64(int)");

	/* isBeforeFirst checks for validity */
	if (isBeforeFirstOrAfterLast()) {
		throw sql::InvalidArgumentException("MySQL_ArtResultSet::getInt64: can't fetch because not on result set");
	}

	if (columnIndex > num_fields || columnIndex == 0) {
		throw sql::InvalidArgumentException("MySQL_ArtResultSet::getInt64: invalid value of 'columnIndex'");
	}

	return (*current_record)[columnIndex - 1].getInt64();
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getInt64() -I- */
int64_t
MySQL_ArtResultSet::getInt64(const sql::SQLString& columnLabel) const
{
	CPP_ENTER("MySQL_ArtResultSet::getInt64(string)");
	return getInt64(findColumn(columnLabel));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getUInt64() -I- */
uint64_t
MySQL_ArtResultSet::getUInt64(const uint32_t columnIndex) const
{
	CPP_ENTER("MySQL_ArtResultSet::getUInt64(int)");

	/* isBeforeFirst checks for validity */
	if (isBeforeFirstOrAfterLast()) {
		throw sql::InvalidArgumentException("MySQL_ArtResultSet::getUInt64: can't fetch because not on result set");
	}

	if (columnIndex > num_fields || columnIndex == 0) {
		throw sql::InvalidArgumentException("MySQL_ArtResultSet::getUInt64: invalid value of 'columnIndex'");
	}

	return (*current_record)[columnIndex - 1].getUInt64();
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getUInt64() -I- */
uint64_t
MySQL_ArtResultSet::getUInt64(const sql::SQLString& columnLabel) const
{
	CPP_ENTER("MySQL_ArtResultSet::getUInt64(string)");
	return getUInt64(findColumn(columnLabel));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getMetaData() -I- */
sql::ResultSetMetaData *
MySQL_ArtResultSet::getMetaData() const
{
	CPP_ENTER("MySQL_ArtResultSet::getMetaData");
	checkValid();
	return meta.get();
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getRow() -I- */
size_t
MySQL_ArtResultSet::getRow() const
{
	CPP_ENTER("MySQL_ArtResultSet::getRow");
	checkValid();
	/* row_position is 0 based */
	return static_cast<size_t> (row_position);
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getRowId() -U- */
sql::RowID *
MySQL_ArtResultSet::getRowId(uint32_t)
{
	CPP_ENTER("MySQL_ArtResultSet::getRowId");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::getRowId()");
	return NULL; // This will shut up compilers
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getRowId() -U- */
sql::RowID *
MySQL_ArtResultSet::getRowId(const sql::SQLString &)
{
	CPP_ENTER("MySQL_ArtResultSet::getRowId");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::getRowId()");
	return NULL; // This will shut up compilers
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getStatement() -I- */
const Statement *
MySQL_ArtResultSet::getStatement() const
{
	CPP_ENTER("MySQL_ArtResultSet::getStatement");
	checkValid();
	return NULL; /* This is a constructed result set - no statement -> NULL */
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getString() -I- */
SQLString
MySQL_ArtResultSet::getString(uint32_t columnIndex) const
{
	CPP_ENTER("MySQL_ArtResultSet::getString(int)");
	CPP_INFO_FMT("this=%p column=%u", this, columnIndex);

	/* isBeforeFirst checks for validity */
	if (isBeforeFirstOrAfterLast()) {
		throw sql::InvalidArgumentException("MySQL_ArtResultSet::getString: can't fetch because not on result set");
	}

	if (columnIndex > num_fields || columnIndex == 0) {
		throw sql::InvalidArgumentException("MySQL_ArtResultSet::getString: invalid value of 'columnIndex'");
	}

	return (*current_record)[columnIndex - 1].getString();
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getString() -I- */
SQLString
MySQL_ArtResultSet::getString(const sql::SQLString& columnLabel) const
{
	CPP_ENTER("MySQL_ArtResultSet::getString(string)");
	return getString(findColumn(columnLabel));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getType() -I- */
sql::ResultSet::enum_type
MySQL_ArtResultSet::getType() const
{
	CPP_ENTER("MySQL_ArtResultSet::getType");
	checkValid();
	return sql::ResultSet::TYPE_SCROLL_INSENSITIVE;
}
/* }}} */


/* {{{ MySQL_ArtResultSet::getWarnings() -U- */
void
MySQL_ArtResultSet::getWarnings()
{
	CPP_ENTER("MySQL_ArtResultSet::getWarnings");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::getWarnings()");
}
/* }}} */


/* {{{ MySQL_ArtResultSet::insertRow() -U- */
void
MySQL_ArtResultSet::insertRow()
{
	CPP_ENTER("MySQL_ArtResultSet::insertRow");
	checkValid();
	 /* TODO - We don't support inserting anyway */
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::insertRow()");
}
/* }}} */


/* {{{ MySQL_ArtResultSet::isAfterLast() -I- */
bool
MySQL_ArtResultSet::isAfterLast() const
{
	CPP_ENTER("MySQL_ArtResultSet::isAfterLast");
	checkValid();
	return (row_position == num_rows + 1);
}
/* }}} */


/* {{{ MySQL_ArtResultSet::isBeforeFirst() -I- */
bool
MySQL_ArtResultSet::isBeforeFirst() const
{
	CPP_ENTER("MySQL_ArtResultSet::isBeforeFirst");
	checkValid();
	return (row_position == 0);
}
/* }}} */


/* {{{ MySQL_ArtResultSet::isClosed() -I- */
bool
MySQL_ArtResultSet::isClosed() const
{
	CPP_ENTER("MySQL_ArtResultSet::isClosed");
	return is_closed;
}
/* }}} */


/* {{{ MySQL_ArtResultSet::isFirst() -I- */
bool
MySQL_ArtResultSet::isFirst() const
{
	CPP_ENTER("MySQL_ArtResultSet::isFirst");
	checkValid();
	/* OR current_record == rs.begin() */
	return (row_position == 1);
}
/* }}} */


/* {{{ MySQL_ArtResultSet::isLast() -I- */
bool
MySQL_ArtResultSet::isLast() const
{
	CPP_ENTER("MySQL_ArtResultSet::isLast");
	checkValid();
	/* OR current_record == rs.end() */
	return (row_position == num_rows);
}
/* }}} */


/* {{{ MySQL_ArtResultSet::isNull() -I- */
bool
MySQL_ArtResultSet::isNull(const uint32_t columnIndex) const
{
	CPP_ENTER("MySQL_ArtResultSet::isNull(int)");
	checkValid();
	if (columnIndex > num_fields || columnIndex == 0) {
		throw sql::InvalidArgumentException("MySQL_ArtResultSet::isNull: invalid value of 'columnIndex'");
	}
	/* isBeforeFirst checks for validity */
	if (isBeforeFirstOrAfterLast()) {
		throw sql::InvalidArgumentException("MySQL_ArtResultSet::getString: can't fetch because not on result set");
	}
	return false;
}
/* }}} */


/* {{{ MySQL_ArtResultSet::isNull() -I- */
bool
MySQL_ArtResultSet::isNull(const sql::SQLString& columnLabel) const
{
	CPP_ENTER("MySQL_ArtResultSet::isNull(string)");
	return isNull(findColumn(columnLabel));
}
/* }}} */


/* {{{ MySQL_ArtResultSet::last() -I- */
bool
MySQL_ArtResultSet::last()
{
	CPP_ENTER("MySQL_ArtResultSet::last");
	checkValid();
	if (num_rows) {
		row_position = num_rows;
		seek();
	}
	return num_rows != 0;
}
/* }}} */


/* {{{ MySQL_ArtResultSet::moveToCurrentRow() -U- */
void
MySQL_ArtResultSet::moveToCurrentRow()
{
	CPP_ENTER("MySQL_ArtResultSet::moveToCurrentRow");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::moveToCurrentRow()");
}
/* }}} */


/* {{{ MySQL_ArtResultSet::moveToInsertRow() -U- */
void
MySQL_ArtResultSet::moveToInsertRow()
{
	CPP_ENTER("MySQL_ArtResultSet::moveToInsertRow");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::moveToInsertRow()");
}
/* }}} */


/* {{{ MySQL_ArtResultSet::next() -I- */
bool
MySQL_ArtResultSet::next()
{
	CPP_ENTER("MySQL_ArtResultSet::next");
	checkValid();
	bool ret = false;
	if (isLast()) {
		afterLast();
	} else if (row_position == 0) {
		first();
		ret = true;
	} else if (row_position > 0 && row_position < num_rows) {
		++current_record;
		++row_position;
		ret = true;
	}
	CPP_INFO_FMT("row_position=%llu num_rows=%llu", row_position, num_rows);
	return ret;
}
/* }}} */


/* {{{ MySQL_ArtResultSet::previous() -I- */
bool
MySQL_ArtResultSet::previous()
{
	CPP_ENTER("MySQL_ArtResultSet::previous");

	/* isBeforeFirst checks for validity */
	if (isBeforeFirst()) {
		return false;
	} else if (isFirst()) {
		beforeFirst();
		return false;
	} else if (row_position > 1) {
		--row_position;
		--current_record;
		return true;
	}
	throw sql::SQLException("Impossible");
}
/* }}} */


/* {{{ MySQL_ArtResultSet::refreshRow() -U- */
void
MySQL_ArtResultSet::refreshRow()
{
	CPP_ENTER("MySQL_ArtResultSet::refreshRow");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ResultSet::refreshRow()");
}
/* }}} */


/* {{{ MySQL_ArtResultSet::relative() -I- */
bool
MySQL_ArtResultSet::relative(const int rows)
{
	CPP_ENTER("MySQL_ArtResultSet::relative");
	checkValid();
	if (rows != 0) {
		if ((row_position + rows) > num_rows || (row_position + rows) < 1) {
			rows > 0? afterLast(): beforeFirst(); /* after last or before first */
		} else {
			row_position += rows;
			seek();
		}
	}

	return (row_position > 0 && row_position <= num_rows);
}
/* }}} */


/* {{{ MySQL_ArtResultSet::rowDeleted() -U- */
bool
MySQL_ArtResultSet::rowDeleted()
{
	CPP_ENTER("MySQL_ArtResultSet::rowDeleted");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::rowDeleted()");
	return false; // This will shut up compilers
}
/* }}} */


/* {{{ MySQL_ArtResultSet::rowInserted() -U- */
bool
MySQL_ArtResultSet::rowInserted()
{
	CPP_ENTER("MySQL_ArtResultSet::rowInserted");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::rowInserted()");
	return false; // This will shut up compilers
}
/* }}} */


/* {{{ MySQL_ArtResultSet::rowUpdated() -U- */
bool
MySQL_ArtResultSet::rowUpdated()
{
	CPP_ENTER("MySQL_ArtResultSet::rowUpdated");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ArtResultSet::rowUpdated()");
	return false; // This will shut up compilers
}
/* }}} */


/* {{{ MySQL_ArtResultSet::rowsCount() -I- */
size_t
MySQL_ArtResultSet::rowsCount() const
{
	CPP_ENTER("MySQL_ArtResultSet::rowsCount");
	checkValid();
	return static_cast<size_t>( num_rows );
}
/* }}} */


/* {{{ MySQL_ArtResultSet::setFetchSize() -U- */
void
MySQL_ArtResultSet::setFetchSize(size_t /* rows */)
{
	CPP_ENTER("MySQL_ArtResultSet::setFetchSize");
	checkValid();
	throw sql::MethodNotImplementedException("MySQL_ResultSet::rowDeleted()");
}
/* }}} */


/* {{{ MySQL_ArtResultSet::wasNull() -I- */
bool
MySQL_ArtResultSet::wasNull() const
{
	CPP_ENTER("MySQL_ArtResultSet::wasNull");
	checkValid();
	/* isBeforeFirst checks for validity */
	if (isBeforeFirstOrAfterLast()) {
		throw sql::InvalidArgumentException("MySQL_ResultSet::wasNull: can't fetch because not on result set");
	}
	return false;
}
/* }}} */

} /* namespace mysql */
} /* namespace sql */


/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */
