[NO ISSUE][COMP] Fix incorrect result of NTH_VALUE() FROM LAST
- user model changes: no
- storage format changes: no
- interface changes: no
Details:
- Fix incorrect result of NTH_VALUE() FROM LAST
with asymmetrical window frame
Change-Id: I7f6a1b358441730cd33a0ff6bde2b34ad5a689a9
Reviewed-on: https://asterix-gerrit.ics.uci.edu/c/asterixdb/+/4283
Tested-by: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Integration-Tests: Jenkins <jenkins@fulliautomatix.ics.uci.edu>
Reviewed-by: Michael Blow <mblow@apache.org>
diff --git a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
index 6ec74cf..82dc344 100644
--- a/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
+++ b/asterixdb/asterix-algebra/src/main/java/org/apache/asterix/translator/SqlppExpressionToPlanTranslator.java
@@ -1239,8 +1239,16 @@
} else if (BuiltinFunctions.NTH_VALUE_IMPL.equals(fi)) {
nestedAggFunc = BuiltinFunctions.SCALAR_FIRST_ELEMENT;
if (fromLast) {
- // reverse order if FROM LAST modifier is present
+ // if FROM LAST modifier is present
+ // 1. reverse order
reverseOrder(orderExprListOut);
+ // 2. reverse frame specification
+ WindowExpression.FrameBoundaryKind tmpFrameStartKind = winFrameStartKind;
+ Expression tmpFrameStartExpr = winFrameStartExpr;
+ winFrameStartKind = reverseFrameBoundaryKind(winFrameEndKind);
+ winFrameStartExpr = winFrameEndExpr;
+ winFrameEndKind = reverseFrameBoundaryKind(tmpFrameStartKind);
+ winFrameEndExpr = tmpFrameStartExpr;
}
if (respectNulls) {
winFrameMaxOjbects = 1;
@@ -1737,4 +1745,22 @@
throw new CompilationException(ErrorCode.COMPILATION_ERROR);
}
}
+
+ private WindowExpression.FrameBoundaryKind reverseFrameBoundaryKind(
+ WindowExpression.FrameBoundaryKind frameBoundaryKind) throws CompilationException {
+ switch (frameBoundaryKind) {
+ case UNBOUNDED_PRECEDING:
+ return WindowExpression.FrameBoundaryKind.UNBOUNDED_FOLLOWING;
+ case BOUNDED_PRECEDING:
+ return WindowExpression.FrameBoundaryKind.BOUNDED_FOLLOWING;
+ case CURRENT_ROW:
+ return WindowExpression.FrameBoundaryKind.CURRENT_ROW;
+ case BOUNDED_FOLLOWING:
+ return WindowExpression.FrameBoundaryKind.BOUNDED_PRECEDING;
+ case UNBOUNDED_FOLLOWING:
+ return WindowExpression.FrameBoundaryKind.UNBOUNDED_PRECEDING;
+ default:
+ throw new CompilationException(ErrorCode.COMPILATION_ERROR);
+ }
+ }
}
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.6.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.6.query.sqlpp
new file mode 100644
index 0000000..4656f74
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.6.query.sqlpp
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description : NTH_VALUE() FROM LAST, from unbounded preceding
+ * Expected Res : SUCCESS
+ */
+
+from [
+ { "x": "a", "y": 1, "p": 0 },
+ { "y": 2, "p": 0 },
+ { "x": null, "y": 3, "p": 0 },
+ { "x": "b", "y": 4, "p": 0 },
+ { "x": "c", "y": 5, "p": 0 },
+
+ { "x": "a", "y": 6, "p": 1 },
+ { "x": null, "y": 7, "p": 1 },
+ { "y": 8, "p": 1 },
+ { "x": "b", "y": 9, "p": 1 },
+ { "x": "c", "y": 10, "p": 1 }
+] t
+select
+ //
+ nth_value(x, 2) from last respect nulls over (partition by p order by y range between unbounded preceding and 1 preceding)
+ as n_up_1p_r,
+ nth_value(x, 2) from last ignore nulls over (partition by p order by y range between unbounded preceding and 1 preceding)
+ as n_up_1p_i,
+ nth_value(x, 2) from last respect nulls over (partition by p order by y range between unbounded preceding and current row)
+ as n_up_cr_r,
+ nth_value(x, 2) from last ignore nulls over (partition by p order by y range between unbounded preceding and current row)
+ as n_up_cr_i,
+ nth_value(x, 2) from last respect nulls over (partition by p order by y range between unbounded preceding and 1 following)
+ as n_up_1f_r,
+ nth_value(x, 2) from last ignore nulls over (partition by p order by y range between unbounded preceding and 1 following)
+ as n_up_1f_i,
+ x, y, p
+order by y
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.7.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.7.query.sqlpp
new file mode 100644
index 0000000..f03711e
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.7.query.sqlpp
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description : NTH_VALUE() FROM LAST, from bounded preceding
+ * Expected Res : SUCCESS
+ */
+
+from [
+ { "x": "a", "y": 1, "p": 0 },
+ { "y": 2, "p": 0 },
+ { "x": null, "y": 3, "p": 0 },
+ { "x": "b", "y": 4, "p": 0 },
+ { "x": "c", "y": 5, "p": 0 },
+
+ { "x": "a", "y": 6, "p": 1 },
+ { "x": null, "y": 7, "p": 1 },
+ { "y": 8, "p": 1 },
+ { "x": "b", "y": 9, "p": 1 },
+ { "x": "c", "y": 10, "p": 1 }
+] t
+select
+ nth_value(x, 2) from last respect nulls over (partition by p order by y range between 3 preceding and 1 preceding)
+ as n_3p_1p_r,
+ nth_value(x, 2) from last ignore nulls over (partition by p order by y range between 3 preceding and 1 preceding)
+ as n_3p_1p_i,
+ nth_value(x, 2) from last respect nulls over (partition by p order by y range between 3 preceding and current row)
+ as n_3p_cr_r,
+ nth_value(x, 2) from last ignore nulls over (partition by p order by y range between 3 preceding and current row)
+ as n_3p_cr_i,
+ nth_value(x, 2) from last respect nulls over (partition by p order by y range between 3 preceding and 1 following)
+ as n_3p_1f_r,
+ nth_value(x, 2) from last ignore nulls over (partition by p order by y range between 3 preceding and 1 following)
+ as n_3p_1f_i,
+ nth_value(x, 2) from last respect nulls over (partition by p order by y range between 3 preceding and unbounded following)
+ as n_3p_uf_r,
+ nth_value(x, 2) from last ignore nulls over (partition by p order by y range between 3 preceding and unbounded following)
+ as n_3p_uf_i,
+ x, y, p
+order by y
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.8.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.8.query.sqlpp
new file mode 100644
index 0000000..ec553e5
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.8.query.sqlpp
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description : NTH_VALUE() FROM LAST, from current row
+ * Expected Res : SUCCESS
+ */
+
+from [
+ { "x": "a", "y": 1, "p": 0 },
+ { "y": 2, "p": 0 },
+ { "x": null, "y": 3, "p": 0 },
+ { "x": "b", "y": 4, "p": 0 },
+ { "x": "c", "y": 5, "p": 0 },
+
+ { "x": "a", "y": 6, "p": 1 },
+ { "x": null, "y": 7, "p": 1 },
+ { "y": 8, "p": 1 },
+ { "x": "b", "y": 9, "p": 1 },
+ { "x": "c", "y": 10, "p": 1 }
+] t
+select
+ nth_value(x, 2) from last respect nulls over (partition by p order by y range between current row and 3 following)
+ as n_cr_3f_r,
+ nth_value(x, 2) from last ignore nulls over (partition by p order by y range between current row and 3 following)
+ as n_cr_3f_i,
+ nth_value(x, 2) from last respect nulls over (partition by p order by y range between current row and unbounded following)
+ as n_cr_uf_r,
+ nth_value(x, 2) from last ignore nulls over (partition by p order by y range between current row and unbounded following)
+ as n_cr_uf_i,
+ x, y, p
+order by y
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.9.query.sqlpp b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.9.query.sqlpp
new file mode 100644
index 0000000..be7adca
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/queries_sqlpp/window/nth_value_01/nth_value_01.9.query.sqlpp
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+/*
+ * Description : NTH_VALUE() FROM LAST, from bounded following
+ * Expected Res : SUCCESS
+ */
+
+from [
+ { "x": "a", "y": 1, "p": 0 },
+ { "y": 2, "p": 0 },
+ { "x": null, "y": 3, "p": 0 },
+ { "x": "b", "y": 4, "p": 0 },
+ { "x": "c", "y": 5, "p": 0 },
+
+ { "x": "a", "y": 6, "p": 1 },
+ { "x": null, "y": 7, "p": 1 },
+ { "y": 8, "p": 1 },
+ { "x": "b", "y": 9, "p": 1 },
+ { "x": "c", "y": 10, "p": 1 }
+] t
+select
+ nth_value(x, 2) from last respect nulls over (partition by p order by y range between 1 following and 3 following)
+ as n_1f_3f_r,
+ nth_value(x, 2) from last ignore nulls over (partition by p order by y range between 1 following and 3 following)
+ as n_1f_3f_i,
+ nth_value(x, 2) from last respect nulls over (partition by p order by y range between 1 following and unbounded following)
+ as n_1f_uf_r,
+ nth_value(x, 2) from last ignore nulls over (partition by p order by y range between 1 following and unbounded following)
+ as n_1f_uf_i,
+ x, y, p
+order by y
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.6.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.6.adm
new file mode 100644
index 0000000..0d6ae8b
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.6.adm
@@ -0,0 +1,10 @@
+{ "n_up_1p_r": null, "n_up_1p_i": null, "n_up_cr_r": null, "n_up_cr_i": null, "n_up_1f_r": "a", "n_up_1f_i": null, "x": "a", "y": 1, "p": 0 }
+{ "n_up_1p_r": null, "n_up_1p_i": null, "n_up_cr_r": "a", "n_up_cr_i": null, "n_up_1f_i": null, "y": 2, "p": 0 }
+{ "n_up_1p_r": "a", "n_up_1p_i": null, "n_up_cr_i": null, "n_up_1f_r": null, "n_up_1f_i": "a", "x": null, "y": 3, "p": 0 }
+{ "n_up_1p_i": null, "n_up_cr_r": null, "n_up_cr_i": "a", "n_up_1f_r": "b", "n_up_1f_i": "b", "x": "b", "y": 4, "p": 0 }
+{ "n_up_1p_r": null, "n_up_1p_i": "a", "n_up_cr_r": "b", "n_up_cr_i": "b", "n_up_1f_r": "b", "n_up_1f_i": "b", "x": "c", "y": 5, "p": 0 }
+{ "n_up_1p_r": null, "n_up_1p_i": null, "n_up_cr_r": null, "n_up_cr_i": null, "n_up_1f_r": "a", "n_up_1f_i": null, "x": "a", "y": 6, "p": 1 }
+{ "n_up_1p_r": null, "n_up_1p_i": null, "n_up_cr_r": "a", "n_up_cr_i": null, "n_up_1f_r": null, "n_up_1f_i": null, "x": null, "y": 7, "p": 1 }
+{ "n_up_1p_r": "a", "n_up_1p_i": null, "n_up_cr_r": null, "n_up_cr_i": null, "n_up_1f_i": "a", "y": 8, "p": 1 }
+{ "n_up_1p_r": null, "n_up_1p_i": null, "n_up_cr_i": "a", "n_up_1f_r": "b", "n_up_1f_i": "b", "x": "b", "y": 9, "p": 1 }
+{ "n_up_1p_i": "a", "n_up_cr_r": "b", "n_up_cr_i": "b", "n_up_1f_r": "b", "n_up_1f_i": "b", "x": "c", "y": 10, "p": 1 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.7.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.7.adm
new file mode 100644
index 0000000..2f7fdba
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.7.adm
@@ -0,0 +1,10 @@
+{ "n_3p_1p_r": null, "n_3p_1p_i": null, "n_3p_cr_r": null, "n_3p_cr_i": null, "n_3p_1f_r": "a", "n_3p_1f_i": null, "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": "a", "y": 1, "p": 0 }
+{ "n_3p_1p_r": null, "n_3p_1p_i": null, "n_3p_cr_r": "a", "n_3p_cr_i": null, "n_3p_1f_i": null, "n_3p_uf_r": "b", "n_3p_uf_i": "b", "y": 2, "p": 0 }
+{ "n_3p_1p_r": "a", "n_3p_1p_i": null, "n_3p_cr_i": null, "n_3p_1f_r": null, "n_3p_1f_i": "a", "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": null, "y": 3, "p": 0 }
+{ "n_3p_1p_i": null, "n_3p_cr_r": null, "n_3p_cr_i": "a", "n_3p_1f_r": "b", "n_3p_1f_i": "b", "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": "b", "y": 4, "p": 0 }
+{ "n_3p_1p_r": null, "n_3p_1p_i": null, "n_3p_cr_r": "b", "n_3p_cr_i": "b", "n_3p_1f_r": "b", "n_3p_1f_i": "b", "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": "c", "y": 5, "p": 0 }
+{ "n_3p_1p_r": null, "n_3p_1p_i": null, "n_3p_cr_r": null, "n_3p_cr_i": null, "n_3p_1f_r": "a", "n_3p_1f_i": null, "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": "a", "y": 6, "p": 1 }
+{ "n_3p_1p_r": null, "n_3p_1p_i": null, "n_3p_cr_r": "a", "n_3p_cr_i": null, "n_3p_1f_r": null, "n_3p_1f_i": null, "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": null, "y": 7, "p": 1 }
+{ "n_3p_1p_r": "a", "n_3p_1p_i": null, "n_3p_cr_r": null, "n_3p_cr_i": null, "n_3p_1f_i": "a", "n_3p_uf_r": "b", "n_3p_uf_i": "b", "y": 8, "p": 1 }
+{ "n_3p_1p_r": null, "n_3p_1p_i": null, "n_3p_cr_i": "a", "n_3p_1f_r": "b", "n_3p_1f_i": "b", "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": "b", "y": 9, "p": 1 }
+{ "n_3p_1p_i": null, "n_3p_cr_r": "b", "n_3p_cr_i": "b", "n_3p_1f_r": "b", "n_3p_1f_i": "b", "n_3p_uf_r": "b", "n_3p_uf_i": "b", "x": "c", "y": 10, "p": 1 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.8.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.8.adm
new file mode 100644
index 0000000..74de5a7
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.8.adm
@@ -0,0 +1,10 @@
+{ "n_cr_3f_r": null, "n_cr_3f_i": "a", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "x": "a", "y": 1, "p": 0 }
+{ "n_cr_3f_r": "b", "n_cr_3f_i": "b", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "y": 2, "p": 0 }
+{ "n_cr_3f_r": "b", "n_cr_3f_i": "b", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "x": null, "y": 3, "p": 0 }
+{ "n_cr_3f_r": "b", "n_cr_3f_i": "b", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "x": "b", "y": 4, "p": 0 }
+{ "n_cr_3f_r": null, "n_cr_3f_i": null, "n_cr_uf_r": null, "n_cr_uf_i": null, "x": "c", "y": 5, "p": 0 }
+{ "n_cr_3f_i": "a", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "x": "a", "y": 6, "p": 1 }
+{ "n_cr_3f_r": "b", "n_cr_3f_i": "b", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "x": null, "y": 7, "p": 1 }
+{ "n_cr_3f_r": "b", "n_cr_3f_i": "b", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "y": 8, "p": 1 }
+{ "n_cr_3f_r": "b", "n_cr_3f_i": "b", "n_cr_uf_r": "b", "n_cr_uf_i": "b", "x": "b", "y": 9, "p": 1 }
+{ "n_cr_3f_r": null, "n_cr_3f_i": null, "n_cr_uf_r": null, "n_cr_uf_i": null, "x": "c", "y": 10, "p": 1 }
\ No newline at end of file
diff --git a/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.9.adm b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.9.adm
new file mode 100644
index 0000000..8840079
--- /dev/null
+++ b/asterixdb/asterix-app/src/test/resources/runtimets/results/window/nth_value_01/nth_value_01.9.adm
@@ -0,0 +1,10 @@
+{ "n_1f_3f_r": null, "n_1f_3f_i": null, "n_1f_uf_r": "b", "n_1f_uf_i": "b", "x": "a", "y": 1, "p": 0 }
+{ "n_1f_3f_r": "b", "n_1f_3f_i": "b", "n_1f_uf_r": "b", "n_1f_uf_i": "b", "y": 2, "p": 0 }
+{ "n_1f_3f_r": "b", "n_1f_3f_i": "b", "n_1f_uf_r": "b", "n_1f_uf_i": "b", "x": null, "y": 3, "p": 0 }
+{ "n_1f_3f_r": null, "n_1f_3f_i": null, "n_1f_uf_r": null, "n_1f_uf_i": null, "x": "b", "y": 4, "p": 0 }
+{ "n_1f_3f_r": null, "n_1f_3f_i": null, "n_1f_uf_r": null, "n_1f_uf_i": null, "x": "c", "y": 5, "p": 0 }
+{ "n_1f_3f_i": null, "n_1f_uf_r": "b", "n_1f_uf_i": "b", "x": "a", "y": 6, "p": 1 }
+{ "n_1f_3f_r": "b", "n_1f_3f_i": "b", "n_1f_uf_r": "b", "n_1f_uf_i": "b", "x": null, "y": 7, "p": 1 }
+{ "n_1f_3f_r": "b", "n_1f_3f_i": "b", "n_1f_uf_r": "b", "n_1f_uf_i": "b", "y": 8, "p": 1 }
+{ "n_1f_3f_r": null, "n_1f_3f_i": null, "n_1f_uf_r": null, "n_1f_uf_i": null, "x": "b", "y": 9, "p": 1 }
+{ "n_1f_3f_r": null, "n_1f_3f_i": null, "n_1f_uf_r": null, "n_1f_uf_i": null, "x": "c", "y": 10, "p": 1 }
\ No newline at end of file