|
|
#if MYSQL_6_9
// Copyright � 2004, 2013, Oracle and/or its affiliates. All rights reserved.
//
// MySQL Connector/NET 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
using System; using System.Collections; using System.Text; using System.Collections.Generic; using Externals.MySql.Data.MySqlClient.Properties; using System.Data;
namespace Externals.MySql.Data.MySqlClient { /// <summary>
/// Summary description for PreparedStatement.
/// </summary>
internal class PreparableStatement : Statement { private int executionCount; private int statementId; BitArray nullMap; List<MySqlParameter> parametersToSend = new List<MySqlParameter>(); MySqlPacket packet; int dataPosition; int nullMapPosition;
public PreparableStatement(MySqlCommand command, string text) : base(command, text) { }
#region Properties
public int ExecutionCount { get { return executionCount; } set { executionCount = value; } }
public bool IsPrepared { get { return statementId > 0; } }
public int StatementId { get { return statementId; } }
#endregion
public virtual void Prepare() { // strip out names from parameter markers
string text; List<string> parameter_names = PrepareCommandText(out text);
// ask our connection to send the prepare command
MySqlField[] paramList = null; statementId = Driver.PrepareStatement(text, ref paramList);
// now we need to assign our field names since we stripped them out
// for the prepare
for (int i = 0; i < parameter_names.Count; i++) { //paramList[i].ColumnName = (string) parameter_names[i];
string parameterName = (string)parameter_names[i]; MySqlParameter p = Parameters.GetParameterFlexible(parameterName, false); if (p == null) throw new InvalidOperationException( String.Format(Resources.ParameterNotFoundDuringPrepare, parameterName)); p.Encoding = paramList[i].Encoding; parametersToSend.Add(p); }
// now prepare our null map
int numNullBytes = 0; if (paramList != null && paramList.Length > 0) { nullMap = new BitArray(paramList.Length); numNullBytes = (nullMap.Count + 7) / 8; }
packet = new MySqlPacket(Driver.Encoding);
// write out some values that do not change run to run
packet.WriteByte(0); packet.WriteInteger(statementId, 4); packet.WriteByte((byte)0); // flags; always 0 for 4.1
packet.WriteInteger(1, 4); // interation count; 1 for 4.1
nullMapPosition = packet.Position; packet.Position += numNullBytes; // leave room for our null map
packet.WriteByte(1); // rebound flag
// write out the parameter types
foreach (MySqlParameter p in parametersToSend) packet.WriteInteger(p.GetPSType(), 2); dataPosition = packet.Position; }
public override void Execute() { // if we are not prepared, then call down to our base
if (!IsPrepared) { base.Execute(); return; }
//TODO: support long data here
// create our null bitmap
// we check this because Mono doesn't ignore the case where nullMapBytes
// is zero length.
// if (nullMapBytes.Length > 0)
// {
// byte[] bits = packet.Buffer;
// nullMap.CopyTo(bits,
// nullMap.CopyTo(nullMapBytes, 0);
// start constructing our packet
// if (Parameters.Count > 0)
// nullMap.CopyTo(packet.Buffer, nullMapPosition);
//if (parameters != null && parameters.Count > 0)
//else
// packet.WriteByte( 0 );
//TODO: only send rebound if parms change
// now write out all non-null values
packet.Position = dataPosition; for (int i = 0; i < parametersToSend.Count; i++) { MySqlParameter p = parametersToSend[i]; nullMap[i] = (p.Value == DBNull.Value || p.Value == null) || p.Direction == ParameterDirection.Output; if (nullMap[i]) continue; packet.Encoding = p.Encoding; p.Serialize(packet, true, Connection.Settings); } if (nullMap != null) nullMap.CopyTo(packet.Buffer, nullMapPosition);
executionCount++;
Driver.ExecuteStatement(packet); }
public override bool ExecuteNext() { if (!IsPrepared) return base.ExecuteNext(); return false; }
/// <summary>
/// Prepares CommandText for use with the Prepare method
/// </summary>
/// <returns>Command text stripped of all paramter names</returns>
/// <remarks>
/// Takes the output of TokenizeSql and creates a single string of SQL
/// that only contains '?' markers for each parameter. It also creates
/// the parameterMap array list that includes all the paramter names in the
/// order they appeared in the SQL
/// </remarks>
private List<string> PrepareCommandText(out string stripped_sql) { StringBuilder newSQL = new StringBuilder(); List<string> parameterMap = new List<string>();
int startPos = 0; string sql = ResolvedCommandText; MySqlTokenizer tokenizer = new MySqlTokenizer(sql); string parameter = tokenizer.NextParameter(); while (parameter != null) { if (parameter.IndexOf(StoredProcedure.ParameterPrefix) == -1) { newSQL.Append(sql.Substring(startPos, tokenizer.StartIndex - startPos)); newSQL.Append("?"); parameterMap.Add(parameter); startPos = tokenizer.StopIndex; } parameter = tokenizer.NextParameter(); } newSQL.Append(sql.Substring(startPos)); stripped_sql = newSQL.ToString(); return parameterMap; }
public virtual void CloseStatement() { if (!IsPrepared) return;
Driver.CloseStatement(statementId); statementId = 0; } } }
#endif
|