package com.tesora.dve.sql.parser; /* * #%L * Tesora Inc. * Database Virtualization Engine * %% * Copyright (C) 2011 - 2014 Tesora Inc. * %% * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * #L% */ import java.sql.Types; import org.apache.commons.lang.StringUtils; import com.tesora.dve.sql.node.expression.ExpressionNode; import com.tesora.dve.sql.node.expression.FunctionCall; import com.tesora.dve.sql.node.expression.IdentifierLiteralExpression; import com.tesora.dve.sql.node.expression.LiteralExpression; import com.tesora.dve.sql.schema.ConnectionContext; import com.tesora.dve.sql.schema.PEColumn; import com.tesora.dve.sql.schema.SchemaContext; import com.tesora.dve.sql.statement.dml.DMLStatement; import com.tesora.dve.sql.statement.dml.UpdateStatement; import com.tesora.dve.sql.util.ListSet; import com.tesora.dve.variables.KnownVariables; /** * Value Nullable Default On Update Insert Set Timestamp Update Set Timestamp * ----- -------- ------- --------- -------------------- -------------------- * null 0 0 not specified yes (1) yes (1) * null 0 0 current_ts yes (1) yes (1) * null 1 0 not specified no no * null 1 0 current_ts no no * null 0 not specified not specified yes (1) yes (1) * null 0 not specified current_ts yes (1) yes (1) * null 1 not specified not specified no no * null 1 not specified current_ts no no * null 0 literal not specified yes (1) yes (1) * null 0 literal current_ts yes (1) yes (1) * null 1 literal not specified no no * null 1 literal current_ts no no * null 0 current_ts not specified yes (1) yes (1) * null 0 current_ts current_ts yes (1) yes (1) * null 1 current_ts not specified no no * null 1 current_ts current_ts no no * null 0 null not specified yes (1) yes (1) * null 0 null current_ts yes (1) yes (1) * null 1 null not specified no no * null 1 null current_ts no no * * literal 0 0 not specified no no * literal 0 0 current_ts no no * literal 1 0 not specified no no * literal 1 0 current_ts no no * literal 0 not specified not specified no no * literal 0 not specified current_ts no no * literal 1 not specified not specified no no * literal 1 not specified current_ts no no * literal 0 literal not specified no no * literal 0 literal current_ts no no * literal 1 literal not specified no no * literal 1 literal current_ts no no * literal 0 current_ts not specified no no * literal 0 current_ts current_ts no no * literal 1 current_ts not specified no no * literal 1 current_ts current_ts no no * literal 0 null not specified no no * literal 0 null current_ts no no * literal 1 null not specified no no * literal 1 null current_ts no no * * current_ts 0 0 not specified yes (2) yes (2) * current_ts 0 0 current_ts yes (2) yes (2) * current_ts 1 0 not specified yes (2) yes (2) * current_ts 1 0 current_ts yes (2) yes (2) * current_ts 0 not specified not specified yes (2) yes (2) * current_ts 0 not specified current_ts yes (2) yes (2) * current_ts 1 not specified not specified yes (2) yes (2) * current_ts 1 not specified current_ts yes (2) yes (2) * current_ts 0 literal not specified yes (2) yes (2) * current_ts 0 literal current_ts yes (2) yes (2) * current_ts 1 literal not specified yes (2) yes (2) * current_ts 1 literal current_ts yes (2) yes (2) * current_ts 0 current_ts not specified yes (2) yes (2) * current_ts 0 current_ts current_ts yes (2) yes (2) * current_ts 1 current_ts not specified yes (2) yes (2) * current_ts 1 current_ts current_ts yes (2) yes (2) * current_ts 0 null not specified yes (2) yes (2) * current_ts 0 null current_ts yes (2) yes (2) * current_ts 1 null not specified yes (2) yes (2) * current_ts 1 null current_ts yes (2) yes (2) * * not specified 0 0 not specified no no (8) * not specified 0 0 current_ts no yes (3) * not specified 1 0 not specified no no (8) * not specified 1 0 current_ts no yes (3) * not specified 0 not specified not specified yes (4) yes * not specified 0 not specified current_ts no (6) yes (3) * not specified 1 not specified not specified no no (8) * not specified 1 not specified current_ts no (6) yes (3) * not specified 0 literal not specified no no (8) * not specified 0 literal current_ts no yes (3) * not specified 1 literal not specified no no (8) * not specified 1 literal current_ts no yes (3) * not specified 0 current_ts not specified yes no (8) * not specified 0 current_ts current_ts yes yes (3) * not specified 1 current_ts not specified yes no (8) * not specified 1 current_ts current_ts yes yes (3) * not specified 0 null not specified no (5) no (8) * not specified 0 null current_ts no (5) yes (3) * not specified 1 null not specified no no (8) * not specified 1 null current_ts no yes (3) * * * 1. if value is null and column is NOT nullable then mysql will insert the current timestamp. * 2. now() or synonyms such as current_timestamp should set current_timestamp; * 3. With an ON UPDATE CURRENT_TIMESTAMP clause and a constant DEFAULT clause, the column is automatically updated to the current timestamp and has the given constant default value. * 4. With neither DEFAULT CURRENT_TIMESTAMP nor ON UPDATE CURRENT_TIMESTAMP, it is the same as specifying both DEFAULT CURRENT_TIMESTAMP and ON UPDATE CURRENT_TIMESTAMP * 5. syntax error * 6. With an ON UPDATE CURRENT_TIMESTAMP clause but no DEFAULT clause, the column is automatically updated to the current timestamp. The default is 0 unless the column is defined with the NULL attribute, in which case the default is NULL * 7. With a DEFAULT clause but no ON UPDATE CURRENT_TIMESTAMP clause, the column has the given default value and is not automatically updated to the current timestamp. * 8. With a constant, the default is the given value. In this case, the column has no automatic properties at all. * */ public abstract class TimestampVariableUtils { public static final String TSFUNC_NOW = "now"; public static final String TSFUNC_CURRENT_TIMESTAMP = "current_timestamp"; public static final String TSFUNC_UNIX_TIMESTAMP = "unix_timestamp"; public static final String TSFUNC_UTC_TIMESTAMP = "utc_timestamp"; public static boolean setTimestampVariableForUnspecifiedColumn(SchemaContext sc, DMLStatement dmls, PEColumn column) { boolean ret = false; // only set the timestamp variable if this is a timestamp column if (column.getType().getBaseType().getDataType() != Types.TIMESTAMP) { return ret; } // for an update statement if the on update is set and // the column is not specified then set the timestamp variable if ((dmls instanceof UpdateStatement) && column.isOnUpdated()) { ret = true; return ret; } boolean isNullable = column.isNullable(); ExpressionNode defaultValue = column.getDefaultValue(); if (defaultValue == null) { // no default value column modifier specified // now we need to know if the on update has also been set or not if (!column.isOnUpdated() && !isNullable) { // on update is not specified so default value becomes current timestamp ret = true; } // else { // With an ON UPDATE CURRENT_TIMESTAMP clause but no DEFAULT clause, // the column is automatically updated to the current timestamp. // The default is 0 unless the column is defined with the NULL attribute, // in which case the default is NULL. // } } else { if (dmls instanceof UpdateStatement) { if (column.isOnUpdated()) { ret = true; } } else { if (column.getDefaultValue() == null) { // null default value // do not set timestamp variable } else { Object o = column.getDefaultValue(); if (o instanceof IdentifierLiteralExpression) { if (StringUtils.equals(((IdentifierLiteralExpression)o).asString(sc.getValues()), "0")) { // do nothing } else { // for a timestamp column only other choice is current_timestamp ret = true; } } else if (o instanceof LiteralExpression) { // for literal default value (ie. 0 or 'yyyy-mm-dd hh:mm:ss') // do not set timestamp variable } } } } return ret; } public static boolean setTimestampVariableForSpecifiedValue(PEColumn column, ExpressionNode value) { boolean ret = false; // only set the timestamp variable if this is a timestamp column if (column.getType().getBaseType().getDataType() != Types.TIMESTAMP) { return ret; } if (value instanceof LiteralExpression) { if (((LiteralExpression) value).isNullLiteral()) { // if value is null and column is NOT nullable // then mysql will insert the current timestamp. if (!column.isNullable()) { ret = true; } } else { // user specified a literal (ie. 0 or 'yyyy-mm-dd hh:mm:ss') // so don't set the timestamp variable } } else if (value instanceof IdentifierLiteralExpression || value instanceof FunctionCall) { // for a timestamp column can only be current_timestamp ret = true; } return ret; } public static boolean isNowFunctionCallSpecified(ListSet<FunctionCall> functions) { boolean usesNowFunction = false; if (functions == null) { return usesNowFunction; } for(FunctionCall fc : functions) { if (isTimestampFunction(fc.getFunctionName().getUnquotedName().get())) { usesNowFunction = true; break; } } return usesNowFunction; } public static boolean isTimestampFunction(String name) { return (isFunctionCurrentTimestamp(name) || isFunctionNow(name) || isFunctionUnixTimestamp(name) || isFunctionUTCTimestamp(name)); } public static boolean isFunctionCurrentTimestamp(String name) { return StringUtils.equalsIgnoreCase(name, TSFUNC_CURRENT_TIMESTAMP); } public static boolean isFunctionNow(String name) { return StringUtils.equalsIgnoreCase(name, TSFUNC_NOW); } public static boolean isFunctionUnixTimestamp(String name) { return StringUtils.equalsIgnoreCase(name, TSFUNC_UNIX_TIMESTAMP); } public static boolean isFunctionUTCTimestamp(String name) { return StringUtils.equalsIgnoreCase(name, TSFUNC_UTC_TIMESTAMP); } /** * The value of 'timestamp' session variable. Can be overriden by DVE * 'dve_repl_slave_timestamp' variable if set to a non-zero value. * * @return The current time in seconds. */ public static long getCurrentUnixTime(ConnectionContext cc) { final Long replicationSlaveTimestamp = KnownVariables.REPL_TIMESTAMP.getValue(cc.getVariableSource()); if ((replicationSlaveTimestamp != null) && (replicationSlaveTimestamp.longValue() != 0L)) { return replicationSlaveTimestamp; } return KnownVariables.TIMESTAMP.getValue(cc.getVariableSource()); } /** * @return The current time in seconds. */ public static long getCurrentSystemTime() { // we should be getting the local timezone of the mysql connection // but for now we will assume that the default is the same as the // Java timezone return Long.valueOf((System.currentTimeMillis() / 1000)); } }