From: Date: October 30 2006 10:51pm Subject: Connector/NET commit: r443 - in trunk: . mysqlclient List-Archive: http://lists.mysql.com/commits/14583 X-Bug: 18186 Message-Id: <200610302151.k9ULp0wX002318@bk-internal.mysql.com> Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Modified: trunk/CHANGES trunk/mysqlclient/MySql.Data.2005.csproj trunk/mysqlclient/PreparableStatement.cs Log: Bug #18186 Problem with implementation of PreparedStatement Apparently Mono doesn't ignore the the case where BitArray yields a byte array of zero length and we try to copy that to an array so we put a check in. Modified: trunk/CHANGES =================================================================== --- trunk/CHANGES 2006-10-30 20:40:34 UTC (rev 442) +++ trunk/CHANGES 2006-10-30 21:50:59 UTC (rev 443) @@ -7,6 +7,7 @@ Bug #23245 Connector Net 5.01 Beta Installer produces Antivirus Error Message Bug #23758 Unable to connect to any server - IPv6 related Bug #22882 Registry key 'Global' access denied + Bug #18186 Problem with implementation of PreparedStatement Other changes ------------- Modified: trunk/mysqlclient/MySql.Data.2005.csproj =================================================================== --- trunk/mysqlclient/MySql.Data.2005.csproj 2006-10-30 20:40:34 UTC (rev 442) +++ trunk/mysqlclient/MySql.Data.2005.csproj 2006-10-30 21:50:59 UTC (rev 443) @@ -11,7 +11,8 @@ MySql.Data - cnet.snk + + JScript Grid IE50 @@ -25,7 +26,7 @@ - true + false bin\net-2.0\Debug\ @@ -112,7 +113,6 @@ - Modified: trunk/mysqlclient/PreparableStatement.cs =================================================================== --- trunk/mysqlclient/PreparableStatement.cs 2006-10-30 20:40:34 UTC (rev 442) +++ trunk/mysqlclient/PreparableStatement.cs 2006-10-30 21:50:59 UTC (rev 443) @@ -33,67 +33,67 @@ { private MySqlField[] paramList; private int executionCount; - private int pageSize; - private int statementId; + private int pageSize; + private int statementId; - public PreparableStatement(MySqlConnection connection, string text) - : base(connection, text) - { - pageSize = 0; - statementId = 0; - } + public PreparableStatement(MySqlConnection connection, string text) + : base(connection, text) + { + pageSize = 0; + statementId = 0; + } #region Properties - public int NumParameters + public int NumParameters { get { return paramList.Length; } } - public int ExecutionCount + public int ExecutionCount { get { return executionCount; } set { executionCount = value; } } - public bool IsPrepared - { - get { return statementId > 0; } - } + public bool IsPrepared + { + get { return statementId > 0; } + } - public int StatementId - { - get { return statementId; } - } + public int StatementId + { + get { return statementId; } + } #endregion - public virtual void Prepare(MySqlParameterCollection parameters) - { - // store our parameters. - this.parameters = parameters; + public virtual void Prepare(MySqlParameterCollection parameters) + { + // store our parameters. + this.parameters = parameters; - // strip out names from parameter markers - string text; - ArrayList parameter_names = PrepareCommandText(out text); + // strip out names from parameter markers + string text; + ArrayList parameter_names = PrepareCommandText(out text); - // ask our connection to send the prepare command - statementId = driver.PrepareStatement(text, ref paramList); + // ask our connection to send the prepare command + 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]; - } + // 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]; + } public override void Execute(MySqlParameterCollection parameters) { - // if we are not prepared, then call down to our base - if (!IsPrepared) - { - base.Execute(parameters); - return; - } + // if we are not prepared, then call down to our base + if (!IsPrepared) + { + base.Execute(parameters); + return; + } MySqlStream stream = new MySqlStream(driver.Encoding); @@ -101,100 +101,104 @@ // create our null bitmap BitArray nullMap = new BitArray(parameters.Count); - // now we run through the parameters that PREPARE sent back and use - // those names to index into the parameters the user gave us. - // if the user set that parameter to NULL, then we set the null map - // accordingly - if (paramList != null) - for (int x=0; x < paramList.Length; x++) - { - MySqlParameter p = parameters[paramList[x].ColumnName]; - if (p.Value == DBNull.Value || p.Value == null) - nullMap[x] = true; - } - byte[] nullMapBytes = new byte[(parameters.Count + 7)/8]; - nullMap.CopyTo(nullMapBytes, 0); + // now we run through the parameters that PREPARE sent back and use + // those names to index into the parameters the user gave us. + // if the user set that parameter to NULL, then we set the null map + // accordingly + if (paramList != null) + for (int x = 0; x < paramList.Length; x++) + { + MySqlParameter p = parameters[paramList[x].ColumnName]; + if (p.Value == DBNull.Value || p.Value == null) + nullMap[x] = true; + } + byte[] nullMapBytes = new byte[(parameters.Count + 7) / 8]; + // we check this because Mono doesn't ignore the case where nullMapBytes + // is zero length. + if (nullMapBytes.Length > 0) + nullMap.CopyTo(nullMapBytes, 0); + // start constructing our packet stream.WriteInteger(statementId, 4); - stream.WriteByte((byte)pageSize); // flags; always 0 for 4.1 - stream.WriteInteger(1, 4); // interation count; 1 for 4.1 - stream.Write(nullMapBytes); + stream.WriteByte((byte)pageSize); // flags; always 0 for 4.1 + stream.WriteInteger(1, 4); // interation count; 1 for 4.1 + stream.Write(nullMapBytes); //if (parameters != null && parameters.Count > 0) - stream.WriteByte(1); // rebound flag + stream.WriteByte(1); // rebound flag //else // packet.WriteByte( 0 ); //TODO: only send rebound if parms change // write out the parameter types - if (paramList != null) - { - foreach (MySqlField param in paramList) - { - MySqlParameter parm = parameters[param.ColumnName]; - stream.WriteInteger((long)parm.GetPSType(), 2); - } + if (paramList != null) + { + foreach (MySqlField param in paramList) + { + MySqlParameter parm = parameters[param.ColumnName]; + stream.WriteInteger((long)parm.GetPSType(), 2); + } - // now write out all non-null values - foreach (MySqlField param in paramList) - { - int index = parameters.IndexOf(param.ColumnName); - if (index == -1) - throw new MySqlException("Parameter '" + param.ColumnName + - "' is not defined."); - MySqlParameter parm = parameters[index]; - if (parm.Value == DBNull.Value || parm.Value == null) - continue; + // now write out all non-null values + foreach (MySqlField param in paramList) + { + int index = parameters.IndexOf(param.ColumnName); + if (index == -1) + throw new MySqlException("Parameter '" + param.ColumnName + + "' is not defined."); + MySqlParameter parm = parameters[index]; + if (parm.Value == DBNull.Value || parm.Value == null) + continue; - stream.Encoding = param.Encoding; - parm.Serialize(stream, true); - } - } + stream.Encoding = param.Encoding; + parm.Serialize(stream, true); + } + } - executionCount ++; + executionCount++; - driver.ExecuteStatement(stream.InternalBuffer.ToArray()); + driver.ExecuteStatement(stream.InternalBuffer.ToArray()); } - public override bool ExecuteNext() - { - if (!IsPrepared) - return base.ExecuteNext(); - return false; - } + public override bool ExecuteNext() + { + if (!IsPrepared) + return base.ExecuteNext(); + return false; + } - /// - /// Prepares CommandText for use with the Prepare method - /// - /// Command text stripped of all paramter names - /// - /// 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 - /// - private ArrayList PrepareCommandText(out string stripped_sql) - { - StringBuilder newSQL = new StringBuilder(); - ArrayList parameterMap = new ArrayList(); + /// + /// Prepares CommandText for use with the Prepare method + /// + /// Command text stripped of all paramter names + /// + /// 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 + /// + private ArrayList PrepareCommandText(out string stripped_sql) + { + StringBuilder newSQL = new StringBuilder(); + ArrayList parameterMap = new ArrayList(); - // tokenize the sql first - ArrayList tokens = TokenizeSql(ProcessedCommandText); - parameterMap.Clear(); + // tokenize the sql first + ArrayList tokens = TokenizeSql(ProcessedCommandText); + parameterMap.Clear(); - foreach (string token in tokens) - { - if ( token[0] != connection.ParameterMarker) - newSQL.Append(token); - else - { - parameterMap.Add(token); - newSQL.Append(connection.ParameterMarker); - } - } + foreach (string token in tokens) + { + if (token[0] != connection.ParameterMarker) + newSQL.Append(token); + else + { + parameterMap.Add(token); + newSQL.Append(connection.ParameterMarker); + } + } - stripped_sql = newSQL.ToString(); - return parameterMap; - } + stripped_sql = newSQL.ToString(); + return parameterMap; + } } }