[ 
https://issues.apache.org/jira/browse/PHOENIX-476?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15558377#comment-15558377
 ] 

James Taylor commented on PHOENIX-476:
--------------------------------------

Thanks for the patch, [~kliew]. Here's some feedback:
- Let's revert this change to ExpressionUtil as it's creating too many diffs in 
other places. Plus, you'll only use the logic to check that an expression is a 
constant in one place:
{code}
-       public static boolean isConstant(Expression expression) {
+    public static boolean isConstant(Expression expression) {
+        return (expression.isStateless() && expression.getDeterminism() == 
Determinism.ALWAYS);
+    }
+
+       public static boolean isPureExpression(Expression expression) {
{code}
- This change in ExpressionCompiler can be much simpler. No need to recreate a 
ColumnDef. Also, PColumn needs to stay immutable, so no setters there. Instead, 
just parse the expressionStr  using {{expressionNode = new 
SQLParser(expressionStr).parseExpression()}} and call 
expressionNode.accept(this) to get the Expression here (and minor nit, but just 
check that {{column.getExpressionStr() != null}}. Shouldn't be any need to 
check if empty too):
{code}
+        if (!SchemaUtil.isPKColumn(column)) {
+            if (column.getExpressionStr() != null && 
!column.getExpressionStr().isEmpty() && column.getDefaultExpression() == null) {
+                // We have the default expression but it has not been compiled 
yet
+                ExpressionCompiler compiler = new ExpressionCompiler(context);
+                ColumnDef columnDef = new ParseNodeFactory().columnDef(
+                        
ColumnName.caseSensitiveColumnName(column.getFamilyName().getString(), 
column.getName().getString()),
+                        column.getDataType().getSqlTypeName(),
+                        column.isNullable(),
+                        column.getMaxLength(),
+                        column.getScale(),
+                        false,
+                        column.getSortOrder(),
+                        column.getExpressionStr(),
+                        column.isRowTimestamp());
+                Expression defaultExpression = 
columnDef.getDefaultExpressionNode().accept(compiler);
+                if (!columnDef.getDefaultExpressionNode().isStateless() || 
!ExpressionUtil.isConstant(defaultExpression)) {
+                    throw new 
SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_CREATE_STATEFUL_DEFAULT)
+                            
.setColumnName(columnDef.getColumnDefName().getColumnName()).build().buildException();
+                }
+                column.setDefaultExpression(defaultExpression);
+            }
+            if (column.getDefaultExpression() != null) {
+                expression = new 
DefaultValueExpression(Arrays.asList(expression, 
column.getDefaultExpression()));
+            }
+        }
{code}
- Also, ColumnDef is immutable and needs to stay that way. Don't bother caching 
the Expression on it here:
{code}
+            if (columnDef.getDefaultExpressionNode() != null) {
+                ExpressionCompiler compiler = new ExpressionCompiler(context);
+                Expression defaultExpression = 
columnDef.getDefaultExpressionNode().accept(compiler);
+                if (!columnDef.getDefaultExpressionNode().isStateless() || 
!ExpressionUtil.isConstant(defaultExpression)) {
+                    throw new 
SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_CREATE_STATEFUL_DEFAULT)
+                            
.setColumnName(columnDef.getColumnDefName().getColumnName()).build().buildException();
+                }
+                columnDef.setDefaultExpression(defaultExpression);
+            }
{code}
- Should be able to revert changes to PColumn and PColumnImpl (and sorry to 
have led you down that path).
- There's a bit of code missing in PTableImpl.newKey() here (if this isn't the 
case, let me know what you mean by the "trailing null issue"):
{code}
     public int newKey(ImmutableBytesWritable key, byte[][] values) {
     ...
            // If some non null pk values aren't set, then throw
            if (i < nColumns) {
                PColumn column = columns.get(i);
                if (column.getDataType().isFixedWidth() || 
!column.isNullable()) {
                    throw new ConstraintViolationException(name.getString() + 
"." + column.getName().getString() + " may not be null");
                }
            }
{code}
You'll need to loop until {{i == nColumns}} to check if the column is a PK 
column with a default value and then evaluate and set the value. You'll need to 
insert null values for PK columns which don't have values before that.


> Support declaration of DEFAULT in CREATE statement
> --------------------------------------------------
>
>                 Key: PHOENIX-476
>                 URL: https://issues.apache.org/jira/browse/PHOENIX-476
>             Project: Phoenix
>          Issue Type: Task
>    Affects Versions: 3.0-Release
>            Reporter: James Taylor
>            Assignee: Kevin Liew
>              Labels: enhancement
>         Attachments: PHOENIX-476.2.patch, PHOENIX-476.3.patch, 
> PHOENIX-476.4.patch, PHOENIX-476.patch
>
>
> Support the declaration of a default value in the CREATE TABLE/VIEW statement 
> like this:
>     CREATE TABLE Persons (
>         Pid int NOT NULL PRIMARY KEY,
>         LastName varchar(255) NOT NULL,
>         FirstName varchar(255),
>         Address varchar(255),
>         City varchar(255) DEFAULT 'Sandnes'
>     )
> To implement this, we'd need to:
> 1. add a new DEFAULT_VALUE key value column in SYSTEM.TABLE and pass through 
> the value when the table is created (in MetaDataClient).
> 2. always set NULLABLE to ResultSetMetaData.columnNoNulls if a default value 
> is present, since the column will never be null.
> 3. add a getDefaultValue() accessor in PColumn
> 4.  for a row key column, during UPSERT use the default value if no value was 
> specified for that column. This could be done in the PTableImpl.newKey method.
> 5.  for a key value column with a default value, we can get away without 
> incurring any storage cost. Although a little bit of extra effort than if we 
> persisted the default value on an UPSERT for key value columns, this approach 
> has the benefit of not incurring any storage cost for a default value.
>     * serialize any default value into KeyValueColumnExpression
>     * in the evaluate method of KeyValueColumnExpression, conditionally use 
> the default value if the column value is not present. If doing partial 
> evaluation, you should not yet return the default value, as we may not have 
> encountered the the KeyValue for the column yet (since a filter evaluates 
> each time it sees each KeyValue, and there may be more than one KeyValue 
> referenced in the expression). Partial evaluation is determined by calling 
> Tuple.isImmutable(), where false means it is NOT doing partial evaluation, 
> while true means it is.
>     * modify EvaluateOnCompletionVisitor by adding a visitor method for 
> RowKeyColumnExpression and KeyValueColumnExpression to set 
> evaluateOnCompletion to true if they have a default value specified. This 
> will cause filter evaluation to execute one final time after all KeyValues 
> for a row have been seen, since it's at this time we know we should use the 
> default value.



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to