/**
   * Customizes table creating procedure for PostgreSQL. One difference with generic implementation
   * is that "bytea" type has no explicit length unlike similar binary types in other databases.
   *
   * @since 1.0.2
   */
  @Override
  public String createTable(DbEntity ent) {
    boolean status;
    if (ent.getDataMap() != null && ent.getDataMap().isQuotingSQLIdentifiers()) {
      status = true;
    } else {
      status = false;
    }
    QuotingStrategy context = getQuotingStrategy(status);
    StringBuilder buf = new StringBuilder();
    buf.append("CREATE TABLE ");

    buf.append(context.quoteFullyQualifiedName(ent));

    buf.append(" (");

    // columns
    Iterator<DbAttribute> it = ent.getAttributes().iterator();
    boolean first = true;
    while (it.hasNext()) {
      if (first) first = false;
      else buf.append(", ");

      DbAttribute at = it.next();

      // attribute may not be fully valid, do a simple check
      if (at.getType() == TypesMapping.NOT_DEFINED) {
        throw new CayenneRuntimeException(
            "Undefined type for attribute '"
                + ent.getFullyQualifiedName()
                + "."
                + at.getName()
                + "'.");
      }

      String[] types = externalTypesForJdbcType(at.getType());
      if (types == null || types.length == 0) {
        throw new CayenneRuntimeException(
            "Undefined type for attribute '"
                + ent.getFullyQualifiedName()
                + "."
                + at.getName()
                + "': "
                + at.getType());
      }

      String type = types[0];
      buf.append(context.quoteString(at.getName())).append(' ').append(type);

      // append size and precision (if applicable)
      if (typeSupportsLength(at.getType())) {
        int len = at.getMaxLength();
        int scale =
            (TypesMapping.isDecimal(at.getType()) && at.getType() != Types.FLOAT) // Postgress
                // don't
                // support
                // notations
                // float(a,
                // b)
                ? at.getScale()
                : -1;

        // sanity check
        if (scale > len) {
          scale = -1;
        }

        if (len > 0) {
          buf.append('(').append(len);

          if (scale >= 0) {
            buf.append(", ").append(scale);
          }

          buf.append(')');
        }
      }

      if (at.isMandatory()) {
        buf.append(" NOT NULL");
      } else {
        buf.append(" NULL");
      }
    }

    // primary key clause
    Iterator<DbAttribute> pkit = ent.getPrimaryKeys().iterator();
    if (pkit.hasNext()) {
      if (first) first = false;
      else buf.append(", ");

      buf.append("PRIMARY KEY (");
      boolean firstPk = true;
      while (pkit.hasNext()) {
        if (firstPk) firstPk = false;
        else buf.append(", ");

        DbAttribute at = pkit.next();
        buf.append(context.quoteString(at.getName()));
      }
      buf.append(')');
    }
    buf.append(')');
    return buf.toString();
  }