protected String jToSql(String javaName, JClass currentClass)
      throws IOException, SchemaException {
    JField jf = currentClass.getFieldByName(javaName);
    if (jf == null)
      throw new SchemaException(
          "field " + javaName + " not a member of class " + currentClass.getClassName(),
          currentClass.getSchemaFileName());

    return jf.getSqlName();
  }
  /* override to insert constraint in table definition */
  protected void writeCheckConstraint(JClass currentClass, String cons_name, JField jf)
      throws IOException {

    constraints +=
        "\nalter table "
            + currentClass.getTableName()
            + " add constraint "
            + cons_name
            + " check ("
            + jf.getSqlName()
            + jf.getConstraint()
            + ");\n";

    cleanupConstraints +=
        "\nalter table " + currentClass.getTableName() + " drop constraint " + cons_name + " ;\n";
  }
  public void inlineField(JClass currentClass, JCompositeField jcf, HashSet fieldNames)
      throws IOException, SchemaException {

    JClass fieldClass = jcf.getJClass();
    Vector fields = new Vector(fieldClass.getAllFields().values());
    String primaryKey = fieldClass.getPrimaryKey();
    String prefix = jcf.getPrefix();
    for (int i = 0; i < fields.size(); i++) {
      JField jf = (JField) fields.elementAt(i);
      String sqlName = jf.getSqlName();

      if (!jf.isDbColumn() || sqlName.equals(primaryKey)) {
        // do nothing ..
      } else if (jf instanceof JCompositeField) {
        throw new SchemaException(
            "Composite Fields not allowed in inline objects", currentClass.getSchemaFileName());
      } else
        schemaFile.write(",\n\t" + prefix + "_" + sqlName + " " + getSqlOutType(currentClass, jf));
      fieldNames.add(prefix + "_" + sqlName);
    }
  }
  /* write the schema line for one field*/
  protected void writeFieldSchema(
      JClass currentClass, JField jf, String primaryKey, boolean is_first)
      throws IOException, SchemaException {
    String sqlName = jf.getSqlName();
    String fieldType = jf.getSqlType();

    String sep = is_first ? "" : ",";
    if (sqlName.equals(primaryKey)) {
      schemaFile.write(sep);
      writePrimaryKey(currentClass, sqlName);
    } else {
      schemaFile.write(sep + "\n\t" + sqlName + " " + getSqlOutType(currentClass, jf));
      if (jf.isUnique()) writeUniqueConstraint(currentClass, jf);
      if (jf.isRequired()) schemaFile.write(" not null");
      else {
        String dbSpecificOptions = getDbSpecificOptions(currentClass, jf, primaryKey);
        if (dbSpecificOptions != null) schemaFile.write(" " + dbSpecificOptions);
      }
    }

    if (jf instanceof JCompositeField
        && ((JCompositeField) jf).getJClass() != null
        && ((JCompositeField) jf).getJClass().isLeaf()) {

      // is a foreign key and has a class to reference
      JCompositeField jcf = ((JCompositeField) jf);
      JClass foreignClass = jcf.getJClass();
      String cons_name = jcf.getConstraintName();
      if (!Checks.exists(cons_name)) {
        cons_name = currentClass.getClassName() + jf.getJavaName();
        if (cons_name.length() > 30) cons_name = cons_name.substring(cons_name.length() - 28);
      }

      cons_name = makeConstraintName(cons_name);
      writeForeignKey(currentClass, cons_name, jf, foreignClass);

    } else if (Checks.exists(jf.getConstraint())) {
      String cons_name = jf.getConstraintName();
      if (!Checks.exists(cons_name)) cons_name = "C_" + jf.getJavaName();
      cons_name = makeConstraintName(cons_name);
      writeCheckConstraint(currentClass, cons_name, jf);
    }
  }
  protected void writeForeignKey(
      JClass currentClass, String cons_name, JField jf, JClass foreignClass) throws IOException {

    constraints +=
        "\nalter table "
            + currentClass.getTableName()
            + " add constraint "
            + cons_name
            + " foreign key ("
            + jf.getSqlName()
            + ") references "
            + foreignClass.getTableName()
            + "("
            + foreignClass.getPrimaryKey()
            + ");\n";
    cleanupConstraints +=
        "\nalter table " + currentClass.getTableName() + " drop constraint " + cons_name + " ;\n";
  }
  public void generate(JClass currentClass) throws IOException, SchemaException {

    schemaFile.write("\ncreate table " + currentClass.getTableName() + "(");

    String primaryKey = currentClass.getPrimaryKey(); // the sql name

    Vector allFields = new Vector(currentClass.getAllFields().values());

    boolean is_first = true;

    JField primField = null;
    HashSet fieldNames = new HashSet();

    if (Checks.exists(primaryKey)) { // set prim key first
      primField = currentClass.getFieldByName(currentClass.getPrimaryKeyJava());
      writeFieldSchema(currentClass, primField, primaryKey, is_first);
      is_first = false;
      fieldNames.add(primField.getSqlName());
    }

    for (int i = 0; i < allFields.size(); i++) {
      JField jf = (JField) allFields.elementAt(i);
      if (jf.isDbColumn() && jf != primField) {
        if (jf instanceof JCompositeField && ((JCompositeField) jf).isInline()) {
          // deal with inlining..
          inlineField(currentClass, (JCompositeField) jf, fieldNames);
        } else {
          if (!fieldNames.contains(jf.getSqlName())) fieldNames.add(jf.getSqlName());
          else
            Debugger.trace(
                "Duplicate column " + jf.getSqlName() + " in Class " + currentClass.getClassName(),
                Debugger.ERROR);
          writeFieldSchema(currentClass, jf, primaryKey, is_first);
        }
        is_first = false;
      }
    }

    if (currentClass.isEndDateable()) schemaFile.write(",\n\t" + END_DATE + " " + END_DATE_TYPE);
    if (currentClass.isVersioned()) schemaFile.write(",\n\t" + VERSION_NUMBER + " int");
    schemaFile.write(");\n");

    if (!currentClass.isManyToMany()) {
      if (needsSequence()) {
        cleanup.write(getDropSeqStmt(currentClass));
        schemaFile.write("\ncreate sequence " + currentClass.getTableName() + "_seq;\n");
      }
    } else {
      String columns = "";
      boolean first_column = true;
      for (int i = 0; i < allFields.size(); i++) {
        JField jf = (JField) allFields.elementAt(i);
        if (!jf.getSqlName().equalsIgnoreCase("")) {
          if (!first_column) columns += ",";
          else first_column = false;
          columns += jf.getSqlName();
        }
      }
      if (allFields.size() > 0) // && !isPostgres)
      {
        constraints +=
            ("\nalter table "
                + currentClass.getTableName()
                + " add constraint "
                + currentClass.getTableName()
                + "_unq primary key "
                + " ("
                + columns
                + ");\n");
      }
    }

    Iterator cons = currentClass.getConstraints();
    while (cons.hasNext()) {
      JConstraint jcons = (JConstraint) cons.next();
      String sOut = convertFields(jcons.getConstraint(), currentClass);
      String consName = makeConstraintName(jcons.getName());

      cleanUpConstraint(currentClass, consName);

      addConstraint(currentClass, consName, jcons, sOut);
    }
    Iterator indexes = currentClass.getIndexes().iterator();
    while (indexes.hasNext()) {
      JIndex index = (JIndex) indexes.next();
      String sOut = convertFields(index.getFields(), currentClass);

      cleanUpIndex(currentClass, index);

      addIndex(currentClass, sOut, index);
    }
  }
 /* helper function to get the sql type to be printed. */
 protected String getSqlOutType(JClass currentClass, JField jf) throws SchemaException {
   return jf.getSqlType();
 }