/// <summary> /// Removes a Message. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="page">The Page.</param> /// <param name="id">The ID of the Message to remove.</param> /// <param name="removeReplies">A value specifying whether or not to remove the replies.</param> /// <returns>True if the Message is removed successfully.</returns> private bool RemoveMessage(DbTransaction transaction, PageInfo page, int id, bool removeReplies) { string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; Message[] messages = GetMessages(transaction, page); if(messages == null) return false; Message message = FindMessage(messages, id); if(message == null) return false; Message parent = FindAnchestor(messages, id); int parentId = parent != null ? parent.ID : -1; UnindexMessage(page, message.ID, message.Subject, message.DateTime, message.Body, transaction); if(removeReplies) { // Recursively remove all replies BEFORE removing parent (depth-first) foreach(Message reply in message.Replies) { if(!RemoveMessage(transaction, page, reply.ID, true)) return false; } } // Remove this message ICommandBuilder builder = GetCommandBuilder(); 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"); query = queryBuilder.AndWhere(query, "Id", WhereOperator.Equals, "Id"); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.Int16, "Id", (short)id)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(!removeReplies && rows == 1) { // Update replies' parent id query = queryBuilder.Update("Message", new string[] { "Parent" }, new string[] { "NewParent" }); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "Parent", WhereOperator.Equals, "OldParent"); parameters = new List<Parameter>(4); if(parentId != -1) parameters.Add(new Parameter(ParameterType.Int16, "NewParent", parentId)); else parameters.Add(new Parameter(ParameterType.Int16, "NewParent", DBNull.Value)); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.Int16, "OldParent", (short)id)); command = builder.GetCommand(transaction, query, parameters); rows = ExecuteNonQuery(command, false); } return rows > 0; }
/// <summary> /// Removes the user group membership for a user. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="username">The username.</param> private void RemoveUserGroupMembership(DbTransaction transaction, string username) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("UserGroupMembership"); query = queryBuilder.Where(query, "User", WhereOperator.Equals, "Username"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Username", username)); DbCommand command = builder.GetCommand(transaction, query, parameters); ExecuteNonQuery(command, false); }
/// <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( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) 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) { finalQuery = queryBuilder.BuildBatchCommand(finalQuery); command = builder.GetCommand(transaction, finalQuery, parameters); rowsDone += ExecuteNonQuery(command, false, true, count); finalQuery = ""; count = 1; parameters.Clear(); } } if(finalQuery.Length > 0) { command = builder.GetCommand(transaction, finalQuery, parameters); rowsDone += ExecuteNonQuery(command, false, true, count); } if(rowsDone == allMessages.Count) { foreach(Message msg in messages) { IndexMessageTree(page, msg, transaction); } CommitTransaction(transaction); return true; } else { RollbackTransaction(transaction); return false; } }
/// <summary> /// Deletes some ACL entries. /// </summary> /// <param name="entries">The entries to delete.</param> /// <returns><c>true</c> if one or more entries were deleted, <c>false</c> otherwise.</returns> private bool DeleteEntries(AclEntry[] entries) { ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); foreach(AclEntry entry in entries) { string query = queryBuilder.DeleteFrom("AclEntry"); query = queryBuilder.Where(query, "Resource", WhereOperator.Equals, "Resource"); query = queryBuilder.AndWhere(query, "Action", WhereOperator.Equals, "Action"); query = queryBuilder.AndWhere(query, "Subject", WhereOperator.Equals, "Subject"); 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)); DbCommand command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) <= 0) { RollbackTransaction(transaction); return false; } } CommitTransaction(transaction); return true; }
/// <summary> /// Cuts the recent changes if necessary. /// </summary> private void CutRecentChangesIfNecessary() { ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectCountFrom("RecentChange"); DbCommand command = builder.GetCommand(transaction, query, new List<Parameter>()); int rows = ExecuteScalar<int>(command, -1, false); int maxChanges = int.Parse(host.GetSettingValue(SettingName.MaxRecentChanges)); if(rows > maxChanges) { // Remove 10% of old changes to avoid 1-by-1 deletion every time a change is made int entriesToDelete = maxChanges / 10; if(entriesToDelete > rows) entriesToDelete = rows; //entriesToDelete += entriesToDelete / 10; // This code is not optimized, but it surely works in most DBMS query = queryBuilder.SelectFrom("RecentChange", new string[] { "Id" }); query = queryBuilder.OrderBy(query, new string[] { "Id" }, new Ordering[] { Ordering.Asc }); command = builder.GetCommand(transaction, query, new List<Parameter>()); DbDataReader reader = ExecuteReader(command); List<int> ids = new List<int>(entriesToDelete); if(reader != null) { while(reader.Read() && ids.Count < entriesToDelete) { ids.Add((int)Convert.ChangeType(reader["Id"],typeof(int))); } CloseReader(reader); } if(ids.Count > 0) { // Given that the IDs to delete can be many, the query is split in many chunks, each one deleting 50 items // This works-around the problem of too many parameters in a RPC call of Oracle // See also CutLog for(int chunk = 0; chunk <= ids.Count / MaxParametersInQuery; chunk++) { query = queryBuilder.DeleteFrom("RecentChange"); List<string> parms = new List<string>(MaxParametersInQuery); List<Parameter> parameters = new List<Parameter>(MaxParametersInQuery); for(int i = chunk * MaxParametersInQuery; i < Math.Min(ids.Count, (chunk + 1) * MaxParametersInQuery); i++) { parms.Add("P" + i.ToString()); parameters.Add(new Parameter(ParameterType.Int32, parms[parms.Count - 1], ids[i])); } query = queryBuilder.WhereIn(query, "Id", parms.ToArray()); command = builder.GetCommand(transaction, query, parameters); if(ExecuteNonQuery(command, false) < 0) { RollbackTransaction(transaction); return; } } } } CommitTransaction(transaction); }
/// <summary> /// Clears the index. /// </summary> /// <param name="state">A state object passed from the index.</param> private void ClearIndex(object state) { // state can be null, depending on when the method is called ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("IndexWordMapping"); query = queryBuilder.AppendForBatch(query, queryBuilder.DeleteFrom("IndexWord")); query = queryBuilder.AppendForBatch(query, queryBuilder.DeleteFrom("IndexDocument")); query= queryBuilder.BuildBatchCommand(query); DbCommand command = null; if (state == null) command = builder.GetCommand(connString, query, new List<Parameter>()); else command = builder.GetCommand((DbTransaction)state, query, new List<Parameter>()); ExecuteNonQuery(command, state == null); }
/// <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> /// Removes a Category. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="category">The Category to remove.</param> /// <returns>True if the Category has been removed successfully.</returns> private bool RemoveCategory(DbTransaction transaction, CategoryInfo category) { string nspace = null; string name = null; NameTools.ExpandFullName(category.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("Category"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); return rows > 0; }
/// <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 finalQuery = queryBuilder.BuildBatchCommand(finalQuery); command = builder.GetCommand(transaction, finalQuery, parameters); rows += ExecuteNonQuery(command, false, true, count); count = 1; finalQuery = ""; parameters.Clear(); } } if(finalQuery.Length > 0) { // Execute remaining queries, if any command = builder.GetCommand(transaction, finalQuery, parameters); rows += ExecuteNonQuery(command, false, true, count); } if(rows == mergedPages.Length) { CommitTransaction(transaction); CategoryInfo result = new CategoryInfo(actualDestination.FullName, this); result.Pages = mergedPages; return result; } else { RollbackTransaction(transaction); return null; } }
/// <summary> /// Deletes a directory and all its contents. /// </summary> /// <param name="transaction">The current transaction to use.</param> /// <param name="fullPath">The full path of the directory.</param> /// <returns><c>true</c> if the directory is deleted, <c>false</c> otherwise.</returns> private bool DeleteDirectory(DbTransaction transaction, string fullPath) { string[] dirs = ListDirectories(transaction, fullPath); foreach(string dir in dirs) { if(!DeleteDirectory(transaction, dir)) { return false; } } ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("Directory"); query = queryBuilder.Where(query, "FullPath", WhereOperator.Equals, "FullPath"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "FullPath", fullPath)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); return rows > 0; }
/// <summary> /// Removes a namespace. /// </summary> /// <param name="nspace">The namespace to remove.</param> /// <returns><c>true</c> if the namespace is removed, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="nspace"/> is <c>null</c>.</exception> public bool RemoveNamespace(NamespaceInfo nspace) { if( nspace==null) throw new ArgumentNullException("nspace"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); foreach(PageInfo page in GetPages(transaction, nspace)) { PageContent content = GetContent(transaction, page, CurrentRevision); UnindexPage(content, transaction); foreach(Message msg in GetMessages(transaction, page)) { UnindexMessageTree(page, msg, transaction); } } QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("Namespace"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", nspace.Name)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows > 0) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows > 0; }
/// <summary> /// Deletes a File. /// </summary> /// <param name="fullName">The full name of the File.</param> /// <returns><c>true</c> if the File is deleted, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="fullName"/> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="fullName"/> is empty or it does not exist.</exception> public bool DeleteFile(string fullName) { if(fullName == null) throw new ArgumentNullException("fullName"); if(fullName.Length == 0) throw new ArgumentException("Full Name cannot be empty", "fullName"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(!FileExists(transaction, fullName)) { RollbackTransaction(transaction); throw new ArgumentException("File does not exist", "fullName"); } QueryBuilder queryBuilder = new QueryBuilder(builder); string directory, filename; SplitFileFullName(fullName, out directory, out filename); string query = queryBuilder.DeleteFrom("File"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Directory", WhereOperator.Equals, "Directory"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", filename)); parameters.Add(new Parameter(ParameterType.String, "Directory", directory)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == 1) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows == 1; }
/// <summary> /// Deletes 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> /// <returns><c>true</c> if the Attachment is deleted, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="pageInfo"/> or <paramref name="name"/> are <c>null</c>.</exception> /// <exception cref="ArgumentException">If <paramref name="name"/> is empty or if the page or attachment do not exist.</exception> public bool DeletePageAttachment(PageInfo pageInfo, string name) { 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"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(!AttachmentExists(transaction, pageInfo, name)) { RollbackTransaction(transaction); throw new ArgumentException("Attachment does not exist", "name"); } QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("Attachment"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Page", WhereOperator.Equals, "Page"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Page", pageInfo.FullName)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == 1) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows == 1; }
/// <summary> /// Removes a user data element. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="username">The username.</param> /// <param name="key">The key.</param> /// <returns><c>true</c> if the data element is removed, <c>false</c> otherwise.</returns> private bool RemoveUserData(DbTransaction transaction, string username, string key) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("UserData"); query = queryBuilder.Where(query, "User", WhereOperator.Equals, "Username"); query = queryBuilder.AndWhere(query, "Key", WhereOperator.Equals, "Key"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Username", username)); parameters.Add(new Parameter(ParameterType.String, "Key", key)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); return rows != -1; // Success also if no elements are removed }
/// <summary> /// Removes a Navigation Path. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="path">The navigation path to remove.</param> /// <returns><c>true</c> if the path is removed, <c>false</c> otherwise.</returns> private bool RemoveNavigationPath(DbConnection connection, NavigationPath path) { string nspace, name; NameTools.ExpandFullName(path.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("NavigationPath"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(connection, query, parameters); int rows = ExecuteNonQuery(command, false); return rows > 0; }
/// <summary> /// Deletes a revision of a page content. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="page">The page.</param> /// <param name="revision">The revision.</param> /// <returns><c>true</c> if the content ir deleted, <c>false</c> otherwise.</returns> private bool DeleteContent(DbConnection connection, PageInfo page, int revision) { string name, nspace; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("PageContent"); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "Revision", WhereOperator.Equals, "Revision"); List<Parameter> parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.String, "Revision", revision)); DbCommand command = builder.GetCommand(connection, query, parameters); int rows = ExecuteNonQuery(command, false); return rows > 0; }
/// <summary> /// Removes a content template. /// </summary> /// <param name="transaction">A database transaction.</param> /// <param name="name">The name of the template to remove.</param> /// <returns><c>true</c> if the template is removed, <c>false</c> otherwise.</returns> private bool RemoveContentTemplate(DbTransaction transaction, string name) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("ContentTemplate"); 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); return rows == 1; }
/// <summary> /// Deletes all data associated to a document. /// </summary> /// <param name="document">The document.</param> /// <param name="state">A state object passed from the index (can be <c>null</c> or a <see cref="T:DbTransaction" />).</param> private void DeleteDataForDocument(IDocument document, object state) { // 1. Delete all data related to a document // 2. Delete all words that have no more mappings ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("IndexDocument"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "DocName"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "DocName", document.Name)); string subQuery = queryBuilder.SelectFrom("IndexWordMapping", new string[] { "Word" }); subQuery = queryBuilder.GroupBy(subQuery, new string[] { "Word" }); string query2 = queryBuilder.DeleteFrom("IndexWord"); query2 = queryBuilder.WhereNotInSubquery(query2, "IndexWord", "Id", subQuery); query = queryBuilder.AppendForBatch(query, query2); query = queryBuilder.BuildBatchCommand(query); DbCommand command = null; if(state != null) command = builder.GetCommand((DbTransaction)state, query, parameters); else command = builder.GetCommand(connString, query, parameters); // Close only if state is null ExecuteNonQuery(command, state == 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 and empty strings are converted to " " if(string.IsNullOrEmpty(value)) 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> /// Deletes the Backups of a Page, up to a specified revision. /// </summary> /// <param name="page">The Page to delete the backups of.</param> /// <param name="revision">The newest revision to delete (newer revision are kept) o -1 to delete all the Backups.</param> /// <returns><c>true</c> if the deletion succeeded, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/> is <c>null</c>.</exception> /// <exception cref="ArgumentOutOfRangeException">If <paramref name="revision"/> is less than -1.</exception> public bool DeleteBackups(PageInfo page, int revision) { if(page == null) throw new ArgumentNullException("page"); if(revision < -1) throw new ArgumentOutOfRangeException("revision", "Invalid Revision"); // 1. Retrieve target content (revision-1 = first kept revision) // 2. Replace the current content (delete, store) // 3. Delete all older revisions up to the specified on (included) "N-m...N" // 4. Re-number remaining revisions starting from FirstRevision (zero) to revision-1 (don't re-number revs -1, -100) ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(GetPage(transaction, page.FullName) == null) { RollbackTransaction(transaction); return false; } int[] baks = GetBackups(transaction, page); if(baks.Length > 0 && revision > baks[baks.Length - 1]) { RollbackTransaction(transaction); return true; } string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("PageContent"); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); if(revision != -1) query = queryBuilder.AndWhere(query, "Revision", WhereOperator.LessThanOrEqualTo, "Revision"); query = queryBuilder.AndWhere(query, "Revision", WhereOperator.GreaterThanOrEqualTo, "FirstRevision"); List<Parameter> parameters = new List<Parameter>(4); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); if(revision != -1) parameters.Add(new Parameter(ParameterType.Int16, "Revision", revision)); parameters.Add(new Parameter(ParameterType.Int16, "FirstRevision", FirstRevision)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == -1) { RollbackTransaction(transaction); return false; } if(revision != -1) { int revisionDelta = revision + 1; query = queryBuilder.UpdateIncrement("PageContent", "Revision", -revisionDelta); query = queryBuilder.Where(query, "Page", WhereOperator.Equals, "Page"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); query = queryBuilder.AndWhere(query, "Revision", WhereOperator.GreaterThanOrEqualTo, "FirstRevision"); parameters = new List<Parameter>(3); parameters.Add(new Parameter(ParameterType.String, "Page", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); parameters.Add(new Parameter(ParameterType.Int16, "FirstRevision", FirstRevision)); command = builder.GetCommand(transaction, query, parameters); rows = ExecuteNonQuery(command, false); if(rows > 0) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows >= 0; } else { CommitTransaction(transaction); return true; } }
/// <summary> /// Deletes the outgoing links of a page and all the target links that include the page. /// </summary> /// <param name="page">The full name of the page.</param> /// <returns><c>true</c> if the links are deleted, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <b>page</b> is <c>null</c>.</exception> /// <exception cref="ArgumentException">If <b>page</b> is empty.</exception> public bool DeleteOutgoingLinks(string page) { if(page == null) throw new ArgumentNullException("page"); if(page.Length == 0) throw new ArgumentException("Page cannot be empty", "page"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("OutgoingLink"); query = queryBuilder.Where(query, "Source", WhereOperator.Equals, "Source"); query = queryBuilder.OrWhere(query, "Destination", WhereOperator.Equals, "Destination"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Source", page)); parameters.Add(new Parameter(ParameterType.String, "Destination", page)); DbCommand command = builder.GetCommand(connString, query, parameters); int rows = ExecuteNonQuery(command); return rows > 0; }
/// <summary> /// Removes a Page. /// </summary> /// <param name="page">The Page to remove.</param> /// <returns>True if the Page is removed successfully.</returns> /// <exception cref="ArgumentNullException">If <paramref name="page"/> is <c>null</c>.</exception> public bool RemovePage(PageInfo page) { if(page == null) throw new ArgumentNullException("page"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(IsDefaultPage(transaction, page)) { RollbackTransaction(transaction); return false; } PageContent currentContent = GetContent(transaction, page, CurrentRevision); if(currentContent != null) { UnindexPage(currentContent, transaction); foreach(Message msg in GetMessages(transaction, page)) { UnindexMessageTree(page, msg, transaction); } } RebindPage(transaction, page, new string[0]); string nspace, name; NameTools.ExpandFullName(page.FullName, out nspace, out name); if( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) nspace = " "; QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("Page"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); query = queryBuilder.AndWhere(query, "Namespace", WhereOperator.Equals, "Namespace"); List<Parameter> parameters = new List<Parameter>(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Namespace", nspace)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows > 0) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows > 0; }
/// <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(string.IsNullOrEmpty(tag)) tag = " "; if(string.IsNullOrEmpty(content)) 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> /// 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( string.IsNullOrEmpty(nspace)||string.IsNullOrEmpty(nspace.Trim())) 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++; } finalQuery = queryBuilder.BuildBatchCommand(finalQuery); command = builder.GetCommand(connection, finalQuery, parameters); rows = ExecuteNonQuery(command, false, true, count); return rows == categories.Length; } else return true; }
/// <summary> /// Removes a plugin's assembly. /// </summary> /// <param name="connection">A database connection.</param> /// <param name="filename">The file name of the assembly to remove, such as "Assembly.dll".</param> /// <returns><c>true</c> if the assembly is removed, <c>false</c> otherwise.</returns> private bool DeletePluginAssembly(DbConnection connection, string filename) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("PluginAssembly"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", filename)); DbCommand command = builder.GetCommand(connection, query, parameters); int rows = ExecuteNonQuery(command, false); return rows == 1; }
/// <summary> /// Removes a user group. /// </summary> /// <param name="group">The group to remove.</param> /// <returns><c>true</c> if the group is removed, <c>false</c> otherwise.</returns> /// <exception cref="ArgumentNullException">If <b>group</b> is <c>null</c>.</exception> public bool RemoveUserGroup(UserGroup group) { if(group == null) throw new ArgumentNullException("group"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("UserGroup"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List<Parameter> parameters = new List<Parameter>(1); parameters.Add(new Parameter(ParameterType.String, "Name", group.Name)); DbCommand command = builder.GetCommand(connString, query, parameters); int rows = ExecuteNonQuery(command); return rows == 1; }