Пример #1
0
        private void InternalBindParameters(string sql, MySqlParameterCollection parameters,
                                            MySqlPacket packet)
        {
            bool sqlServerMode = command.Connection.Settings.SqlServerMode;

            if (packet == null)
            {
                packet         = new MySqlPacket(Driver.Encoding);
                packet.Version = Driver.Version;
                packet.WriteByte(0);
            }

            MySqlTokenizer tokenizer = new MySqlTokenizer(sql);

            tokenizer.ReturnComments = true;
            tokenizer.SqlServerMode  = sqlServerMode;

            int    pos            = 0;
            string token          = tokenizer.NextToken();
            int    parameterCount = 0;

            while (token != null)
            {
                // serialize everything that came before the token (i.e. whitespace)
                packet.WriteStringNoNull(sql.Substring(pos, tokenizer.StartIndex - pos));
                pos = tokenizer.StopIndex;
                if (MySqlTokenizer.IsParameter(token))
                {
                    if ((!parameters.containsUnnamedParameters && token.Length == 1 && parameterCount > 0) || parameters.containsUnnamedParameters && token.Length > 1)
                    {
                        throw new MySqlException(Resources.MixedParameterNamingNotAllowed);
                    }

                    parameters.containsUnnamedParameters = token.Length == 1;
                    if (SerializeParameter(parameters, packet, token, parameterCount))
                    {
                        token = null;
                    }
                    parameterCount++;
                }
                if (token != null)
                {
                    if (sqlServerMode && tokenizer.Quoted && token.StartsWith("[", StringComparison.Ordinal))
                    {
                        token = String.Format("`{0}`", token.Substring(1, token.Length - 2));
                    }
                    packet.WriteStringNoNull(token);
                }
                token = tokenizer.NextToken();
            }
            buffers.Add(packet);
        }
Пример #2
0
        private static List <string> ParseColumns(MySqlTokenizer tokenizer)
        {
            List <string> sc    = new List <string>();
            string        token = tokenizer.NextToken();

            while (token != ")")
            {
                if (token != ",")
                {
                    sc.Add(token);
                }
                token = tokenizer.NextToken();
            }
            return(sc);
        }
Пример #3
0
        private static void ParseConstraint(MySqlSchemaCollection fkTable, MySqlSchemaRow table,
                                            MySqlTokenizer tokenizer, bool includeColumns)
        {
            string         name = tokenizer.NextToken();
            MySqlSchemaRow row  = fkTable.AddRow();

            // make sure this constraint is a FK
            string token = tokenizer.NextToken();

            if (token != "foreign" || tokenizer.Quoted)
            {
                return;
            }
            tokenizer.NextToken(); // read off the 'KEY' symbol
            tokenizer.NextToken(); // read off the '(' symbol

            row["CONSTRAINT_CATALOG"]       = table["TABLE_CATALOG"];
            row["CONSTRAINT_SCHEMA"]        = table["TABLE_SCHEMA"];
            row["TABLE_CATALOG"]            = table["TABLE_CATALOG"];
            row["TABLE_SCHEMA"]             = table["TABLE_SCHEMA"];
            row["TABLE_NAME"]               = table["TABLE_NAME"];
            row["REFERENCED_TABLE_CATALOG"] = null;
            row["CONSTRAINT_NAME"]          = name.Trim(new char[] { '\'', '`' });

            List <string> srcColumns = includeColumns ? ParseColumns(tokenizer) : null;

            // now look for the references section
            while (token != "references" || tokenizer.Quoted)
            {
                token = tokenizer.NextToken();
            }
            string target1 = tokenizer.NextToken();
            string target2 = tokenizer.NextToken();

            if (target2.StartsWith(".", StringComparison.Ordinal))
            {
                row["REFERENCED_TABLE_SCHEMA"] = target1;
                row["REFERENCED_TABLE_NAME"]   = target2.Substring(1).Trim(new char[] { '\'', '`' });
                tokenizer.NextToken(); // read off the '('
            }
            else
            {
                row["REFERENCED_TABLE_SCHEMA"] = table["TABLE_SCHEMA"];
                row["REFERENCED_TABLE_NAME"]   = target1.Substring(1).Trim(new char[] { '\'', '`' });;
            }

            // if we are supposed to include columns, read the target columns
            List <string> targetColumns = includeColumns ? ParseColumns(tokenizer) : null;

            if (includeColumns)
            {
                ProcessColumns(fkTable, row, srcColumns, targetColumns);
            }
            else
            {
                fkTable.Rows.Add(row);
            }
        }
Пример #4
0
        private static List <string> GetPossibleValues(MySqlSchemaRow row)
        {
            string[] types         = new string[] { "ENUM", "SET" };
            string   dtdIdentifier = row["DTD_IDENTIFIER"].ToString().Trim();

            int index = 0;

            for (; index < 2; index++)
            {
                if (dtdIdentifier.StartsWith(types[index], StringComparison.OrdinalIgnoreCase))
                {
                    break;
                }
            }
            if (index == 2)
            {
                return(null);
            }
            dtdIdentifier = dtdIdentifier.Substring(types[index].Length).Trim();
            dtdIdentifier = dtdIdentifier.Trim('(', ')').Trim();

            List <string>  values    = new List <string>();
            MySqlTokenizer tokenzier = new MySqlTokenizer(dtdIdentifier);
            string         token     = tokenzier.NextToken();
            int            start     = tokenzier.StartIndex;

            while (true)
            {
                if (token == null || token == ",")
                {
                    int end = dtdIdentifier.Length - 1;
                    if (token == ",")
                    {
                        end = tokenzier.StartIndex;
                    }

                    string value = dtdIdentifier.Substring(start, end - start).Trim('\'', '\"').Trim();
                    values.Add(value);
                    start = tokenzier.StopIndex;
                }
                if (token == null)
                {
                    break;
                }
                token = tokenzier.NextToken();
            }
            return(values);
        }
Пример #5
0
        /// <summary>
        /// GetForeignKeysOnTable retrieves the foreign keys on the given table.
        /// Since MySQL supports foreign keys on versions prior to 5.0, we can't  use
        /// information schema.  MySQL also does not include any type of SHOW command
        /// for foreign keys so we have to resort to use SHOW CREATE TABLE and parsing
        /// the output.
        /// </summary>
        /// <param name="fkTable">The table to store the key info in.</param>
        /// <param name="tableToParse">The table to get the foeign key info for.</param>
        /// <param name="filterName">Only get foreign keys that match this name.</param>
        /// <param name="includeColumns">Should column information be included in the table.</param>
        private void GetForeignKeysOnTable(MySqlSchemaCollection fkTable, MySqlSchemaRow tableToParse,
                                           string filterName, bool includeColumns)
        {
            string sqlMode = GetSqlMode();

            if (filterName != null)
            {
                filterName = StringUtility.ToLowerInvariant(filterName);
            }

            string sql = string.Format("SHOW CREATE TABLE `{0}`.`{1}`",
                                       tableToParse["TABLE_SCHEMA"], tableToParse["TABLE_NAME"]);
            string       lowerBody = null, body = null;
            MySqlCommand cmd = new MySqlCommand(sql, connection);

            using (MySqlDataReader reader = cmd.ExecuteReader())
            {
                reader.Read();
                body      = reader.GetString(1);
                lowerBody = StringUtility.ToLowerInvariant(body);
            }

            MySqlTokenizer tokenizer = new MySqlTokenizer(lowerBody);

            tokenizer.AnsiQuotes       = sqlMode.IndexOf("ANSI_QUOTES") != -1;
            tokenizer.BackslashEscapes = sqlMode.IndexOf("NO_BACKSLASH_ESCAPES") != -1;

            while (true)
            {
                string token = tokenizer.NextToken();
                // look for a starting contraint
                while (token != null && (token != "constraint" || tokenizer.Quoted))
                {
                    token = tokenizer.NextToken();
                }
                if (token == null)
                {
                    break;
                }

                ParseConstraint(fkTable, tableToParse, tokenizer, includeColumns);
            }
        }
Пример #6
0
        private string GetProcedureParameterLine(MySqlSchemaRow isRow)
        {
            string sql = "SHOW CREATE {0} `{1}`.`{2}`";

            sql = String.Format(sql, isRow["ROUTINE_TYPE"], isRow["ROUTINE_SCHEMA"],
                                isRow["ROUTINE_NAME"]);
            MySqlCommand cmd = new MySqlCommand(sql, connection);

            using (MySqlDataReader reader = cmd.ExecuteReader())
            {
                reader.Read();

                // if we are not the owner of this proc or have permissions
                // then we will get null for the body
                if (reader.IsDBNull(2))
                {
                    return(null);
                }

                string sql_mode = reader.GetString(1);

                string         body      = reader.GetString(2);
                MySqlTokenizer tokenizer = new MySqlTokenizer(body);
                tokenizer.AnsiQuotes       = sql_mode.IndexOf("ANSI_QUOTES") != -1;
                tokenizer.BackslashEscapes = sql_mode.IndexOf("NO_BACKSLASH_ESCAPES") == -1;

                string token = tokenizer.NextToken();
                while (token != "(")
                {
                    token = tokenizer.NextToken();
                }
                int start = tokenizer.StartIndex + 1;
                token = tokenizer.NextToken();
                while (token != ")" || tokenizer.Quoted)
                {
                    token = tokenizer.NextToken();
                    // if we see another ( and we are not quoted then we
                    // are in a size element and we need to look for the closing paren
                    if (token == "(" && !tokenizer.Quoted)
                    {
                        while (token != ")" || tokenizer.Quoted)
                        {
                            token = tokenizer.NextToken();
                        }
                        token = tokenizer.NextToken();
                    }
                }
                return(body.Substring(start, tokenizer.StartIndex - start));
            }
        }
Пример #7
0
        /// <summary>
        ///  Parses out the elements of a procedure parameter data type.
        /// </summary>
        private string ParseDataType(MySqlSchemaRow row, MySqlTokenizer tokenizer)
        {
            StringBuilder dtd = new StringBuilder(
                StringUtility.ToUpperInvariant(tokenizer.NextToken()));

            row["DATA_TYPE"] = dtd.ToString();
            string type = row["DATA_TYPE"].ToString();

            string token = tokenizer.NextToken();

            if (token == "(")
            {
                token = tokenizer.ReadParenthesis();
                dtd.AppendFormat(CultureInfo.InvariantCulture, "{0}", token);
                if (type != "ENUM" && type != "SET")
                {
                    ParseDataTypeSize(row, token);
                }
                token = tokenizer.NextToken();
            }
            else
            {
                dtd.Append(GetDataTypeDefaults(type, row));
            }

            while (token != ")" &&
                   token != "," &&
                   String.Compare(token, "begin", StringComparison.OrdinalIgnoreCase) != 0 &&
                   String.Compare(token, "return", StringComparison.OrdinalIgnoreCase) != 0)
            {
                if (String.Compare(token, "CHARACTER", StringComparison.OrdinalIgnoreCase) == 0 ||
                    String.Compare(token, "BINARY", StringComparison.OrdinalIgnoreCase) == 0)
                {
                } // we don't need to do anything with this
                else if (String.Compare(token, "SET", StringComparison.OrdinalIgnoreCase) == 0 ||
                         String.Compare(token, "CHARSET", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    row["CHARACTER_SET_NAME"] = tokenizer.NextToken();
                }
                else if (String.Compare(token, "ASCII", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    row["CHARACTER_SET_NAME"] = "latin1";
                }
                else if (String.Compare(token, "UNICODE", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    row["CHARACTER_SET_NAME"] = "ucs2";
                }
                else if (String.Compare(token, "COLLATE", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    row["COLLATION_NAME"] = tokenizer.NextToken();
                }
                else
                {
                    dtd.AppendFormat(CultureInfo.InvariantCulture, " {0}", token);
                }
                token = tokenizer.NextToken();
            }

            if (dtd.Length > 0)
            {
                row["DTD_IDENTIFIER"] = dtd.ToString();
            }

            // now default the collation if one wasn't given
            if (string.IsNullOrEmpty(( string )row["COLLATION_NAME"]) &&
                !string.IsNullOrEmpty(( string )row["CHARACTER_SET_NAME"]))
            {
                row["COLLATION_NAME"] = CharSetMap.GetDefaultCollation(
                    row["CHARACTER_SET_NAME"].ToString(), connection);
            }

            // now set the octet length
            if (row["CHARACTER_MAXIMUM_LENGTH"] != null)
            {
                if (row["CHARACTER_SET_NAME"] == null)
                {
                    row["CHARACTER_SET_NAME"] = "";
                }
                row["CHARACTER_OCTET_LENGTH"] =
                    CharSetMap.GetMaxLength(( string )row["CHARACTER_SET_NAME"], connection) *
                    (int)row["CHARACTER_MAXIMUM_LENGTH"];
            }

            return(token);
        }
Пример #8
0
        private void ParseProcedureBody(MySqlSchemaCollection parametersTable, string body,
                                        MySqlSchemaRow row, string nameToRestrict)
        {
            List <string> modes = new List <string>(new string[3] {
                "IN", "OUT", "INOUT"
            });

            string sqlMode = row["SQL_MODE"].ToString();

            int            pos       = 1;
            MySqlTokenizer tokenizer = new MySqlTokenizer(body);

            tokenizer.AnsiQuotes       = sqlMode.IndexOf("ANSI_QUOTES") != -1;
            tokenizer.BackslashEscapes = sqlMode.IndexOf("NO_BACKSLASH_ESCAPES") == -1;
            tokenizer.ReturnComments   = false;
            string token = tokenizer.NextToken();

            // this block will scan for the opening paren while also determining
            // if this routine is a function.  If so, then we need to add a
            // parameter row for the return parameter since it is ordinal position
            // 0 and should appear first.
            while (token != "(")
            {
                if (String.Compare(token, "FUNCTION", StringComparison.OrdinalIgnoreCase) == 0 &&
                    nameToRestrict == null)
                {
                    parametersTable.AddRow();
                    InitParameterRow(row, parametersTable.Rows[0]);
                }
                token = tokenizer.NextToken();
            }
            token = tokenizer.NextToken(); // now move to the next token past the (

            while (token != ")")
            {
                MySqlSchemaRow parmRow = parametersTable.NewRow();
                InitParameterRow(row, parmRow);
                parmRow["ORDINAL_POSITION"] = pos++;

                // handle mode and name for the parameter
                string mode = StringUtility.ToUpperInvariant(token);
                if (!tokenizer.Quoted && modes.Contains(mode))
                {
                    parmRow["PARAMETER_MODE"] = mode;
                    token = tokenizer.NextToken();
                }
                if (tokenizer.Quoted)
                {
                    token = token.Substring(1, token.Length - 2);
                }
                parmRow["PARAMETER_NAME"] = token;

                // now parse data type
                token = ParseDataType(parmRow, tokenizer);
                if (token == ",")
                {
                    token = tokenizer.NextToken();
                }

                // now determine if we should include this row after all
                // we need to parse it before this check so we are correctly
                // positioned for the next parameter
                if (nameToRestrict == null ||
                    String.Compare(parmRow["PARAMETER_NAME"].ToString(), nameToRestrict, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    parametersTable.Rows.Add(parmRow);
                }
            }

            // now parse out the return parameter if there is one.
            token = StringUtility.ToUpperInvariant(tokenizer.NextToken());
            if (String.Compare(token, "RETURNS", StringComparison.OrdinalIgnoreCase) == 0)
            {
                MySqlSchemaRow parameterRow = parametersTable.Rows[0];
                parameterRow["PARAMETER_NAME"] = "RETURN_VALUE";
                ParseDataType(parameterRow, tokenizer);
            }
        }
Пример #9
0
        internal string GetCommandTextForBatching()
        {
            if (batchableCommandText == null)
            {
                // if the command starts with insert and is "simple" enough, then
                // we can use the multi-value form of insert
                if (String.Compare(CommandText.Substring(0, 6), "INSERT", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    MySqlCommand   cmd       = new MySqlCommand("SELECT @@sql_mode", Connection);
                    string         sql_mode  = StringUtility.ToUpperInvariant(cmd.ExecuteScalar().ToString());
                    MySqlTokenizer tokenizer = new MySqlTokenizer(CommandText);
                    tokenizer.AnsiQuotes       = sql_mode.IndexOf("ANSI_QUOTES") != -1;
                    tokenizer.BackslashEscapes = sql_mode.IndexOf("NO_BACKSLASH_ESCAPES") == -1;
                    string token = StringUtility.ToLowerInvariant(tokenizer.NextToken());
                    while (token != null)
                    {
                        if (StringUtility.ToUpperInvariant(token) == "VALUES" &&
                            !tokenizer.Quoted)
                        {
                            token = tokenizer.NextToken();
                            Debug.Assert(token == "(");

                            // find matching right paren, and ensure that parens
                            // are balanced.
                            int openParenCount = 1;
                            while (token != null)
                            {
                                batchableCommandText += token;
                                token = tokenizer.NextToken();

                                if (token == "(")
                                {
                                    openParenCount++;
                                }
                                else if (token == ")")
                                {
                                    openParenCount--;
                                }

                                if (openParenCount == 0)
                                {
                                    break;
                                }
                            }

                            if (token != null)
                            {
                                batchableCommandText += token;
                            }
                            token = tokenizer.NextToken();
                            if (token != null && (token == "," ||
                                                  StringUtility.ToUpperInvariant(token) == "ON"))
                            {
                                batchableCommandText = null;
                                break;
                            }
                        }
                        token = tokenizer.NextToken();
                    }
                }
                // Otherwise use the command verbatim
                else
                {
                    batchableCommandText = CommandText;
                }
            }

            return(batchableCommandText);
        }
Пример #10
0
        private List <ScriptStatement> BreakIntoStatements(bool ansiQuotes, bool noBackslashEscapes)
        {
            string currentDelimiter            = Delimiter;
            int    startPos                    = 0;
            List <ScriptStatement> statements  = new List <ScriptStatement>();
            List <int>             lineNumbers = BreakScriptIntoLines();
            MySqlTokenizer         tokenizer   = new MySqlTokenizer(query);

            tokenizer.AnsiQuotes       = ansiQuotes;
            tokenizer.BackslashEscapes = !noBackslashEscapes;

            string token = tokenizer.NextToken();

            while (token != null)
            {
                if (!tokenizer.Quoted)
                {
                    if (token.ToLower(CultureInfo.InvariantCulture) == "delimiter")
                    {
                        tokenizer.NextToken();
                        AdjustDelimiterEnd(tokenizer);
                        currentDelimiter = query.Substring(tokenizer.StartIndex,
                                                           tokenizer.StopIndex - tokenizer.StartIndex).Trim();
                        startPos = tokenizer.StopIndex;
                    }
                    else
                    {
                        // this handles the case where our tokenizer reads part of the
                        // delimiter
                        if (currentDelimiter.StartsWith(token, StringComparison.OrdinalIgnoreCase))
                        {
                            if ((tokenizer.StartIndex + currentDelimiter.Length) <= query.Length)
                            {
                                if (query.Substring(tokenizer.StartIndex, currentDelimiter.Length) == currentDelimiter)
                                {
                                    token = currentDelimiter;
                                    tokenizer.Position  = tokenizer.StartIndex + currentDelimiter.Length;
                                    tokenizer.StopIndex = tokenizer.Position;
                                }
                            }
                        }

                        int delimiterPos = token.IndexOf(currentDelimiter, StringComparison.OrdinalIgnoreCase);
                        if (delimiterPos != -1)
                        {
                            int endPos = tokenizer.StopIndex - token.Length + delimiterPos;
                            if (tokenizer.StopIndex == query.Length - 1)
                            {
                                endPos++;
                            }
                            string          currentQuery = query.Substring(startPos, endPos - startPos);
                            ScriptStatement statement    = new ScriptStatement();
                            statement.text     = currentQuery.Trim();
                            statement.line     = FindLineNumber(startPos, lineNumbers);
                            statement.position = startPos - lineNumbers[statement.line];
                            statements.Add(statement);
                            startPos = endPos + currentDelimiter.Length;
                        }
                    }
                }
                token = tokenizer.NextToken();
            }

            // now clean up the last statement
            if (startPos < query.Length - 1)
            {
                string sqlLeftOver = query.Substring(startPos).Trim();
                if (!String.IsNullOrEmpty(sqlLeftOver))
                {
                    ScriptStatement statement = new ScriptStatement();
                    statement.text     = sqlLeftOver;
                    statement.line     = FindLineNumber(startPos, lineNumbers);
                    statement.position = startPos - lineNumbers[statement.line];
                    statements.Add(statement);
                }
            }
            return(statements);
        }