VoltXMLElement voltGetXML(SimpleColumnContext context, String realAlias)
        throws HSQLParseException {
        // The voltXML representations of expressions tends to be driven much more by the expression's opType
        // than its Expression class.
        int exprOp = getType();

        // The opType value of "SIMPLE_COLUMN" is a special case that spans Expression classes and seems to
        // need to use the Expression's exact class to be able to correctly determine its VoltXMLElement
        // representation.
        // Last minute "SIMPLE_COLUMN" substitutions can blast a new opType into an Expression of a class
        // other than ExpressionColumn as an optimization for duplicated expressions.
        // VoltDB currently uses "alias" matching to navigate to the correct (duplicate) expression structure
        // typically an ExpressionAggregate.
        // The prototypes dictionary is set up to handle a SIMPLE_COLUMN of any class EXCEPT ExpressionColumn.
        // A SIMPLE_COLUMN ExpressionColumn can be treated as a normal "COLUMN" ExpressionColumn.
        // That case gets explicitly enabled here by fudging the opType from SIMPLE_COLUMN to COLUMN.
        if (exprOp == OpTypes.SIMPLE_COLUMN) {
            VoltXMLElement asResolved = context.resolveSimpleColumn(this);
            if (asResolved != null) {
                return asResolved;
            }
            // ENG-10429 moved the following two lines here. See fix note https://issues.voltdb.com/browse/ENG-10429.
            // convert the SIMPLE_COLUMN into a COLUMN
            opType = OpTypes.COLUMN;
            exprOp = OpTypes.COLUMN;
        }

        // Use the opType to find a pre-initialized prototype VoltXMLElement with the correct
        // name and any required hard-coded values pre-set.
        VoltXMLElement exp = prototypes.get(exprOp);
        if (exp == null) {
            // Must have found an unsupported opType.
            throwForUnsupportedExpression(exprOp);
        }

        // Duplicate the prototype and add any expression particulars needed for the specific opType value,
        // as well as a unique identifier, a possible alias, and child nodes.
        exp = exp.duplicate();
        exp.attributes.put("id", getUniqueId(context.m_session));

        if (realAlias != null) {
            exp.attributes.put("alias", realAlias);
        }
        else if ((alias != null) && (getAlias().length() > 0)) {
            exp.attributes.put("alias", getAlias());
        }

        // Add expression sub type
        if (exprSubType == OpTypes.ANY_QUANTIFIED) {
            exp.attributes.put("opsubtype", "any");
        }
        else if (exprSubType == OpTypes.ALL_QUANTIFIED) {
            exp.attributes.put("opsubtype", "all");
        }

        for (Expression expr : nodes) {
            if (expr != null) {
                VoltXMLElement vxmle = expr.voltGetXML(context, null);
                exp.children.add(vxmle);
                assert(vxmle != null);
            }
        }

        // Few opTypes need additional special case detailing or special case error detection.
        // Very few need access to members defined on specific Expression classes, but they
        // can usually be accessed via down-casting.
        // Even fewer need private members, and they are accessed by delegation to a
        // class-specific voltAnnotate... member function that directly manipulates the
        // VoltXMLElement.
        switch (exprOp) {
        case OpTypes.VALUE:
            // Apparently at this stage, all valid non-NULL values must have a
            // type determined by HSQL.
            // (I'm not sure why this MUST be the case --paul.)
            if (valueData == null) {
                String valueType = (dataType == null) ? "NULL" :
                        Types.getTypeName(dataType.typeCode);
                exp.attributes.put("valuetype", valueType);
                return exp;
            }

            exp.attributes.put("valuetype", Types.getTypeName(dataType.typeCode));

            if (valueData instanceof TimestampData) {
                // When we get the default from the DDL,
                // it gets jammed into a TimestampData object.  If we
                // don't do this, we get a Java class/reference
                // string in the output schema for the DDL.
                // EL HACKO: I'm just adding in the timezone seconds
                // at the moment, hope this is right --izzy
                TimestampData time = (TimestampData) valueData;
                exp.attributes.put("value", Long.toString(Math.round((time.getSeconds() +
                                                                      time.getZone()) * 1e6) +
                                                          time.getNanos() / 1000));
                return exp;
            }

            // convert binary values to hex
            if (valueData instanceof BinaryData) {
                BinaryData bd = (BinaryData) valueData;
                exp.attributes.put("value", hexEncode(bd.getBytes()));
                return exp;
            }

            // Otherwise just string format the value.
            if (dataType instanceof NumberType && ! dataType.isIntegralType()) {
                // remove the scentific exponent notation
                exp.attributes.put("value", new BigDecimal(valueData.toString()).toPlainString());
                return exp;
            }
            exp.attributes.put("value", valueData.toString());
            return exp;

        case OpTypes.COLUMN:
            ExpressionColumn ec = (ExpressionColumn)this;
            return ec.voltAnnotateColumnXML(exp);

        case OpTypes.COALESCE:
            return convertUsingColumnrefToCoaleseExpression(context.m_session, exp, dataType);

        case OpTypes.SQL_FUNCTION:
            FunctionSQL fn = (FunctionSQL)this;
            return fn.voltAnnotateFunctionXML(exp);

        case OpTypes.COUNT:
        case OpTypes.SUM:
        case OpTypes.AVG:
            if (((ExpressionAggregate)this).isDistinctAggregate) {
                exp.attributes.put("distinct", "true");
            }
            return exp;

        case OpTypes.ORDER_BY:
            if (((ExpressionOrderBy)this).isDescending()) {
                exp.attributes.put("desc", "true");
            }
            return exp;

        case OpTypes.CAST:
            if (dataType == null) {
                throw new HSQLParseException(
                        "VoltDB could not determine the type in a CAST operation");
            }
            exp.attributes.put("valuetype", dataType.getNameString());
            return exp;

        case OpTypes.TABLE_SUBQUERY:
            if (subQuery == null || subQuery.queryExpression == null) {
                throw new HSQLParseException("VoltDB could not determine the subquery");
            }
            ExpressionColumn parameters[] = new ExpressionColumn[0];
            exp.children.add(StatementQuery.voltGetXMLExpression(subQuery.queryExpression,
                    parameters, context.m_session));
            return exp;

        case OpTypes.ALTERNATIVE:
            assert(nodes.length == 2);
            // If with ELSE clause, pad NULL with it.
            if (nodes[RIGHT] instanceof ExpressionValue) {
                ExpressionValue val = (ExpressionValue) nodes[RIGHT];
                if (val.valueData == null && val.dataType == Type.SQL_ALL_TYPES) {
                    exp.children.get(RIGHT).attributes.put("valuetype", dataType.getNameString());
                }
            }
        case OpTypes.CASEWHEN:
            // Hsql has check dataType can not be null.
            assert(dataType != null);
            exp.attributes.put("valuetype", dataType.getNameString());
            return exp;

        case OpTypes.WINDOWED_RANK:
        case OpTypes.WINDOWED_DENSE_RANK:
        case OpTypes.WINDOWED_ROW_NUMBER:
        case OpTypes.WINDOWED_COUNT:
        case OpTypes.WINDOWED_MIN:
        case OpTypes.WINDOWED_MAX:
        case OpTypes.WINDOWED_SUM:
            assert(dataType != null);
            assert(this instanceof ExpressionWindowed);
            exp.attributes.put("valuetype", dataType.getNameString());
            ExpressionWindowed erank = (ExpressionWindowed) this;
            return erank.voltAnnotateWindowedAggregateXML(exp, context);

        default:
            return exp;
        }
    }
VoltXMLElement voltGetXML ( SimpleColumnContext context , String realAlias ) throws HSQLParseException { int exprOp = getType ( ) ; if ( exprOp == OpTypes . SIMPLE_COLUMN ) { VoltXMLElement asResolved = context . resolveSimpleColumn ( this ) ; if ( asResolved != null ) { return asResolved ; } opType = OpTypes . COLUMN ; exprOp = OpTypes . COLUMN ; } VoltXMLElement exp = prototypes . get ( exprOp ) ; if ( exp == null ) { throwForUnsupportedExpression ( exprOp ) ; } exp = exp . duplicate ( ) ; exp . attributes . put ( "id" , getUniqueId ( context . m_session ) ) ; if ( realAlias != null ) { exp . attributes . put ( "alias" , realAlias ) ; } else if ( ( alias != null ) && ( getAlias ( ) . length ( ) > 0 ) ) { exp . attributes . put ( "alias" , getAlias ( ) ) ; } if ( exprSubType == OpTypes . ANY_QUANTIFIED ) { exp . attributes . put ( "opsubtype" , "any" ) ; } else if ( exprSubType == OpTypes . ALL_QUANTIFIED ) { exp . attributes . put ( "opsubtype" , "all" ) ; } for ( Expression expr : nodes ) { if ( expr != null ) { VoltXMLElement vxmle = expr . voltGetXML ( context , null ) ; exp . children . add ( vxmle ) ; assert ( vxmle != null ) ; } } switch ( exprOp ) { case OpTypes . VALUE : if ( valueData == null ) { String valueType = ( dataType == null ) ? "NULL" : Types . getTypeName ( dataType . typeCode ) ; exp . attributes . put ( "valuetype" , valueType ) ; return exp ; } exp . attributes . put ( "valuetype" , Types . getTypeName ( dataType . typeCode ) ) ; if ( valueData instanceof TimestampData ) { TimestampData time = ( TimestampData ) valueData ; exp . attributes . put ( "value" , Long . toString ( Math . round ( ( time . getSeconds ( ) + time . getZone ( ) ) * 1e6 ) + time . getNanos ( ) / 1000 ) ) ; return exp ; } if ( valueData instanceof BinaryData ) { BinaryData bd = ( BinaryData ) valueData ; exp . attributes . put ( "value" , hexEncode ( bd . getBytes ( ) ) ) ; return exp ; } if ( dataType instanceof NumberType && ! dataType . isIntegralType ( ) ) { exp . attributes . put ( "value" , new BigDecimal ( valueData . toString ( ) ) . toPlainString ( ) ) ; return exp ; } exp . attributes . put ( "value" , valueData . toString ( ) ) ; return exp ; case OpTypes . COLUMN : ExpressionColumn ec = ( ExpressionColumn ) this ; return ec . voltAnnotateColumnXML ( exp ) ; case OpTypes . COALESCE : return convertUsingColumnrefToCoaleseExpression ( context . m_session , exp , dataType ) ; case OpTypes . SQL_FUNCTION : FunctionSQL fn = ( FunctionSQL ) this ; return fn . voltAnnotateFunctionXML ( exp ) ; case OpTypes . COUNT : case OpTypes . SUM : case OpTypes . AVG : if ( ( ( ExpressionAggregate ) this ) . isDistinctAggregate ) { exp . attributes . put ( "distinct" , "true" ) ; } return exp ; case OpTypes . ORDER_BY : if ( ( ( ExpressionOrderBy ) this ) . isDescending ( ) ) { exp . attributes . put ( "desc" , "true" ) ; } return exp ; case OpTypes . CAST : if ( dataType == null ) { throw new HSQLParseException ( "VoltDB could not determine the type in a CAST operation" ) ; } exp . attributes . put ( "valuetype" , dataType . getNameString ( ) ) ; return exp ; case OpTypes . TABLE_SUBQUERY : if ( subQuery == null || subQuery . queryExpression == null ) { throw new HSQLParseException ( "VoltDB could not determine the subquery" ) ; } ExpressionColumn parameters [ ] = new ExpressionColumn [ 0 ] ; exp . children . add ( StatementQuery . voltGetXMLExpression ( subQuery . queryExpression , parameters , context . m_session ) ) ; return exp ; case OpTypes . ALTERNATIVE : assert ( nodes . length == 2 ) ; if ( nodes [ RIGHT ] instanceof ExpressionValue ) { ExpressionValue val = ( ExpressionValue ) nodes [ RIGHT ] ; if ( val . valueData == null && val . dataType == Type . SQL_ALL_TYPES ) { exp . children . get ( RIGHT ) . attributes . put ( "valuetype" , dataType . getNameString ( ) ) ; } } case OpTypes . CASEWHEN : assert ( dataType != null ) ; exp . attributes . put ( "valuetype" , dataType . getNameString ( ) ) ; return exp ; case OpTypes . WINDOWED_RANK : case OpTypes . WINDOWED_DENSE_RANK : case OpTypes . WINDOWED_ROW_NUMBER : case OpTypes . WINDOWED_COUNT : case OpTypes . WINDOWED_MIN : case OpTypes . WINDOWED_MAX : case OpTypes . WINDOWED_SUM : assert ( dataType != null ) ; assert ( this instanceof ExpressionWindowed ) ; exp . attributes . put ( "valuetype" , dataType . getNameString ( ) ) ; ExpressionWindowed erank = ( ExpressionWindowed ) this ; return erank . voltAnnotateWindowedAggregateXML ( exp , context ) ; default : return exp ; } }
VoltDB added method to get a non-catalog-dependent
representation of this HSQLDB object.
@param context The context encapsulates the current Session object and (optionally)
select statement display columns that may be needed to resolve some names.
@return A VoltXML tree structure.
@throws HSQLParseException