The "Row" Command |
This command is used to either insert or replace a single row or update one or more rows. As you are directly manipulating Windows Installer tables your best source of information would be generic Windows Installer documentation. Almost all database manipulations MAKEMSI does internally uses this command to do the work.
If you are unsure how as to how to code "row" commands (whether or not you are providing an SQL where clause) you can use the "MsiDiff.VBS" command to create them for you. Simply create a backup of your database and make the changes with "ORCA". It is then a simple matter of using the "Compare -> MAKEMSI Format" shortcut to compare the "before" and "after" databases and generate the appropriate commands for you to paste in.
The command must be used within a "Table" block so that it knows which Windows Installer table is being updated.
This command takes these parameters:
You will be told if the column name is invalid (please remember that it is case sensitive). Columns are modified in the order supplied.
MAKEMSI knows the type of column and therefore how to correctly apply the value you supply as follows:
If not supplied then an empty record is created before being populated with the information you supply. You must therefore supply values for at least all of the fields whose definitions indicated that they were not allowed to be null (otherwise a runtime error will result - this is probably the most likely reason for any failure). If a record exists with the same primary keys it will be updated.
Some good examples can be found here:
You supply any string value for this parameter, which if it appears anywhere in any columns value will be replaced with a reference (vbscript expression) to the current fields value.
This would for example allow you to modify one or more bits within an attributes integer. For string fields be sure to use "*" in front of the column name. Some partial samples are:
... @SelfRef="{*}" *Attributes="{*} or msidbControlAttributesNoPrefix" ... @SelfRef="{ColVal}" *Text=^replace({ColVal}, "icense", "icence")^ ...
For more complex requirements you can also directly reference fields (of the "oRec" record) such as with "oRec.StringData(2)" to get the data from the tables second column as a string. For even more complex requirements you would use the "@CODE" parameter.
If you are making row changes then you probably want to use the "UPDATE" parameter on the "/Row" command (see it for some example code). By default updates to the row fields are not written back to the msi.
The VBSCRIPT variable containing the record is called "oRec", fields are ordered/typed as per the table's TableDefinition (although "column macros" make it easier to access the records data).
The VBSCRIPT is executed before any of the records fields have been modified.
The default for this parameter can be set via the DEFAULT_ROWS_METHOD macro. This is initially "REPLACE".
I recommend using as tight a validation as possible, particularly if your built MSIs are not being automatically validated. Only you will know what constitutes an error for any particular row command, for example if you have duplicated a key do you intend to replace the existing record or is this a mistake?
You should pass "" to turn off all row validation (not recommended) otherwise you should pass a validation mode followed by zero or more exclusions (all space separated).
Valid modes are:
All exclusions begin with a minus sign ("-") and apply to all columns in a table unless it starts with a column's name followed by a colon (":"). An example of two exclusions are "-Sequence:UNDERFLOW -MISSINGDATA". The following are all valid types of exclusions:
Note that you can override the text of the above mentioned error messages with your own alternative by creating macros such as "@VALIDATE_TEXT_FOR_MISSINGDATA".
If an error is detected then all columns failing validation are listed. It appears to be a Windows installer bug that "null" fields (in non-nullable columns) are not reported.
If the "@WHERE" parameter is used then the "DEFAULT_ROW_VALIDATE_WHERE" macro is used for the default value (initially "FETCH"), otherwise the "DEFAULT_ROW_VALIDATE_NO_WHERE" macro is used for (initially "FIELD").
EXAMPLE |
As well as the examples shown below you should also have a look at those for the "/Row" command.
An example that overrides the default row validation:
<$Table "_Storages" CREATE="N"> <$Row Name="SomeMsi" Data="SomeMsiWeWillPerformNestedInstallOn.msi" @Validate="NEW -MISSINGDATA"> <$/Table> <$MsiExtraFiles "Data1.cab">
Get the current value of the "ProductCode" property (abort if not found):
dim MsiProductCode : MsiProductCode = "" <$Table "Property"> <$Row @Where="Property = 'ProductCode'" @OK=^? = 1^ @Code="Y"> MsiProductCode = <$COLSTR.Property.Value> <$/Row> <$/Table> say "MsiProductCode = " & MsiProductCode
Some table manipulation:
<$TableDefinition "CustomTable4Testing"> <$Column "Field1" TYPE="s72" KEY="Y"> <$Column "Field2" TYPE="s72"> <$Column "Field3" TYPE="S72"> <$Column "Field4" TYPE="S72"> <$/TableDefinition> <$Table "CustomTable4Testing"> ;--- Create the table ---------------------------------------------------- <$TableCreate> ;--- Insert some fields -------------------------------------------------- <$Row Field1="1.1" Field2="1.2" Field3="1.3" Field4="1.4"> <$Row Field1="2.1" Field2="2.2" Field3="2.3" Field4="2.4"> <$Row Field1="3.1" Field2="3.2" Field3="3.3" Field4="3.4"> <$Row Field1="4.1" Field2="4.2" Field3="4.3" Field4="4.4"> <$Row Field1="5.1" Field2="5.2" Field3="5.3" Field4="5.4"> <$Row Field1="6.1" Field2="6.2" Field3="6.3" Field4="6.4"> <$Row Field1="7.1" Field2="7.2" Field3="7.3" Field4="7.4"> <$Row Field1="8.1" Field2="8.2" Field3="8.3" Field4="8.4"> <$Row Field1="9.1" Field2="9.2" Field3="9.3" Field4="9.4"> <$Row Field1="10.1" Field2="9.2"> ;;WORKS as F3 & F4 allow NULLS ;--- Update some rows ("WHERE" clause used, expect 2 matches) ------------ <$Row @Where="Field4='5.4' or Field4='6.4'" @OK="=2" Field2="bbbb" Field3="cccc"> <$/Table> ;--- Delete all rows in the "Error" table ----------------------------------- <$Table "Error"> <$RowsDeleteAll> <$/Table> ;--- Change the "Attributes" column on some rows in the "Control" table ----- <$Table "Control"> ;--- The bit map should be "Fixed" size (make sure "fixed" bit set) ------ <$Row @Where="`Control` = 'BannerBitmap'" Attributes=^{*} or &H00100000^ @SelfRef=^{*}^ @OK=^? > 0^> <$/Table> ;--- Remove the "LicenseAgreementDlg" Dialog (from flow of events) ---------- <$Table "ControlEvent"> ;--- Take care of the "Next" button from the "WelcomeDlg" ---------------- #( <$Row @OK=^? = 1^ @Where="`Dialog_` = 'WelcomeDlg' and `Control_` = 'Next' and `Event`='NewDialog' and `Argument` = 'LicenseAgreementDlg' and `Condition` = '1'" Argument="UserRegistrationDlg" ;;Skip licence and go straight here! > #) ;--- Take care of the "Back" button from the "UserRegistrationDlg" ------- #( <$Row @OK=^? = 1^ @Where="`Dialog_` = 'UserRegistrationDlg' and `Control_` = 'Back' and `Event`='NewDialog' and `Argument` = 'LicenseAgreementDlg' and `Condition` = '1'" Argument="WelcomeDlg" ;;Skip licence and go straight here! > #) <$/Table>
Changing spelling of "license" to "licence" in the licence dialog:
#if ['<$UISAMPLE_LICENCE_SPELLING_C_OR_S>' = 'c'] ;--- We are changing spelling from "license" to "licence" --------------- #ifndef REMOVED_LicenseAgreementDlg <$Table "Control"> #( ;--- Look at licence dialog rows ------------------------------------ <$Row @Where=^`Dialog_` = 'LicenseAgreementDlg'^ @SelfRef="{*}" *Text=^replace({*}, "icense", "icence")^ > #) <$/Table> #endif <$Table "RadioButton"> #( ;--- Look at all rows ----------------------------------------------- <$Row @Where=^^ @SelfRef="{*}" *Text=^replace({*}, "icense", "icence")^ > #) <$/Table> #endif