// Copyright (c) 2006-2008 MySQL AB, 2008-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.Text; using System.IO; using System.Data; using System.Collections.Specialized; using MySql.Data.MySqlClient.Properties; namespace MySql.Data.MySqlClient { /// /// /// public class MySqlBulkLoader { // constant values private const string defaultFieldTerminator = "\t"; private const string defaultLineTerminator = "\n"; private const char defaultEscapeCharacter = '\\'; // fields private string fieldTerminator; private string lineTerminator; private string charSet; private string tableName; private int numLinesToIgnore; private MySqlConnection connection; private string filename; private int timeout; private bool local; private string linePrefix; private char fieldQuotationCharacter; private bool fieldQuotationOptional; private char escapeChar; private MySqlBulkLoaderPriority priority; private MySqlBulkLoaderConflictOption conflictOption; private StringCollection columns; private StringCollection expressions; public MySqlBulkLoader(MySqlConnection connection) { Connection = connection; Local = true; FieldTerminator = defaultFieldTerminator; LineTerminator = defaultLineTerminator; FieldQuotationCharacter = Char.MinValue; ConflictOption = MySqlBulkLoaderConflictOption.None; columns = new StringCollection(); expressions = new StringCollection(); } #region Properties /// /// Gets or sets the connection. /// /// The connection. public MySqlConnection Connection { get { return connection; } set { connection = value; } } /// /// Gets or sets the field terminator. /// /// The field terminator. public string FieldTerminator { get { return fieldTerminator; } set { fieldTerminator = value; } } /// /// Gets or sets the line terminator. /// /// The line terminator. public string LineTerminator { get { return lineTerminator; } set { lineTerminator = value; } } /// /// Gets or sets the name of the table. /// /// The name of the table. public string TableName { get { return tableName; } set { tableName = value; } } /// /// Gets or sets the character set. /// /// The character set. public string CharacterSet { get { return charSet; } set { charSet = value; } } /// /// Gets or sets the name of the file. /// /// The name of the file. public string FileName { get { return filename; } set { filename = value; } } /// /// Gets or sets the timeout. /// /// The timeout. public int Timeout { get { return timeout; } set { timeout = value; } } /// /// Gets or sets a value indicating whether the filename that is to be loaded /// is local to the client or not /// /// true if local; otherwise, false. public bool Local { get { return local; } set { local = value; } } /// /// Gets or sets the number of lines to skip. /// /// The number of lines to skip. public int NumberOfLinesToSkip { get { return numLinesToIgnore; } set { numLinesToIgnore = value; } } /// /// Gets or sets the line prefix. /// /// The line prefix. public string LinePrefix { get { return linePrefix; } set { linePrefix = value; } } /// /// Gets or sets the field quotation character. /// /// The field quotation character. public char FieldQuotationCharacter { get { return fieldQuotationCharacter; } set { fieldQuotationCharacter = value; } } /// /// Gets or sets a value indicating whether [field quotation optional]. /// /// /// true if [field quotation optional]; otherwise, false. /// public bool FieldQuotationOptional { get { return fieldQuotationOptional; } set { fieldQuotationOptional = value; } } /// /// Gets or sets the escape character. /// /// The escape character. public char EscapeCharacter { get { return escapeChar; } set { escapeChar = value; } } /// /// Gets or sets the conflict option. /// /// The conflict option. public MySqlBulkLoaderConflictOption ConflictOption { get { return conflictOption; } set { conflictOption = value; } } /// /// Gets or sets the priority. /// /// The priority. public MySqlBulkLoaderPriority Priority { get { return priority; } set { priority = value; } } /// /// Gets the columns. /// /// The columns. public StringCollection Columns { get { return columns; } } /// /// Gets the expressions. /// /// The expressions. public StringCollection Expressions { get { return expressions; } } #endregion /// /// Execute the load operation /// /// The number of rows inserted. public int Load() { bool openedConnection = false; if (Connection == null) throw new InvalidOperationException(Resources.ConnectionNotSet); // next we open up the connetion if it is not already open if (connection.State != ConnectionState.Open) { openedConnection = true; connection.Open(); } try { string sql = BuildSqlCommand(); MySqlCommand cmd = new MySqlCommand(sql, Connection); cmd.CommandTimeout = Timeout; return cmd.ExecuteNonQuery(); } finally { if (openedConnection) connection.Close(); } } private string BuildSqlCommand() { StringBuilder sql = new StringBuilder("LOAD DATA "); if (Priority == MySqlBulkLoaderPriority.Low) sql.Append("LOW_PRIORITY "); else if (Priority == MySqlBulkLoaderPriority.Concurrent) sql.Append("CONCURRENT "); if (Local) sql.Append("LOCAL "); sql.Append("INFILE "); if (Path.DirectorySeparatorChar == '\\') sql.AppendFormat("'{0}' ", FileName.Replace(@"\", @"\\")); else sql.AppendFormat("'{0}' ", FileName); if (ConflictOption == MySqlBulkLoaderConflictOption.Ignore) sql.Append("IGNORE "); else if (ConflictOption == MySqlBulkLoaderConflictOption.Replace) sql.Append("REPLACE "); sql.AppendFormat("INTO TABLE {0} ", TableName); if (CharacterSet != null) sql.AppendFormat("CHARACTER SET {0} ", CharacterSet); StringBuilder optionSql = new StringBuilder(String.Empty); if (FieldTerminator != defaultFieldTerminator) optionSql.AppendFormat("TERMINATED BY '{0}' ", FieldTerminator); if (FieldQuotationCharacter != Char.MinValue) optionSql.AppendFormat("{0} ENCLOSED BY '{1}' ", FieldQuotationOptional ? "OPTIONALLY" : "", FieldQuotationCharacter); if (EscapeCharacter != defaultEscapeCharacter && EscapeCharacter != Char.MinValue) optionSql.AppendFormat("ESCAPED BY '{0}' ", EscapeCharacter); if (optionSql.Length > 0) sql.AppendFormat("FIELDS {0}", optionSql.ToString()); optionSql = new StringBuilder(String.Empty); if (LinePrefix != null && LinePrefix.Length > 0) optionSql.AppendFormat("STARTING BY '{0}' ", LinePrefix); if (LineTerminator != defaultLineTerminator) optionSql.AppendFormat("TERMINATED BY '{0}' ", LineTerminator); if (optionSql.Length > 0) sql.AppendFormat("LINES {0}", optionSql.ToString()); if (NumberOfLinesToSkip > 0) sql.AppendFormat("IGNORE {0} LINES ", NumberOfLinesToSkip); if (Columns.Count > 0) { sql.Append("("); sql.Append(Columns[0]); for (int i = 1; i < Columns.Count; i++) sql.AppendFormat(",{0}", Columns[i]); sql.Append(") "); } if (Expressions.Count > 0) { sql.Append("SET "); sql.Append(Expressions[0]); for (int i = 1; i < Expressions.Count; i++) sql.AppendFormat(",{0}", Expressions[i]); } return sql.ToString(); } } /// /// /// public enum MySqlBulkLoaderPriority { /// /// This is the default and indicates normal priority /// None, /// /// Low priority will cause the load operation to wait until all readers of the table /// have finished. This only affects storage engines that use only table-level locking /// such as MyISAM, Memory, and Merge. /// Low, /// /// Concurrent priority is only relevant for MyISAM tables and signals that if the table /// has no free blocks in the middle that other readers can retrieve data from the table /// while the load operation is happening. /// Concurrent } /// /// /// public enum MySqlBulkLoaderConflictOption { /// /// This is the default and indicates normal operation. In the event of a LOCAL load, this /// is the same as ignore. When the data file is on the server, then a key conflict will /// cause an error to be thrown and the rest of the data file ignored. /// None, /// /// Replace column values when a key conflict occurs. /// Replace, /// /// Ignore any rows where the primary key conflicts. /// Ignore } }