Declarative Objectivity (DO) Language : Data Clauses : SET Clause
SET Clause
A SET clause updates the value of one or more attributes or collection elements.   
Syntax 
setClause : SET assignment (',' assignment)*;
assignment : targetValue TO replacementValue;
replacementValue : expression;
targetValue : reachableValue ;
Used In 
UPDATE Statement
Quick Look 
Update the reward points for a particular customer:
UPDATE Customer WHERE lastName == 'Green' SET rewardPoints TO 1500;
Increment the rate factor of rental company location in California:
UPDATE Locations WHERE address.state == 'CA' SET rateFactor TO rateFactor + 30;
Assign a postal code to a particular customer’s address:
UPDATE Customer WHERE lastName == 'Green' SET address.postalCode TO '95128';
Update a rental contract so that it references an existing customer:
UPDATE RentalContract WHERE trackingNumber == 10 SET customer TO 3-3-1-5;
Update a rental contract so that it references a newly created vehicle:
UPDATE RentalContract WHERE trackingNumber == 453 SET vehicle TO CREATE Vehicle{license: 'ABC1997'};
Set the first element in a rental company’s list of location references, and return the updated list:
UPDATE RentalCompany SET locations[0] TO 3-3-1-19 RETURN locations;
Replace all of a rental company’s locations in the specified zip code with a specified location, and return the updated list of locations:
UPDATE RentalCompany SET locations[address.postalCode == '95128'] TO 3-3-1-19 RETURN locations;
Set the last 3 service records of a particular vehicle to a particular string:
UPDATE Vehicle WHERE license == 'ABC1997' SET servRecs[-3:] TO 'oil change' RETURN servRecs;
Indicate that all retired vehicles in the rental company are unavailable:
UPDATE RentalCompany SET vehicles[retired == true].available TO false RETURN vehicles;
Discussion 
A SET clause occurs in an UPDATE Statement, and performs one or more assignment operations, where each such operation replaces one or more target values with a replacement value. You can specify multiple assignment operations as a comma-separated list of assignment expressions.
Within each assignment expression, you provide a targetValue expression that evaluates to a single target value or to a sequence of target values within the current context object. A targetValue expression may return:
The value of a direct or indirect attribute of the current context object.
The values of one or more elements in a list or a map that is directly or indirectly related to the current context object.
Note: You cannot change the value of a set element; see Why SET Doesn’t Replace Elements of a Set.
The values of a specified attribute held by multiple elements in a collection that is directly or indirectly related to the current context object.
An assignment expression also includes a replacementValue expression, which may be a simple literal expression or a more complex operator expression whose operands are literals, attribute values of the current context object, and so on.
The value returned by replacementValue must be of a type that is compatible with the type of the specified target value(s). Under most circumstances, the replacement and target values are of exactly the same type. For example, if you are assigning into a Date attribute, you normally specify a Date value as the replacement value. Under certain circumstances, you may need to specify a replacementValue whose type characteristics differ from the target attribute in one or more ways; see Assignment and Type Compatibility.
When targetValue evaluates to a sequence of multiple values, the SET operation replaces each of those values with the same replacement value.
Setting References
When a target value is a reference to a persistent object, the replacement value can be a reference to a newly created object:
You can use a nested CREATE Statement to create (and obtain a reference to) a new object of the referenced class or a subclass of that class:
UPDATE RentalContract WHERE trackingNumber == 453 SET vehicle TO CREATE Vehicle{license: 'ABC1997'};
You can use LET to assign the result of a CREATE Statement to a parameter, and then specify the parameter as the value to be set:
LET v = CREATE Vehicle{license: 'ABC1997'};
UPDATE RentalContract WHERE trackingNumber == 453 SET vehicle TO $v;
Note:If more than one RentalContract is qualified by the WHERE clause, the above statement will create a separate Vehicle object to set in each RentalContract’s vehicle attribute. Each new Vehicle object would have the same specified value for its license attribute, but would have a unique object identifier.
Alternatively, the replacement value can be a reference to an existing object:
You can use an object identifier (OID literal) to specify a reference to an existing object. The object must be of the referenced class or a subclass of that class:
UPDATE RentalContract WHERE trackingNumber == 345 SET vehicle TO 3-3-1-9;
You can query for the object to be set, use LET to assign the query result to a parameter, and extract a reference to the object from the parameter (see Obtaining a Reference to an Existing Object From a Parameter):
LET v = FROM Vehicle WHERE license == 'ABC1997' RETURN license;
UPDATE RentalContract WHERE trackingNumber == 345 SET vehicle TO $v[0].__identifier__;
Setting Bidirectional References
When a target value is a bidirectional reference to a persistent object, the SET operation automatically updates all inverses as appropriate.
For example, the example schema defines a bidirectional relationship between the RentalContract class and the Customer class through a pair of inverse reference attributes (namely, the RentalContract’s customer attribute and the Customer’s rentals attribute). This enables a customer to have multiple rental contracts, where each rental contract belongs to exactly one customer.
Consider what happens when you assign a customer to a particular rental contract. This statement not only assigns the Customer reference to the RentalContract’s customer attribute, but also automatically adds the RentalContract reference to the Customer’s rentals collection:
UPDATE RentalContract WHERE trackingNumber == 10 SET customer TO 3-3-1-5;
Now consider what happens if you subsequently assign a different customer to the same RentalContract:
UPDATE RentalContract WHERE trackingNumber == 10 SET customer TO 3-3-1-26;
This statement:
Explicitly assigns the replacement Customer (3-3-1-26) to the RentalContract’s customer attribute.
Implicitly adds the RentalContract to the rentals collection of the replacement Customer (3-3-1-26).
Implicitly removes the RentalContract from the rentals collection of the replaced Customer (3-3-1-5).
When a SET operation updates a bidirectional-reference attribute that has a to-many inverse, it simply adds a new reference to the inverse; there is no limit to the number of references that can be added. If the inverse is to-one, the SET operation first clears the inverse as necessary to set it to a null reference (0-0-0-0), and then performs the update.
For example, the example schema defines a bidirectional relationship between the Stall class and the Vehicle class through a pair of inverse reference attributes (namely, the Stall’s occupiedBy attribute and the Vehicle’s atStall attribute). This enables a stall to be occupied by at most one vehicle, where that vehicle “knows” which stall it’s in, and can be in only one stall at a time.
Consider what happens when you assign a particular Vehicle to a Stall’s occupiedBy attribute. The statement automatically updates the inverse atStall attribute in the Vehicle by setting it to a reference to the updated Stall:
UPDATE Stall WHERE number == 42 SET occupiedBy TO 3-3-1-38 RETURN occupiedBy;
If the Vehicle had previously been linked with some other Stall, the SET operation in effect “switches” the Vehicle from its original Stall to the new Stall (#42). To prepare for the switch, the SET operation begins by implicitly clearing the Vehicle’s atStall attribute, setting it to null and also setting the original Stall’s occupiedBy attribute to null.
Setting Embedded Objects
When a target value is an embedded object, you use an object structure to specify the replacement values to be set within the embedded object. For example:
UPDATE Customer WHERE lastName == 'Mertz' SET address TO Address{street:'321 Easy St.', city:'San Jose'};
The object structure must include the name of the appropriate embeddable class or a subclass of that class.
The specified object structure updates the entire embedded object. Attributes that are included in the object structure are set to the specified values; attributes that are omitted from the object structure are cleared (set to their default values), and any previous values for the omitted attributes are discarded.
For example, say customer Mertz had an old address with the postal code 95128. The above UPDATE statement sets new values for street and city in the embedded Address. Because postalCode is not included in the object structure, that attribute’s value is cleared (set to null).
Setting Whole Collections
When a target value is itself a list, set, or map, you use a collection structure to specify the replacement collection. For example:
UPDATE Customer WHERE lastName == 'Mertz' SET rentals TO LIST{3-3-1-8, 3-3-1-43};
Note:The collection to be replaced must be a variable-size collection. An error occurs if the attribute holds a fixed-size collection. (When a collection is fixed-size, you set its elements individually; see Setting List Elements.)
The collection structure must specify the type of collection expected by the attribute (LIST, SET, or MAP).
The collection structure must include a value for every element that is to belong to the updated collection. If the collection structure specifies values for more or fewer elements, the collection is resized as necessary. For example, say customer Mertz currently has a list of references to 25 rental contracts. Executing the UPDATE statement above provides new reference values for only two elements, and the references in the other 23 elements are discarded.
Setting List Elements
When the target value or values are individual elements of a list, you can indicate the elements you want to update by specifying their positions within the list:
Use a collection-element expression that specifies an index, to replace the value at a single index position. For example:
UPDATE RentalCompany SET locations[0] TO 3-3-1-19 RETURN locations;
Use a collection-element expression that specifies a range of indexes, to replace the value at each index position in the range. For example:
UPDATE Vehicle WHERE license == 'ABC1997' SET servRecs[0:5] TO 'oil change' RETURN servRecs;
Note:A SET operation can be used only to replace the values of existing elements; you cannot use SET to add new elements to the list. Consequently, no update is made if you specify an index position that does not yet exist in the list.
Note:A SET operation affects only the value at an explicitly specified index position. If the list contains duplicate values at other positions, they are left unchanged. (This behavior differs from REMOVE, which affects all occurrences of a specified value in the list.)
If the elements of a list are referenced or embedded objects, you can indicate the ones you want to replace by using a collection-element expression that includes a predicate expression. The value of each qualifying element is replaced by the replacementValue. For example:
UPDATE RentalCompany SET locations[address.postalCode == '95128'] TO 3-3-1-19 RETURN locations;
Setting Map Elements
Each element in a map is a key:value pair, where the key and the value are of types specified by the map. A SET operation can replace the value within a key:value pair, but cannot modify the key.
     
You can indicate the map elements to be updated by qualifying their values with a predicate expression. Each qualifying value is replaced by the replacementValue. For example, if the RentalCompany’s customers map has any elements whose values are references to Customers with the user identifier 'driverGuy', the following statement replaces those references with a reference to some other Customer object:
UPDATE RentalCompany SET customers[userId == 'driverGuy'] TO 3-3-1-13 RETURN customers;
Setting Attribute Values Within Collected Objects
When the elements of a collection are referenced or embedded objects, you can use SET to replace an attribute value within some or all of those objects. The same replacementValue is assigned to the attribute in each object, so this can be a useful technique for initializing a particular attribute in many objects in a single batch operation. The collection of objects can be a list, set, or map.
You can replace a particular attribute value within every object in a collection by specifying a targetValue of the form collection.attribute, where collection evaluates to a collection that is reachable from the current context object, and attribute is an attribute of the collection element class. You can replace an attribute value in a subset of collected objects by using a collection-element expression to indicate that subset. For example:
The following statement iterates through the Vehicle objects in the RentalCompany’s vehicles collection, and sets the retired attribute of each Vehicle to false:
UPDATE RentalCompany SET vehicles.retired TO false RETURN vehicles;
The following statement uses a predicate expression to update the availability of just the retired vehicles:
UPDATE RentalCompany SET vehicles[retired == true].available TO false RETURN vehicles;
The following statement uses a range of indexes to update the rate factor of just the first 25 locations:
UPDATE RentalCompany SET locations[0:25].rateFactor TO 3.0 RETURN locations;
Note: You can use index ranges only with lists, which maintain their elements in a predictable order.
Why SET Doesn’t Replace Elements of a Set
You cannot use a SET operation to replace an element of a set, because doing so would violate the integrity of the collection. A set organizes its elements based on their identity or values, and when a SET operation replaces an element, it does so without causing the set to perform any necessary reorganization. The effect would be to introduce an element into the set that the set would not be able to find again. Consequently, the following statement, which attempts to replace the qualifying vehicle with a reference to another vehicle, returns an error because the vehicles collection of a RentalCompany is a set:
UPDATE RentalCompany SET vehicles[license == 'ABC1997'] TO 3-3-1-38 RETURN vehicles;
If you need to replace an element of a set, you must first execute a statement with a REMOVE Clause to remove the unwanted element, and then execute a statement with an ADD Clause to add the desired element.
Note:Although you cannot use SET to directly replace a set element, you can use SET to replace attribute values obtained from set elements.
Assignment and Type Compatibility
An attribute’s data type is described by the logical type and settings specified by the attribute structure with which the attribute was created. The attribute’s data type determines the characteristics of the values that can be assigned to it.
In general, you can always assign a value to a target attribute if their data types are identical—that is, if they share the same logical type and all the same settings. It is also possible to assign a value to a target attribute if the value’s data type is compatible with that of the attribute. Two data types are compatible if they have different but compatible logical types, or if they share the same logical type, but have one or more different settings. An error is returned if you attempt to assign a value to a target attribute with an incompatible data type.
Compatibility between two data types means that at least some values of one type can be represented as values of the other type. When you assign a value to a target attribute of a compatible data type, DO checks whether the particular value can be represented in the target attribute’s type. If so, the value is converted automatically to the target attribute’s type and then assigned. Otherwise, an error is returned, and you must perform an explicit operation to transform the value as appropriate before retrying the assignment.
Assigning a value to an attribute with a different but compatible data type is normally part of a multi-step schema-evolution procedure for changing an attribute’s data type; see Replacing an Obsolete Attribute While Preserving its Values. A typical scenario is to use a SET operation to transfer the value from an obsolete attribute to a new attribute, where the data types of the two attributes differ in a compatible way.
Compatible Logical Types
When you assign a value to a target attribute that has a different but compatible logical type, the value is automatically represented as a value of the attribute’s logical type. For example, when you assign an Integer value to a target attribute whose logical type is Real, the assignment operation automatically represents the value as a floating-point number and sets it in the attribute.
An error is returned if you attempt to assign a value to a target attribute that has an incompatible logical type. In general, two logical types are incompatible if there is simply no way to predict how automatic conversion between the types should take place, particularly when information might be lost during the conversion. For example, it’s impossible to predict the best way of representing a Real value such as 3.5 as an Integer. You must explicitly convert the Real value to an Integer value —for example, by using a math operator such as ROUND or TRUNCATE—before you can assign it to an Integer attribute.
Even when a value’s logical type is compatible with that of the target attribute, assignment cannot take place if the value is out of range or the wrong size for the attribute. Additional operations may be needed to transform the value so that it can be assigned to the attribute. For example, a String value containing multiple characters is too long to fit in a Character attribute. You must explicitly extract a single character from such a String value—example, by using the string operator SUBSTRING—before you can assign it to the Character attribute.
The following table shows the result of assigning a value to a target attribute of a compatible logical type:
 
Value’s Logical Type
Target Attribute’s Logical Type
Result of Assigning the Value to the Target Attribute
Character
String
Value is represented as a single-character String value.
 
Error if the Character value is outside the character set that can be represented by the attribute’s encoding.
Integer
Real
Value is represented as a floating-point value.
Reference
Value is represented as an object identifier, which may, but need not, correspond to an existing persistent object.
 
Error if the Integer value’s storage or encoding is incompatible with the settings for object identifiers.
Date
DateTime
Value is represented as a DateTime value with a minimal time component.
DateTime
Date
Value is represented as a Date value with no time component. The original time component is discarded.
List  1 
Set
Value is represented as a Set collection. Any duplicate elements in the list are discarded. The list’s element ordering is likely to change if the target attribute is an ordered set.
Reference
Integer
Value’s object identifier is represented as a 64-bit Integer value.
 
Error if the object identifier’s storage or encoding is incompatible with the attribute’s settings.
Set  1 
List
Value is represented as a List collection. Element ordering is preserved.
String
Character
Value is represented as a Character value.
 
Error if the String value contains more than one character, or if the character is outside the character set that can be represented by the Character attribute’s storage.
1. The element type of a List or Set value must be compatible with the element type of the target attribute’s collection.
Same Logical Type, Different Settings
An attribute of a given logical type has storage and encoding settings that specify various characteristics of the attribute’s values. Such characteristics typically limit the range or size of these values. For example, an Integer attribute has a storage setting that specifies whether values may be 8, 16, 32, or 64 bits in size, which in turn determines the range of integer values the attribute can hold. The settings and their options are described by the attribute structure for each logical type.
When you assign a value to an attribute that has the same logical type but a different storage or encoding setting, DO checks whether the value can be represented using the different settings. If so, the value is converted automatically. For example, if you assign a 16-bit integer value to an attribute whose storage setting is B32, the integer value is automatically converted to a 32-bit value.
An error occurs if you attempt to assign a value to an attribute that cannot accommodate it. For example, if you assign a 32-bit integer value to an attribute whose storage setting is B8, you’ll get an error if the particular value being assigned is larger than the maximum integer that can be stored in 8 bits. In such a case, you may want to perform an explicit operation to transform the value in some way so that it fits within the attribute’s available storage.
The following table indicates what happens when you assign a value to a target attribute when the value and the attribute have the same logical type but differ in some other setting. (The table omits logical types that do not support a choice of settings.)
   
Logical Type of Value and Target Attribute
Value’s Settings
Target Attribute’s Settings
Result of Assigning the Value to the Target Attribute
Character
Smaller storage size
Larger storage size
Value is converted automatically.
Larger storage size
Smaller storage size
Error if the Character value is a code point that does not fit within the target attribute’s storage size; otherwise, value is converted automatically.
Integer
Smaller storage size
Larger storage size
Value is converted automatically.
Larger storage size
Smaller storage size
Error if the Integer value does not fit within the target attribute’s storage size; otherwise, value is converted automatically.
Unsigned encoding
Signed encoding
Error if the Integer value is out of range; otherwise, value is converted automatically.
Signed encoding
Unsigned encoding
Real
Smaller storage size
Larger storage size
Value is converted automatically.
Larger storage size
Smaller storage size
Error if the Real value does not fit within the target attribute’s storage size; otherwise, value is converted automatically.
String
Byte encoding
Utf8, Utf16, Utf32 encoding
Value is converted automatically.
Utf8, Utf16, Utf32 encoding
Byte encoding
Error if the String value has a character that cannot be represented as a single byte; otherwise, value is converted automatically.
Variable or optimized storage
Fixed-capacity storage of maximum size N
Error if the String value’s size is greater than N .
Variable or fixed-capacity storage
Optimized storage
Value is converted automatically.
Fixed-capacity or optimized storage
Variable storage
Value is converted automatically.
Smaller fixed capacity
Larger fixed capacity
Value is converted automatically.
Larger fixed capacity
Smaller fixed capacity of size N
Error if the String value’s size is greater than N .
DateTime
Storage for offset
No storage for offset
Value is converted automatically.
No storage for offset
Storage for offset
Reference
Referenced class A
Referenced class is superclass of A
Value can be set without conversion.
Referenced class B
Referenced class is subclass of B
Error; a Reference to a class cannot be set in an attribute expecting a reference to its subclass.
List 1
Variable storage
Fixed-size storage for N elements
Error if the List value has a greater or smaller number of elements than are required by the target attribute.
Fixed-size storage of N elements
Variable storage
Value is converted automatically.
Smaller fixed size
Larger fixed size
Error, because the List value has a greater or smaller number of elements than are required by the target attribute.
Larger fixed size
Smaller fixed size of N elements
Default collection implementation
TreeListOfReferences implementation type
Error if the elements of the List value are not references; otherwise, value is converted automatically.
TreeListOfReferences implementation type
Default collection implementation
Value is converted automatically.
Set 1
TreeSetOfReferences implementation type
HashSetOfReferences implementation type
Value is converted automatically.
HashSetOfReferences implementation type
TreeSetOfReferences implementation type
Map 1 
TreeMapOfReferences implementation type
HashMapOfReferences implementation type
Value is converted automatically.
HashMapOfReferences implementation type
TreeMapOfReferences implementation type
TreeMapOfReferences or HashMapOfReferences implementation type
NameMapOfReferences implementation type
Error; incompatible key types.
NameMapOfReferences implementation type
TreeMapOfReferences or HashMapOfReferences implementation type
1. The element type of a List, Set, or Map value must be compatible with the element type of the target attribute’s collection.