Using field accessors to nullable fields

The nullability of a field defines whether the field can contain a null. A field containing a null does not contain a value.

For example, you can have a data set whose record schema contains an age field. If the age field of a particular record is null, the age is not known for the person corresponding to the record.

As part of processing a record field, you can detect a null and take the appropriate action. For instance, you can omit the null field from a calculation, signal an error condition, or take some other action.

To recognize a nullable field, the field of the interface must be defined to be nullable. You include the keyword nullable in the interface specification of a field to make it nullable. For example, all fields of the operator shown in the following figure are nullable:

Figure 1. AddOperator with nullable field informationShows the addoperator with nullable field information

The following code example is the describeOperator() function for AddOperator:

Table 1. Nullable fields in describeOperator() schema code
Comment Code
 
 
 
 
 
 
 
6
 
7
APT_Status AddOperator::describeOperator()
{
	setKind(APT_Operator::eParallel);

	setInputDataSets(1);
	setOutputDataSets(1);

	setInputInterfaceSchema("record (field1:nullable int32;"
		"field2:nullable int32)",0);
	setOutInterfaceSchema("record (field1:nullable int32;"
		"field2:nullable int32)",0);

	return APT_StatusOk;

}
6
Specify that all fields of the interface schema of input 0 are nullable. You can individually specify any or all fields of the interface schema as nullable.
7
Specify that all fields of the output interface schema are nullable. For the first record in the output data set, and after each call to APT_OutputCursor::putRecord(), the null indicator in all nullable output fields is set, marking the field as containing a null. Writing a value to an output field clears the null indicator.
If an input field to an operator contains null and the corresponding operator interface field is not nullable, InfoSphere DataStage issues a fatal error and aborts your application. You can use view adapters to prevent a fatal error in this case.
Both input and output accessors contain member functions for working with nulls. For input accessors, you use:
isNull()
Returns true if the accessor references a field containing a null.
isNullAt()
Returns true if the accessor references a vector element containing a null.
isNullable()
Returns true if the accessor references a nullable field.
For output accessors, you use:
isNull()
Returns true if the accessor references a field containing a null.
isNullAt()
Returns true if the accessor references a vector element containing a null.
isNullable()
Returns true if the accessor references a nullable field.
clearIsNull()
Clears the null indicator for the field referenced by an accessor and sets the field to the default value. If isNullable() returns false, clearIsNull() does nothing.
For the first record in the output data set, and after each call to APT_OutputCursor::putRecord(), the null indicator in all nullable output fields of the new output record is set, marking the field as containing a null. Writing a value to an output field clears the null indicator, so it is typically unnecessary to call clearIsNull().
clearIsNullAt()
Clears the null indicator for the vector element referenced by an accessor, and sets the value of the field to the default value for its type.
setIsNull()
Sets the null indicator for the field referenced by an accessor, marking the field to contain a null. setIsNull() requires that isNullable() returns true.
Because the null flag for all nullable output fields is initially set, you only need to call setIsNull() if you have written valid data to an output field and later decide to set the field to null.
setIsNullAt()
Sets the null indicator for a vector element referenced by an accessor, marking the field to contain a null.

You typically use the operator* member function of an input and output accessor to obtain the value of a field. For an input accessor, using operator* on a field containing a null causes a requirements violation and aborts your application. Therefore, you must first determine if a nullable input field contains a null, using isNull(), before attempting to access it.

For an output accessor, calling operator* always clears the null indicator for a nullable field, marking the field to contain valid data. You can use setIsNull() to explicitly set the null indicator in an output field, if necessary.

How you choose to handle nulls detected in an input field or what conditions cause an output field to be set to null is determined by your operator logic. Often, a null in an input field will be propagated through to the output. For example, the following code example is the APT_Operator::runLocally() function for AddOperator:

Table 2. Handling nullable fields in runLocally() code
Comment Code
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
 
16
 
 
18
 
 
20
APT_Status AddOperator::runLocally()
{
		APT_InputCursor inCur;
		APT_OutputCursor outCur;

		setupInputCursor(&inCur, 0); 
		setupOutputCursor(&outCur, 0); 

		APT_InputAccessorToInt32 field1InAcc("field1", &inCur); 
		APT_InputAccessorToInt32 field2InAcc("field2", &inCur); 

		APT_OutputAccessorToInt32 field1OutAcc("field1", &outCur); 
		APT_OutputAccessorToInt32 field2OutAcc("field2", &outCur); 
		APT_OutputAccessorToInt32 totalOutAcc("total", &outCur); 

		while (inCur.getRecord()) 
		{ 
			if (!field1InAcc.isNull()) 
					*field1OutAcc = *field1InAcc; 

			if (!field2InAcc.isNull()) 
					*field2OutAcc = *field2InAcc; 

			if (!field1InAcc.isNull() && !field2InAcc.isNull()) 
					*totalOutAcc = *field1InAcc + *field2InAcc;

				outCur.putRecord();
		}
		return APT_StatusOk;
}
14
Use field1InAcc.isNull() to determine if field1 contains a null. If not, copy it to the output record.
16
Determine if field2 contains a null. If not, copy it to the output record.
18
If both field1 and field2 contain valid data, perform the addition. Writing to total clears the null indicator for the field.
20
Call APT_OutputCursor::putRecord() to write the output record.