// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. namespace WixToolset.Dtf.WindowsInstaller { using System; using System.Text; using System.Collections.Generic; using System.Collections.ObjectModel; /// /// Defines a table in an installation database. /// public class TableInfo { private string name; private ColumnCollection columns; private ReadOnlyCollection primaryKeys; /// /// Creates a table definition. /// /// Name of the table. /// Columns in the table. /// The primary keys of the table. public TableInfo(string name, ICollection columns, IList primaryKeys) { if (String.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } if (columns == null || columns.Count == 0) { throw new ArgumentNullException("columns"); } if (primaryKeys == null || primaryKeys.Count == 0) { throw new ArgumentNullException("primaryKeys"); } this.name = name; this.columns = new ColumnCollection(columns); this.primaryKeys = new List(primaryKeys).AsReadOnly(); foreach (string primaryKey in this.primaryKeys) { if (!this.columns.Contains(primaryKey)) { throw new ArgumentOutOfRangeException("primaryKeys"); } } } internal TableInfo(Database db, string name) { if (db == null) { throw new ArgumentNullException("db"); } if (String.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); } this.name = name; using (View columnsView = db.OpenView("SELECT * FROM `{0}`", name)) { this.columns = new ColumnCollection(columnsView); } this.primaryKeys = new ReadOnlyCollection( TableInfo.GetTablePrimaryKeys(db, name)); } /// /// Gets the name of the table. /// public string Name { get { return this.name; } } /// /// Gets information about the columns in this table. /// ///

/// This property queries the database every time it is called, /// to ensure the returned values are up-to-date. For best performance, /// hold onto the returned collection if using it more than once. ///

public ColumnCollection Columns { get { return this.columns; } } /// /// Gets the names of the columns that are primary keys of the table. /// public IList PrimaryKeys { get { return this.primaryKeys; } } /// /// Gets an SQL CREATE string that can be used to create the table. /// public string SqlCreateString { get { StringBuilder s = new StringBuilder("CREATE TABLE `"); s.Append(this.name); s.Append("` ("); int count = 0; foreach (ColumnInfo col in this.Columns) { if (count > 0) { s.Append(", "); } s.Append(col.SqlCreateString); count++; } s.Append(" PRIMARY KEY "); count = 0; foreach (string key in this.PrimaryKeys) { if (count > 0) { s.Append(", "); } s.AppendFormat("`{0}`", key); count++; } s.Append(')'); return s.ToString(); } } /// /// Gets an SQL INSERT string that can be used insert a new record into the table. /// ///

/// The values are expressed as question-mark tokens, to be supplied by the record. ///

public string SqlInsertString { get { StringBuilder s = new StringBuilder("INSERT INTO `"); s.Append(this.name); s.Append("` ("); int count = 0; foreach (ColumnInfo col in this.Columns) { if (count > 0) { s.Append(", "); } s.AppendFormat("`{0}`", col.Name); count++; } s.Append(") VALUES ("); while (count > 0) { count--; s.Append("?"); if (count > 0) { s.Append(", "); } } s.Append(')'); return s.ToString(); } } /// /// Gets an SQL SELECT string that can be used to select all columns of the table. /// ///

/// The columns are listed explicitly in the SELECT string, as opposed to using "SELECT *". ///

public string SqlSelectString { get { StringBuilder s = new StringBuilder("SELECT "); int count = 0; foreach (ColumnInfo col in this.Columns) { if (count > 0) s.Append(", "); s.AppendFormat("`{0}`", col.Name); count++; } s.AppendFormat(" FROM `{0}`", this.Name); return s.ToString(); } } /// /// Gets a string representation of the table. /// /// The name of the table. public override string ToString() { return this.name; } private static IList GetTablePrimaryKeys(Database db, string table) { if (table == "_Tables") { return new string[] { "Name" }; } else if (table == "_Columns") { return new string[] { "Table", "Number" }; } else if (table == "_Storages") { return new string[] { "Name" }; } else if (table == "_Streams") { return new string[] { "Name" }; } else { int hrec; uint ret = RemotableNativeMethods.MsiDatabaseGetPrimaryKeys( (int) db.Handle, table, out hrec); if (ret != 0) { throw InstallerException.ExceptionFromReturnCode(ret); } using (Record rec = new Record((IntPtr) hrec, true, null)) { string[] keys = new string[rec.FieldCount]; for (int i = 0; i < keys.Length; i++) { keys[i] = rec.GetString(i + 1); } return keys; } } } } }