docs: VoltXMLElement voltAnnotateFunctionXML(VoltXMLElement exp)
      {
          // XXX Should this throw HSQLParseException instead?
          assert(getType() == OpTypes.SQL_FUNCTION);
  
          exp.attributes.put("name", name);
          exp.attributes.put("valuetype", dataType.getNameString());
          if (parameterArg != -1) {
              exp.attributes.put("result_type_parameter_index", String.valueOf(parameterArg));
          }
          int volt_funcType = funcType;
  
          String implied_argument = null;
          int keywordConstant = 0;
  
          switch (funcType) {
          case FUNC_SUBSTRING_CHAR :
              // A little tweaking is needed here because VoltDB wants to define separate functions for 2-argument and 3-argument SUBSTRING
              if (nodes.length == 2 || nodes[2] == null) {
                  volt_funcType = FUNC_VOLT_SUBSTRING_CHAR_FROM;
              }
              exp.attributes.put("function_id", String.valueOf(volt_funcType));
              return exp;
  
              // A little tweaking is needed in some other cases because VoltDB
          	// wants to define separate functions for each leading keyword
          	// argument, eliminating the hard-coded node[0] value.
  
          case FUNC_TRIM_CHAR :
              implied_argument = null;
              keywordConstant = ((Integer) nodes[0].valueData).intValue();
              switch (keywordConstant) {
  
                  case Tokens.BOTH :
                      implied_argument = "BOTH";
                      break;
  
                  case Tokens.LEADING :
                      implied_argument = "LEADING";
                      break;
  
                  case Tokens.TRAILING :
                      implied_argument = "TRAILING";
                      break;
  
                  default :
                      throw Error.runtimeError(ErrorCode.U_S0500,
                                               "FunctionSQL");
              }
              assert(implied_argument != null);
              exp.attributes.put("function_id", String.valueOf(keywordConstant + SQL_TRIM_VOLT_FUNC_OFFSET));
              exp.attributes.put("implied_argument", implied_argument);
              // Having accounted for the first argument, remove it from the child expression list.
              exp.children.remove(0);
              return exp;
  
          case FUNC_EXTRACT :
              implied_argument = null;
              keywordConstant = ((Integer) nodes[0].valueData).intValue();
              switch (keywordConstant) {
              case Tokens.DAY_NAME :
              // case DTIType.DAY_NAME :
                  implied_argument = "DAY_NAME";
                  break;
              case Tokens.MONTH_NAME :
              // case DTIType.MONTH_NAME :
                  implied_argument = "MONTH_NAME";
                  break;
              case Tokens.QUARTER :
              // case DTIType.QUARTER :
                  implied_argument = "QUARTER";
                  break;
              case Tokens.DAY_OF_YEAR :
              // case DTIType.DAY_OF_YEAR :
                  implied_argument = "DAY_OF_YEAR";
                  break;
              case Tokens.WEEKDAY :
                  implied_argument = "WEEKDAY";
                  break;
              case Tokens.DAY_OF_WEEK :
              // case DTIType.DAY_OF_WEEK :
                  implied_argument = "DAY_OF_WEEK";
                  break;
              case Tokens.WEEK:
                  keywordConstant = Tokens.WEEK_OF_YEAR;
              case Tokens.WEEK_OF_YEAR :
              // case DTIType.WEEK_OF_YEAR :
                  implied_argument = "WEEK_OF_YEAR";
                  break;
              case Types.SQL_INTERVAL_YEAR :
                  implied_argument = "INTERVAL_YEAR";
                  break;
              case Types.SQL_INTERVAL_MONTH :
                  implied_argument = "SQL_INTERVAL_MONTH";
                  break;
              case Types.SQL_INTERVAL_DAY :
                  implied_argument = "SQL_INTERVAL_DAY";
                  break;
              case Types.SQL_INTERVAL_HOUR :
                  implied_argument = "SQL_INTERVAL_HOUR";
                  break;
              case Types.SQL_INTERVAL_MINUTE :
                  implied_argument = "SQL_INTERVAL_MINUTE";
                  break;
              case Types.SQL_INTERVAL_SECOND :
                  implied_argument = "SQL_INTERVAL_SECOND";
                  break;
              case Tokens.YEAR :
                  implied_argument = "YEAR";
                  break;
              case Tokens.MONTH :
                  implied_argument = "MONTH";
                  break;
              case Tokens.DAY_OF_MONTH :
              // case DTIType.DAY_OF_MONTH :
                  keywordConstant = Tokens.DAY;
              case Tokens.DAY :
                  implied_argument = "DAY";
                  break;
              case Tokens.HOUR :
                  implied_argument = "HOUR";
                  break;
              case Tokens.MINUTE :
                  implied_argument = "MINUTE";
                  break;
              case Tokens.SECOND :
                  implied_argument = "SECOND";
                  break;
              case Tokens.SECONDS_MIDNIGHT :
              // case DTIType.SECONDS_MIDNIGHT :
                  implied_argument = "SECONDS_MIDNIGHT";
                  break;
              case Tokens.TIMEZONE_HOUR :
              // case DTIType.TIMEZONE_HOUR :
                  implied_argument = "TIMEZONE_HOUR";
                  break;
              case Tokens.TIMEZONE_MINUTE :
              // case DTIType.TIMEZONE_MINUTE :
                  implied_argument = "TIMEZONE_MINUTE";
                  break;
              default :
                  throw Error.runtimeError(ErrorCode.U_S0500, "DateTimeTypeForVoltDB: " + String.valueOf(keywordConstant));
              }
  
              assert(implied_argument != null);
              exp.attributes.put("function_id", String.valueOf(keywordConstant + SQL_EXTRACT_VOLT_FUNC_OFFSET));
              exp.attributes.put("implied_argument", implied_argument);
              // Having accounted for the first argument, remove it from the child expression list.
              exp.children.remove(0);
              return exp;
  
          case FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_SINCE_EPOCH :
              implied_argument = null;
              keywordConstant = ((Integer) nodes[0].valueData).intValue();
              int since_epoch_func = -1;
              switch (keywordConstant) {
              case Tokens.SECOND :
                  implied_argument = "SECOND";
                  since_epoch_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_SINCE_EPOCH_SECOND;
                  break;
              case Tokens.MILLIS :
              case Tokens.MILLISECOND:
                  implied_argument = "MILLISECOND";
                  since_epoch_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_SINCE_EPOCH_MILLISECOND;
                  break;
              case Tokens.MICROS :
              case Tokens.MICROSECOND :
                  implied_argument = "MICROSECOND";
                  since_epoch_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_SINCE_EPOCH_MICROSECOND;
                  break;
              default:
                  throw Error.runtimeError(ErrorCode.U_S0500, "DateTimeTypeForVoltDB: " + String.valueOf(keywordConstant));
              }
  
              assert(implied_argument != null);
              assert(-1 != since_epoch_func);
              exp.attributes.put("function_id", String.valueOf(since_epoch_func));
              exp.attributes.put("implied_argument", implied_argument);
  
              // Having accounted for the first argument, remove it from the child expression list.
              exp.children.remove(0);
              return exp;
  
          case FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TO_TIMESTAMP :
              implied_argument = null;
              keywordConstant = ((Integer) nodes[0].valueData).intValue();
              int to_timestamp_func = -1;
              switch (keywordConstant) {
              case Tokens.SECOND :
                  implied_argument = "SECOND";
                  to_timestamp_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TO_TIMESTAMP_SECOND;
                  break;
              case Tokens.MILLIS :
              case Tokens.MILLISECOND :
                  implied_argument = "MILLISECOND";
                  to_timestamp_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TO_TIMESTAMP_MILLISECOND;
                  break;
              case Tokens.MICROS :
              case Tokens.MICROSECOND :
                  implied_argument = "MICROSECOND";
                  to_timestamp_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TO_TIMESTAMP_MICROSECOND;
                  break;
              default:
                  throw Error.runtimeError(ErrorCode.U_S0500, "DateTimeTypeForVoltDB: " + String.valueOf(keywordConstant));
              }
  
              assert(-1 != to_timestamp_func);
              exp.attributes.put("function_id", String.valueOf(to_timestamp_func));
              exp.attributes.put("implied_argument", implied_argument);
  
              // Having accounted for the first argument, remove it from the child expression list.
              exp.children.remove(0);
              return exp;
  
          case FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TRUNCATE_TIMESTAMP :
              implied_argument = null;
              keywordConstant = ((Integer) nodes[0].valueData).intValue();
              int truncate_func = -1;
              switch (keywordConstant) {
              case Tokens.YEAR :
                  implied_argument = "YEAR";
                  truncate_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TRUNCATE_YEAR;
                  break;
              case Tokens.QUARTER :
                  implied_argument = "QUARTER";
                  truncate_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TRUNCATE_QUARTER;
                  break;
              case Tokens.MONTH :
                  implied_argument = "MONTH";
                  truncate_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TRUNCATE_MONTH;
                  break;
              case Tokens.DAY :
                  implied_argument = "DAY";
                  truncate_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TRUNCATE_DAY;
                  break;
              case Tokens.HOUR :
                  implied_argument = "HOUR";
                  truncate_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TRUNCATE_HOUR;
                  break;
              case Tokens.MINUTE :
                  implied_argument = "MINUTE";
                  truncate_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TRUNCATE_MINUTE;
                  break;
              case Tokens.SECOND :
                  implied_argument = "SECOND";
                  truncate_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TRUNCATE_SECOND;
                  break;
              case Tokens.MILLIS:
              case Tokens.MILLISECOND :
                  implied_argument = "MILLISECOND";
                  truncate_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TRUNCATE_MILLISECOND;
                  break;
              case Tokens.MICROS:
              case Tokens.MICROSECOND :
                  implied_argument = "MICROSECOND";
                  truncate_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_TRUNCATE_MICROSECOND;
                  break;
              default:
                  throw Error.runtimeError(ErrorCode.U_S0500, "DateTimeTypeForVoltDB: " + String.valueOf(keywordConstant));
              }
  
              assert(implied_argument != null);
              assert(-1 != truncate_func);
              exp.attributes.put("function_id", String.valueOf(truncate_func));
              exp.attributes.put("implied_argument", implied_argument);
  
              // Having accounted for the first argument, remove it from the child expression list.
              exp.children.remove(0);
              return exp;
  
          case FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DISTANCE :
              Type leftChildType = nodes[0].dataType;
              Type rightChildType = nodes[1].dataType;
  
              // in here the only cases needed to be handled are distance between polygon-to-point
              // and point-to-point.
              assert(leftChildType.isGeographyType() || leftChildType.isGeographyPointType());
              assert(rightChildType.isGeographyPointType());
  
              if (leftChildType.isGeographyType()) {
                  exp.attributes.put("function_id", String.valueOf(FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DISTANCE_POLYGON_POINT));
              }
              else {
                  exp.attributes.put("function_id", String.valueOf(FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DISTANCE_POINT_POINT));
              }
              return exp;
  
          case FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DWITHIN:
              Type firstArgType = nodes[0].dataType;
              Type secondArgType = nodes[1].dataType;
              Type thirdArgType = nodes[2].dataType;
  
              // valid first and second arguments are geo types
              // third argument, distance, is a numeric type
              // resolveTypes() has logic to perform the type-validity for arguments
              assert(firstArgType.isGeographyType() || firstArgType.isGeographyPointType());
              assert(secondArgType.isGeographyPointType());
              assert(thirdArgType.isNumberType());
  
              if (firstArgType.isGeographyType()) {
                  exp.attributes.put("function_id", String.valueOf(FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DWITHIN_POLYGON_POINT));
              }
              else {
                  exp.attributes.put("function_id", String.valueOf(FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DWITHIN_POINT_POINT));
              }
              return exp;
  
          case FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_ASTEXT:
              // only valid types for asText are geography and geography-point
              // resolveTypes in FunctionForVoltDB will block any other types
              // as unsupported types
              assert(nodes[0].dataType.isGeographyPointType() || nodes[0].dataType.isGeographyType());
  
              if (nodes[0].dataType.isGeographyPointType()) {
                  exp.attributes.put("function_id", String.valueOf(FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_ASTEXT_GEOGRAPHY_POINT));
              }
              else {
                  exp.attributes.put("function_id", String.valueOf(FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_ASTEXT_GEOGRAPHY));
              }
              return exp;
  
          case FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DATEADD :
              implied_argument = null;
              keywordConstant = ((Integer) nodes[0].valueData).intValue();
              int dateadd_func = -1;
              switch (keywordConstant) {
              case Tokens.YEAR :
                  implied_argument = "YEAR";
                  dateadd_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DATEADD_YEAR;
                  break;
              case Tokens.QUARTER :
                  implied_argument = "QUARTER";
                  dateadd_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DATEADD_QUARTER;
                  break;
              case Tokens.MONTH :
                  implied_argument = "MONTH";
                  dateadd_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DATEADD_MONTH;
                  break;
              case Tokens.DAY :
                  implied_argument = "DAY";
                  dateadd_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DATEADD_DAY;
                  break;
              case Tokens.HOUR :
                  implied_argument = "HOUR";
                  dateadd_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DATEADD_HOUR;
                  break;
              case Tokens.MINUTE :
                  implied_argument = "MINUTE";
                  dateadd_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DATEADD_MINUTE;
                  break;
              case Tokens.SECOND :
                  implied_argument = "SECOND";
                  dateadd_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DATEADD_SECOND;
                  break;
              case Tokens.MILLIS:
              case Tokens.MILLISECOND :
                  implied_argument = "MILLISECOND";
                  dateadd_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DATEADD_MILLISECOND;
                  break;
              case Tokens.MICROS:
              case Tokens.MICROSECOND :
                  implied_argument = "MICROSECOND";
                  dateadd_func = FunctionForVoltDB.FunctionDescriptor.FUNC_VOLT_DATEADD_MICROSECOND;
                  break;
              default:
                  throw Error.runtimeError(ErrorCode.U_S0500, "DateTimeTypeForVoltDB: " + String.valueOf(keywordConstant));
              }
  
              assert(implied_argument != null);
              assert(-1 != dateadd_func);
              exp.attributes.put("function_id", String.valueOf(dateadd_func));
              exp.attributes.put("implied_argument", implied_argument);
  
              // Having accounted for the first argument, remove it from the child expression list.
              exp.children.remove(0);
              return exp;
  
          default :
              if (voltDisabled != null) {
                  exp.attributes.put("disabled", voltDisabled);
              }
              exp.attributes.put("function_id", String.valueOf(volt_funcType));
              return exp;
          }
      }