1 5 package org.h2.table; 6 7 import java.sql.SQLException ; 8 import java.sql.Time ; 9 import java.sql.Timestamp ; 10 11 import org.h2.command.Parser; 12 import org.h2.engine.Constants; 13 import org.h2.engine.Mode; 14 import org.h2.engine.Session; 15 import org.h2.expression.ConditionAndOr; 16 import org.h2.expression.Expression; 17 import org.h2.expression.SequenceValue; 18 import org.h2.expression.ValueExpression; 19 import org.h2.message.Message; 20 import org.h2.result.Row; 21 import org.h2.schema.Schema; 22 import org.h2.schema.Sequence; 23 import org.h2.util.StringUtils; 24 import org.h2.value.DataType; 25 import org.h2.value.Value; 26 import org.h2.value.ValueInt; 27 import org.h2.value.ValueNull; 28 import org.h2.value.ValueString; 29 import org.h2.value.ValueTime; 30 import org.h2.value.ValueTimestamp; 31 32 35 public class Column { 36 private Table table; 37 private String name; 38 private int type; 39 private long precision; 40 private int scale; 41 private int columnId; 42 private boolean nullable = true; 43 private Expression defaultExpression; 44 private Expression checkConstraint; 45 private String checkConstraintSQL; 46 private String originalSQL; 47 private boolean autoIncrement; 48 private long start; 49 private long increment; 50 private boolean convertNullToDefault; 51 private Sequence sequence; 52 private boolean isComputed; 53 private TableFilter computeTableFilter; 54 private int selectivity; 55 private SingleColumnResolver resolver; 56 private String comment; 57 58 public static final int NOT_NULLABLE = 0, NULLABLE = 1, NULLABLE_UNKNOWN = 2; 60 61 public Column(String name, int type, long precision, int scale) { 62 this.name = name; 63 this.type = type; 64 this.precision = precision; 65 this.scale = scale; 66 } 67 68 public Column getClone() { 69 Column newColumn = new Column(name, type, precision, scale); 70 newColumn.nullable = nullable; 73 newColumn.defaultExpression = defaultExpression; 74 newColumn.originalSQL = originalSQL; 75 newColumn.convertNullToDefault = convertNullToDefault; 77 newColumn.sequence = sequence; 78 newColumn.comment = comment; 79 return newColumn; 80 } 81 82 public boolean getComputed() { 83 return isComputed; 84 } 85 86 public Value computeValue(Session session, Row row) throws SQLException { 87 computeTableFilter.setSession(session); 88 computeTableFilter.set(row); 89 return defaultExpression.getValue(session); 90 } 91 92 public void setComputed(boolean computed, Expression expression) { 93 this.isComputed = computed; 94 this.defaultExpression = expression; 95 } 96 97 void setTable(Table table, int columnId) { 98 this.table = table; 99 this.columnId = columnId; 100 } 101 102 public Table getTable() { 103 return table; 104 } 105 106 public void setDefaultExpression(Session session, Expression defaultExpression) throws SQLException { 107 if(defaultExpression != null) { 109 defaultExpression = defaultExpression.optimize(session); 110 if(defaultExpression.isConstant()) { 111 defaultExpression = ValueExpression.get(defaultExpression.getValue(session)); 112 } 113 } 114 this.defaultExpression = defaultExpression; 115 } 116 117 public int getColumnId() { 118 return columnId; 119 } 120 121 public String getSQL() { 122 return Parser.quoteIdentifier(name); 123 } 124 125 public String getName() { 126 return name; 127 } 128 129 public int getType() { 130 return type; 131 } 132 133 public long getPrecision() { 134 return precision; 135 } 136 137 public int getScale() { 138 return scale; 139 } 140 141 public void setNullable(boolean b) { 142 nullable = b; 143 } 144 145 public Value validateConvertUpdateSequence(Session session, Value value) throws SQLException { 146 if(value == null) { 147 if(defaultExpression == null) { 148 value = ValueNull.INSTANCE; 149 } else { 150 value = defaultExpression.getValue(session).convertTo(type); 151 } 152 } 153 if (value == ValueNull.INSTANCE) { 154 if(convertNullToDefault) { 155 value = defaultExpression.getValue(session).convertTo(type); 156 } 157 if (value == ValueNull.INSTANCE && !nullable) { 158 if(Mode.getCurrentMode().convertInsertNullToZero) { 159 DataType dt = DataType.getDataType(type); 160 if(dt.decimal) { 161 value = ValueInt.get(0).convertTo(type); 162 } else if(dt.type==Value.TIMESTAMP) { 163 value = ValueTimestamp.getNoCopy(new Timestamp (System.currentTimeMillis())); 164 } else if(dt.type==Value.TIME) { 165 value = ValueTime.get(Time.valueOf("0:0:0")); 167 } else if(dt.type==Value.DATE) { 168 value = ValueTimestamp.getNoCopy(new Timestamp (System.currentTimeMillis())).convertTo(dt.type); 169 } else { 170 value = ValueString.get("").convertTo(type); 171 } 172 } else { 173 throw Message.getSQLException(Message.NULL_NOT_ALLOWED, name); 174 } 175 } 176 } 177 if(checkConstraint != null) { 178 resolver.setValue(value); 179 Value v = checkConstraint.getValue(session); 180 if(Boolean.FALSE.equals(v.getBoolean())) { 182 throw Message.getSQLException(Message.CHECK_CONSTRAINT_VIOLATED_1, checkConstraint.getSQL()); 183 } 184 } 185 value = value.convertScale(Mode.getCurrentMode().convertOnlyToSmallerScale, scale); 186 if (precision > 0 && value.getPrecision() > precision) { 187 throw Message.getSQLException(Message.VALUE_TOO_LONG_1, name); 188 } 189 updateSequenceIfRequired(session, value); 190 return value; 191 } 192 193 private void updateSequenceIfRequired(Session session, Value value) throws SQLException { 194 if(sequence != null) { 195 long current = sequence.getCurrentValue(); 196 long increment = sequence.getIncrement(); 197 long now = value.getLong(); 198 boolean update = false; 199 if(increment > 0 && now > current) { 200 update = true; 201 } else if(increment < 0 && now < current) { 202 update = true; 203 } 204 if(update) { 205 sequence.setStartValue(now + increment); 206 session.setLastIdentity(now); 207 sequence.flush(); 208 } 209 } 210 } 211 212 public void convertAutoIncrementToSequence(Session session, Schema schema, int id, boolean temporary) throws SQLException { 213 if(!getAutoIncrement()) { 214 throw Message.getInternalError(); 215 } 216 if(originalSQL.equals("IDENTITY")) { 217 originalSQL = "BIGINT"; 218 } 219 String sequenceName; 220 for(int i=0; ; i++) { 221 sequenceName = "SYSTEM_SEQUENCE_" + i; 222 if(schema.findSequence(sequenceName) == null) { 223 break; 224 } 225 } 226 Sequence sequence = new Sequence(schema, id, sequenceName, true); 227 sequence.setStartValue(start); 228 sequence.setIncrement(increment); 229 if(!temporary) { 230 session.getDatabase().addSchemaObject(session, sequence); 231 } 232 setAutoIncrement(false, 0, 0); 233 SequenceValue seq = new SequenceValue(sequence); 234 setDefaultExpression(session, seq); 235 setSequence(sequence); 236 } 237 238 public void prepareExpression(Session session) throws SQLException { 239 if(defaultExpression != null) { 240 computeTableFilter = new TableFilter(session, table, null, false); 241 defaultExpression.mapColumns(computeTableFilter, 0); 242 defaultExpression = defaultExpression.optimize(session); 243 } 244 } 245 246 public String getCreateSQL() { 247 StringBuffer buff = new StringBuffer (); 248 if(name != null) { 249 buff.append(Parser.quoteIdentifier(name)); 250 buff.append(' '); 251 } 252 if(originalSQL != null) { 253 buff.append(originalSQL); 254 } else { 255 buff.append(DataType.getDataType(type).name); 256 switch (type) { 257 case Value.DECIMAL: 258 buff.append("("); 259 buff.append(precision); 260 buff.append(", "); 261 buff.append(scale); 262 buff.append(")"); 263 break; 264 case Value.BYTES: 265 case Value.STRING: 266 case Value.STRING_IGNORECASE: 267 buff.append("("); 268 buff.append(precision); 269 buff.append(")"); 270 break; 271 } 272 } 273 if(defaultExpression != null) { 274 String sql = defaultExpression.getSQL(); 275 if(sql != null) { 276 if(isComputed) { 277 buff.append(" AS "); 278 buff.append(sql); 279 } else if(defaultExpression != null) { 280 buff.append(" DEFAULT "); 281 buff.append(sql); 282 } 283 } 284 } 285 if (!nullable) { 286 buff.append(" NOT NULL"); 287 } 288 if (convertNullToDefault) { 289 buff.append(" NULL_TO_DEFAULT"); 290 } 291 if(sequence != null) { 292 buff.append(" SEQUENCE "); 293 buff.append(sequence.getSQL()); 294 } 295 if(selectivity != 0) { 296 buff.append(" SELECTIVITY "); 297 buff.append(selectivity); 298 } 299 if(checkConstraint != null) { 300 buff.append(" CHECK "); 301 buff.append(checkConstraintSQL); 302 } 303 if(comment != null) { 304 buff.append(" COMMENT "); 305 buff.append(StringUtils.quoteStringSQL(comment)); 306 } 307 return buff.toString(); 308 } 309 310 public boolean getNullable() { 311 return nullable; 312 } 313 314 public void setOriginalSQL(String original) { 315 originalSQL = original; 316 } 317 318 public String getOriginalSQL() { 319 return originalSQL; 320 } 321 322 public Expression getDefaultExpression() { 323 return defaultExpression; 324 } 325 326 public boolean getAutoIncrement() { 327 return autoIncrement; 328 } 329 330 public void setAutoIncrement(boolean autoInc, long start, long increment) { 331 this.autoIncrement = autoInc; 332 this.start = start; 333 this.increment = increment; 334 this.nullable = false; 335 if(autoInc) { 336 convertNullToDefault = true; 337 } 338 } 339 340 public void setConvertNullToDefault(boolean convert) { 341 this.convertNullToDefault = convert; 342 } 343 344 public void rename(String newName) { 345 this.name = newName; 346 } 347 348 public void setSequence(Sequence sequence) { 349 this.sequence = sequence; 350 } 351 352 public Sequence getSequence() { 353 return sequence; 354 } 355 356 public int getSelectivity() { 357 return selectivity == 0 ? Constants.SELECTIVITY_DEFAULT : selectivity; 358 } 359 360 public void setSelectivity(int selectivity) { 361 selectivity = selectivity < 0 ? 0 : (selectivity > 100 ? 100 : selectivity); 362 this.selectivity = selectivity; 363 } 364 365 public void addCheckConstraint(Session session, Expression expr) throws SQLException { 366 resolver = new SingleColumnResolver(this); 367 synchronized(this) { 368 String oldName = name; 369 if(name == null) { 370 name = "VALUE"; 371 } 372 expr.mapColumns(resolver, 0); 373 name = oldName; 374 } 375 expr = expr.optimize(session); 376 resolver.setValue(ValueNull.INSTANCE); 377 expr.getValue(session); 379 if(checkConstraint == null) { 380 checkConstraint = expr; 381 } else { 382 checkConstraint = new ConditionAndOr(ConditionAndOr.AND, checkConstraint, expr); 383 } 384 checkConstraintSQL = getCheckConstraintSQL(session, name); 385 } 386 387 public Expression getCheckConstraint(Session session, String asColumnName) throws SQLException { 388 if(checkConstraint == null) { 389 return null; 390 } 391 Parser parser = new Parser(session); 392 String sql; 393 synchronized(this) { 394 String oldName = name; 395 name = asColumnName; 396 sql = checkConstraint.getSQL(); 397 name = oldName; 398 } 399 Expression expr = parser.parseExpression(sql); 400 return expr; 401 } 402 403 public String getDefaultSQL() { 404 return defaultExpression == null ? "" : defaultExpression.getSQL(); 405 } 406 407 public int getPrecisionAsInt() { 408 return precision > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int)precision; 409 } 410 411 public DataType getDataType() { 412 return DataType.getDataType(type); 413 } 414 415 public String getCheckConstraintSQL(Session session, String name) throws SQLException { 416 Expression constraint = getCheckConstraint(session, name); 417 return constraint == null ? "" : constraint.getSQL(); 418 } 419 420 public void setComment(String comment) { 421 this.comment = comment; 422 } 423 424 public String getComment() { 425 return comment; 426 } 427 428 } 429 | Popular Tags |