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

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

Thanks for the patch, [~kliew]. FYI, a fair amount of the work is already done 
thanks to functional indexes. Here's some feedback:
- In the grammar file, allow DEFAULT to be any expression (i.e. it'll end up 
being a ParseNode).
- Set the ColumnDef expressionStr argument based on the defaultNode.toString(). 
We could potentially add a new ColumnDef constructor that takes a ParseNode 
instead of String and a getExpressionNode() getter. You could check here that 
defaultNode.isStateless() is true and raise an exception if it isn't.
- In CreateTableCompiler, compile ColumnDef.getExpressionNode() using an 
ExpressionCompiler and verify that defaultExpression.isStateless() and 
defaultExpression.getDeterminism() == Determinism.ALWAYS. The latter will rule 
out CURRENT_DATE() and NEXT VALUE FOR expressions.
- For PColumn, we already have getExpressionStr() which is all we need for now. 
We might want to add the following to cache the Expression version of the same
{code}
Expression getDefaultExpression(PhoenixConnection conn);
{code}
The getDefaultExpression will be similar to the PTable.getIndexMaintainer call 
in that it'll parse and compile the string and cache it on PColumnImpl.
- The default value will be persisted in SYSTEM.CATALOG in the COLUMN_DEF 
column already based on ColumnDef.getExpressionStr(). It'll also flow already 
between client and server in PColumn (which is great).
- Instead of always setting the default value in UpsertCompiler for UPSERT 
VALUE, you can only set it for row key columns. This logic can live in 
PTable.newKey() method - just use the default value if a column value is null 
which has a default. You can use ExpressionUtil.getConstantExpression() to 
evaluate it dynamically to get the actual bytes to use (which will be returned 
in ptr).
- For other, non PK columns, you don't need to store the value at all (see 
discussion above). Instead, in ExpressionCompiler.resolveColumn(), before 
returning {{ref}} (but only if it's not a PK column), you'd check if the 
PColumn has a default value using PColumn.getExpressionStr(). If it does, you'd 
wrap the {{ref}} in a CoalesceFunction with the first child being {{ref}} and 
the second child being the defaultExpression. In this way, when evaluated, we'd 
fall back to the default value if the column has no value.
- For indexes, copy over the expressionStr from the PColumn of the data table 
in MetaDataClient.createIndex() when we're creating the ColumnDef for covered 
columns (might already be occurring).

One open question, using this technique, what if the default value changes? Any 
thoughts on this, [~lhofhansl]? Since we didn't persist it before, rows that 
already exist would get the new default value. We don't have a mechanism for it 
to be changed now, so it's a bit of a theoretical issue currently. I suppose in 
theory we could persist the old value if the value were to change. Or lookup 
the default value for the column based on the timestamp of the data cell (which 
would get complicated).


> 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.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