You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
8.7 KiB
282 lines
8.7 KiB
// Copyright (c) 2009 Sun Microsystems, Inc.
|
|
//
|
|
// This program is free software; you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License version 2 as published by
|
|
// the Free Software Foundation
|
|
//
|
|
// There are special exceptions to the terms and conditions of the GPL
|
|
// as it is applied to this software. View the full text of the
|
|
// exception in file EXCEPTIONS in the directory of this software
|
|
// distribution.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, write to the Free Software
|
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Data;
|
|
using MySql.Data.MySqlClient.Properties;
|
|
using MySql.Data.Types;
|
|
using System.Diagnostics;
|
|
|
|
namespace MySql.Data.MySqlClient
|
|
{
|
|
internal class ResultSet
|
|
{
|
|
private Driver driver;
|
|
private bool hasRows;
|
|
private bool[] uaFieldsUsed;
|
|
private MySqlField[] fields;
|
|
private IMySqlValue[] values;
|
|
private Hashtable fieldHashCS;
|
|
private Hashtable fieldHashCI;
|
|
private int rowIndex;
|
|
private bool readDone;
|
|
private bool isSequential;
|
|
private int seqIndex;
|
|
private bool isOutputParameters;
|
|
private int affectedRows;
|
|
private int insertedId;
|
|
private int statementId;
|
|
private int totalRows;
|
|
private int skippedRows;
|
|
|
|
public ResultSet(int affectedRows, int insertedId)
|
|
{
|
|
this.affectedRows = affectedRows;
|
|
this.insertedId = insertedId;
|
|
readDone = true;
|
|
}
|
|
|
|
public ResultSet(Driver d, int statementId, int numCols)
|
|
{
|
|
affectedRows = -1;
|
|
insertedId = -1;
|
|
driver = d;
|
|
this.statementId = statementId;
|
|
rowIndex = -1;
|
|
LoadColumns(numCols);
|
|
isOutputParameters = driver.HasStatus(ServerStatusFlags.OutputParameters);
|
|
hasRows = GetNextRow();
|
|
readDone = !hasRows;
|
|
}
|
|
|
|
#region Properties
|
|
|
|
public bool HasRows
|
|
{
|
|
get { return hasRows; }
|
|
}
|
|
|
|
public int Size
|
|
{
|
|
get { return fields == null ? 0 : fields.Length; }
|
|
}
|
|
|
|
public MySqlField[] Fields
|
|
{
|
|
get { return fields; }
|
|
}
|
|
|
|
public IMySqlValue[] Values
|
|
{
|
|
get { return values; }
|
|
}
|
|
|
|
public bool IsOutputParameters
|
|
{
|
|
get { return isOutputParameters; }
|
|
set { isOutputParameters = value; }
|
|
}
|
|
|
|
public int AffectedRows
|
|
{
|
|
get { return affectedRows; }
|
|
}
|
|
|
|
public int InsertedId
|
|
{
|
|
get { return insertedId; }
|
|
}
|
|
|
|
public int TotalRows
|
|
{
|
|
get { return totalRows; }
|
|
}
|
|
|
|
public int SkippedRows
|
|
{
|
|
get { return skippedRows; }
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// return the ordinal for the given column name
|
|
/// </summary>
|
|
/// <param name="name"></param>
|
|
/// <returns></returns>
|
|
public int GetOrdinal(string name)
|
|
{
|
|
// first we try a quick hash lookup
|
|
object ordinal = fieldHashCS[name];
|
|
if (ordinal != null)
|
|
return (int)ordinal;
|
|
|
|
// ok that failed so we use our CI hash
|
|
ordinal = fieldHashCI[name];
|
|
if (ordinal != null)
|
|
return (int)ordinal;
|
|
|
|
// Throw an exception if the ordinal cannot be found.
|
|
throw new IndexOutOfRangeException(
|
|
String.Format(Resources.CouldNotFindColumnName, name));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieve the value as the given column index
|
|
/// </summary>
|
|
/// <param name="index">The column value to retrieve</param>
|
|
/// <returns>The value as the given column</returns>
|
|
public IMySqlValue this[int index]
|
|
{
|
|
get
|
|
{
|
|
if (rowIndex < 0)
|
|
throw new MySqlException(Resources.AttemptToAccessBeforeRead);
|
|
|
|
// keep count of how many columns we have left to access
|
|
uaFieldsUsed[index] = true;
|
|
|
|
if (isSequential && index != seqIndex)
|
|
{
|
|
if (index < seqIndex)
|
|
throw new MySqlException(Resources.ReadingPriorColumnUsingSeqAccess);
|
|
while (seqIndex < (index - 1))
|
|
driver.SkipColumnValue(values[++seqIndex]);
|
|
values[index] = driver.ReadColumnValue(index, fields[index], values[index]);
|
|
seqIndex = index;
|
|
}
|
|
|
|
return values[index];
|
|
}
|
|
}
|
|
|
|
private bool GetNextRow()
|
|
{
|
|
bool fetched = driver.FetchDataRow(statementId, Size);
|
|
if (fetched)
|
|
totalRows++;
|
|
return fetched;
|
|
}
|
|
|
|
|
|
public bool NextRow(CommandBehavior behavior)
|
|
{
|
|
if (readDone) return false;
|
|
|
|
if ((behavior & CommandBehavior.SingleRow) != 0 && rowIndex == 0)
|
|
return false;
|
|
|
|
isSequential = (behavior & CommandBehavior.SequentialAccess) != 0;
|
|
seqIndex = -1;
|
|
|
|
// if we are at row index >= 0 then we need to fetch the data row and load it
|
|
if (rowIndex >= 0)
|
|
{
|
|
bool fetched = false;
|
|
try
|
|
{
|
|
fetched = GetNextRow();
|
|
}
|
|
catch (MySqlException ex)
|
|
{
|
|
if (ex.Number == 1317) fetched = false;
|
|
}
|
|
|
|
if (!fetched)
|
|
{
|
|
readDone = true;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (!isSequential) ReadColumnData(false);
|
|
rowIndex++;
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Closes the current resultset, dumping any data still on the wire
|
|
/// </summary>
|
|
public void Close()
|
|
{
|
|
if (readDone) return;
|
|
|
|
// if we have rows but the user didn't read the first one then mark it as skipped
|
|
if (HasRows && rowIndex == -1)
|
|
skippedRows++;
|
|
while (driver.SkipDataRow())
|
|
{
|
|
totalRows++;
|
|
skippedRows++;
|
|
}
|
|
readDone = true;
|
|
}
|
|
|
|
public bool FieldRead(int index)
|
|
{
|
|
Debug.Assert(Size > index);
|
|
return uaFieldsUsed[index];
|
|
}
|
|
|
|
public void SetValueObject(int i, IMySqlValue valueObject)
|
|
{
|
|
Debug.Assert(values != null);
|
|
Debug.Assert(i < values.Length);
|
|
values[i] = valueObject;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Loads the column metadata for the current resultset
|
|
/// </summary>
|
|
private void LoadColumns(int numCols)
|
|
{
|
|
fields = driver.GetColumns(numCols);
|
|
|
|
values = new IMySqlValue[numCols];
|
|
uaFieldsUsed = new bool[numCols];
|
|
fieldHashCS = new Hashtable();
|
|
fieldHashCI = new Hashtable(StringComparer.InvariantCultureIgnoreCase);
|
|
|
|
for (int i = 0; i < fields.Length; i++)
|
|
{
|
|
string columnName = fields[i].ColumnName;
|
|
if (!fieldHashCS.ContainsKey(columnName))
|
|
fieldHashCS.Add(columnName, i);
|
|
if (!fieldHashCI.ContainsKey(columnName))
|
|
fieldHashCI.Add(columnName, i);
|
|
values[i] = fields[i].GetValueObject();
|
|
}
|
|
}
|
|
|
|
private void ReadColumnData(bool outputParms)
|
|
{
|
|
for (int i = 0; i < Size; i++)
|
|
values[i] = driver.ReadColumnValue(i, fields[i], values[i]);
|
|
if (outputParms)
|
|
{
|
|
bool rowExists = driver.FetchDataRow(statementId, fields.Length);
|
|
rowIndex = 0;
|
|
if (rowExists)
|
|
throw new MySqlException(Resources.MoreThanOneOPRow);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|