docs: public DataType parse( DdlTokenStream tokens ) throws ParsingException {
          DataType result = null;
  
          if (isDatatype(tokens, DataTypes.DTYPE_CODE_CHAR_STRING)) {
              result = parseCharStringType(tokens);
          } else if (isDatatype(tokens, DataTypes.DTYPE_CODE_NCHAR_STRING)) {
              result = parseNationalCharStringType(tokens);
          } else if (isDatatype(tokens, DataTypes.DTYPE_CODE_BIT_STRING)) {
              result = parseBitStringType(tokens);
          } else if (isDatatype(tokens, DataTypes.DTYPE_CODE_EXACT_NUMERIC)) {
              result = parseExactNumericType(tokens);
          } else if (isDatatype(tokens, DataTypes.DTYPE_CODE_APROX_NUMERIC)) {
              result = parseApproxNumericType(tokens);
          } else if (isDatatype(tokens, DataTypes.DTYPE_CODE_DATE_TIME)) {
              result = parseDateTimeType(tokens);
          } else if (isDatatype(tokens, DataTypes.DTYPE_CODE_MISC)) {
              result = parseMiscellaneousType(tokens);
          } else {
              result = parseCustomType(tokens);
          }
  
          /*
           * (FROM http://www.postgresql.org/docs/8.4/static/arrays.html) 
          8.14.1. Declaration of Array Types
  
          To illustrate the use of array types, we create this table:
  
          CREATE TABLE sal_emp (
              name            text,
              pay_by_quarter  integer[],
              schedule        text[][]
          );
  
          As shown, an array data type is named by appending square brackets ([]) to the data type name of the array elements. 
          The above command will create a table named sal_emp with a column of type text (name), a one-dimensional array of type 
          integer (pay_by_quarter), which represents the employee's salary by quarter, and a two-dimensional array of text (schedule), 
          which represents the employee's weekly schedule.
  
          The syntax for CREATE TABLE allows the exact size of arrays to be specified, for example:
  
          CREATE TABLE tictactoe (
              squares   integer[3][3]
          );
  
          However, the current implementation ignores any supplied array size limits, i.e., the behavior is the same as for 
          arrays of unspecified length.
  
          The current implementation does not enforce the declared number of dimensions either. Arrays of a particular element 
          type are all considered to be of the same type, regardless of size or number of dimensions. So, declaring the array size 
          or number of dimensions in CREATE TABLE is simply documentation; it does not affect run-time behavior.
  
          An alternative syntax, which conforms to the SQL standard by using the keyword ARRAY, can be used for one-dimensional 
          arrays. pay_by_quarter could have been defined as:
  
              pay_by_quarter  integer ARRAY[4],
  
          Or, if no array size is to be specified:
  
              pay_by_quarter  integer ARRAY,
          */
  
          if (tokens.canConsume('[')) {
              if (!tokens.canConsume(']')) {
                  // assume integer value
                  tokens.consume();
                  tokens.consume(']');
              }
  
              if (tokens.canConsume('[')) {
                  if (!tokens.canConsume(']')) {
                      // assume integer value
                      tokens.consume();
                      tokens.consume(']');
                  }
              }
          }
  
          return result;
      }