// created on 12/6/2002 at 20:29
// Npgsql.NpgsqlRowDescription.cs
//
// Author:
// Francisco Jr. (fxjrlists@yahoo.com.br)
//
// Copyright (C) 2002 The Npgsql Development Team
// npgsql-general@gborg.postgresql.org
// http://gborg.postgresql.org/project/npgsql/projdisplay.php
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; 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.IO;
using System.Text;
using System.Net;
using NpgsqlTypes;
namespace Npgsql
{
///
/// This struct represents the internal data of the RowDescription message.
///
///
// [FIXME] Is this name OK? Does it represent well the struct intent?
// Should it be a struct or a class?
internal struct NpgsqlRowDescriptionFieldData
{
public String name; // Protocol 2/3
public Int32 table_oid; // Protocol 3
public Int16 column_attribute_number; // Protocol 3
public Int32 type_oid; // Protocol 2/3
public Int16 type_size; // Protocol 2/3
public Int32 type_modifier; // Protocol 2/3
public FormatCode format_code; // Protocol 3. 0 text, 1 binary
public NpgsqlBackendTypeInfo type_info; // everything we know about this field type
}
///
/// This class represents a RowDescription message sent from
/// the PostgreSQL.
///
///
internal sealed class NpgsqlRowDescription
{
// Logging related values
private static readonly String CLASSNAME = "NpgsqlRowDescription";
private NpgsqlRowDescriptionFieldData[] fields_data;
private string[] fields_index;
private ProtocolVersion protocol_version;
public NpgsqlRowDescription(ProtocolVersion protocolVersion)
{
protocol_version = protocolVersion;
}
public void ReadFromStream(Stream input_stream, Encoding encoding, NpgsqlBackendTypeMapping type_mapping)
{
switch (protocol_version)
{
case ProtocolVersion.Version2 :
ReadFromStream_Ver_2(input_stream, encoding, type_mapping);
break;
case ProtocolVersion.Version3 :
ReadFromStream_Ver_3(input_stream, encoding, type_mapping);
break;
}
}
private void ReadFromStream_Ver_2(Stream input_stream, Encoding encoding, NpgsqlBackendTypeMapping type_mapping)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");
Byte[] input_buffer = new Byte[10]; // Max read will be 4 + 2 + 4
// Read the number of fields.
input_stream.Read(input_buffer, 0, 2);
Int16 num_fields = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(input_buffer, 0));
// Temporary FieldData object to get data from stream and put in array.
NpgsqlRowDescriptionFieldData fd;
fields_data = new NpgsqlRowDescriptionFieldData[num_fields];
fields_index = new string[num_fields];
// Now, iterate through each field getting its data.
for (Int16 i = 0; i < num_fields; i++)
{
fd = new NpgsqlRowDescriptionFieldData();
// Set field name.
fd.name = PGUtil.ReadString(input_stream, encoding);
// Read type_oid(Int32), type_size(Int16), type_modifier(Int32)
input_stream.Read(input_buffer, 0, 4 + 2 + 4);
fd.type_oid = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 0));
fd.type_info = type_mapping[fd.type_oid];
fd.type_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt16(input_buffer, 4));
fd.type_modifier = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(input_buffer, 6));
// Add field data to array.
fields_data[i] = fd;
fields_index[i] = fd.name;
}
}
private void ReadFromStream_Ver_3(Stream input_stream, Encoding encoding, NpgsqlBackendTypeMapping type_mapping)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");
Byte[] input_buffer = new Byte[4]; // Max read will be 4 + 2 + 4 + 2 + 4 + 2
// Read the length of message.
// [TODO] Any use for now?
PGUtil.ReadInt32(input_stream, input_buffer);
Int16 num_fields = PGUtil.ReadInt16(input_stream, input_buffer);
// Temporary FieldData object to get data from stream and put in array.
NpgsqlRowDescriptionFieldData fd;
fields_data = new NpgsqlRowDescriptionFieldData[num_fields];
fields_index = new string[num_fields];
for (Int16 i = 0; i < num_fields; i++)
{
fd = new NpgsqlRowDescriptionFieldData();
fd.name = PGUtil.ReadString(input_stream, encoding);
fd.table_oid = PGUtil.ReadInt32(input_stream, input_buffer);
fd.column_attribute_number = PGUtil.ReadInt16(input_stream, input_buffer);
fd.type_oid = PGUtil.ReadInt32(input_stream, input_buffer);
fd.type_info = type_mapping[fd.type_oid];
fd.type_size = PGUtil.ReadInt16(input_stream, input_buffer);
fd.type_modifier = PGUtil.ReadInt32(input_stream, input_buffer);
fd.format_code = (FormatCode)PGUtil.ReadInt16(input_stream, input_buffer);
fields_data[i] = fd;
fields_index[i] = fd.name;
}
}
public NpgsqlRowDescriptionFieldData this[Int32 index]
{
get
{
return fields_data[index];
}
}
public Int16 NumFields
{
get
{
return (Int16)fields_data.Length;
}
}
public Int16 FieldIndex(String fieldName)
{
// First try to find the index with IndexOf (case-sensitive)
Int16 result = (Int16)Array.IndexOf(fields_index, fieldName, 0, fields_index.Length);
if (result != -1)
{
return result;
}
else
{
foreach(string name in fields_index)
{
++result;
if (string.Compare(name, fieldName, true) == 0)
return result;
}
}
throw new ArgumentOutOfRangeException("fieldName", fieldName, "Field name not found");
}
}
}