001package gu.sql2java.generator;
002
003import java.sql.DatabaseMetaData;
004import java.sql.Types;
005import java.text.SimpleDateFormat;
006import java.util.Calendar;
007import java.util.Date;
008import java.util.List;
009import java.util.Random;
010import java.util.Vector;
011import java.util.regex.Matcher;
012import java.util.regex.Pattern;
013
014import org.apache.commons.lang.builder.EqualsBuilder;
015import org.apache.commons.lang.builder.ToStringBuilder;
016
017import com.google.common.base.Function;
018import com.google.common.base.Strings;
019import com.google.common.collect.ImmutableMap;
020import com.google.common.collect.Maps;
021import com.google.common.primitives.Primitives;
022import com.google.common.reflect.TypeToken;
023
024import gu.sql2java.generator.CodeWriter;
025import gu.sql2java.generator.Database;
026import gu.sql2java.generator.StringUtilities;
027import gu.sql2java.generator.Table;
028import net.gdface.utils.MiscellaneousUtils;
029
030public class Column implements Cloneable, Comparable<Column>,MappedType {
031        private String catalog;
032        private String schema;
033        private String tableName;
034        private String name;
035        private String remarks;
036        private String defaultValue;
037        private int size;
038        private int decDigits;
039        private int radix;
040        private int nullable;
041        private int ordinal;
042        private short type;
043        private boolean isPrimaryKey;
044        private String strCheckingType = "";
045        private String autoincrement;
046        private Database db;
047        private List<Column> foreignKeys = new Vector<Column>();
048        private List<Column> importedKeys = new Vector<Column>();
049        private String typeName = "";
050        private volatile String invalidValueAnn;
051        private volatile Boolean preAlloc;
052        private static Random rand = new Random();
053
054        @Override
055        public String toString() {
056                return new ToStringBuilder(this)
057                                .append("catalog",catalog)
058                                .append("schema",schema)
059                                .append("tableName",tableName)
060                                .append("name",name)
061                                .append("remarks",remarks)
062                                .append("defaultValue",defaultValue)
063                                .append("size",size)
064                                .append("decDigits",decDigits)
065                                .append("radix",radix)
066                                .append("nullable",nullable)
067                                .append("ordinal",ordinal)
068                                .append("type",type)
069                                .append("isPrimaryKey",isPrimaryKey)
070                                .append("autoincrement",autoincrement)
071                                .append("typeName",typeName)
072                                .toString();
073        }
074
075        @Override
076        public boolean equals(Object obj) {
077                if(super.equals(obj))return true;
078                if(!(obj instanceof Column))return false;
079                Column other = (Column)obj;
080                return new EqualsBuilder()
081                                .append(catalog,other.catalog)
082                                .append(schema,other.schema)
083                                .append(tableName,other.tableName)
084                                .append(name,other.name)
085                                .append(remarks,other.remarks)
086                                .append(defaultValue,other.defaultValue)
087                                .append(size,other.size)
088                                .append(decDigits,other.decDigits)
089                                .append(radix,other.radix)
090                                .append(nullable,other.nullable)
091                                .append(ordinal,other.ordinal)
092                                .append(type,other.type)
093                                .append(isPrimaryKey,other.isPrimaryKey)
094                                .append(autoincrement,other.autoincrement)
095                                .append(typeName,other.typeName)
096                                .isEquals();
097        }
098
099        public void setCheckingType(String strValue) {
100                this.strCheckingType = strValue;
101        }
102
103        public String getCheckingType() {
104                return this.strCheckingType;
105        }
106
107        public void setDatabase(Database db) {
108                this.db = db;
109        }
110
111        public void setCatalog(String catalog) {
112                this.catalog = catalog;
113        }
114
115        public void setSchema(String schema) {
116                this.schema = schema;
117        }
118
119        public void setTableName(String tableName) {
120                this.tableName = tableName;
121        }
122
123        public void setName(String name) {
124                this.name = null == name ? "" : name.replaceAll("\\W", "");
125        }
126
127        public void setType(short type) {
128                this.type = type;
129        }
130
131        public void setSize(int size) {
132                this.size = size;
133        }
134
135        public void setDecimalDigits(int decDigits) {
136                this.decDigits = decDigits;
137        }
138
139        public void setRadix(int radix) {
140                this.radix = radix;
141        }
142
143        public void setNullable(int nullable) {
144                this.nullable = nullable;
145        }
146
147        public void setRemarks(String remarks) {
148                if (remarks != null) {
149                        this.remarks = remarks.replaceAll("/\\*", "SLASH*").replaceAll("\\*/", "*SLASH");
150                }
151        }
152
153        public void setDefaultValue(String defaultValue) {
154                this.defaultValue = defaultValue;
155        }
156
157        public void setOrdinalPosition(int ordinal) {
158                this.ordinal = ordinal;
159        }
160
161        public void isPrimaryKey(boolean isKey) {
162                this.isPrimaryKey = isKey;
163        }
164
165        public String getCatalog() {
166                return this.catalog;
167        }
168
169        public String getSchema() {
170                return this.schema;
171        }
172
173        public String getTableName() {
174                return this.tableName;
175        }
176
177        public String getName() {
178                return this.name;
179        }
180
181        public short getType() {
182                return this.type;
183        }
184
185        public int getSize() {
186                return this.size;
187        }
188
189        public int getDecimalDigits() {
190                return this.decDigits;
191        }
192
193        public int getRadix() {
194                return this.radix;
195        }
196
197        public int getNullable() {
198                return this.nullable;
199        }
200
201        public String getNullableAsString() {
202                return this.getNullable() != 0 ? "nullable" : "null not allowed";
203        }
204
205        public int getOrdinalPosition() {
206                return this.ordinal;
207        }
208
209        public boolean isPrimaryKey() {
210                return this.isPrimaryKey;
211        }
212
213        public String getFullName() {
214                return this.tableName + "." + this.getName();
215        }
216
217        public String getConstName() {
218                return this.getName().toUpperCase();
219        }
220
221        public String getIDConstName() {
222                return (this.tableName + "_ID_" + this.getName()).toUpperCase();
223        }
224        public String getIDMaskConstName() {
225                return (this.tableName + "_ID_" + this.getName()).toUpperCase() + "_MASK";
226        }
227        public Object clone() throws CloneNotSupportedException {
228                return super.clone();
229        }
230
231        private void tuoe() {
232                throw new UnsupportedOperationException("Not supported yet: " + this.getTableName() + "." + this.getName() + " "
233                                + this.getJavaTypeAsTypeName());
234        }
235
236        private void tiae() {
237                throw new IllegalArgumentException("No primary type associated: " + this.getTableName() + "." + this.getName());
238        }
239
240        public int getMappedType() {
241                switch (this.getType()) {
242                        case Types.ARRAY : {
243                                return M_ARRAY;
244                        }
245                        case Types.BIGINT : {
246                                return M_LONG;
247                        }
248                        case Types.BINARY : {
249                                return M_BYTES;
250                        }
251                        case Types.BIT : {
252                                return M_BOOLEAN;
253                        }
254                        case Types.BLOB : {
255                                return M_BLOB;
256                        }
257                        case Types.BOOLEAN : {
258                                return M_BOOLEAN;
259                        }
260                        case Types.CHAR : {
261                                return M_STRING;
262                        }
263                        case Types.CLOB : {
264                                return M_CLOB;
265                        }
266                        case Types.DATALINK : {
267                                return M_URL;
268                        }
269                        case Types.DATE : {
270                                if ("java.util.Date".equals(CodeWriter.dateClassName)) {
271                                        return M_UTILDATE;
272                                }
273                                if ("java.sql.Date".equals(CodeWriter.dateClassName)) {
274                                        return M_SQLDATE;
275                                }
276                                if ("java.util.Calendar".equals(CodeWriter.dateClassName)) {
277                                        return M_CALENDAR;
278                                }
279                                this.tuoe();
280                        }
281                        case Types.DECIMAL : {
282                                return this.getDecimalDigits() > 0 ? M_BIGDECIMAL : M_LONG;
283                        }
284                        case Types.DISTINCT : {
285                                return M_OBJECT;
286                        }
287                        case Types.DOUBLE : {
288                                return M_DOUBLE;
289                        }
290                        case Types.FLOAT : {
291                                return M_DOUBLE;
292                        }
293                        case Types.INTEGER : {
294                                return this.getTypeName().equalsIgnoreCase("INT UNSIGNED") ? M_LONG : M_INTEGER;
295                        }
296                        case Types.JAVA_OBJECT : {
297                                return M_OBJECT;
298                        }
299                        case Types.LONGVARBINARY : {
300                                return M_BYTES;
301                        }
302                        case Types.LONGVARCHAR : {
303                                return M_STRING;
304                        }
305                        case Types.NUMERIC : {
306                                return this.getDecimalDigits() > 0 ? M_BIGDECIMAL : M_LONG;
307                        }
308                        case Types.OTHER : {
309                                return M_OBJECT;
310                        }
311                        case Types.REAL : {
312                                return M_FLOAT;
313                        }
314                        case Types.REF : {
315                                return M_REF;
316                        }
317                        case Types.SMALLINT : {
318                                return M_INTEGER;
319                        }
320                        case Types.STRUCT : {
321                                return M_OBJECT;
322                        }
323                        case Types.TIME : {
324                                if ("java.util.Date".equals(CodeWriter.timeClassName)) {
325                                        return M_UTILDATE;
326                                }
327                                if ("java.sql.Time".equals(CodeWriter.timeClassName)) {
328                                        return M_TIME;
329                                }
330                                if ("java.util.Calendar".equals(CodeWriter.timeClassName)) {
331                                        return M_CALENDAR;
332                                }
333                                this.tuoe();
334                        }
335                        case Types.TIMESTAMP : {
336                                if ("java.util.Date".equals(CodeWriter.timestampClassName)) {
337                                        return M_UTILDATE;
338                                }
339                                if ("java.sql.Timestamp".equals(CodeWriter.timestampClassName)) {
340                                        return M_TIMESTAMP;
341                                }
342                                if ("java.util.Calendar".equals(CodeWriter.timestampClassName)) {
343                                        return M_CALENDAR;
344                                }
345                                this.tuoe();
346                        }
347                        case Types.TINYINT : {
348                                return M_INTEGER;
349                        }
350                        case Types.VARBINARY : {
351                                return M_BYTES;
352                        }
353                        case Types.VARCHAR : {
354                                return M_STRING;
355                        }
356                }
357                this.tuoe();
358                return -1;
359        }
360
361        public String getQuerySetMethod() {
362                switch (this.getType()) {
363                        case Types.ARRAY : {
364                                return "setArray";
365                        }
366                        case Types.BIGINT : {
367                                return "setBigDecimal";
368                        }
369                        case Types.BINARY : {
370                                return "setBytes";
371                        }
372                        case Types.BIT : {
373                                return "setBoolean";
374                        }
375                        case Types.BLOB : {
376                                return "setBlob";
377                        }
378                        case Types.BOOLEAN : {
379                                return "setBoolean";
380                        }
381                        case Types.CHAR : {
382                                return "setString";
383                        }
384                        case Types.CLOB : {
385                                return "setClob";
386                        }
387                        case Types.DATALINK : {
388                                return "setURL";
389                        }
390                        case Types.DATE : {
391                                return "setDate";
392                        }
393                        case Types.DECIMAL : {
394                                return this.getDecimalDigits() > 0 ? "setBigDecimal" : "setLong";
395                        }
396                        case Types.DISTINCT : {
397                                return "setObject";
398                        }
399                        case Types.DOUBLE : {
400                                return "setDouble";
401                        }
402                        case Types.FLOAT : {
403                                return "setDouble";
404                        }
405                        case Types.INTEGER : {
406                                return this.getTypeName().equalsIgnoreCase("INT UNSIGNED") ? "setLong" : "setInt";
407                        }
408                        case Types.JAVA_OBJECT : {
409                                return "setObject";
410                        }
411                        case Types.LONGVARBINARY : {
412                                return "setBytes";
413                        }
414                        case Types.LONGVARCHAR : {
415                                return "setString";
416                        }
417                        case Types.NUMERIC : {
418                                return this.getDecimalDigits() > 0 ? "setBigDecimal" : "setLong";
419                        }
420                        case Types.OTHER : {
421                                return "setObject";
422                        }
423                        case Types.REAL : {
424                                return "setFloat";
425                        }
426                        case Types.REF : {
427                                return "setRef";
428                        }
429                        case Types.SMALLINT : {
430                                return "setInt";
431                        }
432                        case Types.STRUCT : {
433                                return "setObject";
434                        }
435                        case Types.TIME : {
436                                if ("java.util.Date".equals(CodeWriter.timeClassName)) {
437                                        return "setDate";
438                                }
439                                if ("java.sql.Time".equals(CodeWriter.timeClassName)) {
440                                        return "setTime";
441                                }
442                                this.tuoe();
443                        }
444                        case Types.TIMESTAMP : {
445                                if ("java.util.Date".equals(CodeWriter.timestampClassName)) {
446                                        return "setDate";
447                                }
448                                if ("java.sql.Timestamp".equals(CodeWriter.timestampClassName)) {
449                                        return "setTimestamp";
450                                }
451                                this.tuoe();
452                        }
453                        case Types.TINYINT : {
454                                return "setInt";
455                        }
456                        case Types.VARBINARY : {
457                                return "setBytes";
458                        }
459                        case Types.VARCHAR : {
460                                return "setString";
461                        }
462                }
463                this.tuoe();
464                return "setObject";
465        }
466        /**
467         * @return 返回对应的Java类型
468         */
469        public Class<?> getJavaClass() {
470                switch (this.getMappedType()) {
471                        case M_ARRAY : {
472                                return java.sql.Array.class;
473                        }
474                        case M_BIGDECIMAL : {
475                                return java.math.BigDecimal.class;
476                        }
477                        case M_BOOLEAN : {
478                                return Boolean.class;
479                        }
480                        case M_BYTES : {
481                                try {
482                                        return Class.forName(CodeWriter.binaryClassName);
483                                } catch (ClassNotFoundException e) {
484                                        throw new RuntimeException(e);
485                                }
486                        }
487                        case M_CLOB : {
488                                // map Clob to java.lang.String
489                                return String.class;
490                        }
491                        case M_SQLDATE : {
492                                return java.sql.Date.class;
493                        }
494                        case M_UTILDATE : {
495                                return java.util.Date.class;
496                        }
497                        case M_DOUBLE : {
498                                return Double.class;
499                        }
500                        case M_FLOAT : {
501                                return Float.class;
502                        }
503                        case M_BLOB : {
504                                try {
505                                        return Class.forName(CodeWriter.binaryClassName);
506                                } catch (ClassNotFoundException e) {
507                                        throw new RuntimeException(e);
508                                }
509                        }
510                        case M_INTEGER : {
511                                return Integer.class;
512                        }
513                        case M_LONG : {
514                                return Long.class;
515                        }
516                        case M_REF : {
517                                return java.sql.Ref.class;
518                        }
519                        case M_STRING : {
520                                return String.class;
521                        }
522                        case M_TIME : {
523                                return java.sql.Time.class;
524                        }
525                        case M_TIMESTAMP : {
526                                return java.sql.Timestamp.class;
527                        }
528                        case M_URL : {
529                                return java.net.URL.class;
530                        }
531                        case M_OBJECT : {
532                                return Object.class;
533                        }
534                        case M_CALENDAR : {
535                                return java.util.Calendar.class;
536                        }
537                }
538                this.tiae();
539                return null;
540        }
541        private String getJavaType(Class<?> type) {
542                if(type.isArray()){
543                        return getJavaType(type.getComponentType()) + "[]";
544                }
545                if(type.isPrimitive()){
546                        return type.getSimpleName();
547                }
548                if(type.getPackage().getName().equals("java.lang")){
549                        return type.getSimpleName();
550                }
551                return type.getName();
552        }
553        /**
554         * 返回对应的Java类型,除java语言内置类型(java.lang)外,其他类型返回全名
555         * @return
556         */
557        public String getJavaType() {
558                return getJavaType(getJavaClass());
559        }
560        
561        public boolean hasPrimaryType() {
562                return this.getJavaPrimaryType() != null;
563        }
564
565        public String getJavaPrimaryType() throws IllegalArgumentException {
566                int decimalDigits = this.getDecimalDigits();
567                if ((this.type == Types.DECIMAL || this.type == Types.NUMERIC) && decimalDigits == 0) {
568                        if (this.size == 1) {
569                                return "boolean";
570                        }
571                        if (this.size < 3) {
572                                return "byte";
573                        }
574                        if (this.size < 5) {
575                                return "short";
576                        }
577                        if (this.size < 10) {
578                                return "int";
579                        }
580                        if (this.size < 19) {
581                                return "long";
582                        }
583                }
584                switch (this.getMappedType()) {
585                        case M_BOOLEAN : {
586                                return "boolean";
587                        }
588                        case M_SQLDATE : {
589                                return "long";
590                        }
591                        case M_UTILDATE : {
592                                return "long";
593                        }
594                        case M_DOUBLE : {
595                                return "double";
596                        }
597                        case M_FLOAT : {
598                                return "float";
599                        }
600                        case M_INTEGER : {
601                                return "int";
602                        }
603                        case M_LONG : {
604                                return "long";
605                        }
606                        case M_TIME : {
607                                return "long";
608                        }
609                        case M_TIMESTAMP : {
610                                return "long";
611                        }
612                }
613                return null;
614        }
615        
616        public String getNullInstead(){
617                if(isDate()){
618                        return "new "+getJavaType() + "(0L)";
619                }else if(isString()){
620                        return "\"\"";
621                }else{
622                        String primitiveName = getJavaPrimaryType();            
623                        if(null != primitiveName){
624                                ImmutableMap<String, Class<?>> primtypes = Maps.uniqueIndex(Primitives.allWrapperTypes(),new Function<Class<?>,String>(){
625                                        @Override
626                                        public String apply(Class<?> input) {
627                                                return Primitives.unwrap(input).getSimpleName();
628                                        }});
629                                Class<?> wrapType = primtypes.get(primitiveName);
630                                if(Number.class.isAssignableFrom(wrapType) || Character.class==wrapType){
631                                        return wrapType.getSimpleName()+".MIN_VALUE";
632                                }else if(Boolean.class == wrapType)
633                                        return wrapType.getSimpleName()+".FALSE";
634                                tuoe();
635                        }
636                }
637                return "null";
638        }
639        public String getJavaTypeAsTypeName() {
640                switch (this.getType()) {
641                        case Types.ARRAY : {
642                                return "Types.ARRAY";
643                        }
644                        case Types.BIGINT : {
645                                return "Types.BIGINT";
646                        }
647                        case Types.BINARY : {
648                                return "Types.BINARY";
649                        }
650                        case Types.BIT : {
651                                return "Types.BIT";
652                        }
653                        case Types.BLOB : {
654                                return "Types.BLOB";
655                        }
656                        case Types.BOOLEAN : {
657                                return "Types.BOOLEAN";
658                        }
659                        case Types.CHAR : {
660                                return "Types.CHAR";
661                        }
662                        case Types.CLOB : {
663                                return "Types.CLOB";
664                        }
665                        case Types.DATALINK : {
666                                return "Types.DATALINK";
667                        }
668                        case Types.DATE : {
669                                return "Types.DATE";
670                        }
671                        case Types.DECIMAL : {
672                                return "Types.DECIMAL";
673                        }
674                        case Types.DISTINCT : {
675                                return "Types.DISTINCT";
676                        }
677                        case Types.DOUBLE : {
678                                return "Types.DOUBLE";
679                        }
680                        case Types.FLOAT : {
681                                return "Types.FLOAT";
682                        }
683                        case Types.INTEGER : {
684                                return "Types.INTEGER";
685                        }
686                        case Types.JAVA_OBJECT : {
687                                return "Types.JAVA_OBJECT";
688                        }
689                        case Types.LONGVARBINARY : {
690                                return "Types.LONGVARBINARY";
691                        }
692                        case Types.LONGVARCHAR : {
693                                return "Types.LONGVARCHAR";
694                        }
695                        case Types.NULL : {
696                                return "Types.NULL";
697                        }
698                        case Types.NUMERIC : {
699                                return "Types.NUMERIC";
700                        }
701                        case Types.OTHER : {
702                                return "Types.OTHER";
703                        }
704                        case Types.REAL : {
705                                return "Types.REAL";
706                        }
707                        case Types.REF : {
708                                return "Types.REF";
709                        }
710                        case Types.SMALLINT : {
711                                return "Types.SMALLINT";
712                        }
713                        case Types.STRUCT : {
714                                return "Types.STRUCT";
715                        }
716                        case Types.TIME : {
717                                return "Types.TIME";
718                        }
719                        case Types.TIMESTAMP : {
720                                return "Types.TIMESTAMP";
721                        }
722                        case Types.TINYINT : {
723                                return "Types.TINYINT";
724                        }
725                        case Types.VARBINARY : {
726                                return "Types.VARBINARY";
727                        }
728                        case Types.VARCHAR : {
729                                return "Types.VARCHAR";
730                        }
731                }
732                return "unkown SQL type " + this.getType();
733        }
734
735        /**
736         * @return 字段类型是否有长度限制
737         */
738        public boolean isSizeLimit(){
739                switch (this.getMappedType()) {
740                case M_ARRAY : 
741                case M_BYTES : 
742                case M_CLOB : 
743                case M_BLOB : 
744                case M_STRING :
745                        return true;
746                default:
747                        return false;
748                }
749        }
750        /**
751         * @return 字段类型是否有最大长度限制
752         */
753        public boolean isMaxSize(){
754                switch (this.getType()) {
755                case Types.BLOB : 
756                case Types.CLOB :
757                case Types.NCLOB :
758                case Types.LONGVARBINARY : 
759                case Types.LONGVARCHAR : 
760                case Types.VARBINARY : 
761                case Types.VARCHAR :
762                case Types.NVARCHAR :
763                        return true;
764                default:
765                        return false;
766                }
767        }
768        /**
769         * @return 字段类型是否有固定长度限制
770         */
771        public boolean isFixSize(){
772                switch (this.getType()) {
773                case Types.ARRAY :
774                case Types.BINARY :
775                case Types.CHAR :
776                case Types.NCHAR:
777                        return true;
778                default:
779                        return false;
780                }
781        }
782
783        public boolean isCrossableDefaultvalue(){
784                return defaultValue != null && !defaultValue.equals("CURRENT_TIMESTAMP");
785        }
786        public boolean isColumnNumeric() {
787                switch (this.getMappedType()) {
788                        case M_BIGDECIMAL :
789                        case M_DOUBLE :
790                        case M_FLOAT :
791                        case M_INTEGER :
792                        case M_LONG : {
793                                return true;
794                        }
795                }
796                return false;
797        }
798
799        public boolean isString() {
800                return M_STRING == this.getMappedType();
801        }
802        public boolean isFloat() {
803                return M_FLOAT == this.getMappedType();
804        }
805        public boolean isDate() {
806                switch (this.getMappedType()) {
807                case M_SQLDATE: 
808                case M_UTILDATE :
809                case M_TIME :
810                case M_TIMESTAMP : 
811                        return true;
812                }
813                return false;
814        }
815        public boolean isBinary() {
816                switch (this.getMappedType()) {
817                case M_BYTES: 
818                case M_BLOB:
819                        return true;
820                }
821                return false;
822        }
823        public boolean isCalendar() {
824                return this.getMappedType() == M_CALENDAR;
825        }
826
827        public boolean hasCompareTo() throws Exception {
828                switch (this.getMappedType()) {
829                        case M_ARRAY : {
830                                return false;
831                        }
832                        case M_BIGDECIMAL : {
833                                return true;
834                        }
835                        case M_BOOLEAN : {
836                                return true;
837                        }
838                        case M_BYTES : {
839                                return CodeWriter.binaryIsByteBuffer();
840                        }
841                        case M_CLOB : {
842                                // Clob map to java.lang.String that has compareTo
843                                return true;
844                        }
845                        case M_SQLDATE : {
846                                return true;
847                        }
848                        case M_UTILDATE : {
849                                return true;
850                        }
851                        case M_DOUBLE : {
852                                return true;
853                        }
854                        case M_FLOAT : {
855                                return true;
856                        }
857                        case M_BLOB : {
858                                return CodeWriter.binaryIsByteBuffer();
859                        }
860                        case M_INTEGER : {
861                                return true;
862                        }
863                        case M_LONG : {
864                                return true;
865                        }
866                        case M_REF : {
867                                return false;
868                        }
869                        case M_STRING : {
870                                return true;
871                        }
872                        case M_TIME : {
873                                return true;
874                        }
875                        case M_TIMESTAMP : {
876                                return true;
877                        }
878                        case M_URL : {
879                                return false;
880                        }
881                        case M_OBJECT : {
882                                return false;
883                        }
884                        case M_CALENDAR : {
885                                return true;
886                        }
887                }
888                return false;
889        }
890
891        public boolean useEqualsInSetter() throws Exception {
892                // 优先使用equals方法
893                if(hasCompareTo())return true;
894                switch (this.getMappedType()) {
895                        case M_BOOLEAN : {
896                                return true;
897                        }
898                        case M_URL : {
899                                return true;
900                        }
901                }
902                return false;
903        }
904
905        public String getResultSetMethodObject(String pos) {
906                return this.getResultSetMethodObject("rs", pos);
907        }
908
909        public String getResultSetMethodObject(String resultSet, String pos) {
910                switch (this.getMappedType()) {
911                        case M_ARRAY : {
912                                return resultSet + ".getArray(" + pos + ")";
913                        }
914                        case M_LONG : {
915                                return CodeWriter.MGR_CLASS + ".getLong(" + resultSet + ", " + pos + ")";
916                        }
917                        case M_BYTES : {
918                                return CodeWriter.MGR_CLASS + ".getBytes(" + resultSet + ", " + pos + ")";
919                        }
920                        case M_BLOB : {
921                                return CodeWriter.MGR_CLASS + ".getBlob(" + resultSet + ", " + pos + ")";
922                        }
923                        case M_BOOLEAN : {
924                                return CodeWriter.MGR_CLASS + ".getBoolean(" + resultSet + ", " + pos + ")";
925                        }
926                        case M_STRING : {
927                                return resultSet + ".getString(" + pos + ")";
928                        }
929                        case M_CLOB : {
930                                return CodeWriter.MGR_CLASS + ".getClob(" + resultSet + ", " + pos + ")";
931                        }
932                        case M_URL : {
933                                return resultSet + ".getURL(" + pos + ")";
934                        }
935                        case M_BIGDECIMAL : {
936                                return resultSet + ".getBigDecimal(" + pos + ")";
937                        }
938                        case M_DOUBLE : {
939                                return CodeWriter.MGR_CLASS + ".getDouble(" + resultSet + ", " + pos + ")";
940                        }
941                        case M_FLOAT : {
942                                return CodeWriter.MGR_CLASS + ".getFloat(" + resultSet + ", " + pos + ")";
943                        }
944                        case M_INTEGER : {
945                                return CodeWriter.MGR_CLASS + ".getInteger(" + resultSet + ", " + pos + ")";
946                        }
947                        case M_OBJECT : {
948                                return resultSet + ".getObject(" + pos + ")";
949                        }
950                        case M_REF : {
951                                return resultSet + ".getRef(" + pos + ")";
952                        }
953                        case M_SQLDATE : {
954                                return resultSet + ".getDate(" + pos + ")";
955                        }
956                        case M_TIME : {
957                                return resultSet + ".getTime(" + pos + ")";
958                        }
959                        case M_TIMESTAMP : {
960                                return resultSet + ".getTimestamp(" + pos + ")";
961                        }
962                        case M_UTILDATE : {
963                                switch (this.getType()) {
964                                        case Types.TIME : {
965                                                return resultSet + ".getTime(" + pos + ")";
966                                        }
967                                        case Types.TIMESTAMP : {
968                                                return resultSet + ".getTimestamp(" + pos + ")";
969                                        }
970                                        case Types.DATE : {
971                                                return resultSet + ".getDate(" + pos + ")";
972                                        }
973                                }
974                                this.tuoe();
975                        }
976                        case M_CALENDAR : {
977                                return CodeWriter.MGR_CLASS + ".getCalendar(" + resultSet + ", " + pos + ")";
978                        }
979                }
980                this.tuoe();
981                return null;
982        }
983
984        public String getPreparedStatementMethod(String var, int pos) {
985                return this.getPreparedStatementMethod(var, String.valueOf(pos));
986        }
987
988        public String getPreparedStatementMethod(String var, String pos) {
989                StringBuffer sb = new StringBuffer();
990                StringBuffer end = new StringBuffer();
991                end.append(pos).append(", ").append(var).append(");");
992                String fillNullStart = Boolean.TRUE == CodeWriter.getFillNull() ? "" : "if(fillNull){";
993                String fillNullEnd = Boolean.TRUE == CodeWriter.getFillNull() ? "" : "}";
994        Pattern p = Pattern.compile("^((?:SQL_LIKE_WILDCARD\\s*\\+)*)([\\w\\. \\(\\)-]*)((?:\\+\\s*SQL_LIKE_WILDCARD)*)$");
995        
996        Matcher m = p.matcher(var);
997        if(!m.matches()){
998                throw new IllegalArgumentException(String.format("Not match found %s", var));
999        }
1000                String v = m.group(2);
1001                sb.append("if (").append(v).append(" == null) {"+fillNullStart+" ps.setNull(").append(pos).append(", ")
1002                                .append(this.getJavaTypeAsTypeName()).append(");").append(fillNullEnd).append(" } else { ");
1003                end.append(" }");
1004                switch (this.getMappedType()) {
1005                        case M_ARRAY : {
1006                                return sb.append("ps.setArray(").append(end).toString();
1007                        }
1008                        case M_LONG : {
1009                                return sb.append(CodeWriter.MGR_CLASS).append(".setLong(ps, ").append(end).toString();
1010                        }
1011                        case M_BYTES : {
1012                                return sb.append(CodeWriter.MGR_CLASS).append(".setBytes("+this.getJavaTypeAsTypeName()+",ps, ").append(end).toString();
1013                        }
1014                        case M_BLOB : {
1015                                return sb.append(CodeWriter.MGR_CLASS).append(".setBlob(ps, ").append(end).toString();
1016                        }
1017                        case M_BOOLEAN : {
1018                                return sb.append(CodeWriter.MGR_CLASS).append(".setBoolean(ps, ").append(end).toString();
1019                        }
1020                        case M_STRING : {
1021                                return sb.append("ps.setString(").append(end).toString();
1022                        }
1023                        case M_CLOB : {
1024                                return sb.append(CodeWriter.MGR_CLASS).append(".setClob(ps, ").append(end).toString();
1025                        }
1026                        case M_URL : {
1027                                return sb.append("ps.setURL(").append(end).toString();
1028                        }
1029                        case M_BIGDECIMAL : {
1030                                return sb.append("ps.setBigDecimal(").append(end).toString();
1031                        }
1032                        case M_DOUBLE : {
1033                                return sb.append(CodeWriter.MGR_CLASS).append(".setDouble(ps, ").append(end).toString();
1034                        }
1035                        case M_INTEGER : {
1036                                return sb.append(CodeWriter.MGR_CLASS).append(".setInteger(ps, ").append(end).toString();
1037                        }
1038                        case M_OBJECT : {
1039                                return sb.append("ps.setObject(").append(end).toString();
1040                        }
1041                        case M_FLOAT : {
1042                                return sb.append(CodeWriter.MGR_CLASS).append(".setFloat(ps, ").append(end).toString();
1043                        }
1044                        case M_SQLDATE : {
1045                                return sb.append("ps.setDate(").append(end).toString();
1046                        }
1047                        case M_TIME : {
1048                                return sb.append("ps.setTime(").append(end).toString();
1049                        }
1050                        case M_TIMESTAMP : {
1051                                return sb.append("ps.setTimestamp(").append(end).toString();
1052                        }
1053                        case M_UTILDATE : {
1054                                switch (this.getType()) {
1055                                        case Types.TIMESTAMP : {
1056                                                return sb.append("ps.setTimestamp(").append(pos).append(", new java.sql.Timestamp(").append(var)
1057                                                                .append(".getTime())); }").toString();
1058                                        }
1059                                        case Types.DATE : {
1060                                                return sb.append("ps.setDate(").append(pos).append(", new java.sql.Date(").append(var)
1061                                                                .append(".getTime())); }").toString();
1062                                        }
1063                                        case Types.TIME : {
1064                                                return sb.append("ps.setTime(").append(pos).append(", new java.sql.Time(").append(var)
1065                                                                .append(".getTime())); }").toString();
1066                                        }
1067                                }
1068                                return null;
1069                        }
1070                        case M_CALENDAR : {
1071                                return sb.append(CodeWriter.MGR_CLASS).append(".setCalendar(ps, ").append(end).toString();
1072                        }
1073                        case M_REF : {
1074                                sb.setLength(0);
1075                                sb.append("ps.setRef(").append(end);
1076                                sb.setLength(sb.length() - 2);
1077                                return sb.toString();
1078                        }
1079                }
1080                sb.setLength(0);
1081                sb.append("ps.setObject(").append(end);
1082                sb.setLength(sb.length() - 2);
1083                return sb.toString();
1084        }
1085
1086        public String getStringConvertionMethod() {
1087                switch (this.getMappedType()) {
1088                        case M_BIGDECIMAL : {
1089                                return "new java.math.BigDecimal";
1090                        }
1091                        case M_BOOLEAN : {
1092                                return "new Boolean";
1093                        }
1094                        case M_SQLDATE : {
1095                                return "new java.sql.Date";
1096                        }
1097                        case M_DOUBLE : {
1098                                return "new Double";
1099                        }
1100                        case M_FLOAT : {
1101                                return "new Float";
1102                        }
1103                        case M_INTEGER : {
1104                                return "new Integer";
1105                        }
1106                        case M_LONG : {
1107                                return "new Long";
1108                        }
1109                        case M_STRING : {
1110                                return "";
1111                        }
1112                        case M_UTILDATE :
1113                        case M_TIME :
1114                        case M_TIMESTAMP : {
1115                                if ("java.util.GregorianCalendar".equals(CodeWriter.dateClassName)) {
1116                                        return "GregorianDate";
1117                                }
1118                                return CodeWriter.MGR_CLASS + ".getDateFromString";
1119                        }
1120                }
1121                System.err.println(
1122                                " unknown mapped type " + this.getMappedType() + " (" + this.getType() + ") for " + this.getFullName());
1123                return "";
1124        }
1125
1126        public String getDefaultWidget() {
1127                if (this.isForeignKey()) {
1128                        return "SelectWidget";
1129                }
1130                if (this.isString() && (this.getSize() > 200 || this.getSize() == -1)) {
1131                        return "TextAreaWidget";
1132                }
1133                switch (this.getMappedType()) {
1134                        case M_BOOLEAN : {
1135                                return "BooleanWidget";
1136                        }
1137                        case M_SQLDATE :
1138                        case M_UTILDATE :
1139                        case M_TIME :
1140                        case M_TIMESTAMP : {
1141                                return "DateWidget";
1142                        }
1143                        case M_BIGDECIMAL :
1144                        case M_DOUBLE :
1145                        case M_FLOAT :
1146                        case M_INTEGER :
1147                        case M_LONG : {
1148                                return "NumericWidget";
1149                        }
1150                        case M_ARRAY :
1151                        case M_BYTES :
1152                        case M_CLOB :
1153                        case M_REF :
1154                        case M_STRING :
1155                        case M_URL :
1156                        case M_OBJECT : {
1157                                return "InputWidget";
1158                        }
1159                }
1160                System.err.println("type unknown for " + this.getFullName());
1161                return "";
1162        }
1163
1164        public boolean isVersion() {
1165                if (!CodeWriter.optimisticLockType.equalsIgnoreCase("timestamp")) {
1166                        return false;
1167                }
1168                if (!this.getName().equalsIgnoreCase(CodeWriter.optimisticLockColumn)) {
1169                        return false;
1170                }
1171                if (this.getMappedType() == M_LONG || this.getMappedType() == M_STRING) {
1172                        return true;
1173                }
1174                return false;
1175        }
1176
1177        public Table getTable() {
1178                return this.db.getTable(this.getTableName());
1179        }
1180
1181        public void addForeignKey(Column col, 
1182                        String fkName, 
1183                        short keySeq,
1184                        Table.ForeignKeyRule updateRule,
1185                        Table.ForeignKeyRule deleteRule) {
1186                this.foreignKeys.add(col);
1187                this.getTable().addForeignKey(this, fkName,keySeq, updateRule, deleteRule);
1188        }
1189
1190        public List<Column> getForeignKeys() {
1191                return this.foreignKeys;
1192        }
1193
1194        public void addImportedKey(Column col) {
1195                this.importedKeys.add(col);
1196                this.getTable().addImportedKey(col);
1197        }
1198
1199        public List<Column> getImportedKeys() {
1200                return this.importedKeys;
1201        }
1202
1203        public int countImportedKeys() {
1204                return this.importedKeys.size();
1205        }
1206
1207        public boolean isImportedKey() {
1208                if (this.countImportedKeys() > 0) {
1209                        return true;
1210                }
1211                return false;
1212        }
1213
1214        public Column getForeignColumn() {
1215                return (Column) this.foreignKeys.get(0);
1216        }
1217
1218        public int countForeignKeys() {
1219                return this.foreignKeys.size();
1220        }
1221
1222        public boolean isForeignKey() {
1223                if (this.countForeignKeys() > 0) {
1224                        return true;
1225                }
1226                return false;
1227        }
1228
1229        public String getPropertyTag() {
1230                return (this.getTableName() + "." + this.getName()).toLowerCase();
1231        }
1232
1233        public String getDefaultRules() {
1234                String rule = "";
1235                rule = this.getNullable() == 0 && !this.isPrimaryKey() ? rule + " nullnotallowed" : rule + " nullallowed";
1236                if (this.getType() == 91 || this.getType() == 93) {
1237                        rule = rule + " dateformat";
1238                }
1239                return rule;
1240        }
1241
1242        public boolean getDefaultIncludeFor(String webElement) {
1243                return true;
1244        }
1245        
1246        private static final String EMPTY_STRING = "";
1247        /**
1248         * 生成缺省值字符串
1249         * @param nullInstead 指示{@link #defaultValue}为 {@code null}时是否用字符串'null'代替
1250         * @return
1251         */
1252        public String getDefaultValue(boolean nullInstead) {
1253                String empty = nullInstead?"null":EMPTY_STRING;
1254                if(!CodeWriter.getPropertyBoolean("codewriter.generate.defaultvalue")){
1255                        return empty;
1256                }
1257                if (null != this.defaultValue) {
1258                        if (this.isColumnNumeric()) {
1259                                try {
1260                                        double value = Double.parseDouble(this.defaultValue);
1261                                        switch (this.getMappedType()) {
1262                                                case M_BIGDECIMAL :
1263                                                case M_INTEGER :
1264                                                case M_LONG : {
1265                                                        return this.generateNewNumeric(this.getJavaType(), this.defaultValue);
1266                                                }
1267                                                case M_DOUBLE :
1268                                                case M_FLOAT : {
1269                                                        return this.generateNewNumeric(this.getJavaType(), String.valueOf(value));
1270                                                }
1271                                        }
1272                                        return empty;
1273                                } catch (NumberFormatException nfe) {
1274                                        return empty;
1275                                }
1276                        }
1277                        if (this.isDate()) {
1278                                try {
1279                                        return generateDateDefaultValue(this.getJavaType(),this.defaultValue);
1280                                } catch (IllegalArgumentException pe) {
1281                                        return empty;
1282                                }
1283                        }
1284                        if (this.isString()) {
1285                                return "\"" + this.defaultValue + '\"';
1286                        }
1287                        if (M_BOOLEAN == this.getMappedType()) {
1288                                return "Boolean.valueOf(\"" + ("1".equals(this.defaultValue) ? "true" : "false")
1289                                                + "\").booleanValue()";
1290                        }
1291                }
1292                return this.defaultValue == null ? empty : this.defaultValue;
1293        }
1294        /** 兼容之前版本 */
1295        public String getDefaultValue() {
1296                return getDefaultValue(false);
1297        }
1298        /** 返回{@link #defaultValue}原始值 */
1299        public String getOriginalDefaultValue(){
1300                return this.defaultValue;
1301        }
1302        /** SQL 类型日期字符串转为java 日期对象 */
1303        private static Date parseSqlDate(String source){
1304                if(null == source)
1305                        throw new IllegalArgumentException();
1306                try{
1307                        return java.sql.Date.valueOf(source);
1308                }catch(IllegalArgumentException e){
1309                        try{
1310                                return java.sql.Time.valueOf(source);
1311                        }catch(IllegalArgumentException e2){
1312                                return java.sql.Timestamp.valueOf(source);
1313                        }
1314                }
1315        }
1316        /** 生成日期类型缺省值语句 */
1317        private String generateDateDefaultValue(String type, String parameter) {
1318                StringBuffer sb = new StringBuffer(100);
1319                Date parsedDate = parseSqlDate(parameter);
1320                String dateStr;
1321                switch(this.getMappedType()){
1322                case M_UTILDATE:{
1323                        String instanceName="";
1324                        if(parsedDate instanceof java.sql.Date){
1325                                instanceName = "new java.text.SimpleDateFormat(\"yyyy-MM-dd\")";
1326                        }else if(parsedDate instanceof java.sql.Time){
1327                                instanceName = "new java.text.SimpleDateFormat(\"HH:mm:ss\")";
1328                        }else if(parsedDate instanceof java.sql.Timestamp){
1329                                instanceName = "new java.text.SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\")";
1330                        }else{
1331                                throw new IllegalStateException("invalid type");
1332                        }
1333                        sb.append(instanceName).append(".parse(\"").append(parsedDate.toString()).append("\",new java.text.ParsePosition(0))");
1334                        break;
1335                }
1336                case M_SQLDATE:{
1337                        dateStr = new java.sql.Date(parsedDate.getTime()).toString();
1338                        sb.append(type).append(".valueOf(\"").append(dateStr).append("\")");    
1339                        break;
1340                }
1341                case M_TIME:{
1342                        dateStr = new java.sql.Time(parsedDate.getTime()).toString();
1343                        sb.append(type).append(".valueOf(\"").append(dateStr).append("\")");    
1344                        break;
1345                }
1346                case M_TIMESTAMP:{
1347                        dateStr = new java.sql.Timestamp(parsedDate.getTime()).toString();
1348                        sb.append(type).append(".valueOf(\"").append(dateStr).append("\")");    
1349                        break;
1350                }
1351                default:
1352                        return EMPTY_STRING;
1353                }
1354                return sb.toString();
1355        }       
1356        
1357        private String generateNewNumeric(String type, String parameter) {
1358                StringBuffer sb = new StringBuffer(70);
1359                sb.append("new ").append(type);
1360                sb.append('(').append(parameter).append(')');
1361                return sb.toString();
1362        }
1363
1364        /** 生成缺省值({@link #defaultValue})的注释信息 */
1365        public String commentOfDefaultValue(){
1366                return Strings.isNullOrEmpty(defaultValue)?EMPTY_STRING: "/* DEFAULT:'"+defaultValue+"'*/";
1367        }
1368        /** 生成缺省值赋值语句 */
1369    public String getDefaultValueAssignment(boolean nullInstead){
1370        StringBuffer buffer = new StringBuffer();
1371        String value = getDefaultValue(nullInstead);
1372        if(!value.isEmpty())
1373                buffer.append(" = ").append(value);
1374        return buffer.toString();
1375    }
1376        public String getRemarks() {
1377                return this.remarks == null ? "" : this.remarks;
1378        }
1379
1380        public String getJavaName() {
1381                return this.convertName(this.getName());
1382        }
1383
1384        public String getSampleData() {
1385                if (this.getNullable() > 1 && rand.nextInt(20) == 10) {
1386                        return "";
1387                }
1388                if (this.isColumnNumeric()) {
1389                        return "" + rand.nextInt(100);
1390                }
1391                if (this.isDate()) {
1392                        Calendar rightNow = Calendar.getInstance();
1393                        rightNow.set(2000 + rand.nextInt(20), 1 + rand.nextInt(12), 1 + rand.nextInt(28), rand.nextInt(23),
1394                                        rand.nextInt(60), rand.nextInt(60));
1395                        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
1396                        return dateFormat.format(rightNow.getTime());
1397                }
1398                return StringUtilities.getSampleString((int) this.getSize());
1399        }
1400
1401        private String escape(String s) {
1402                return StringUtilities.escape((String) s);
1403        }
1404
1405        private String escape() {
1406                return this.escape(this.getName());
1407        }
1408
1409        public String convertName(String columnName) {
1410                return StringUtilities.convertName((String) columnName, true);
1411        }
1412
1413        public String convertName(Column col) {
1414                return this.convertName(col.getName());
1415        }
1416
1417        public String convertName() {
1418                return this.convertName(this.name);
1419        }
1420
1421        public String getImportedKeyVarName() {
1422                return this.convertName(this.escape() + "_collection");
1423        }
1424
1425        public String getGetMethod() {
1426                return this.convertName("get_" + this.escape());
1427        }
1428
1429        public String getSetMethod() {
1430                return this.convertName("set_" + this.escape());
1431        }
1432        public String getReadMethod() {
1433                return this.convertName("read_" + this.escape());
1434        }
1435        public String getWriteMethod() {
1436                return this.convertName("write_" + this.escape());
1437        }
1438        public String getModifiedMethod() {
1439                return this.convertName("check_" + this.escape() + "_modified");
1440        }
1441
1442        public String getInitializedMethod() {
1443                return this.convertName("check_" + this.escape() + "_initialized");
1444        }
1445        public String getGetCacheMethod() {
1446                return this.convertName("get_bean_by_" + this.escape());
1447        }
1448        public String getPutCacheMethod() {
1449                return this.convertName("put_by_" + this.escape());
1450        }
1451        public String getPutIfAbsentCacheMethod() {
1452                return this.convertName("put_If_absent_by_" + this.escape());
1453        }
1454        public String getReplaceCacheMethod() {
1455                return this.convertName("replace_by_" + this.escape());
1456        }
1457
1458        public String bitAndExpression(String varName){
1459                if(this.getTable().countColumns()>32){
1460                        int pos = getOrdinalPosition()-1;
1461                        return String.format("(%s[%d] & (1 << %d))",varName,pos>>6,pos & 0x3f);
1462                }else{
1463                        return String.format("(%s & %s)", varName,getIDMaskConstName());
1464                }
1465        }
1466        
1467        public String bitORAssignExpression(String varName){
1468                if(this.getTable().countColumns()>32){
1469                        int pos = getOrdinalPosition()-1;
1470                        return String.format("%s[%d] |= (1 << %d)",varName,pos>>6,pos & 0x3f);
1471                }else{
1472                        return String.format("%s |= %s", varName,getIDMaskConstName());
1473                }
1474        }       
1475        public String bitResetAssignExpression(String varName){
1476                if(this.getTable().countColumns()>32){
1477                        int pos = getOrdinalPosition()-1;
1478                        return String.format("%s[%d] &= (~(1 << %d))",varName,pos>>6,pos & 0x3f);
1479                }else{
1480                        return String.format("%s &= (~%s)", varName,getIDMaskConstName());
1481                }
1482        }
1483        public String getWidgetMethod() {
1484                return this.convertName("get_" + this.escape() + "_widget");
1485        }
1486
1487        public String getVarName() {
1488                return this.convertName(this.escape());
1489        }
1490        public String getCacheVarName() {
1491                return this.convertName(this.escape() + "_cacher");
1492        }
1493        public String getFullVarName() {
1494                return this.convertName(this.name +"_of_" + this.getTable().getBasename(true));
1495        }
1496        public String getModifiedVarName() {
1497                return this.convertName(this.escape() + "_is_modified");
1498        }
1499
1500        public String getInitializedVarName() {
1501                return this.convertName(this.escape() + "_is_initialized");
1502        }
1503
1504        public String getImportedKeyModifiedVarName() {
1505                return this.convertName(this.escape() + "_collection_is_modified");
1506        }
1507
1508        public String getImportedKeyInitializedVarName() {
1509                return this.convertName(this.escape() + "_collection_is_initialized");
1510        }
1511
1512        public String getImportedKeyInitializedMethod() {
1513                return this.convertName("is_" + this.escape() + "_collection_initialized");
1514        }
1515
1516        public String getImportedKeyGetMethod() {
1517                return this.convertName("get_" + this.escape() + "_collection");
1518        }
1519
1520        public String getImportedKeyAddMethod() {
1521                return this.convertName("add_" + this.escape() + "");
1522        }
1523
1524        public String getImportedKeySetMethod() {
1525                return this.convertName("set_" + this.escape() + "_collection");
1526        }
1527
1528        public String getImportedKeyModifiedMethod() {
1529                return this.convertName("is_" + this.escape() + "_collection_modified");
1530        }
1531
1532        public String getForeignKeyVarName() {
1533                return this.convertName(this.escape() + "_object");
1534        }
1535
1536        public String getForeignKeyModifiedVarName() {
1537                return this.convertName(this.escape() + "_object_is_modified");
1538        }
1539
1540        public String getForeignKeyInitializedVarName() {
1541                return this.convertName(this.escape() + "_object_is_initialized");
1542        }
1543
1544        public String getForeignKeyInitializedMethod() {
1545                return this.convertName("is_" + this.escape() + "_object_initialized");
1546        }
1547
1548        public String getForeignKeyGetMethod(String col) {
1549                return this.convertName("get_" + this.escape() + "_object");
1550        }
1551
1552        public String getForeignKeySetMethod(String col) {
1553                return this.convertName("set_" + this.escape() + "_object");
1554        }
1555
1556        public String getForeignKeyModifiedMethod(String col) {
1557                return this.convertName("is_" + this.escape() + "_object_modified");
1558        }
1559        
1560        public String getTypeName() {
1561                return this.typeName;
1562        }
1563
1564        public void setTypeName(String typeName) {
1565                this.typeName = typeName;
1566        }
1567
1568        public int compareTo(Column obj) {
1569                return  this.ordinal - obj.ordinal;
1570        }
1571
1572        public String getAutoincrement() {
1573                return autoincrement;
1574        }
1575
1576        public void setAutoincrement(String autoincrement) {
1577                this.autoincrement = autoincrement;
1578        }
1579        public boolean isAutoincrement(){
1580                return "YES".equals(this.autoincrement);
1581        }
1582        public boolean isNotNull(){
1583                return DatabaseMetaData.columnNoNulls  == this.nullable ;
1584        }
1585        
1586        private static final String IV_PREFIX = "invalidvalue.";
1587        private static final String IV_NUMBER = IV_PREFIX + "number";
1588        private static final String IV_DATE = IV_PREFIX + "date";
1589        private static final String PA_PREFIX = "prealloc.";
1590        private static final String PA_STRING = PA_PREFIX + "string.limit";
1591        private static final String PA_BINARY = PA_PREFIX + "binary.limit";
1592        private String getCustomInvalidValueAnn(){
1593                String iv = CodeWriter.getProperty(IV_PREFIX + ".table." + getTableName() + "."+ getName());
1594                if(iv != null){
1595                        return String.format("@CodegenInvalidValue(\"%s\")",iv);
1596                }
1597                String exp = CodeWriter.getProperty(IV_PREFIX + ".table." + getTableName() + "."+ getName()+".exp" );
1598                if(exp != null){
1599                        return String.format("@CodegenInvalidValue(exp=\"%s\")",exp);
1600                }
1601                return null;
1602        }
1603        public String getInvalidValueAnn(){
1604                if(invalidValueAnn == null){
1605                        synchronized (this) {
1606                                if(invalidValueAnn == null){
1607                                        invalidValueAnn = getCustomInvalidValueAnn();
1608                                        if(invalidValueAnn == null){
1609                                                if(isAutoincrement() || (getForeignKeys().size() ==1 && getForeignColumn().isAutoincrement())){
1610                                                        invalidValueAnn = "@CodegenInvalidValue(\"0\")";
1611                                                } else if(isString()){
1612                                                        // 空字符串为无效值
1613                                                        invalidValueAnn = "@CodegenInvalidValue";
1614                                                } else if(isBinary()){
1615                                                        // 空数组为无效值
1616                                                        invalidValueAnn = "@CodegenInvalidValue";
1617                                                } else if(isColumnNumeric()){
1618                                                        String iv = CodeWriter.getProperty(IV_NUMBER , "-1");                                                   
1619                                                        invalidValueAnn = "@CodegenInvalidValue(\"" + iv + "\")";
1620                                                } else if(isDate()){
1621                                                        String iv = CodeWriter.getProperty(IV_DATE , "0");                              
1622                                                        invalidValueAnn = "@CodegenInvalidValue(\"" + iv + "\")";
1623                                                }else {
1624                                                        invalidValueAnn = "";
1625                                                }
1626                                        } 
1627                                }
1628                        }
1629                }
1630                return invalidValueAnn;
1631        }
1632        
1633        private boolean isPreAlloc0(){
1634                if(TypeToken.of(getJavaClass()).isPrimitive()){
1635                        return true;
1636                }
1637                String columns = CodeWriter.getProperty(PA_PREFIX + ".table." + getTableName());
1638                if(columns != null){
1639                        if( MiscellaneousUtils.elementsOf(columns).contains(getName())){
1640                                return true;
1641                        }
1642                }
1643                if(isString()){
1644                        return getSize() <= CodeWriter.getPropertyInteger(PA_STRING);
1645                }
1646                if(isBinary()){
1647                        return getSize() <= CodeWriter.getPropertyInteger(PA_BINARY);                   
1648                }
1649                return false;
1650        }
1651        public boolean isPreAlloc(){
1652                if(preAlloc == null){
1653                        synchronized (this) {
1654                                if(preAlloc == null){
1655                                        preAlloc = isPreAlloc0();
1656                                }
1657                        }
1658                }
1659                return preAlloc;
1660        }
1661
1662}