public InsertInto ( string table, string columns, string parameters ) : string | ||
table | string | The destination table. |
columns | string | The columns names. |
parameters | string | The parameters names. |
return | string |
/// <summary> /// Records a message to the System Log. /// </summary> /// <param name="message">The Log Message.</param> /// <param name="entryType">The Type of the Entry.</param> /// <param name="user">The User.</param> /// <param name="wiki">The wiki, <c>null</c> if is an application level log.</param> /// <remarks>This method <b>should not</b> write messages to the Log using the method IHost.LogEntry. /// This method should also never throw exceptions (except for parameter validation).</remarks> /// <exception cref="ArgumentNullException">If <b>message</b> or <b>user</b> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>message</b> or <b>user</b> are empty.</exception> public void LogEntry(string message, EntryType entryType, string user, string wiki) { if (message == null) { throw new ArgumentNullException("message"); } if (message.Length == 0) { throw new ArgumentException("Message cannot be empty", "message"); } if (user == null) { throw new ArgumentNullException("user"); } if (user.Length == 0) { throw new ArgumentException("User cannot be empty", "user"); } ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.InsertInto("Log", new string[] { "DateTime", "EntryType", "User", "Message", "Wiki" }, new string[] { "DateTime", "EntryType", "User", "Message", "Wiki" }); List <Parameter> parameters = new List <Parameter>(5); parameters.Add(new Parameter(ParameterType.DateTime, "DateTime", DateTime.UtcNow)); parameters.Add(new Parameter(ParameterType.Char, "EntryType", EntryTypeToChar(entryType))); parameters.Add(new Parameter(ParameterType.String, "User", Sanitize(user))); parameters.Add(new Parameter(ParameterType.String, "Message", Sanitize(message))); parameters.Add(new Parameter(ParameterType.String, "Wiki", string.IsNullOrEmpty(wiki) ? "" : Sanitize(wiki))); try { DbCommand command = builder.GetCommand(connString, query, parameters); int rows = ExecuteNonQuery(command, true, false); // No transaction - accurate log sizing is not really a concern if (rows > -1) { int logSize = LogSize; if (logSize > int.Parse(host.GetGlobalSettingValue(GlobalSettingName.MaxLogSize))) { CutLog((int)(logSize * 0.75)); } } } catch { } }
/// <summary> /// Obtains the lock. /// </summary> /// <returns><c>true</c> if the lock has been obtained, <c>false</c> otherwise.</returns> public override bool Obtain() { ICommandBuilder builder = _sqlStorageProviderUtility.GetCommandBuilder2(); DbConnection connection = builder.GetConnection(_connString); DbTransaction transaction = _sqlStorageProviderUtility.BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("SearchIndexLock"); query = queryBuilder.Where(query, "Wiki", WhereOperator.Equals, "Wiki"); query = queryBuilder.AndWhere(query, "Name", WhereOperator.Equals, "Name"); List <Parameter> parameters = new List <Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Wiki", _wiki)); parameters.Add(new Parameter(ParameterType.String, "Name", _name)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = _sqlStorageProviderUtility.ExecuteNonQuery(command, false); if (rows != 0) { _sqlStorageProviderUtility.RollbackTransaction(transaction); return(false); // Deletion command failed (0 is the only accepted value) } query = queryBuilder.InsertInto("SearchIndexLock", new string[] { "wiki", "Name", "Value" }, new string[] { "Wiki", "Name", "Value" }); parameters = new List <Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Wiki", _wiki)); parameters.Add(new Parameter(ParameterType.String, "Name", _name)); parameters.Add(new Parameter(ParameterType.String, "Value", "locked")); command = builder.GetCommand(transaction, query, parameters); rows = _sqlStorageProviderUtility.ExecuteNonQuery(command, false); if (rows == 1) { _sqlStorageProviderUtility.CommitTransaction(transaction); } else { _sqlStorageProviderUtility.RollbackTransaction(transaction); } return(rows == 1); }
/// <summary> /// Binds a Page with one or more Categories. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="page">The Page to bind.</param> /// <param name="categories">The Categories to bind the Page with.</param> /// <returns>True if the binding succeeded.</returns> /// <remarks>After a successful operation, the Page is bound with all and only the categories passed as argument.</remarks> private bool RebindPage(DbConnection connection, PageInfo page, string[] categories) { string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if(nspace == null) nspace = ""; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("CategoryBinding"); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(connection, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows < 0) return false; if(categories.Length > 0) { string finalQuery = ""; parameters = new List<Parameter>(categories.Length * 3); int count = 0; string countString; foreach(string cat in categories) { countString = count.ToString(); query = queryBuilder.InsertInto("CategoryBinding", new string[] { "Namespace", "Category", "Page" }, new string[] { "Namespace" + countString, "Category" + countString, "Page" + countString }); finalQuery = queryBuilder.AppendForBatch(finalQuery, query); parameters.Add(new Parameter(ParameterType.String, "Namespace" + countString, nspace)); parameters.Add(new Parameter(ParameterType.String, "Category" + countString, NameTools.GetLocalName(cat))); parameters.Add(new Parameter(ParameterType.String, "Page" + countString, name)); count++; } command = builder.GetCommand(connection, finalQuery, parameters); rows = ExecuteNonQuery(command, false); return rows == categories.Length; } else return true; }
/// <summary> /// Removes all messages for a page and stores the new messages. /// </summary> /// <param name="page">The page.</param> /// <param name="messages">The new messages to store.</param> /// <returns><c>true</c> if the messages are stored, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/> or <paramref name="messages"/> are <c>null</c>.</exception> public bool BulkStoreMessages(PageInfo page, Message[] messages) { if(page == null) throw new ArgumentNullException("page"); if(messages == null) throw new ArgumentNullException("messages"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(GetPage(transaction, page.FullName) == null) { RollbackTransaction(transaction); return false; } foreach(Message msg in GetMessages(transaction, page)) { UnindexMessageTree(page, msg, transaction); } string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if(nspace == null) nspace = ""; QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("Message"); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(transaction, query, parameters); ExecuteNonQuery(command, false); List<Message> allMessages; List<int> parents; UnTreeMessages(messages, out allMessages, out parents, -1); string finalQuery = ""; int count = 1; string countString; parameters = new List<Parameter>(MaxStatementsInBatch * 8); int rowsDone = 0; for(int i = 0; i < allMessages.Count; i++) { // Execute the batch in smaller chunks Message msg = allMessages[i]; int parent = parents[i]; countString = count.ToString(); query = queryBuilder.InsertInto("Message", new string[] { "Page", "Namespace", "Id", "Parent", "Username", "Subject", "DateTime", "Body" }, new string[] { "Page" + countString, "Namespace" + countString, "Id" + countString, "Parent" + countString, "Username" + countString, "Subject" + countString, "DateTime" + countString, "Body" + countString }); parameters.Add(new Parameter(ParameterType.String, "Page" + countString, name)); parameters.Add(new Parameter(ParameterType.String, "Namespace" + countString, nspace)); parameters.Add(new Parameter(ParameterType.Int16, "Id" + countString, (short)msg.ID)); if(parent != -1) parameters.Add(new Parameter(ParameterType.Int16, "Parent" + countString, parent)); else parameters.Add(new Parameter(ParameterType.Int16, "Parent" + countString, DBNull.Value)); parameters.Add(new Parameter(ParameterType.String, "Username" + countString, msg.Username)); parameters.Add(new Parameter(ParameterType.String, "Subject" + countString, msg.Subject)); parameters.Add(new Parameter(ParameterType.DateTime, "DateTime" + countString, msg.DateTime)); parameters.Add(new Parameter(ParameterType.String, "Body" + countString, msg.Body)); finalQuery = queryBuilder.AppendForBatch(finalQuery, query); count++; if(count == MaxStatementsInBatch) { command = builder.GetCommand(transaction, finalQuery, parameters); rowsDone += ExecuteNonQuery(command, false); finalQuery = ""; count = 1; parameters.Clear(); } } if(finalQuery.Length > 0) { command = builder.GetCommand(transaction, finalQuery, parameters); rowsDone += ExecuteNonQuery(command, false); } if(rowsDone == allMessages.Count) { foreach(Message msg in messages) { IndexMessageTree(page, msg, transaction); } CommitTransaction(transaction); return true; } else { RollbackTransaction(transaction); return false; } }
/// <summary> /// Adds a new Navigation Path. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="nspace">The target namespace (<c>null</c> for the root).</param> /// <param name="name">The Name of the Path.</param> /// <param name="pages">The Pages array.</param> /// <returns>The correct <see cref="T:NavigationPath"/> object.</returns> private NavigationPath AddNavigationPath(DbTransaction transaction, string nspace, string name, PageInfo[] pages) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query, finalQuery = ""; List<Parameter> parameters = new List<Parameter>(3 * pages.Length); int count = 0; string countString; foreach(PageInfo page in pages) { countString = count.ToString(); query = queryBuilder.InsertInto("NavigationPath", new string[] { "Name", "Namespace", "Page", "Number" }, new string[] { "Name" + countString, "Namespace" + countString, "Page" + countString, "Number" + countString }); parameters.Add(new Parameter(ParameterType.String, "Name" + countString, name)); parameters.Add(new Parameter(ParameterType.String, "Namespace" + countString, nspace)); parameters.Add(new Parameter(ParameterType.String, "Page" + countString, NameTools.GetLocalName(page.FullName))); parameters.Add(new Parameter(ParameterType.Int32, "Number" + countString, (short)count)); finalQuery = queryBuilder.AppendForBatch(finalQuery, query); count++; } DbCommand command = builder.GetCommand(transaction, finalQuery, parameters); int rows = ExecuteNonQuery(command, false); if(rows == pages.Length) { NavigationPath result = new NavigationPath(NameTools.GetFullName(nspace, name), this); result.Pages = Array.ConvertAll<PageInfo, string>(pages, (x) => { return x.FullName; }); return result; } else return null; }
/// <summary> /// Adds a new namespace. /// </summary> /// <param name="name">The name of the namespace.</param> /// <returns>The correct <see cref="T:NamespaceInfo"/> object.</returns> /// <exception cref="ArgumentNullException">If <paramref name="name"/> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="name"/> is empty.</exception> public NamespaceInfo AddNamespace(string name) { if(name == null) throw new ArgumentNullException("name"); if(name.Length == 0) throw new ArgumentException("Name cannot be empty", "name"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.InsertInto("Namespace", new string[] { "Name" }, new string[] { "Name" }); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", name)); DbCommand command = builder.GetCommand(connString, query, parameters); int rows = ExecuteNonQuery(command); if(rows == 1) return new NamespaceInfo(name, this, null); else return null; }
/// <summary> /// Adds a new Message to a Page. /// </summary> /// <param name="page">The Page.</param> /// <param name="username">The Username.</param> /// <param name="subject">The Subject.</param> /// <param name="dateTime">The Date/Time.</param> /// <param name="body">The Body.</param> /// <param name="parent">The Parent Message ID, or -1.</param> /// <returns>True if the Message is added successfully.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/>, <paramref name="username"/>, <paramref name="subject"/> or <paramref name="body"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="username"/> or <paramref name="subject"/> are empty.</exception> /// <exception cref="ArgumentOutOfRangeException">If <paramref name="parent"/> is less than -1.</exception> public bool AddMessage(PageInfo page, string username, string subject, DateTime dateTime, string body, int parent) { if(page == null) throw new ArgumentNullException("page"); if(username == null) throw new ArgumentNullException("username"); if(username.Length == 0) throw new ArgumentException("Username cannot be empty", "username"); if(subject == null) throw new ArgumentNullException("subject"); if(subject.Length == 0) throw new ArgumentException("Subject cannot be empty", "subject"); if(body == null) throw new ArgumentNullException("body"); // body can be empty if(parent < -1) throw new ArgumentOutOfRangeException("parent", "Invalid Parent Message ID"); string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if(nspace == null) nspace = ""; ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(parent != -1 && FindMessage(GetMessages(transaction, page), parent) == null) { RollbackTransaction(transaction); return false; } QueryBuilder queryBuilder = new QueryBuilder(builder); short freeId = -1; string query = queryBuilder.SelectFrom("Message", new string[] { "Id" }); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.OrderBy(query, new string[] { "Id" }, new Ordering[] { Ordering.Desc }); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(transaction, query, parameters); freeId = ExecuteScalar<short>(command, -1, false); if(freeId == -1) freeId = 0; else freeId++; query = queryBuilder.InsertInto("Message", new string[] { "Page", "Namespace", "Id", "Parent", "Username", "Subject", "DateTime", "Body" }, new string[] { "Page", "Namespace", "Id", "Parent", "Username", "Subject", "DateTime", "Body" }); parameters = new List<Parameter>(8); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.Int16, "Id", freeId)); if(parent != -1) parameters.Add(new Parameter(ParameterType.Int16, "Parent", parent)); else parameters.Add(new Parameter(ParameterType.Int16, "Parent", DBNull.Value)); parameters.Add(new Parameter(ParameterType.String, "Username", username)); parameters.Add(new Parameter(ParameterType.String, "Subject", subject)); parameters.Add(new Parameter(ParameterType.DateTime, "DateTime", dateTime)); parameters.Add(new Parameter(ParameterType.String, "Body", body)); command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == 1) { IndexMessage(page, freeId, subject, dateTime, body, transaction); CommitTransaction(transaction); return true; } else { RollbackTransaction(transaction); return false; } }
/// <summary> /// Stores a Page Attachment. /// </summary> /// <param name="pageInfo">The Page Info that owns the Attachment.</param> /// <param name="name">The name of the Attachment, for example "myfile.jpg".</param> /// <param name="sourceStream">A Stream object used as <b>source</b> of a byte stream, /// i.e. the method reads from the Stream and stores the content properly.</param> /// <param name="overwrite"><c>true</c> to overwrite an existing Attachment.</param> /// <returns><c>true</c> if the Attachment is stored, <c>false</c> otherwise.</returns> /// <remarks>If <b>overwrite</b> is <c>false</c> and Attachment already exists, the method returns <c>false</c>.</remarks> /// <exception cref="ArgumentNullException">If <paramref name="pageInfo"/>, <paramref name="name"/> or <paramref name="sourceStream"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="name"/> is empty or if <paramref name="sourceStream"/> does not support reading.</exception> public bool StorePageAttachment(PageInfo pageInfo, string name, System.IO.Stream sourceStream, bool overwrite) { if(pageInfo == null) throw new ArgumentNullException("pageInfo"); if(name == null) throw new ArgumentNullException("name"); if(name.Length == 0) throw new ArgumentException("Name cannot be empty", "name"); if(sourceStream == null) throw new ArgumentNullException("sourceStream"); if(!sourceStream.CanRead) throw new ArgumentException("Cannot read from Source Stream", "sourceStream"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); bool attachmentExists = AttachmentExists(transaction, pageInfo, name); if(attachmentExists && !overwrite) { RollbackTransaction(transaction); return false; } // To achieve decent performance, an UPDATE query is issued if the attachment exists, // otherwise an INSERT query is issued QueryBuilder queryBuilder = new QueryBuilder(builder); string query; List<Parameter> parameters; byte[] attachmentData = null; int size = Tools.ReadStream(sourceStream, ref attachmentData, MaxFileSize); if(size < 0) { RollbackTransaction(transaction); throw new ArgumentException("Source Stream contains too much data", "sourceStream"); } if(attachmentExists) { query = queryBuilder.Update("Attachment", new string[] { "Size", "LastModified", "Data" }, new string[] { "Size", "LastModified", "Data" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Page", WhereOperator.Equals, "Page"); parameters = new List<Parameter>(5); parameters.Add(new Parameter(ParameterType.Int64, "Size", (long)size)); parameters.Add(new Parameter(ParameterType.DateTime, "LastModified", DateTime.Now)); parameters.Add(new Parameter(ParameterType.ByteArray, "Data", attachmentData)); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Page", pageInfo.FullName)); } else { query = queryBuilder.InsertInto("Attachment", new string[] { "Name", "Page", "Size", "Downloads", "LastModified", "Data" }, new string[] { "Name", "Page", "Size", "Downloads", "LastModified", "Data" }); parameters = new List<Parameter>(6); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Page", pageInfo.FullName)); parameters.Add(new Parameter(ParameterType.Int64, "Size", (long)size)); parameters.Add(new Parameter(ParameterType.Int32, "Downloads", 0)); parameters.Add(new Parameter(ParameterType.DateTime, "LastModified", DateTime.Now)); parameters.Add(new Parameter(ParameterType.ByteArray, "Data", attachmentData)); } DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == 1) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows == 1; }
/// <summary> /// Stores the outgoing links of a page, overwriting existing data. /// </summary> /// <param name="page">The full name of the page.</param> /// <param name="outgoingLinks">The full names of the pages that <b>page</b> links to.</param> /// <returns><c>true</c> if the outgoing links are stored, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <b>page</b> or <b>outgoingLinks</b> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>page</b> or <b>outgoingLinks</b> are empty.</exception> public bool StoreOutgoingLinks(string page, string[] outgoingLinks) { if(page == null) throw new ArgumentNullException("page"); if(page.Length == 0) throw new ArgumentException("Page cannot be empty", "page"); if(outgoingLinks == null) throw new ArgumentNullException("outgoingLinks"); foreach(string link in outgoingLinks) { if(link == null) throw new ArgumentNullException("outgoingLinks"); if(link.Length == 0) throw new ArgumentException("Link cannot be empty", "outgoingLinks"); } // 1. Delete old values, if any // 2. Store new values ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("OutgoingLink"); query = queryBuilder.Where(query, "Source", WhereOperator.Equals, "Source"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Source", page)); DbCommand command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) < 0) { RollbackTransaction(transaction); return false; } foreach(string link in outgoingLinks) { query = queryBuilder.InsertInto("OutgoingLink", new string[] { "Source", "Destination" }, new string[] { "Source", "Destination" }); parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Source", page)); parameters.Add(new Parameter(ParameterType.String, "Destination", link)); command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows != 1) { RollbackTransaction(transaction); return false; } } CommitTransaction(transaction); return true; }
/// <summary> /// Stores the value of a Setting. /// </summary> /// <param name="name">The name of the Setting.</param> /// <param name="value">The value of the Setting. Value cannot contain CR and LF characters, which will be removed.</param> /// <returns>True if the Setting is stored, false otherwise.</returns> /// <remarks>This method stores the Value immediately.</remarks> public bool SetSetting(string name, string value) { if(name == null) throw new ArgumentNullException("name"); if(name.Length == 0) throw new ArgumentException("Name cannot be empty", "name"); // 1. Delete old value, if any // 2. Store new value // Nulls are converted to empty strings if(value == null) value = ""; ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("Setting"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", name)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == -1) { RollbackTransaction(transaction); return false; // Deletion command failed (0-1 are OK) } query = queryBuilder.InsertInto("Setting", new string[] { "Name", "Value" }, new string[] { "Name", "Value" }); parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Value", value)); command = builder.GetCommand(transaction, query, parameters); rows = ExecuteNonQuery(command, false); if(rows == 1) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows == 1; }
/// <summary> /// Sets a meta-data items' content. /// </summary> /// <param name="item">The item.</param> /// <param name="tag">The tag that specifies the context (usually the namespace).</param> /// <param name="content">The content.</param> /// <returns><c>true</c> if the content is set, <c>false</c> otherwise.</returns> public bool SetMetaDataItem(MetaDataItem item, string tag, string content) { if(tag == null) tag = ""; if(content == null) content = ""; // 1. Delete old value, if any // 2. Store new value ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("MetaDataItem"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Tag", WhereOperator.Equals, "Tag"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", item.ToString())); parameters.Add(new Parameter(ParameterType.String, "Tag", tag)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == -1) { RollbackTransaction(transaction); return false; } query = queryBuilder.InsertInto("MetaDataItem", new string[] { "Name", "Tag", "Data" }, new string[] { "Name", "Tag", "Content" }); parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Name", item.ToString())); parameters.Add(new Parameter(ParameterType.String, "Tag", tag)); parameters.Add(new Parameter(ParameterType.String, "Content", content)); command = builder.GetCommand(transaction, query, parameters); rows = ExecuteNonQuery(command, false); if(rows == 1) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows == 1; }
/// <summary> /// Records a message to the System Log. /// </summary> /// <param name="message">The Log Message.</param> /// <param name="entryType">The Type of the Entry.</param> /// <param name="user">The User.</param> /// <remarks>This method <b>should not</b> write messages to the Log using the method IHost.LogEntry. /// This method should also never throw exceptions (except for parameter validation).</remarks> /// <exception cref="ArgumentNullException">If <b>message</b> or <b>user</b> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>message</b> or <b>user</b> are empty.</exception> public void LogEntry(string message, EntryType entryType, string user) { if(message == null) throw new ArgumentNullException("message"); if(message.Length == 0) throw new ArgumentException("Message cannot be empty", "message"); if(user == null) throw new ArgumentNullException("user"); if(user.Length == 0) throw new ArgumentException("User cannot be empty", "user"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.InsertInto("Log", new string[] { "DateTime", "EntryType", "User", "Message" }, new string[] { "DateTime", "EntryType", "User", "Message" }); List<Parameter> parameters = new List<Parameter>(4); parameters.Add(new Parameter(ParameterType.DateTime, "DateTime", DateTime.Now)); parameters.Add(new Parameter(ParameterType.Char, "EntryType", EntryTypeToChar(entryType))); parameters.Add(new Parameter(ParameterType.String, "User", Sanitize(user))); parameters.Add(new Parameter(ParameterType.String, "Message", Sanitize(message))); try { DbCommand command = builder.GetCommand(connString, query, parameters); ExecuteNonQuery(command, true); // No transaction - accurate log sizing is not really a concern int logSize = LogSize; if(logSize > int.Parse(host.GetSettingValue(SettingName.MaxLogSize))) { CutLog((int)(logSize * 0.75)); } } catch { } }
/// <summary> /// Stores a ACL entry. /// </summary> /// <param name="entry">The entry to store.</param> /// <returns><c>true</c> if the entry was stored, <c>false</c> otherwise.</returns> private bool StoreEntry(AclEntry entry) { ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.InsertInto("AclEntry", new string[] { "Resource", "Action", "Subject", "Value" }, new string[] { "Resource", "Action", "Subject", "Value" }); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Resource", entry.Resource)); parameters.Add(new Parameter(ParameterType.String, "Action", entry.Action)); parameters.Add(new Parameter(ParameterType.String, "Subject", entry.Subject)); parameters.Add(new Parameter(ParameterType.Char, "Value", AclEntryValueToChar(entry.Value))); DbCommand command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) != 1) { RollbackTransaction(transaction); return false; } CommitTransaction(transaction); return true; }
/// <summary> /// Prepares the plugin status row, if necessary. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="typeName">The Type name of the plugin.</param> private void PreparePluginStatusRow(DbTransaction transaction, string typeName) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectCountFrom("PluginStatus"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", typeName)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteScalar<int>(command, -1, false); if(rows == -1) return; if(rows == 0) { // Insert a neutral row (enabled, empty config) query = queryBuilder.InsertInto("PluginStatus", new string[] { "Name", "Enabled", "Configuration" }, new string[] { "Name", "Enabled", "Configuration" }); parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Name", typeName)); parameters.Add(new Parameter(ParameterType.Boolean, "Enabled", true)); parameters.Add(new Parameter(ParameterType.String, "Configuration", "")); command = builder.GetCommand(transaction, query, parameters); ExecuteNonQuery(command, false); } }
/// <summary> /// Saves data for a new document. /// </summary> /// <param name="document">The document.</param> /// <param name="content">The content words.</param> /// <param name="title">The title words.</param> /// <param name="keywords">The keywords.</param> /// <param name="state">A state object passed from the index (can be <c>null</c> or a <see cref="T:DbTransaction" />).</param> /// <returns>The number of stored occurrences.</returns> private int SaveDataForDocument(IDocument document, WordInfo[] content, WordInfo[] title, WordInfo[] keywords, object state) { // 1. Insert document // 2. Insert all new words // 3. Load all word IDs // 4. Insert mappings // On error, return without rolling back if state != null, rollback otherwise // On completion, commit if state == null ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); DbTransaction transaction = null; if(state != null) transaction = (DbTransaction)state; else { DbConnection connection = builder.GetConnection(connString); transaction = BeginTransaction(connection); } uint freeDocumentId = GetFreeElementId(IndexElementType.Documents, transaction); uint freeWordId = GetFreeElementId(IndexElementType.Words, transaction); // Insert the document string query = queryBuilder.InsertInto("IndexDocument", new string[] { "Id", "Name", "Title", "TypeTag", "DateTime" }, new string[] { "Id", "Name", "Title", "TypeTag", "DateTime" }); List<Parameter> parameters = new List<Parameter>(5); parameters.Add(new Parameter(ParameterType.Int32, "Id", (int)freeDocumentId)); parameters.Add(new Parameter(ParameterType.String, "Name", document.Name)); parameters.Add(new Parameter(ParameterType.String, "Title", document.Title)); parameters.Add(new Parameter(ParameterType.String, "TypeTag", document.TypeTag)); parameters.Add(new Parameter(ParameterType.DateTime, "DateTime", document.DateTime)); DbCommand command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) != 1) { if(state == null) RollbackTransaction(transaction); return -1; } document.ID = freeDocumentId; List<WordInfo> allWords = new List<WordInfo>(content.Length + title.Length + keywords.Length); allWords.AddRange(content); allWords.AddRange(title); allWords.AddRange(keywords); List<WordInfo> existingWords = new List<WordInfo>(allWords.Count / 2); Dictionary<string, uint> wordIds = new Dictionary<string, uint>(1024); // Try to blindly insert all words (assumed to be lowercase and clean from diacritics) query = queryBuilder.InsertInto("IndexWord", new string[] { "Id", "Text" }, new string[] { "Id", "Text" }); parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.Int32, "Id", 0)); parameters.Add(new Parameter(ParameterType.String, "Text", "")); foreach(WordInfo word in allWords) { parameters[0].Value = (int)freeWordId; parameters[1].Value = word.Text; command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false, false) == 1) { wordIds.Add(word.Text, freeWordId); freeWordId++; } else { existingWords.Add(word); } } // Load IDs of all existing words query = queryBuilder.SelectFrom("IndexWord", new string[] { "Id" }); query = queryBuilder.Where(query, "Text", WhereOperator.Equals, "Text"); parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Text", "")); foreach(WordInfo word in existingWords) { parameters[0].Value = word.Text; command = builder.GetCommand(transaction, query, parameters); int id = ExecuteScalar<int>(command, -1, false); if(id == -1) { if(state == null) RollbackTransaction(transaction); return -1; } if(!wordIds.ContainsKey(word.Text)) { wordIds.Add(word.Text, (uint)id); } else if(wordIds[word.Text] != (uint)id) throw new InvalidOperationException("Word ID mismatch"); } // Insert all mappings query = queryBuilder.InsertInto("IndexWordMapping", new string[] { "Word", "Document", "FirstCharIndex", "WordIndex", "Location" }, new string[] { "Word", "Document", "FirstCharIndex", "WordIndex", "Location" }); parameters = new List<Parameter>(5); parameters.Add(new Parameter(ParameterType.Int32, "Word", 0)); parameters.Add(new Parameter(ParameterType.Int32, "Document", (int)freeDocumentId)); parameters.Add(new Parameter(ParameterType.Int16, "FirstCharIndex", 0)); parameters.Add(new Parameter(ParameterType.Int16, "WordIndex", 0)); parameters.Add(new Parameter(ParameterType.Byte, "Location", 0)); foreach(WordInfo word in allWords) { parameters[0].Value = (int)wordIds[word.Text]; parameters[1].Value = (int)freeDocumentId; parameters[2].Value = (short)word.FirstCharIndex; parameters[3].Value = (short)word.WordIndex; parameters[4].Value = word.Location.Location; command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) != 1) { if(state == null) RollbackTransaction(transaction); return -1; } } if(state == null) CommitTransaction(transaction); return allWords.Count; }
/// <summary> /// Stores the content for a revision. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="content">The content.</param> /// <param name="revision">The revision.</param> /// <returns><c>true</c> if the content is stored, <c>false</c> otherwise.</returns> private bool SetContent(DbTransaction transaction, PageContent content, int revision) { string name, nspace; NameTools.ExpandFullName(content.PageInfo.FullName, out nspace, out name); if(nspace == null) nspace = ""; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.InsertInto("PageContent", new string[] { "Page", "Namespace", "Revision", "Title", "User", "LastModified", "Comment", "Content", "Description" }, new string[] { "Page", "Namespace", "Revision", "Title", "User", "LastModified", "Comment", "Content", "Description" }); List<Parameter> parameters = new List<Parameter>(9); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.Int16, "Revision", revision)); parameters.Add(new Parameter(ParameterType.String, "Title", content.Title)); parameters.Add(new Parameter(ParameterType.String, "User", content.User)); parameters.Add(new Parameter(ParameterType.DateTime, "LastModified", content.LastModified)); if(!string.IsNullOrEmpty(content.Comment)) parameters.Add(new Parameter(ParameterType.String, "Comment", content.Comment)); else parameters.Add(new Parameter(ParameterType.String, "Comment", DBNull.Value)); parameters.Add(new Parameter(ParameterType.String, "Content", content.Content)); if(!string.IsNullOrEmpty(content.Description)) parameters.Add(new Parameter(ParameterType.String, "Description", content.Description)); else parameters.Add(new Parameter(ParameterType.String, "Description", DBNull.Value)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows != 1) return false; if(content.Keywords.Length > 0) { parameters = new List<Parameter>(content.Keywords.Length * 4); string fullQuery = ""; int count = 0; string countString; foreach(string kw in content.Keywords) { countString = count.ToString(); query = queryBuilder.InsertInto("PageKeyword", new string[] { "Page", "Namespace", "Revision", "Keyword" }, new string[] { "Page" + countString, "Namespace" + countString, "Revision" + countString, "Keyword" + countString }); fullQuery = queryBuilder.AppendForBatch(fullQuery, query); parameters.Add(new Parameter(ParameterType.String, "Page" + countString, name)); parameters.Add(new Parameter(ParameterType.String, "Namespace" + countString, nspace)); parameters.Add(new Parameter(ParameterType.Int16, "Revision" + countString, revision)); parameters.Add(new Parameter(ParameterType.String, "Keyword" + countString, kw)); count++; } command = builder.GetCommand(transaction, fullQuery, parameters); rows = ExecuteNonQuery(command, false); return rows == content.Keywords.Length; } else return true; }
/// <summary> /// Closes the sql index output. /// </summary> public override void Close() { string fileName = _fileName; // make sure it's all written out _indexOutput.Flush(); long originalLength = _indexOutput.Length(); _indexOutput.Close(); Stream fileStream = new StreamInput(CacheDirectory.OpenInput(fileName)); try { // push the file stream up to the db. ICommandBuilder builder = _sqlStorageProviderUtility.GetCommandBuilder2(); DbConnection connection = builder.GetConnection(_connString); DbTransaction transaction = _sqlStorageProviderUtility.BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); //bool fileExists = FileExists(transaction, _wiki, _fileName); // To achieve decent performance, an UPDATE query is issued if the file exists, // otherwise an INSERT query is issued string query; List <Parameter> parameters; byte[] fileData = null; int size = Tools.ReadStream(fileStream, ref fileData, MaxFileSize); if (size < 0) { _sqlStorageProviderUtility.RollbackTransaction(transaction); throw new ArgumentException("Source Stream contains too much data", "sourceStream"); } //if(fileExists) { // query = queryBuilder.Update("SearchIndex", new string[] { "Size", "LastModified", "Data" }, new string[] { "Size", "LastModified", "Data" }); // query = queryBuilder.Where(query, "Wiki", WhereOperator.Equals, "Wiki"); // query = queryBuilder.AndWhere(query, "Name", WhereOperator.Equals, "Name"); // parameters = new List<Parameter>(5); // parameters.Add(new Parameter(ParameterType.String, "Wiki", _wiki)); // parameters.Add(new Parameter(ParameterType.Int64, "Size", (long)originalLength)); // parameters.Add(new Parameter(ParameterType.DateTime, "LastModified", DateTime.Now.ToUniversalTime())); // parameters.Add(new Parameter(ParameterType.ByteArray, "Data", fileData)); // parameters.Add(new Parameter(ParameterType.String, "Name", _fileName)); //} //else { query = queryBuilder.InsertInto("SearchIndex", new string[] { "Wiki", "Name", "Size", "LastModified", "Data" }, new string[] { "Wiki", "Name", "Size", "LastModified", "Data" }); parameters = new List <Parameter>(5); parameters.Add(new Parameter(ParameterType.String, "Wiki", _wiki)); parameters.Add(new Parameter(ParameterType.String, "Name", _fileName)); parameters.Add(new Parameter(ParameterType.Int64, "Size", (long)originalLength)); parameters.Add(new Parameter(ParameterType.DateTime, "LastModified", DateTime.Now.ToUniversalTime())); parameters.Add(new Parameter(ParameterType.ByteArray, "Data", fileData)); //} DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = _sqlStorageProviderUtility.ExecuteNonQuery(command, false); if (rows == 1) { _sqlStorageProviderUtility.CommitTransaction(transaction); } else { _sqlStorageProviderUtility.RollbackTransaction(transaction); } } finally { fileStream.Dispose(); } // clean up _indexOutput = null; GC.SuppressFinalize(this); }
/// <summary> /// Merges two Categories. /// </summary> /// <param name="source">The source Category.</param> /// <param name="destination">The destination Category.</param> /// <returns>The correct <see cref="T:CategoryInfo" /> object.</returns> /// <remarks>The destination Category remains, while the source Category is deleted, and all its Pages re-bound /// in the destination Category.</remarks> /// <exception cref="ArgumentNullException">If <paramref name="source"/> or <paramref name="destination"/> are <c>null</c>.</exception> public CategoryInfo MergeCategories(CategoryInfo source, CategoryInfo destination) { if(source == null) throw new ArgumentNullException("source"); if(destination == null) throw new ArgumentNullException("destination"); // 1. Check for same namespace // 2. Load all pages in source // 3. Load all pages in destination // 4. Merge lists in memory // 5. Delete all destination bindings // 6. Delete source cat // 7. Insert new bindings stored in memory string sourceNs = NameTools.GetNamespace(source.FullName); string destinationNs = NameTools.GetNamespace(destination.FullName); // If one is null and the other not null, fail if(sourceNs == null && destinationNs != null || sourceNs != null && destinationNs == null) return null; else { // Both non-null or both null if(sourceNs != null) { // Both non-null, check names NamespaceInfo tempSource = new NamespaceInfo(sourceNs, this, null); NamespaceInfo tempDest = new NamespaceInfo(destinationNs, this, null); // Different names, fail if(new NamespaceComparer().Compare(tempSource, tempDest) != 0) return null; } // else both null, OK } string nspace = sourceNs != null ? sourceNs : ""; ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); CategoryInfo actualSource = GetCategory(transaction, source.FullName); CategoryInfo actualDestination = GetCategory(transaction, destination.FullName); if(actualSource == null) { RollbackTransaction(transaction); return null; } if(actualDestination == null) { RollbackTransaction(transaction); return null; } string destinationName = NameTools.GetLocalName(actualDestination.FullName); string[] mergedPages = MergeArrays(actualSource.Pages, actualDestination.Pages); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("CategoryBinding"); query = queryBuilder.Where(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "Category", WhereOperator.Equals, "Category"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.String, "Category", destinationName)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == -1) { RollbackTransaction(transaction); return null; } if(!RemoveCategory(transaction, source)) { RollbackTransaction(transaction); return null; } string finalQuery = ""; parameters = new List<Parameter>(MaxStatementsInBatch * 3); rows = 0; int count = 1; string countString; foreach(string page in mergedPages) { // This batch is executed in small chunks (MaxStatementsInBatch) to avoid exceeding DB's max batch length/size countString = count.ToString(); query = queryBuilder.InsertInto("CategoryBinding", new string[] { "Namespace", "Category", "Page" }, new string[] { "Namespace" + countString, "Category" + countString, "Page" + countString }); finalQuery = queryBuilder.AppendForBatch(finalQuery, query); parameters.Add(new Parameter(ParameterType.String, "Namespace" + countString, nspace)); parameters.Add(new Parameter(ParameterType.String, "Category" + countString, destinationName)); parameters.Add(new Parameter(ParameterType.String, "Page" + countString, NameTools.GetLocalName(page))); count++; if(count == MaxStatementsInBatch) { // Batch is complete -> execute command = builder.GetCommand(transaction, finalQuery, parameters); rows += ExecuteNonQuery(command, false); count = 1; finalQuery = ""; parameters.Clear(); } } if(finalQuery.Length > 0) { // Execute remaining queries, if any command = builder.GetCommand(transaction, finalQuery, parameters); rows += ExecuteNonQuery(command, false); } if(rows == mergedPages.Length) { CommitTransaction(transaction); CategoryInfo result = new CategoryInfo(actualDestination.FullName, this); result.Pages = mergedPages; return result; } else { RollbackTransaction(transaction); return null; } }
/// <summary> /// Stores the value of a Setting. /// </summary> /// <param name="name">The name of the Setting.</param> /// <param name="value">The value of the Setting. Value cannot contain CR and LF characters, which will be removed.</param> /// <returns>True if the Setting is stored, false otherwise.</returns> /// <remarks>This method stores the Value immediately.</remarks> public bool SetSetting(string name, string value) { if (name == null) { throw new ArgumentNullException("name"); } if (name.Length == 0) { throw new ArgumentException("Name cannot be empty", "name"); } // 1. Delete old value, if any // 2. Store new value // Nulls are converted to empty strings if (value == null) { value = ""; } ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("GlobalSetting"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List <Parameter> parameters = new List <Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", name)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if (rows == -1) { RollbackTransaction(transaction); return(false); // Deletion command failed (0-1 are OK) } query = queryBuilder.InsertInto("GlobalSetting", new string[] { "Name", "Value" }, new string[] { "Name", "Value" }); parameters = new List <Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Value", value)); command = builder.GetCommand(transaction, query, parameters); rows = ExecuteNonQuery(command, false); if (rows == 1) { CommitTransaction(transaction); } else { RollbackTransaction(transaction); } return(rows == 1); }