Ripley Lorrin created IGNITE-29048:
--------------------------------------

             Summary: Preserve column aliases during dynamic schema updates
                 Key: IGNITE-29048
                 URL: https://issues.apache.org/jira/browse/IGNITE-29048
             Project: Ignite
          Issue Type: Bug
          Components: cache
    Affects Versions: 2.18, 2.17
            Reporter: Ripley Lorrin
             Fix For: 2.19


When a Cache is starting, it is possible to configure an Alias to the SQL 
Columns in order to perform queries using this alias.

However, in the event of a dynamic schema update using 
{{GridQueryProcessor#dynamicColumnAdd}} or 
{{{}GridQueryProcessor#dynamicColumnRemove{}}}, the underlying called method 
{{GridQueryProcessor#processDynamicAddColumn}} omits the "alias" argument while 
adding a {{{}QueryBinaryProperty{}}}. (it is always set to null).

This results in an impossibility to properly set an alias during a dynamic 
schema change, thus a system that relies on aliases for queries will experience 
failures for dynamically added fields.

The problem affects not only a dynamic column addition, but also the dynamic 
drop by causality: if a system uses aliases to dynamically delete a dynamically 
added column (that does not save their alias in the 
{{{}QueryBinaryProperty{}}}), Ignite will rightly say that the column does not 
exist.

Here is my proposed solution to allow the preservation of column aliases during 
dynamic schema updates - it consists of two one-liners.
h2. *{{GridQueryProcessor (ignite-core)}}*

{color:#4c9aff}*Current snippet*{color}

 
{code:java}
 private void processDynamicAddColumn(QueryTypeDescriptorImpl d, 
List<QueryField> cols)
        throws IgniteCheckedException {
        List<GridQueryProperty> props = new ArrayList<>(cols.size());        
for (QueryField col : cols) {
            try {
                props.add(new QueryBinaryProperty(
                    ctx,
                    col.name(),
                    null,
                    Class.forName(col.typeName()),
                    false,
                    null, // <-- this is where the alias should be injected
                    !col.isNullable(),
                    null,
                    col.precision(),
                    col.scale()));
            }
            catch (ClassNotFoundException e) {
                throw new SchemaOperationException("Class not found for new 
property: " + col.typeName());
            }
        }        for (GridQueryProperty p : props)
            d.addProperty(p, true);
    } {code}
 

*{color:#00875a}Proposed snippet{color}* 
{code:java}
 for (QueryField col : cols) {
    try {
        props.add(new QueryBinaryProperty(
            ctx,
            col.name(),
            null,
            Class.forName(col.typeName()),
            false,
            col.alias(),
            !col.isNullable(),
            null,
            col.precision(),
            col.scale()));
    }
    catch (ClassNotFoundException e) {
        throw new SchemaOperationException("Class not found for new property: " 
+ col.typeName());
    }
}{code}
----------------

An edition should be done in ignite-indexing's {{GridH2Table}} to take into 
account that the column alias should be taken instead of the name if present. 
h2. {{*GridH2Table (ignite-indexing)*}}

{color:#4c9aff}Current snippet{color}
{code:java}
// And now, let's add new columns
for (QueryField col : cols) {
    if (doesColumnExist(col.name()))
        return;

    try {
        Column c = new Column(col.name(), 
DataType.getTypeFromClass(Class.forName(col.typeName())));

        c.setNullable(col.isNullable());

        newCols[pos++] = c;
    }
    catch (ClassNotFoundException e) {
        throw new IgniteSQLException("H2 data type not found for class: " + 
col.typeName(), e);
    }
}{code}
 

{color:#00875a}Proposed snippet{color}

 
{code:java}
// And now, let's add new columns
for (QueryField col : cols) {
    if (doesColumnExist(col.alias()))
        return;

    try {
        Column c = new Column(col.alias(), 
DataType.getTypeFromClass(Class.forName(col.typeName())));

        c.setNullable(col.isNullable());

        newCols[pos++] = c;
    }
    catch (ClassNotFoundException e) {
        throw new IgniteSQLException("H2 data type not found for class: " + 
col.typeName(), e);
    }
} {code}
 

 

Replacing the name with the alias does not pose an issue for systems that rely 
on the 'name', because {{QueryFields}} conveniently set the name as the alias 
as a fallback.
{code:java}
/**
* @return Field alias.
*/
public String alias() {
return alias != null ? alias : name;
}{code}
 

 

 



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to