aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2025-01-16 16:50:58 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2025-01-16 17:03:02 +0300
commitb97da5f54c0edb261f74824aa9a8a643a4ae75f6 (patch)
tree2ea3dc77615160742cba9eb802c81191e62ab650
parent7e86bcaf10a418760708b0be68e02abd715b745b (diff)
downloadydb-b97da5f54c0edb261f74824aa9a8a643a4ae75f6.tar.gz
Intermediate changes
commit_hash:aad4c6091d19bafc760b4b238153622f73166199
-rw-r--r--yql/essentials/docs/.yfm20
-rw-r--r--yql/essentials/docs/.yfmlint6
-rw-r--r--yql/essentials/docs/a.yaml28
-rw-r--r--yql/essentials/docs/en/_includes/cast_examples.md16
-rw-r--r--yql/essentials/docs/en/_includes/decimal_args.md5
-rw-r--r--yql/essentials/docs/en/builtins/aggregation.md615
-rw-r--r--yql/essentials/docs/en/builtins/basic.md1213
-rw-r--r--yql/essentials/docs/en/builtins/codegen.md181
-rw-r--r--yql/essentials/docs/en/builtins/dict.md282
-rw-r--r--yql/essentials/docs/en/builtins/index.md12
-rw-r--r--yql/essentials/docs/en/builtins/json.md1170
-rw-r--r--yql/essentials/docs/en/builtins/list.md602
-rw-r--r--yql/essentials/docs/en/builtins/struct.md359
-rw-r--r--yql/essentials/docs/en/builtins/toc_i.yaml13
-rw-r--r--yql/essentials/docs/en/builtins/types.md637
-rw-r--r--yql/essentials/docs/en/builtins/window.md247
-rw-r--r--yql/essentials/docs/en/index.md10
-rw-r--r--yql/essentials/docs/en/recipes/accessing-json.md103
-rw-r--r--yql/essentials/docs/en/recipes/index.md9
-rw-r--r--yql/essentials/docs/en/recipes/modifying-json.md23
-rw-r--r--yql/essentials/docs/en/recipes/toc_i.yaml7
-rw-r--r--yql/essentials/docs/en/syntax/_assets/join-YQL-06.pngbin0 -> 24792 bytes
-rw-r--r--yql/essentials/docs/en/syntax/action.md145
-rw-r--r--yql/essentials/docs/en/syntax/commit.md17
-rw-r--r--yql/essentials/docs/en/syntax/declare.md36
-rw-r--r--yql/essentials/docs/en/syntax/discard.md29
-rw-r--r--yql/essentials/docs/en/syntax/export_import.md63
-rw-r--r--yql/essentials/docs/en/syntax/expressions.md550
-rw-r--r--yql/essentials/docs/en/syntax/flatten.md145
-rw-r--r--yql/essentials/docs/en/syntax/group_by.md267
-rw-r--r--yql/essentials/docs/en/syntax/index.md22
-rw-r--r--yql/essentials/docs/en/syntax/insert_into.md33
-rw-r--r--yql/essentials/docs/en/syntax/into_result.md16
-rw-r--r--yql/essentials/docs/en/syntax/join.md143
-rw-r--r--yql/essentials/docs/en/syntax/lexer.md235
-rw-r--r--yql/essentials/docs/en/syntax/not_yet_supported.md14
-rw-r--r--yql/essentials/docs/en/syntax/pragma.md421
-rw-r--r--yql/essentials/docs/en/syntax/process.md78
-rw-r--r--yql/essentials/docs/en/syntax/reduce.md108
-rw-r--r--yql/essentials/docs/en/syntax/select/assume_order_by.md14
-rw-r--r--yql/essentials/docs/en/syntax/select/concat.md44
-rw-r--r--yql/essentials/docs/en/syntax/select/distinct.md19
-rw-r--r--yql/essentials/docs/en/syntax/select/from.md22
-rw-r--r--yql/essentials/docs/en/syntax/select/from_as_table.md17
-rw-r--r--yql/essentials/docs/en/syntax/select/from_select.md17
-rw-r--r--yql/essentials/docs/en/syntax/select/index.md102
-rw-r--r--yql/essentials/docs/en/syntax/select/limit_offset.md22
-rw-r--r--yql/essentials/docs/en/syntax/select/order_by.md20
-rw-r--r--yql/essentials/docs/en/syntax/select/sample.md38
-rw-r--r--yql/essentials/docs/en/syntax/select/toc_i.yaml17
-rw-r--r--yql/essentials/docs/en/syntax/select/toc_p.yaml2
-rw-r--r--yql/essentials/docs/en/syntax/select/union.md63
-rw-r--r--yql/essentials/docs/en/syntax/select/unique_distinct_hints.md10
-rw-r--r--yql/essentials/docs/en/syntax/select/where.md11
-rw-r--r--yql/essentials/docs/en/syntax/select/with.md32
-rw-r--r--yql/essentials/docs/en/syntax/select/without.md16
-rw-r--r--yql/essentials/docs/en/syntax/subquery.md190
-rw-r--r--yql/essentials/docs/en/syntax/toc_i.yaml23
-rw-r--r--yql/essentials/docs/en/syntax/use.md24
-rw-r--r--yql/essentials/docs/en/syntax/values.md45
-rw-r--r--yql/essentials/docs/en/syntax/window.md153
-rw-r--r--yql/essentials/docs/en/toc.yaml2
-rw-r--r--yql/essentials/docs/en/toc_i.yaml11
-rw-r--r--yql/essentials/docs/en/types/cast.md74
-rw-r--r--yql/essentials/docs/en/types/containers.md26
-rw-r--r--yql/essentials/docs/en/types/index.md12
-rw-r--r--yql/essentials/docs/en/types/json.md187
-rw-r--r--yql/essentials/docs/en/types/optional.md50
-rw-r--r--yql/essentials/docs/en/types/primitive.md188
-rw-r--r--yql/essentials/docs/en/types/special.md14
-rw-r--r--yql/essentials/docs/en/types/toc_i.yaml17
-rw-r--r--yql/essentials/docs/en/types/type_string.md70
-rw-r--r--yql/essentials/docs/en/udf/list/datetime.md501
-rw-r--r--yql/essentials/docs/en/udf/list/digest.md43
-rw-r--r--yql/essentials/docs/en/udf/list/histogram.md19
-rw-r--r--yql/essentials/docs/en/udf/list/hyperscan.md108
-rw-r--r--yql/essentials/docs/en/udf/list/index.md18
-rw-r--r--yql/essentials/docs/en/udf/list/ip.md47
-rw-r--r--yql/essentials/docs/en/udf/list/math.md140
-rw-r--r--yql/essentials/docs/en/udf/list/pcre.md22
-rw-r--r--yql/essentials/docs/en/udf/list/pire.md115
-rw-r--r--yql/essentials/docs/en/udf/list/re2.md122
-rw-r--r--yql/essentials/docs/en/udf/list/string.md148
-rw-r--r--yql/essentials/docs/en/udf/list/toc_base.yaml16
-rw-r--r--yql/essentials/docs/en/udf/list/toc_i.yaml2
-rw-r--r--yql/essentials/docs/en/udf/list/unicode.md159
-rw-r--r--yql/essentials/docs/en/udf/list/url.md203
-rw-r--r--yql/essentials/docs/en/udf/list/yson.md308
-rw-r--r--yql/essentials/docs/presets.yaml49
-rw-r--r--yql/essentials/docs/ru/_includes/cast_examples.md16
-rw-r--r--yql/essentials/docs/ru/_includes/decimal_args.md4
-rw-r--r--yql/essentials/docs/ru/_includes/frompg.md15
-rw-r--r--yql/essentials/docs/ru/_includes/topg.md35
-rw-r--r--yql/essentials/docs/ru/builtins/aggregation.md802
-rw-r--r--yql/essentials/docs/ru/builtins/basic.md1564
-rw-r--r--yql/essentials/docs/ru/builtins/codegen.md182
-rw-r--r--yql/essentials/docs/ru/builtins/dict.md445
-rw-r--r--yql/essentials/docs/ru/builtins/index.md13
-rw-r--r--yql/essentials/docs/ru/builtins/json.md1199
-rw-r--r--yql/essentials/docs/ru/builtins/list.md991
-rw-r--r--yql/essentials/docs/ru/builtins/struct.md470
-rw-r--r--yql/essentials/docs/ru/builtins/toc_i.yaml13
-rw-r--r--yql/essentials/docs/ru/builtins/types.md986
-rw-r--r--yql/essentials/docs/ru/builtins/window.md240
-rw-r--r--yql/essentials/docs/ru/index.md11
-rw-r--r--yql/essentials/docs/ru/recipes/accessing-json.md103
-rw-r--r--yql/essentials/docs/ru/recipes/index.md8
-rw-r--r--yql/essentials/docs/ru/recipes/modifying-json.md23
-rw-r--r--yql/essentials/docs/ru/recipes/toc_i.yaml7
-rw-r--r--yql/essentials/docs/ru/syntax/_assets/join-YQL-06.pngbin0 -> 24792 bytes
-rw-r--r--yql/essentials/docs/ru/syntax/action.md145
-rw-r--r--yql/essentials/docs/ru/syntax/commit.md16
-rw-r--r--yql/essentials/docs/ru/syntax/declare.md39
-rw-r--r--yql/essentials/docs/ru/syntax/discard.md28
-rw-r--r--yql/essentials/docs/ru/syntax/export_import.md61
-rw-r--r--yql/essentials/docs/ru/syntax/expressions.md560
-rw-r--r--yql/essentials/docs/ru/syntax/flatten.md138
-rw-r--r--yql/essentials/docs/ru/syntax/group_by.md265
-rw-r--r--yql/essentials/docs/ru/syntax/index.md22
-rw-r--r--yql/essentials/docs/ru/syntax/insert_into.md33
-rw-r--r--yql/essentials/docs/ru/syntax/into_result.md19
-rw-r--r--yql/essentials/docs/ru/syntax/join.md146
-rw-r--r--yql/essentials/docs/ru/syntax/lexer.md331
-rw-r--r--yql/essentials/docs/ru/syntax/not_yet_supported.md14
-rw-r--r--yql/essentials/docs/ru/syntax/pragma.md464
-rw-r--r--yql/essentials/docs/ru/syntax/process.md80
-rw-r--r--yql/essentials/docs/ru/syntax/reduce.md110
-rw-r--r--yql/essentials/docs/ru/syntax/select/assume_order_by.md14
-rw-r--r--yql/essentials/docs/ru/syntax/select/concat.md44
-rw-r--r--yql/essentials/docs/ru/syntax/select/distinct.md18
-rw-r--r--yql/essentials/docs/ru/syntax/select/from.md25
-rw-r--r--yql/essentials/docs/ru/syntax/select/from_as_table.md16
-rw-r--r--yql/essentials/docs/ru/syntax/select/from_select.md18
-rw-r--r--yql/essentials/docs/ru/syntax/select/index.md144
-rw-r--r--yql/essentials/docs/ru/syntax/select/limit_offset.md28
-rw-r--r--yql/essentials/docs/ru/syntax/select/order_by.md20
-rw-r--r--yql/essentials/docs/ru/syntax/select/sample.md38
-rw-r--r--yql/essentials/docs/ru/syntax/select/toc_i.yaml17
-rw-r--r--yql/essentials/docs/ru/syntax/select/toc_p.yaml2
-rw-r--r--yql/essentials/docs/ru/syntax/select/union.md68
-rw-r--r--yql/essentials/docs/ru/syntax/select/unique_distinct_hints.md23
-rw-r--r--yql/essentials/docs/ru/syntax/select/where.md10
-rw-r--r--yql/essentials/docs/ru/syntax/select/with.md32
-rw-r--r--yql/essentials/docs/ru/syntax/select/without.md15
-rw-r--r--yql/essentials/docs/ru/syntax/subquery.md193
-rw-r--r--yql/essentials/docs/ru/syntax/toc_i.yaml23
-rw-r--r--yql/essentials/docs/ru/syntax/use.md23
-rw-r--r--yql/essentials/docs/ru/syntax/values.md45
-rw-r--r--yql/essentials/docs/ru/syntax/window.md156
-rw-r--r--yql/essentials/docs/ru/toc.yaml2
-rw-r--r--yql/essentials/docs/ru/toc_i.yaml11
-rw-r--r--yql/essentials/docs/ru/types/cast.md73
-rw-r--r--yql/essentials/docs/ru/types/containers.md26
-rw-r--r--yql/essentials/docs/ru/types/index.md12
-rw-r--r--yql/essentials/docs/ru/types/json.md196
-rw-r--r--yql/essentials/docs/ru/types/optional.md53
-rw-r--r--yql/essentials/docs/ru/types/primitive.md209
-rw-r--r--yql/essentials/docs/ru/types/special.md16
-rw-r--r--yql/essentials/docs/ru/types/toc_i.yaml20
-rw-r--r--yql/essentials/docs/ru/types/type_string.md70
-rw-r--r--yql/essentials/docs/ru/types/yson.md457
-rw-r--r--yql/essentials/docs/ru/udf/list/datetime.md507
-rw-r--r--yql/essentials/docs/ru/udf/list/digest.md126
-rw-r--r--yql/essentials/docs/ru/udf/list/histogram.md19
-rw-r--r--yql/essentials/docs/ru/udf/list/hyperscan.md104
-rw-r--r--yql/essentials/docs/ru/udf/list/index.md18
-rw-r--r--yql/essentials/docs/ru/udf/list/ip.md46
-rw-r--r--yql/essentials/docs/ru/udf/list/math.md174
-rw-r--r--yql/essentials/docs/ru/udf/list/pcre.md21
-rw-r--r--yql/essentials/docs/ru/udf/list/pire.md114
-rw-r--r--yql/essentials/docs/ru/udf/list/postgres.md300
-rw-r--r--yql/essentials/docs/ru/udf/list/re2.md121
-rw-r--r--yql/essentials/docs/ru/udf/list/string.md152
-rw-r--r--yql/essentials/docs/ru/udf/list/toc_base.yaml17
-rw-r--r--yql/essentials/docs/ru/udf/list/toc_i.yaml2
-rw-r--r--yql/essentials/docs/ru/udf/list/unicode.md180
-rw-r--r--yql/essentials/docs/ru/udf/list/url.md196
-rw-r--r--yql/essentials/docs/ru/udf/list/yson.md309
-rwxr-xr-xyql/essentials/docs/scripts/doc_upgrade_arc.sh88
-rw-r--r--yql/essentials/docs/ya.make5
-rw-r--r--yql/essentials/ya.make1
181 files changed, 25667 insertions, 0 deletions
diff --git a/yql/essentials/docs/.yfm b/yql/essentials/docs/.yfm
new file mode 100644
index 0000000000..76d4c6019f
--- /dev/null
+++ b/yql/essentials/docs/.yfm
@@ -0,0 +1,20 @@
+allowHTML: true
+langs: ['en','ru']
+singlePage: true
+docs-viewer:
+ project-name: yql-core
+ abc-slug: yql
+ index-page:
+ hidden:
+ testing: false
+ production: false
+ title: YQL core
+ description: Язык запросов YQL
+ auto-release-to:
+ testing: false
+ prod: false
+ single-page:
+ supported: true
+ startrek:
+ queue: YQLSUPPORT
+ components: [docs]
diff --git a/yql/essentials/docs/.yfmlint b/yql/essentials/docs/.yfmlint
new file mode 100644
index 0000000000..fa6ba04a89
--- /dev/null
+++ b/yql/essentials/docs/.yfmlint
@@ -0,0 +1,6 @@
+log-levels:
+ YFM001: 'error' # Inline code length
+
+# Inline code length
+YFM001:
+ maximum: 140
diff --git a/yql/essentials/docs/a.yaml b/yql/essentials/docs/a.yaml
new file mode 100644
index 0000000000..21abfd70da
--- /dev/null
+++ b/yql/essentials/docs/a.yaml
@@ -0,0 +1,28 @@
+title: Essentials docs
+service: yql
+
+ci:
+ secret: sec-01g9mj0b528x9wg348pdh5nv8n
+ runtime:
+ sandbox:
+ owner: YQL
+
+ actions:
+ # определение экшена, который будет вызван при пулл-реквесте,
+ # затрагивающим вашу документацию
+ docs:
+ title: Deploy docs
+ flow: deploy-pr-docs
+ triggers:
+ - on: pr
+
+ flows:
+ deploy-pr-docs:
+ jobs:
+ deploy:
+ title: Deploy docs
+ task: common/docs/deploy
+ input:
+ targets: yql/essentials/docs
+ arcanum_review_id: ${context.launch_pull_request_info.pull_request.id}
+ notify: true # оставлять комментарий к ПР с ссылкой на выложенную документацию
diff --git a/yql/essentials/docs/en/_includes/cast_examples.md b/yql/essentials/docs/en/_includes/cast_examples.md
new file mode 100644
index 0000000000..a7735c3a15
--- /dev/null
+++ b/yql/essentials/docs/en/_includes/cast_examples.md
@@ -0,0 +1,16 @@
+
+```yql
+SELECT
+ CAST("12345" AS Double), -- 12345.0
+ CAST(1.2345 AS Uint8), -- 1
+ CAST(12345 AS String), -- "12345"
+ CAST("1.2345" AS Decimal(5, 2)), -- 1.23
+ CAST("xyz" AS Uint64) IS NULL, -- true, because it failed
+ CAST(-1 AS Uint16) IS NULL, -- true, a negative integer cast to an unsigned integer
+ CAST([-1, 0, 1] AS List<Uint8?>), -- [null, 0, 1]
+ --The item type is optional: the failed item is cast to null.
+ CAST(["3.14", "bad", "42"] AS List<Float>), -- [3.14, 42]
+ --The item type is not optional: the failed item has been deleted.
+ CAST(255 AS Uint8), -- 255
+ CAST(256 AS Uint8) IS NULL -- true, out of range
+```
diff --git a/yql/essentials/docs/en/_includes/decimal_args.md b/yql/essentials/docs/en/_includes/decimal_args.md
new file mode 100644
index 0000000000..60b818ec59
--- /dev/null
+++ b/yql/essentials/docs/en/_includes/decimal_args.md
@@ -0,0 +1,5 @@
+For the Decimal parametric data type, two additional arguments are specified:
+
+* Total number of decimal places (up to 35, inclusive).
+* Number of places after the decimal point (out of the total number, meaning it can't be larger than the previous argument).
+
diff --git a/yql/essentials/docs/en/builtins/aggregation.md b/yql/essentials/docs/en/builtins/aggregation.md
new file mode 100644
index 0000000000..96a395d61d
--- /dev/null
+++ b/yql/essentials/docs/en/builtins/aggregation.md
@@ -0,0 +1,615 @@
+# Aggregate functions
+
+## COUNT {#count}
+
+Counting the number of rows in the table (if `*` or constant is specified as the argument) or non-empty values in a table column (if the column name is specified as an argument).
+
+Like other aggregate functions, it can be combined with [GROUP BY](../syntax/group_by.md) to get statistics on the parts of the table that correspond to the values in the columns being grouped. Use the modifier [DISTINCT](../syntax/group_by.md#distinct) to count distinct values.
+
+### Examples
+
+```yql
+SELECT COUNT(*) FROM my_table;
+```
+
+```yql
+SELECT key, COUNT(value) FROM my_table GROUP BY key;
+```
+
+```yql
+SELECT COUNT(DISTINCT value) FROM my_table;
+```
+
+## MIN and MAX {#min-max}
+
+Minimum or maximum value.
+
+As an argument, you may use an arbitrary computable expression with a numeric result.
+
+### Examples
+
+```yql
+SELECT MIN(value), MAX(value) FROM my_table;
+```
+
+## SUM {#sum}
+
+Sum of the numbers.
+
+As an argument, you may use an arbitrary computable expression with a numeric result.
+
+Integers are automatically expanded to 64 bits to reduce the risk of overflow.
+
+```yql
+SELECT SUM(value) FROM my_table;
+```
+
+## AVG {#avg}
+
+Arithmetic average.
+
+As an argument, you may use an arbitrary computable expression with a numeric result.
+
+Integer values and time intervals are automatically converted to Double.
+
+### Examples
+
+```yql
+SELECT AVG(value) FROM my_table;
+```
+
+## COUNT_IF {#count-if}
+
+Number of rows for which the expression specified as the argument is true (the expression's calculation result is true).
+
+The value `NULL` is equated to `false` (if the argument type is `Bool?`).
+
+The function *does not* do the implicit type casting to Boolean for strings and numbers.
+
+### Examples
+
+```yql
+SELECT
+ COUNT_IF(value % 2 == 1) AS odd_count
+```
+
+{% note info %}
+
+To count distinct values in rows meeting the condition, unlike other aggregate functions, you can't use the modifier [DISTINCT](../syntax/group_by.md#distinct) because arguments contain no values. To get this result, use in the subquery the built-in function [IF](../builtins/basic.md#if) with two arguments (to get `NULL` in else), and apply an outer [COUNT(DISTINCT ...)](#count) to its result.
+
+{% endnote %}
+
+## SUM_IF and AVG_IF {#sum-if}
+
+Sum or arithmetic average, but only for the rows that satisfy the condition passed by the second argument.
+
+Therefore, `SUM_IF(value, condition)` is a slightly shorter notation for `SUM(IF(condition, value))`, same for `AVG`. The argument's data type expansion is similar to the same-name functions without a suffix.
+
+### Examples
+
+```yql
+SELECT
+ SUM_IF(value, value % 2 == 1) AS odd_sum,
+ AVG_IF(value, value % 2 == 1) AS odd_avg,
+FROM my_table;
+```
+
+When you use [aggregation factories](basic.md#aggregationfactory), a `Tuple` containing a value and a predicate is passed as the first [AGGREGATE_BY](#aggregate-by) argument.
+
+```yql
+$sum_if_factory = AggregationFactory("SUM_IF");
+$avg_if_factory = AggregationFactory("AVG_IF");
+
+SELECT
+ AGGREGATE_BY(AsTuple(value, value % 2 == 1), $sum_if_factory) AS odd_sum,
+ AGGREGATE_BY(AsTuple(value, value % 2 == 1), $avg_if_factory) AS odd_avg
+FROM my_table;
+```
+
+## SOME {#some}
+
+Get the value for an expression specified as an argument, for one of the table rows. Gives no guarantee of which row is used. It's similar to the [any()](https://clickhouse.tech/docs/en/sql-reference/aggregate-functions/reference/any/) function in ClickHouse.
+
+Because of no guarantee, `SOME` is computationally cheaper than [MIN / MAX](#min-max) often used in similar situations.
+
+### Examples
+
+```yql
+SELECT
+ SOME(value)
+FROM my_table;
+```
+
+{% note alert %}
+
+When the aggregate function `SOME` is called multiple times, it's **not** guaranteed that all the resulting values are taken from the same row of the source table. To get this guarantee, pack the values into any container and pass it to `SOME`. For example, in the case of a structure, you can apply [AsStruct](../builtins/basic.md#asstruct)
+
+{% endnote %}
+
+
+
+## CountDistinctEstimate, HyperLogLog, and HLL {#countdistinctestimate}
+
+Approximating the number of unique values using the [HyperLogLog](https://en.wikipedia.org/wiki/HyperLogLog) algorithm. Logically, it does the same thing as [COUNT(DISTINCT ...)](#count), but runs much faster at the cost of some error.
+
+Arguments:
+
+1. Estimated value
+2. Accuracy (4 to 18 inclusive, 14 by default).
+
+By selecting accuracy, you can trade added resource and RAM consumption for decreased error.
+
+All the three functions are aliases at the moment, but `CountDistinctEstimate` may start using a different algorithm in the future.
+
+### Examples
+
+```yql
+SELECT
+ CountDistinctEstimate(my_column)
+FROM my_table;
+```
+
+```yql
+SELECT
+ HyperLogLog(my_column, 4)
+FROM my_table;
+```
+
+
+
+## AGGREGATE_LIST {#agg-list}
+
+Get all column values as a list. When combined with `DISTINCT,` it returns only distinct values. The optional second parameter sets the maximum number of values to be returned. A zero limit value means unlimited.
+
+If you know already that you have few distinct values, use the `AGGREGATE_LIST_DISTINCT` aggregate function to build the same result in memory (that might not be enough for a large number of distinct values).
+
+The order of elements in the result list depends on the implementation and can't be set externally. To return an ordered list, sort the result, for example, with [ListSort](list.md#listsort).
+
+To return a list of multiple values from one line, **DO NOT** use the `AGGREGATE_LIST` function several times, but add all the needed values to a container, for example, via [AsList](basic.md#aslist) or [AsTuple](basic.md#astuple), then pass this container to a single `AGGREGATE_LIST` call.
+
+For example, you can combine it with `DISTINCT` and the function [String::JoinFromList](../udf/list/string.md) (it's an equivalent of `','.join(list)` in Python) to output to a string all the values found in the column after [GROUP BY](../syntax/group_by.md).
+
+### Examples
+
+```yql
+SELECT
+ AGGREGATE_LIST( region ),
+ AGGREGATE_LIST( region, 5 ),
+ AGGREGATE_LIST( DISTINCT region ),
+ AGGREGATE_LIST_DISTINCT( region ),
+ AGGREGATE_LIST_DISTINCT( region, 5 )
+FROM users
+```
+
+```yql
+-- An equivalent of GROUP_CONCAT in MySQL
+SELECT
+ String::JoinFromList(CAST(AGGREGATE_LIST(region, 2) AS List<String>), ",")
+FROM users
+```
+
+These functions also have a short notation: `AGG_LIST` and `AGG_LIST_DISTINCT`.
+
+{% note alert %}
+
+Execution is **NOT** lazy, so when you use it, be sure that the list has a reasonable size (about a thousand items or less). To stay on the safe side, better use a second optional numeric argument that limits the number of items in the list.
+
+{% endnote %}
+
+
+
+## MAX_BY and MIN_BY {#max-min-by}
+
+Return the value of the first argument for the table row where the second argument is minimum/maximum.
+
+You can optionally specify the third argument N that affects behavior if the table has multiple rows with the same minimum or maximum value:
+
+* If N is omitted, the value of one of the rows is returned, and the other rows are discarded.
+* If N is specified, the list is returned with all values, but their number can't exceed N. All values after the number are discarded.
+
+When choosing N, we recommend that you don't exceed several hundreds or thousands to avoid issues with the memory limit.
+
+If your task needs absolutely all values, and their number is measured in dozens of thousands or more, then instead of those aggregate functions better use `JOIN` on the source table with a subquery doing `GROUP BY + MIN/MAX` on the desired columns of this table.
+
+{% note warning "Attention" %}
+
+If the second argument is always `NULL`, the aggregation result is `NULL`.
+
+{% endnote %}
+
+When you use [aggregation factories](basic.md#aggregationfactory), a `Tuple` containing a value and a key is passed as the first [AGGREGATE_BY](#aggregate-by) argument.
+
+### Examples
+
+```yql
+SELECT
+ MIN_BY(value, LENGTH(value)),
+ MAX_BY(value, key, 100)
+FROM my_table;
+```
+
+```yql
+$min_by_factory = AggregationFactory("MIN_BY");
+$max_by_factory = AggregationFactory("MAX_BY", 100);
+
+SELECT
+ AGGREGATE_BY(AsTuple(value, LENGTH(value)), $min_by_factory),
+ AGGREGATE_BY(AsTuple(value, key), $max_by_factory)
+FROM my_table;
+```
+
+
+
+## TOP and BOTTOM {#top-bottom}
+
+Return a list of the maximum/minimum values of an expression. The first argument is an expression, the second argument limits the number of items.
+
+### Examples
+
+```yql
+SELECT
+ TOP(key, 3),
+ BOTTOM(value, 3)
+FROM my_table;
+```
+
+```yql
+$top_factory = AggregationFactory("TOP", 3);
+$bottom_factory = AggregationFactory("BOTTOM", 3);
+
+SELECT
+ AGGREGATE_BY(key, $top_factory),
+ AGGREGATE_BY(value, $bottom_factory)
+FROM my_table;
+```
+
+## TOP_BY and BOTTOM_BY {#top-bottom-by}
+
+Return a list of values of the first argument for the rows containing the maximum/minimum values of the second argument. The third argument limits the number of items in the list.
+
+When you use [aggregation factories](basic.md#aggregationfactory), a `Tuple` containing a value and a key is passed as the first [AGGREGATE_BY](#aggregate-by) argument. In this case, the limit for the number of items is passed by the second argument at factory creation.
+
+### Examples
+
+```yql
+SELECT
+ TOP_BY(value, LENGTH(value), 3),
+ BOTTOM_BY(value, key, 3)
+FROM my_table;
+```
+
+```yql
+$top_by_factory = AggregationFactory("TOP_BY", 3);
+$bottom_by_factory = AggregationFactory("BOTTOM_BY", 3);
+
+SELECT
+ AGGREGATE_BY(AsTuple(value, LENGTH(value)), $top_by_factory),
+ AGGREGATE_BY(AsTuple(value, key), $bottom_by_factory)
+FROM my_table;
+```
+
+
+
+## TOPFREQ and MODE {#topfreq-mode}
+
+Getting an **approximate** list of the most common values in a column with an estimation of their count. Returns a list of structures with two fields:
+
+* `Value`: the frequently occurring value that was found.
+* `Frequency`: An estimated value occurrence in the table.
+
+Required argument: the value itself.
+
+Optional arguments:
+
+1. For `TOPFREQ`, the desired number of items in the result. `MODE` is an alias to `TOPFREQ` with this argument set to 1. For `TOPFREQ`, this argument is also 1 by default.
+2. The number of items in the buffer used: lets you trade memory consumption for accuracy. Default: 100.
+
+### Examples
+
+```yql
+SELECT
+ MODE(my_column),
+ TOPFREQ(my_column, 5, 1000)
+FROM my_table;
+```
+
+
+
+## STDDEV and VARIANCE {#stddev-variance}
+
+Standard deviation and variance in a column. Those functions use a [single-pass parallel algorithm](https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm), whose result may differ from the more common methods requiring two passes through the data.
+
+By default, the sample variance and standard deviation are calculated. Several write methods are available:
+
+* with the `POPULATION` suffix/prefix, for example: `VARIANCE_POPULATION`, `POPULATION_VARIANCE` calculates the variance or standard deviation for the population.
+* With the `SAMPLE` suffix/prefix or without a suffix, for example, `VARIANCE_SAMPLE`, `SAMPLE_VARIANCE`, `SAMPLE` calculate sample variance and standard deviation.
+
+Several abbreviated aliases are also defined, for example, `VARPOP` or `STDDEVSAMP`.
+
+If all the values passed are `NULL`, it returns `NULL`.
+
+### Examples
+
+```yql
+SELECT
+ STDDEV(numeric_column),
+ VARIANCE(numeric_column)
+FROM my_table;
+```
+
+
+
+## CORRELATION and COVARIANCE {#correlation-covariance}
+
+Correlation and covariance between two columns.
+
+Abbreviated versions are also available: `CORR` or `COVAR`. For covariance, there are also versions with the `SAMPLE`/`POPULATION` suffix that are similar to [VARIANCE](#stddev-variance) above.
+
+Unlike most other aggregate functions, they don't skip `NULL`, but accept it as 0.
+
+When you use [aggregation factories](basic.md#aggregationfactory), a `Tuple` containing two values is passed as the first [AGGREGATE_BY](#aggregate-by) argument.
+
+### Examples
+
+```yql
+SELECT
+ CORRELATION(numeric_column, another_numeric_column),
+ COVARIANCE(numeric_column, another_numeric_column)
+FROM my_table;
+```
+
+```yql
+$corr_factory = AggregationFactory("CORRELATION");
+
+SELECT
+ AGGREGATE_BY(AsTuple(numeric_column, another_numeric_column), $corr_factory)
+FROM my_table;
+```
+
+
+
+## PERCENTILE and MEDIAN {#percentile-median}
+
+Calculating percentiles using the amortized version of the [TDigest](https://github.com/tdunning/t-digest) algorithm. `MEDIAN`: An alias for `PERCENTILE(N, 0.5)`.
+
+{% note info "Restriction" %}
+
+The first argument (N) must be a table column name. If you need to bypass this restriction, use a subquery. The restriction is introduced to simplify calculations, since the implementation merges the calls with the same first argument (N) into a single pass.
+
+{% endnote %}
+
+```yql
+SELECT
+ MEDIAN(numeric_column),
+ PERCENTILE(numeric_column, 0.99)
+FROM my_table;
+```
+
+
+
+## HISTOGRAM {#histogram}
+
+Plotting an approximate histogram based on a numeric expression with automatic selection of buckets.
+
+[Auxiliary functions](../udf/list/histogram.md)
+
+### Basic settings
+
+You can limit the number of buckets using an optional argument. The default value is 100. Keep in mind that added accuracy costs you more computing resources and may negatively affect the query execution time. In extreme cases, it may affect your query success.
+
+### Support for weights
+
+You can specify a "weight" for each value used in the histogram. To do this, pass to the aggregate function the second argument with an expression for calculating the weight. The weight of `1.0` is always used by default. If you use non-standard weights, you may also use the third argument to limit the number of buckets.
+
+If you pass two arguments, the meaning of the second argument is determined by its type (if it's an integer literal, it limits the number of buckets, otherwise it's used as a weight).
+
+### Algorithms
+
+* [Source whitepaper](http://jmlr.org/papers/volume11/ben-haim10a/ben-haim10a.pdf);
+
+Various modifications of the algorithm are available:
+
+```yql
+AdaptiveDistanceHistogram
+AdaptiveWeightHistogram
+AdaptiveWardHistogram
+BlockWeightHistogram
+BlockWardHistogram
+```
+
+By default, `HISTOGRAM` is a synonym for `AdaptiveWardHistogram`. Both functions are equivalent and interchangeable in all contexts.
+
+The Distance, Weight, and Ward algorithms differ in the formulas that combine two points into one:
+
+```c++
+ TWeightedValue CalcDistanceQuality(const TWeightedValue& left, const TWeightedValue& right) {
+ return TWeightedValue(right.first - left.first, left.first);
+ }
+
+ TWeightedValue CalcWeightQuality(const TWeightedValue& left, const TWeightedValue& right) {
+ return TWeightedValue(right.second + left.second, left.first);
+ }
+
+ TWeightedValue CalcWardQuality(const TWeightedValue& left, const TWeightedValue& right) {
+ const double N1 = left.second;
+ const double N2 = right.second;
+ const double mu1 = left.first;
+ const double mu2 = right.first;
+ return TWeightedValue(N1 * N2 / (N1 + N2) * (mu1 - mu2) * (mu1 - mu2), left.first);
+ }
+```
+
+Difference between Adaptive and Block:
+
+{% block info %}
+
+Contrary to adaptive histogram, block histogram doesn't rebuild bins after each point is added. Instead, it accumulates points and if the amount of points overflows specified limits, it shrinks all the points at once to produce a histogram. Indeed, there exist two limits and two shrinkage operations:
+
+1. FastGreedyShrink is fast but coarse. It is used to shrink from upper limit to intermediate limit (override FastGreedyShrink to set specific behaviour).
+2. SlowShrink is slow, but produces finer histogram. It shrinks from the intermediate limit to the actual number of bins in a manner similar to that in adaptive histogram (set CalcQuality in 34constuctor)
+While FastGreedyShrink is used most of the time, SlowShrink is mostly used for histogram finalization
+
+{% endblock %}
+
+### If you need an accurate histogram
+
+1. You can use the aggregate functions described below with fixed bucket grids: [LinearHistogram](#linearhistogram) or [LogarithmicHistogram](#linearhistogram).
+2. You can calculate the bucket number for each row and apply to it [GROUP BY](../syntax/group_by.md).
+
+When you use [aggregation factories](basic.md#aggregationfactory), a `Tuple` containing a value and a weight is passed as the first [AGGREGATE_BY](#aggregate-by) argument.
+
+### Examples
+
+```yql
+SELECT
+ HISTOGRAM(numeric_column)
+FROM my_table;
+```
+
+```yql
+SELECT
+ Histogram::Print(
+ HISTOGRAM(numeric_column, 10),
+ 50
+ )
+FROM my_table;
+```
+
+```yql
+$hist_factory = AggregationFactory("HISTOGRAM");
+
+SELECT
+ AGGREGATE_BY(AsTuple(numeric_column, 1.0), $hist_factory)
+FROM my_table;
+```
+
+## LinearHistogram, LogarithmicHistogram, and LogHistogram {#linearhistogram}
+
+Plotting a histogram based on an explicitly specified fixed bucket scale.
+
+Arguments:
+
+1. Expression used to plot the histogram. All the following arguments are optional.
+2. Spacing between the `LinearHistogram` buckets or the logarithm base for `LogarithmicHistogram`/`LogHistogram` (those are aliases). In both cases, the default value is 10.
+3. Minimum value. By default, it's minus infinity.
+4. Maximum value. By default, it's plus infinity.
+
+The format of the result is totally similar to [adaptive histograms](#histogram), so you can use the same [set of auxiliary functions](../udf/list/histogram.md).
+
+If the spread of input values is uncontrollably large, we recommend that you specify the minimum and maximum values to prevent potential failures due to high memory consumption.
+
+### Examples
+
+```yql
+SELECT
+ LogarithmicHistogram(numeric_column, 2)
+FROM my_table;
+```
+
+
+
+## BOOL_AND, BOOL_OR and BOOL_XOR {#bool-and-or-xor}
+
+### Signature
+
+```yql
+BOOL_AND(Bool?)->Bool?
+BOOL_OR(Bool?)->Bool?
+BOOL_XOR(Bool?)->Bool?
+```
+
+Apply the relevant logical operation (`AND`/`OR`/`XOR`) to all values in a Boolean column or expression.
+
+Unlike most other aggregate functions, these functions **don't skip** `NULL` during aggregation and use the following rules:
+
+- `true AND null == null`
+- `false OR null == null`
+
+For `BOOL_AND`:
+
+- If at least one `NULL` value is present, the result is `NULL` regardless of `true` values in the expression.
+- If at least one `false` value is present, the result changes to `false` regardless of `NULL` values in the expression.
+
+For `BOOL_OR`:
+
+- If at least one `NULL` value is present, the result changes to `NULL` regardless of `false` values in the expression.
+- If at least one `true` value is present, the result changes to `true` regardless of `NULL` values in the expression.
+
+For `BOOL_XOR`:
+
+- The result is `NULL` if any `NULL` is found.
+
+Examples of such behavior can be found below.
+
+To skip `NULL` values during aggregation, use the `MIN`/`MAX` or `BIT_AND`/`BIT_OR`/`BIT_XOR` functions.
+
+### Examples
+
+```yql
+$data = [
+ <|nonNull: true, nonFalse: true, nonTrue: NULL, anyVal: true|>,
+ <|nonNull: false, nonFalse: NULL, nonTrue: NULL, anyVal: NULL|>,
+ <|nonNull: false, nonFalse: NULL, nonTrue: false, anyVal: false|>,
+];
+
+SELECT
+ BOOL_AND(nonNull) as nonNullAnd, -- false
+ BOOL_AND(nonFalse) as nonFalseAnd, -- NULL
+ BOOL_AND(nonTrue) as nonTrueAnd, -- false
+ BOOL_AND(anyVal) as anyAnd, -- false
+ BOOL_OR(nonNull) as nonNullOr, -- true
+ BOOL_OR(nonFalse) as nonFalseOr, -- true
+ BOOL_OR(nonTrue) as nonTrueOr, -- NULL
+ BOOL_OR(anyVal) as anyOr, -- true
+ BOOL_XOR(nonNull) as nonNullXor, -- true
+ BOOL_XOR(nonFalse) as nonFalseXor, -- NULL
+ BOOL_XOR(nonTrue) as nonTrueXor, -- NULL
+ BOOL_XOR(anyVal) as anyXor, -- NULL
+FROM AS_TABLE($data);
+```
+
+## BIT_AND, BIT_OR and BIT_XOR {#bit-and-or-xor}
+
+Apply the relevant bitwise operation to all values of a numeric column or expression.
+
+### Examples
+
+```yql
+SELECT
+ BIT_XOR(unsigned_numeric_value)
+FROM my_table;
+```
+
+## SessionStart {#session-start}
+
+No arguments. It's allowed only if there is [SessionWindow](../syntax/group_by.md#session-window) in [GROUP BY](../syntax/group_by.md) / [PARTITION BY](../syntax/window.md#partition).
+Returns the value of the `SessionWindow` key column. If `SessionWindow` has two arguments, it returns the minimum value of the first argument within the group/section.
+In the case of the expanded version `SessionWindow`, it returns the value of the second element from the tuple returned by `<calculate_lambda>`, for which the first tuple element is `True`.
+
+
+## AGGREGATE_BY and MULTI_AGGREGATE_BY {#aggregate-by}
+
+Applying an [aggregation factory](basic.md#aggregationfactory) to all values of a column or expression. The `MULTI_AGGREGATE_BY` function requires that the value of a column or expression has a structure, tuple, or list, and applies the factory to each individual element, placing the result in a container of the same format. If different values of a column or expression contain lists of different length, the resulting list will have the smallest of the source lengths.
+
+1. Column, `DISTINCT` column or expression.
+2. Factory.
+
+### Examples
+
+```yql
+$count_factory = AggregationFactory("COUNT");
+
+SELECT
+ AGGREGATE_BY(DISTINCT column, $count_factory) as uniq_count
+FROM my_table;
+
+SELECT
+ MULTI_AGGREGATE_BY(nums, AggregationFactory("count")) as count,
+ MULTI_AGGREGATE_BY(nums, AggregationFactory("min")) as min,
+ MULTI_AGGREGATE_BY(nums, AggregationFactory("max")) as max,
+ MULTI_AGGREGATE_BY(nums, AggregationFactory("avg")) as avg,
+ MULTI_AGGREGATE_BY(nums, AggregationFactory("percentile", 0.9)) as p90
+FROM my_table;
+```
+
+
diff --git a/yql/essentials/docs/en/builtins/basic.md b/yql/essentials/docs/en/builtins/basic.md
new file mode 100644
index 0000000000..dfd3adb049
--- /dev/null
+++ b/yql/essentials/docs/en/builtins/basic.md
@@ -0,0 +1,1213 @@
+
+# Basic built-in functions
+
+Below are the general-purpose functions. For specialized functions, there are separate articles: [aggregate functions](aggregation.md), [window functions](window.md), and functions for [lists](list.md), [dictionaries](dict.md), [structures](struct.md), [data types](types.md), and [code generation](codegen.md).
+
+
+
+## COALESCE {#coalesce}
+
+Iterates through the arguments from left to right and returns the first non-empty argument found. To be sure that the result is non-empty (not of an [optional type](../types/optional.md)), the rightmost argument must be of this type (often a literal is used for this). With a single argument, returns this argument unchanged.
+
+Lets you pass potentially empty values to functions that can't handle them by themselves.
+
+A short format using the low-priority `??` operator is available (lower than the Boolean operations). You can use the `NVL` alias.
+
+### Examples
+
+```yql
+SELECT COALESCE(
+ maybe_empty_column,
+ "it's empty!"
+) FROM my_table;
+```
+
+```yql
+SELECT
+ maybe_empty_column ?? "it's empty!"
+FROM my_table;
+```
+
+```yql
+SELECT NVL(
+ maybe_empty_column,
+ "it's empty!"
+) FROM my_table;
+```
+
+All three examples above are equivalent.
+
+
+
+## LENGTH {#length}
+
+Returns the length of the string in bytes. This function is also available under the `LEN` name .
+
+### Examples
+
+```yql
+SELECT LENGTH("foo");
+```
+
+```yql
+SELECT LEN("bar");
+```
+
+{% note info %}
+
+To calculate the length of a string in Unicode characters, you can use the function [Unicode::GetLength](../udf/list/unicode.md).<br/><br/>To get the number of elements in the list, use the function [ListLength](list.md#listlength).
+
+{% endnote %}
+
+
+## SUBSTRING {#substring}
+
+Returns a substring.
+
+Required arguments:
+
+* Source string;
+* Position: The offset from the beginning of the string in bytes (integer) or `NULL` meaning "from the beginning".
+
+Optional arguments:
+
+* Substring length: The number of bytes starting from the specified position (an integer, or the default `NULL` meaning "up to the end of the source string").
+
+Indexing starts from zero. If the specified position and length are beyond the string, returns an empty string.
+If the input string is optional, the result is also optional.
+
+### Examples
+
+```yql
+SELECT SUBSTRING("abcdefg", 3, 1); -- d
+```
+
+```yql
+SELECT SUBSTRING("abcdefg", 3); -- defg
+```
+
+```yql
+SELECT SUBSTRING("abcdefg", NULL, 3); -- abc
+```
+
+
+
+## FIND {#find}
+
+Finding the position of a substring in a string.
+
+Required arguments:
+
+* Source string;
+* The substring being searched for.
+
+Optional arguments:
+
+* A position in bytes to start the search with (an integer or `NULL` by default that means "from the beginning of the source string").
+
+Returns the first substring position found or `NULL` (meaning that the desired substring hasn't been found starting from the specified position).
+
+### Examples
+
+```yql
+SELECT FIND("abcdefg_abcdefg", "abc"); -- 0
+```
+
+```yql
+SELECT FIND("abcdefg_abcdefg", "abc", 1); -- 8
+```
+
+```yql
+SELECT FIND("abcdefg_abcdefg", "abc", 9); -- null
+```
+
+## RFIND {#rfind}
+
+Reverse finding the position of a substring in a string, from the end to the beginning.
+
+Required arguments:
+
+* Source string;
+* The substring being searched for.
+
+Optional arguments:
+
+* A position in bytes to start the search with (an integer or `NULL` by default, meaning "from the end of the source string").
+
+Returns the first substring position found or `NULL` (meaning that the desired substring hasn't been found starting from the specified position).
+
+### Examples
+
+```yql
+SELECT RFIND("abcdefg_abcdefg", "bcd"); -- 9
+```
+
+```yql
+SELECT RFIND("abcdefg_abcdefg", "bcd", 8); -- 1
+```
+
+```yql
+SELECT RFIND("abcdefg_abcdefg", "bcd", 0); -- null
+```
+
+
+
+## StartsWith, EndsWith {#starts_ends_with}
+
+Checking for a prefix or suffix in a string.
+
+Required arguments:
+
+* Source string;
+* The substring being searched for.
+
+The arguments can be of the `String` or `Utf8` type and can be optional.
+
+### Examples
+
+```yql
+SELECT StartsWith("abc_efg", "abc") AND EndsWith("abc_efg", "efg"); -- true
+```
+
+```yql
+SELECT StartsWith("abc_efg", "efg") OR EndsWith("abc_efg", "abc"); -- false
+```
+
+```yql
+SELECT StartsWith("abcd", NULL); -- null
+```
+
+```yql
+SELECT EndsWith(NULL, Utf8("")); -- null
+```
+
+
+
+## IF {#if}
+
+Checks the condition: `IF(condition_expression, then_expression, else_expression)`.
+
+It's a simplified alternative for [CASE WHEN ... THEN ... ELSE ... END](../syntax/expressions.md#case).
+
+You may omit the `else_expression` argument. In this case, if the condition is false (`condition_expression` returned `false`), an empty value is returned with the type corresponding to `then_expression` and allowing for `NULL`. Hence, the result will have an [optional data type](../types/optional.md).
+
+### Examples
+
+```yql
+SELECT
+ IF(foo > 0, bar, baz) AS bar_or_baz,
+ IF(foo > 0, foo) AS only_positive_foo
+FROM my_table;
+```
+
+
+
+## NANVL {#nanvl}
+
+Replaces the values of `NaN` (not a number) in expressions like `Float`, `Double`, or [Optional](../types/optional.md).
+
+Arguments:
+
+1. The expression where you want to make a replacement.
+2. The value to replace `NaN`.
+
+If one of the arguments is `Double`, the result is`Double`, otherwise, it's `Float`. If one of the arguments is `Optional`, then the result is `Optional`.
+
+### Examples
+
+```yql
+SELECT
+ NANVL(double_column, 0.0)
+FROM my_table;
+```
+
+
+
+## Random... {#random}
+
+Generates a pseudorandom number:
+
+* `Random()`: A floating point number (Double) from 0 to 1.
+* `RandomNumber()`: An integer from the complete Uint64 range.
+* `RandomUuid()`: [Uuid version 4](https://tools.ietf.org/html/rfc4122#section-4.4).
+
+### Signatures
+
+```yql
+Random(T1[, T2, ...])->Double
+RandomNumber(T1[, T2, ...])->Uint64
+RandomUuid(T1[, T2, ...])->Uuid
+```
+
+No arguments are used for random number generation: they are only needed to control the time of the call. A new random number is returned at each call. Therefore:
+
+* If Random is called again within a **same query** and with a same set of arguments, the same set of random numbers is returned. Keep in mind that we mean the arguments themselves (i.e., the text between parentheses) rather than their values.
+
+* Calling of Random with the same set of arguments in **different queries** returns different sets of random numbers.
+
+{% note warning %}
+
+If Random is used in [named expressions](../syntax/expressions.md#named-nodes), its one-time calculation is not guaranteed. Depending on the optimizers and runtime environment, it can be counted both once and multiple times. To make sure it's only counted once, materialize a named expression into a table.
+
+{% endnote %}
+
+Use cases:
+
+* `SELECT RANDOM(1);`: Get one random value for the entire query and use it multiple times (to get multiple random values, you can pass various constants of any type).
+* `SELECT RANDOM(1) FROM table;`: The same random number for each row in the table.
+* `SELECT RANDOM(1), RANDOM(2) FROM table;`: Two random numbers for each row of the table, all the numbers in each of the columns are the same.
+* `SELECT RANDOM(some_column) FROM table;`: Different random numbers for each row in the table.
+* `SELECT RANDOM(some_column), RANDOM(some_column) FROM table;`: Different random numbers for each row of the table, but two identical numbers within the same row.
+* `SELECT RANDOM(some_column), RANDOM(some_column + 1) FROM table;` or `SELECT RANDOM(some_column), RANDOM(other_column) FROM table;`: Two columns, with different numbers in both.
+
+### Examples
+
+```yql
+SELECT
+ Random(key) -- [0, 1)
+FROM my_table;
+```
+
+```yql
+SELECT
+ RandomNumber(key) -- [0, Max<Uint64>)
+FROM my_table;
+```
+
+```yql
+SELECT
+ RandomUuid(key) -- Uuid version 4
+FROM my_table;
+```
+
+```yql
+SELECT
+ RANDOM(column) AS rand1,
+ RANDOM(column) AS rand2, -- same as rand1
+ RANDOM(column, 1) AS randAnd1, -- different from rand1/2
+ RANDOM(column, 2) AS randAnd2 -- different from randAnd1
+FROM my_table;
+```
+
+
+## CurrentUtc... {#current-utc}
+
+`CurrentUtcDate()`, `CurrentUtcDatetime()` and `CurrentUtcTimestamp()`: Getting the current date and/or time in UTC. The result data type is specified at the end of the function name.
+
+The arguments are optional and work same as [RANDOM](#random).
+
+### Examples
+
+```yql
+SELECT CurrentUtcDate();
+```
+
+```yql
+SELECT CurrentUtcTimestamp(TableRow()) FROM my_table;
+```
+
+
+
+## CurrentTz... {#current-tz}
+
+`CurrentTzDate()`, `CurrentTzDatetime()`, and `CurrentTzTimestamp()`: Get the current date and/or time in the [IANA time zone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) specified in the first argument. The result data type is specified at the end of the function name.
+
+The arguments that follow are optional and work same as [RANDOM](#random).
+
+### Examples
+
+```yql
+SELECT CurrentTzDate("Europe/Moscow");
+```
+
+```yql
+SELECT CurrentTzTimestamp("Europe/Moscow", TableRow()) FROM my_table;
+```
+
+## AddTimezone
+
+Adding the time zone information to the date/time in UTC. In the result of `SELECT` or after `CAST`, a `String` will be subject to the time zone rules used to calculate the time offset.
+
+Arguments:
+
+1. Date: the type is `Date`/`Datetime`/`Timestamp`.
+2. [The IANA name of the time zone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
+
+Result type: `TzDate`/`TzDatetime`/`TzTimestamp`, depending on the input data type.
+
+### Examples
+
+```yql
+SELECT AddTimezone(Datetime("2018-02-01T12:00:00Z"), "Europe/Moscow");
+```
+
+## RemoveTimezone
+
+Removing the time zone data and converting the value to date/time in UTC.
+
+Arguments:
+
+1. Date: the type is `TzDate`/`TzDatetime`/`TzTimestamp`.
+
+Result type: `Date`/`Datetime`/`Timestamp`, depending on the input data type.
+
+### Examples
+
+```yql
+SELECT RemoveTimezone(TzDatetime("2018-02-01T12:00:00,Europe/Moscow"));
+```
+
+
+
+## Version {#version}
+
+`Version()` returns a string describing the current version of the node processing the request. In some cases, such as during rolling upgrades, it might return different strings depending on which node processes the request. It does not accept any arguments.
+
+### Examples
+
+```yql
+SELECT Version();
+```
+
+
+
+## MAX_OF, MIN_OF, GREATEST, and LEAST {#max-min}
+
+Returns the minimum or maximum among N arguments. Those functions let you replace the SQL standard statement `CASE WHEN a < b THEN a ELSE b END` that would be too sophisticated for N more than two.
+
+The argument types must be mutually castable and accept `NULL`.
+
+`GREATEST` is a synonym for `MAX_OF` and `LEAST` is a synonym for `MIN_OF`.
+
+### Examples
+
+```yql
+SELECT MIN_OF(1, 2, 3);
+```
+
+
+
+## AsTuple, AsStruct, AsList, AsDict, AsSet, AsListStrict, AsDictStrict and AsSetStrict {#as-container}
+
+Creates containers of the applicable types. For container literals, [operator notation](#containerliteral) is also supported.
+
+Specifics:
+
+* The container elements are passed in arguments. Hence, the number of elements in the resulting container is equal to the number of arguments passed, except when the dictionary keys repeat.
+* `AsTuple` and `AsStruct` can be called without arguments, and also the arguments can have different types.
+* The field names in `AsStruct` are set using `AsStruct(field_value AS field_name)`.
+* Creating a list requires at least one argument if you need to output the element types. To create an empty list with the given type of elements, use the function [ListCreate](list.md#listcreate). You can create an empty list as an `AsList()` call without arguments. In this case, this expression will have the `EmptyList` type.
+* Creating a dictionary requires at least one argument if you need to output the element types. To create an empty dictionary with the given type of elements, use the function [DictCreate](dict.md#dictcreate). You can create an empty dictionary as an `AsDict()` call without arguments, in this case, this expression will have the `EmptyDict` type.
+* Creating a set requires at least one argument if you need to output element types. To create an empty set with the given type of elements, use the function [SetCreate](dict.md#setcreate). You can create an empty set as an `AsSet()` call without arguments, in this case, this expression will have the `EmptySet` type.
+* `AsList` outputs the common type of elements in the list. A type error is raised in the case of incompatible types.
+* `AsDict` separately outputs the common types for keys and values. A type error is raised in the case of incompatible types.
+* `AsSet` outputs common types for keys. A type error is raised in the case of incompatible types.
+* `AsListStrict`, `AsDictStrict`, `AsSetStrict` require the same type for their arguments.
+* `AsDict` and `AsDictStrict` expect `Tuple` of two elements as arguments (key and value, respectively). If the keys repeat, only the value for the first key remains in the dictionary.
+* `AsSet` and `AsSetStrict` expect keys as arguments.
+
+### Examples
+
+```yql
+SELECT
+ AsTuple(1, 2, "3") AS `tuple`,
+ AsStruct(
+ 1 AS a,
+ 2 AS b,
+ "3" AS c
+ ) AS `struct`,
+ AsList(1, 2, 3) AS `list`,
+ AsDict(
+ AsTuple("a", 1),
+ AsTuple("b", 2),
+ AsTuple("c", 3)
+ ) AS `dict`,
+ AsSet(1, 2, 3) AS `set`
+```
+
+
+
+## Container literals {#containerliteral}
+
+Some containers support operator notation for their literal values:
+
+* Tuple: `(value1, value2...)`;
+* Structure: `<|name1: value1, name2: value2...|>`;
+* List: `[value1, value2,...]`;
+* Dictionary: `{key1: value1, key2: value2...}`;
+* Set: `{key1, key2...}`.
+
+In every case, you can use an insignificant trailing comma. For a tuple with one element, this comma is required: `(value1,)`.
+For field names in the structure literal, you can use an expression that can be calculated at evaluation time, for example, string literals or identifiers (including those enclosed in backticks).
+
+For nested lists, use [AsList](#as-container), for nested dictionaries, use [AsDict](#as-container), for nested sets, use [AsSet](#as-container), for nested tuples, use [AsTuple](#as-container), for nested structures, use [AsStruct](#as-container).
+
+### Examples
+
+```yql
+$name = "computed " || "member name";
+SELECT
+ (1, 2, "3") AS `tuple`,
+ <|
+ `complex member name`: 2.3,
+ b: 2,
+ $name: "3",
+ "inline " || "computed member name": false
+ |> AS `struct`,
+ [1, 2, 3] AS `list`,
+ {
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ } AS `dict`,
+ {1, 2, 3} AS `set`
+```
+
+
+
+## Variant {#variant}
+
+`Variant()` creates a variant value over a tuple or structure.
+
+Arguments:
+
+* Value
+* String with a field name or tuple index
+* Variant type
+
+### Example
+
+```yql
+$var_type = Variant<foo: Int32, bar: Bool>;
+
+SELECT
+ Variant(6, "foo", $var_type) as Variant1Value,
+ Variant(false, "bar", $var_type) as Variant2Value;
+```
+
+## AsVariant {#asvariant}
+
+`AsVariant()` creates a value of a [variant over a structure](../types/containers.md) including one field. This value can be implicitly converted to any variant over a structure that has a matching data type for this field name and might include more fields with other names.
+
+Arguments:
+
+* Value
+* A string with the field name
+
+### Example
+
+```yql
+SELECT
+ AsVariant(6, "foo") as VariantValue
+```
+
+## Visit, VisitOrDefault {#visit}
+
+Processes the possible values of a variant over a structure or tuple using the provided handler functions for each field/element of the variant.
+
+### Signature
+
+```yql
+Visit(Variant<key1: K1, key2: K2, ...>, K1->R AS key1, K2->R AS key2, ...)->R
+Visit(Variant<K1, K2, ...>, K1->R, K2->R, ...)->R
+
+VisitOrDefault(Variant<K1, K2, ...>{Flags:AutoMap}, R, [K1->R, [K2->R, ...]])->R
+VisitOrDefault(Variant<key1: K1, key2: K2, ...>{Flags:AutoMap}, R, [K1->R AS key1, [K2->R AS key2, ...]])->R
+```
+
+### Arguments
+
+* For a variant over structure: accepts the variant as the positional argument and named arguments (handlers) corresponding to each field of the variant.
+* For a variant over tuple: accepts the variant and handlers for each element of the variant as positional arguments.
+* `VisitOrDefault` includes an additional positional argument (on the second place) for the default value, enabling the omission of certain handlers.
+
+### Example
+
+```yql
+$vartype = Variant<num: Int32, flag: Bool, str: String>;
+$handle_num = ($x) -> { return 2 * $x; };
+$handle_flag = ($x) -> { return If($x, 200, 10); };
+$handle_str = ($x) -> { return Unwrap(CAST(LENGTH($x) AS Int32)); };
+
+$visitor = ($var) -> { return Visit($var, $handle_num AS num, $handle_flag AS flag, $handle_str AS str); };
+SELECT
+ $visitor(Variant(5, "num", $vartype)), -- 10
+ $visitor(Just(Variant(True, "flag", $vartype))), -- Just(200)
+ $visitor(Just(Variant("somestr", "str", $vartype))), -- Just(7)
+ $visitor(Nothing(OptionalType($vartype))), -- Nothing(Optional<Int32>)
+ $visitor(NULL) -- NULL
+;
+```
+
+## VariantItem {#variantitem}
+
+Returns the value of a homogeneous variant (i.e., a variant containing fields/elements of the same type).
+
+### Signature
+
+```yql
+VariantItem(Variant<key1: K, key2: K, ...>{Flags:AutoMap})->K
+VariantItem(Variant<K, K, ...>{Flags:AutoMap})->K
+```
+
+### Example
+
+```yql
+$vartype1 = Variant<num1: Int32, num2: Int32, num3: Int32>;
+SELECT
+ VariantItem(Variant(7, "num2", $vartype1)), -- 7
+ VariantItem(Just(Variant(5, "num1", $vartype1))), -- Just(5)
+ VariantItem(Nothing(OptionalType($vartype1))), -- Nothing(Optional<Int32>)
+ VariantItem(NULL) -- NULL
+;
+```
+
+## Way {#way}
+
+Returns an active field (active index) of a variant over a struct (tuple).
+
+### Signature
+
+```yql
+Way(Variant<key1: K1, key2: K2, ...>{Flags:AutoMap})->Utf8
+Way(Variant<K1, K2, ...>{Flags:AutoMap})->Uint32
+```
+
+### Example
+
+```yql
+$vr = Variant(1, "0", Variant<Int32, String>);
+$vrs = Variant(1, "a", Variant<a:Int32, b:String>);
+SELECT Way($vr); -- 0
+SELECT Way($vrs); -- "a"
+```
+
+
+## Enum {#enum}
+
+`Enum()` creates an enumeration value.
+
+Arguments:
+
+* A string with the field name
+* Enumeration type
+
+### Example
+
+```yql
+$enum_type = Enum<Foo, Bar>;
+SELECT
+ Enum("Foo", $enum_type) as Enum1Value,
+ Enum("Bar", $enum_type) as Enum2Value;
+```
+
+## AsEnum {#asenum}
+
+`AsEnum()` creates a value of [enumeration](../types/containers.md) including one element. This value can be implicitly cast to any enumeration containing such a name.
+
+Arguments:
+
+* A string with the name of an enumeration item
+
+### Example
+
+```yql
+SELECT
+ AsEnum("Foo");
+```
+
+
+
+## AsTagged, Untag {#as-tagged}
+
+Wraps the value in the [Tagged data type](../types/special.md) with the specified tag, preserving the physical data type. `Untag`: The reverse operation.
+
+Required arguments:
+
+1. Value of any type.
+2. Tag name.
+
+Returns a copy of the value from the first argument with the specified tag in the data type.
+
+Examples of use cases:
+
+* Returns to the client's web interface the media files from BASE64-encoded strings.
+* Prevent passing of invalid values at the boundaries of UDF calls.
+* Additional refinements at the level of returned columns types.
+
+## TablePath {#tablepath}
+
+Access to the current table name, which might be needed when you use [CONCAT](../syntax/select/concat.md#concat), and other related functions.
+
+No arguments. Returns a string with the full path or an empty string and warning when used in an unsupported context (for example, when working with a subquery or a range of 1000+ tables).
+
+{% note info %}
+
+The [TablePath](#tablepath), [TableName](#tablename), and [TableRecordIndex](#tablerecordindex) functions don't support temporary and anonymous tables (they return an empty string or 0 for [TableRecordIndex](#tablerecordindex)).
+These functions are calculated when [executing](../syntax/select/index.md#selectexec) projections in `SELECT`, and by that time the current table may already be temporary.
+To avoid such a situation, create a subquery for calculating these functions, as shown in the second example below.
+
+{% endnote %}
+
+### Examples
+
+```yql
+SELECT TablePath() FROM CONCAT(table_a, table_b);
+```
+
+```yql
+SELECT key, tpath_ AS path FROM (SELECT a.*, TablePath() AS tpath_ FROM RANGE(`my_folder`) AS a)
+WHERE key IN $subquery;
+```
+
+## TableName {#tablename}
+
+Get the table name based on the table path. You can obtain the path using the [TablePath](#tablepath) function.
+
+Optional arguments:
+
+* Path to the table, `TablePath()` is used by default (see also its limitations).
+* Specifying the system ("yt") whose rules are used to determine the table name. You need to specify the system only if [USE](../syntax/use.md) doesn't specify the current cluster.
+
+### Examples
+
+```yql
+USE cluster;
+SELECT TableName() FROM CONCAT(table_a, table_b);
+```
+
+
+## TableRecordIndex {#tablerecordindex}
+
+Access to the current sequence number of a row in the physical source table, **starting from 1** (depends on the storage implementation).
+
+No arguments. When used in combination with [CONCAT](../syntax/select/concat.md#concat), and other similar mechanisms, numbering restarts for each input table. If used in an incorrect context, it returns 0.
+
+### Example
+
+```yql
+SELECT TableRecordIndex() FROM my_table;
+```
+
+## TableRow, JoinTableRow {#tablerow}
+
+Getting the entire table row as a structure. No arguments. `JoinTableRow` in case of `JOIN` always returns a structure with table prefixes.
+
+### Example
+
+```yql
+SELECT TableRow() FROM my_table;
+```
+
+## FileContent and FilePath {#file-content-path}
+
+The `FileContent` and `FilePath` argument is a string with an alias.
+
+### Examples
+
+```yql
+SELECT "Content of "
+ || FilePath("my_file.txt")
+ || ":\n"
+ || FileContent("my_file.txt");
+```
+
+## FolderPath {#folderpath}
+
+Getting the path to the root of a directory with several "attached" files with the common prefix specified.
+
+The argument is a string with a prefix among aliases.
+
+See also [PRAGMA File](../syntax/pragma.md#file) and [PRAGMA Folder](../syntax/pragma.md#folder).
+
+### Examples
+
+```yql
+PRAGMA File("foo/1.txt", "http://url/to/somewhere");
+PRAGMA File("foo/2.txt", "http://url/to/somewhere/else");
+PRAGMA File("bar/3.txt", "http://url/to/some/other/place");
+
+SELECT FolderPath("foo"); -- The directory at the return path will
+ -- include the files 1.txt and 2.txt downloaded from the above links
+```
+
+## ParseFile
+
+Get a list of values from the attached text file. It can be combined with [IN](../syntax/expressions.md#in), attaching the file by URL.
+
+Only one file format is supported: one value per line.
+
+Two required arguments:
+
+1. List cell type: only strings and numeric types are supported.
+2. The name of the attached file.
+
+{% note info %}
+
+The return value is a lazy list. For repeat use, wrap it in the function [ListCollect](list.md#listcollect)
+
+{% endnote %}
+
+### Examples
+
+```yql
+SELECT ListLength(ParseFile("String", "my_file.txt"));
+```
+
+```yql
+SELECT * FROM my_table
+WHERE int_column IN ParseFile("Int64", "my_file.txt");
+```
+
+## Ensure... {#ensure}
+
+Checking for the user conditions:
+
+* `Ensure()`: Checking whether the predicate is true at query execution.
+* `EnsureType()`: Checking that the expression type exactly matches the specified type.
+* `EnsureConvertibleTo()`: A soft check of the expression type (with the same rules as for implicit type conversion).
+
+If the check fails, the entire query fails.
+
+Arguments:
+
+1. An expression that will result from a function call if the check is successful. It's also checked for the data type in the corresponding functions.
+2. Ensure uses a Boolean predicate that is checked for being `true`. The other functions use the data type that can be obtained using the [relevant functions](types.md), or a string literal with a [text description of the type](../types/type_string.md).
+3. An optional string with an error comment to be included in the overall error message when the query is complete. The data itself can't be used for type checks, since the data check is performed at query validation (or can be an arbitrary expression in the case of Ensure).
+
+To check the conditions based on the final calculation result, it's convenient to combine Ensure with [DISCARD SELECT](../syntax/discard.md).
+
+### Examples
+
+```yql
+SELECT Ensure(
+ value,
+ value < 100,
+ "value out or range"
+) AS value FROM my_table;
+```
+
+```yql
+SELECT EnsureType(
+ value,
+ TypeOf(other_value),
+ "expected value and other_value to be of same type"
+) AS value FROM my_table;
+```
+
+```yql
+SELECT EnsureConvertibleTo(
+ value,
+ Double?,
+ "expected value to be numeric"
+) AS value FROM my_table;
+```
+
+## EvaluateExpr, EvaluateAtom {#evaluate_expr_atom}
+
+Evaluate an expression before the start of the main calculation and input its result to the query as a literal (constant). In many contexts, where only a constant would be expected in standard SQL (for example, in table names, in the number of rows in [LIMIT](../syntax/select/limit_offset.md), and so on), this functionality is implicitly enabled automatically.
+
+EvaluateExpr can be used where the grammar already expects an expression. For example, you can use it to:
+
+* Round the current time to days, weeks, or months and insert it into the query to ensure correct [query caching](../syntax/pragma.md#yt.querycachemode), although usually when [functions are used to get the current time](#current-utc), query caching is completely disabled.
+* Run a heavy calculation with a small result once per query instead of once per job.
+
+EvaluateAtom lets you dynamically create an [atom](../types/special.md), but since atoms are mainly controlled from a lower [s-expressions](/docs/s_expressions/functions) level, it's generally not recommended to use this function directly.
+
+The only argument for both functions is the expression for calculation and substitution.
+
+Restrictions:
+
+* The expression must not trigger MapReduce operations.
+* This functionality is fully locked in YQL over YDB.
+
+### Examples
+
+```yql
+$now = CurrentUtcDate();
+SELECT EvaluateExpr(
+ DateTime::MakeDate(DateTime::StartOfWeek($now)
+ )
+);
+```
+
+
+## Literals of primitive types {#data-type-literals}
+
+For primitive types, you can create literals based on string literals.
+
+### Syntax
+
+`<Primitive type>( <string>[, <additional attributes>] )`
+
+Unlike `CAST("myString" AS MyType)`:
+
+* The check for literal's castability to the desired type occurs at validation.
+* The result is non-optional.
+
+For the data types `Date`, `Datetime`, `Timestamp`, and `Interval`, literals are supported only in the format corresponding to [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601). `Interval` has the following differences from the standard:
+
+* It supports the negative sign for shifts to the past.
+* Microseconds can be expressed as fractional parts of seconds.
+* You can't use units of measurement exceeding one week.
+* The options with the beginning/end of the interval and with repetitions, are not supported.
+
+For the data types `TzDate`, `TzDatetime`, `TzTimestamp`, literals are also set in the format meeting [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601), but instead of the optional Z suffix, they specify the [IANA name of the time zone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones), separated by comma (for example, GMT or Europe/Moscow).
+
+{% include [decimal args](../_includes/decimal_args.md) %}
+
+### Examples
+
+```yql
+SELECT
+ Bool("true"),
+ Uint8("0"),
+ Int32("-1"),
+ Uint32("2"),
+ Int64("-3"),
+ Uint64("4"),
+ Float("-5"),
+ Double("6"),
+ Decimal("1.23", 5, 2), -- up to 5 decimal digits, with 2 after the decimal point
+ String("foo"),
+ Utf8("Hello"),
+ Yson("<a=1>[3;%false]"),
+ Json(@@{"a":1,"b":null}@@),
+ Date("2017-11-27"),
+ Datetime("2017-11-27T13:24:00Z"),
+ Timestamp("2017-11-27T13:24:00.123456Z"),
+ Interval("P1DT2H3M4.567890S"),
+ TzDate("2017-11-27,Europe/Moscow"),
+ TzDatetime("2017-11-27T13:24:00,America/Los_Angeles"),
+ TzTimestamp("2017-11-27T13:24:00.123456,GMT"),
+ Uuid("f9d5cc3f-f1dc-4d9c-b97e-766e57ca4ccb");
+```
+
+## ToBytes and FromBytes {#to-from-bytes}
+
+Conversion of [primitive data types](../types/primitive.md) to a string with their binary representation and back. Numbers are represented in the [little endian](https://en.wikipedia.org/wiki/Endianness#Little-endian) format.
+
+### Examples
+
+```yql
+SELECT
+ ToBytes(123), -- "\u0001\u0000\u0000\u0000"
+ FromBytes(
+ "\xd2\x02\x96\x49\x00\x00\x00\x00",
+ Uint64
+ ); -- 1234567890ul
+```
+
+
+
+## ByteAt {#byteat}
+
+Getting the byte value inside a string at an index counted from the beginning of the string. If an invalid index is specified, `NULL` is returned.
+
+Arguments:
+
+1. String: `String` or `Utf8`.
+2. Index: `Uint32`.
+
+### Examples
+
+```yql
+SELECT
+ ByteAt("foo", 0), -- 102
+ ByteAt("foo", 1), -- 111
+ ByteAt("foo", 9); -- NULL
+```
+
+
+
+## ...Bit {#bitops}
+
+`TestBit()`, `ClearBit()`, `SetBit()` and `FlipBit()`: Test, clear, set, or flip a bit in an unsigned number using the specified bit sequence number.
+
+Arguments:
+
+1. An unsigned number that's subject to the operation. TestBit is also implemented for strings.
+2. Number of the bit.
+
+TestBit returns `true/false`. The other functions return a copy of their first argument with the corresponding conversion.
+
+### Examples
+
+```yql
+SELECT
+ TestBit(1u, 0), -- true
+ SetBit(8u, 0); -- 9
+```
+
+
+
+## Abs {#abs}
+
+The absolute value of the number.
+
+### Examples
+
+```yql
+SELECT Abs(-123); -- 123
+```
+
+
+
+## Just {#optional-ops}
+
+`Just()`: Change the value's data type to [optional](../types/optional.md) from the current data type (i.e.,`T` is converted to `T?`).
+
+The reverse operation is [Unwrap](#optional-ops).
+
+### Examples
+
+```yql
+SELECT
+ Just("my_string"); -- String?
+```
+
+## Unwrap {#unwrap}
+
+`Unwrap()`: Converting the [optional](../types/optional.md) value of the data type to the relevant non-optional type, raising a runtime error if the data is `NULL`. This means that `T?` becomes `T`.
+
+If the value isn't [optional](../types/optional.md), then the function returns its first argument unchanged.
+
+Arguments:
+
+1. Value to be converted.
+2. An optional string with a comment for the error text.
+
+Reverse operation is [Just](#optional-ops).
+
+### Examples
+
+```yql
+$value = Just("value");
+
+SELECT Unwrap($value, "Unexpected NULL for $value");
+```
+
+## Nothing {#nothing}
+
+`Nothing()`: Create an empty value for the specified [Optional](../types/optional.md) data type.
+
+### Examples
+
+```yql
+SELECT
+ Nothing(String?); -- an empty (NULL) value with the String? type
+```
+
+[Learn more about ParseType and other functions for data types](types.md).
+
+
+
+## Callable {#callable}
+
+Create a callable value with the specified signature from a lambda function. It's usually used to put callable values into containers.
+
+Arguments:
+
+1. Type.
+2. Lambda function.
+
+### Examples
+
+```yql
+$lambda = ($x) -> {
+ RETURN CAST($x as String)
+};
+
+$callables = AsTuple(
+ Callable(Callable<(Int32)->String>, $lambda),
+ Callable(Callable<(Bool)->String>, $lambda),
+);
+
+SELECT $callables.0(10), $callables.1(true);
+```
+
+
+
+## Pickle, Unpickle {#pickle}
+
+`Pickle()` and `StablePickle()` serialize an arbitrary object into a sequence of bytes, if possible. Typical non-serializable objects are Callable and Resource. The serialization format is not versioned and can be used within a single query. For the Dict type, the StablePickle function pre-sorts the keys, and for Pickle, the order of dictionary elements in the serialized representation isn't defined.
+
+`Unpickle()` is the inverse operation (deserialization), where with the first argument being the data type of the result and the second argument is the string with the result of `Pickle()` or `StablePickle()`.
+
+### Examples
+
+```yql
+SELECT *
+FROM my_table
+WHERE Digest::MurMurHash32(
+ Pickle(TableRow())
+ ) %10 ==0; -- actually, it is better to use TABLESAMPLE
+
+$buf = Pickle(123);
+SELECT Unpickle(Int32, $buf);
+```
+
+
+
+## StaticMap
+
+Transforms a structure or tuple by applying a lambda function to each item.
+
+Arguments:
+
+* Structure or tuple.
+* Lambda for processing items.
+
+Result: a structure or tuple with the same number and naming of items as in the first argument, and with item data types determined by lambda results.
+
+### Examples
+
+```yql
+SELECT *
+FROM (
+ SELECT
+ StaticMap(TableRow(), ($item) -> {
+ return CAST($item AS String);
+ })
+ FROM my_table
+) FLATTEN COLUMNS; -- converting all columns to rows
+```
+
+
+
+## StaticZip
+
+Merges structures or tuples element-by-element. All arguments (one or more) must be either structures with the same set of fields or tuples of the same length.
+The result will be a structure or tuple, respectively.
+Each item of the result is a tuple comprised of items taken from arguments.
+
+### Examples
+
+```yql
+$one = <|k1:1, k2:2.0|>;
+$two = <|k1:3.0, k2:4|>;
+
+-- Adding two structures item-by-item
+SELECT StaticMap(StaticZip($one, $two), ($tuple)->($tuple.0 + $tuple.1)) AS sum;
+```
+
+
+
+## StaticFold, StaticFold1 {#staticfold}
+
+```yql
+StaticFold(obj:Struct/Tuple, initVal, updateLambda)
+StaticFold1(obj:Struct/Tuple, initLambda, updateLambda)
+```
+
+Left fold over struct/tuple elements.
+The folding of tuples is done in order from the element with the lower index to the element with the larger one; for structures, the order is not guaranteed.
+
+- `obj` - object to fold
+- `initVal` - _(for StaticFold)_ initial fold state
+- `initLambda` - _(for StaticFold1)_ lambda that produces initial fold state from the first element
+- `updateLambda` - lambda that produces the new state (arguments are the next element and the previous state)
+
+
+`StaticFold(<|key_1:$el_1, key_2:$el_2, ..., key_n:$el_n|>, $init, $f)` transforms into:
+
+```yql
+$f($el_n, ...$f($el_2, $f($init, el_1))...)
+```
+
+`StaticFold1(<|key_1:$el_1, key_2:$el_2, ..., key_n:$el_n|>, $f0, $f)`:
+
+```yql
+$f($el_n, ...$f($el_2, $f($f0($init), el_1))...)
+```
+
+`StaticFold1(<||>, $f0, $f)` returns `NULL`.
+
+Works with tuples in the same way.
+
+
+## AggregationFactory {#aggregationfactory}
+
+Create a factory for [aggregation functions](aggregation.md) to separately describe the methods of aggregation and data types subject to aggregation.
+
+Arguments:
+
+1. A string in double quotes with the name of an aggregate function, for example ["MIN"](aggregation.md#min).
+2. Optional parameters of the aggregate function that are data-independent. For example, the percentile value in [PERCENTILE](aggregation.md#percentile).
+
+The resulting factory can be used as the second parameter of the function [AGGREGATE_BY](aggregation.md#aggregate-by).
+If the aggregate function is applied to two columns instead of one, as, for example, [MIN_BY](aggregation.md#minby), then in [AGGREGATE_BY](aggregation.md#aggregate-by), the first argument passes a `Tuple` of two values. See more details in the description of the applicable aggregate function.
+
+### Examples
+
+```yql
+$factory = AggregationFactory("MIN");
+SELECT
+ AGGREGATE_BY (value, $factory) AS min_value -- apply the MIN aggregation to the "value" column
+FROM my_table;
+```
+
+## AggregateTransformInput {#aggregatetransform}
+
+`AggregateTransformInput()` converts an [aggregation factory](aggregation.md), for example, obtained using the [AggregationFactory](#aggregationfactory) function, to other factory, in which the specified transformation of input items is performed before starting aggregation.
+
+Arguments:
+
+1. Aggregation factory.
+2. A lambda function with one argument that converts an input item.
+
+### Examples
+
+```yql
+$f = AggregationFactory("sum");
+$g = AggregateTransformInput($f, ($x) -> (cast($x as Int32)));
+$h = AggregateTransformInput($f, ($x) -> ($x * 2));
+SELECT ListAggregate([1,2,3], $f); -- 6
+SELECT ListAggregate(["1","2","3"], $g); -- 6
+SELECT ListAggregate([1,2,3], $h); -- 12
+```
+
+## AggregateTransformOutput {#aggregatetransformoutput}
+
+`AggregateTransformOutput()` converts an [aggregation factory](aggregation.md), for example, obtained using the [AggregationFactory](#aggregationfactory) function, to other factory, in which the specified transformation of the result is performed after ending aggregation.
+
+Arguments:
+
+1. Aggregation factory.
+2. A lambda function with one argument that converts the result.
+
+### Examples
+
+```yql
+$f = AggregationFactory("sum");
+$g = AggregateTransformOutput($f, ($x) -> ($x * 2));
+SELECT ListAggregate([1,2,3], $f); -- 6
+SELECT ListAggregate([1,2,3], $g); -- 12
+```
+
+## AggregateFlatten {#aggregateflatten}
+
+Adapts a factory for [aggregation functions](aggregation.md), for example, obtained using the [AggregationFactory](#aggregationfactory) function in a way that allows aggregation of list input items. This operation is similar to [FLATTEN LIST BY](../syntax/flatten.md): Each list item is aggregated.
+
+Arguments:
+
+1. Aggregation factory.
+
+### Examples
+
+```yql
+$i = AggregationFactory("AGGREGATE_LIST_DISTINCT");
+$j = AggregateFlatten($i);
+SELECT AggregateBy(x, $j) from (
+ select [1,2] as x
+ union all
+ select [2,3] as x
+); -- [1, 2, 3]
+```
+
+## YQL::, s-expressions {#s-expressions}
+
+For the full list of internal YQL functions, see the [documentation for s-expressions](/docs/s_expressions/functions), an alternative low-level YQL syntax. Any of the functions listed there can also be called from the SQL syntax by adding the `YQL::` prefix to its name. However, we don't recommend doing this, because this mechanism is primarily intended to temporarily bypass possible issues and for internal testing purposes.
+
+If the function is available in SQL syntax without the `YQL::` prefix, then its behavior may differ from the same-name function from the s-expressions documentation, if any.
+
diff --git a/yql/essentials/docs/en/builtins/codegen.md b/yql/essentials/docs/en/builtins/codegen.md
new file mode 100644
index 0000000000..2728742947
--- /dev/null
+++ b/yql/essentials/docs/en/builtins/codegen.md
@@ -0,0 +1,181 @@
+# Functions for code generation
+
+When running calculations, you can generate the code including [S-expressions](/docs/s_expressions) nodes. This uses a mechanism for packing the code in the [resource](../types/special.md). After building the code, you can insert it into the main program using the [EvaluateCode](#evaluatecode) function. For debugging purposes, you can convert the code to a string using the [FormatCode](#formatcode) function.
+
+Possible node types in S-expressions that can be used for code generation:
+
+* An atom is an untyped string of zero or more characters.
+* A list is a sequence of zero or more nodes. It corresponds to the `tuple` type in SQL.
+* A call of a built-in function consists of a name expressed by an atom and a sequence of zero or more nodes that are arguments to this function.
+* Lambda function declaration consists of declaring the names of arguments and a node that is the root of the body for this lambda function.
+* The lambda function argument is a node that can only be used inside the body of the lambda function.
+* World is a special node that labels I/O operations.
+
+The S-expressions nodes form a directed graph. Atoms are always leaf nodes, because they cannot contain child nodes.
+
+In the text representation, S-expressions have the following format:
+
+* Atom: `'"foo"`. The apostrophe character (') denotes quoting of the next line that is usually enclosed in quotation marks.
+* List: `'("foo" "bar")`. The apostrophe character (') denotes that there will be no function call in parentheses.
+* Calling the built-in function: `(foo "bar")`. The first item inside the brackets is the mandatory name of the function followed by the function arguments.
+* Declaring a lambda function: `(lambda '(x y) (+ x y))`. The `lambda` keyword is followed by a list of argument names and then by the body of the lambda function.
+* The lambda function argument is `x`. Unlike an atom, a string without an apostrophe character (') references a name in the current scope. When declaring a lambda function, the names of arguments are added to the body's visibility scope, and, if needed, the name is hidden from the global scope.
+* The `world`.
+
+## FormatCode
+
+Serializing the code as [S-expressions](/docs/s_expressions). The code must not contain free arguments of functions, hence, to serialize the lambda function code, you must pass it completely, avoiding passing individual expressions that might contain lambda function arguments.
+
+### Examples
+
+```yql
+SELECT FormatCode(AtomCode("foo"));
+-- (
+-- (return '"foo")
+-- )
+```
+
+## WorldCode
+
+Build a code node with the `world` type.
+
+### Examples
+
+```yql
+SELECT FormatCode(WorldCode());
+-- (
+-- (return world)
+-- )
+```
+
+## AtomCode
+
+Build a code node with the `atom` type from a string passed to the argument.
+
+### Examples
+
+```yql
+SELECT FormatCode(AtomCode("foo"));
+-- (
+-- (return '"foo")
+-- )
+```
+
+## ListCode
+
+Build a code node with the `list` type from a set of nodes or lists of code nodes passed to arguments. In this case, lists of arguments are built in as separately listed code nodes.
+
+### Examples
+
+```yql
+SELECT FormatCode(ListCode(
+ AtomCode("foo"),
+ AtomCode("bar")));
+-- (
+-- (return '('"foo" '"bar"))
+-- );
+
+SELECT FormatCode(ListCode(AsList(
+ AtomCode("foo"),
+ AtomCode("bar"))));
+-- (
+-- (return '('"foo" '"bar"))
+-- )
+```
+
+## FuncCode
+
+Build a code node with the `built-in function call` from a string with the function name and a set of nodes or lists of code nodes passed to arguments. In this case, lists of arguments are built in as separately listed code nodes.
+
+### Examples
+
+```yql
+SELECT FormatCode(FuncCode(
+ "Baz",
+ AtomCode("foo"),
+ AtomCode("bar")));
+-- (
+-- (return (Baz '"foo" '"bar"))
+-- )
+
+SELECT FormatCode(FuncCode(
+ "Baz",
+ AsList(
+ AtomCode("foo"),
+ AtomCode("bar"))));
+-- (
+-- (return (Baz '"foo" '"bar"))
+-- )
+```
+
+## LambdaCode
+
+You can build a code node with the `lambda function declaration` type from:
+
+* [a Lambda function](../syntax/expressions.md#lambda), if you know the number of arguments in advance. In this case, the nodes of the `argument` type will be passed as arguments to this lambda function.
+* The number of arguments and a [lambda function](../syntax/expressions.md#lambda) with one argument. In this case, a list of nodes of the `argument`type will be passed as an argument to this lambda function.
+
+### Examples
+
+```yql
+SELECT FormatCode(LambdaCode(($x, $y) -> {
+ RETURN FuncCode("+", $x, $y);
+}));
+-- (
+-- (return (lambda '($1 $2) (+ $1 $2)))
+-- )
+
+SELECT FormatCode(LambdaCode(2, ($args) -> {
+ RETURN FuncCode("*", Unwrap($args[0]), Unwrap($args[1]));
+}));
+-- (
+-- (return (lambda '($1 $2) (* $1 $2)))
+-- )
+```
+
+## EvaluateCode
+
+Substituting the code node passed in the argument, into the main program code.
+
+### Examples
+
+```yql
+SELECT EvaluateCode(FuncCode("Int32", AtomCode("1"))); -- 1
+
+$lambda = EvaluateCode(LambdaCode(($x, $y) -> {
+ RETURN FuncCode("+", $x, $y);
+}));
+SELECT $lambda(1, 2); -- 3
+```
+
+## ReprCode
+
+Substituting the code node representing the result of evaluating an expression passed in the argument, into the main program.
+
+### Examples
+
+```yql
+$add3 = EvaluateCode(LambdaCode(($x) -> {
+ RETURN FuncCode("+", $x, ReprCode(1 + 2));
+}));
+SELECT $add3(1); -- 4
+```
+
+## QuoteCode
+
+Substituting into the main program the code node that represents an expression or a [lambda function](../syntax/expressions.md#lambda) passed in the argument. If free arguments of lambda functions were found during the substitution, they are calculated and substituted into the code as in the [ReprCode](#reprcode) function.
+
+### Examples
+
+```yql
+$lambda = ($x, $y) -> { RETURN $x + $y };
+$makeClosure = ($y) -> {
+ RETURN EvaluateCode(LambdaCode(($x) -> {
+ RETURN FuncCode("Apply", QuoteCode($lambda), $x, ReprCode($y))
+ }))
+};
+
+$closure = $makeClosure(2);
+SELECT $closure(1); -- 3
+```
+
diff --git a/yql/essentials/docs/en/builtins/dict.md b/yql/essentials/docs/en/builtins/dict.md
new file mode 100644
index 0000000000..5659d9ff50
--- /dev/null
+++ b/yql/essentials/docs/en/builtins/dict.md
@@ -0,0 +1,282 @@
+# Functions for dictionaries
+
+## DictCreate {#dictcreate}
+
+Construct an empty dictionary. Two arguments are passed: for a key and a value. Each argument specifies a string with the data type declaration or the type itself built by [type functions](types.md). There are no dictionaries with an unknown key or value type in YQL. As a key, you can set a [primitive data type](../types/primitive.md), except for `Yson` and `Json` that may be [optional](../types/optional.md) or a tuple of them of a length of at least two.
+
+[Documentation for the type definition format](../types/type_string.md).
+
+### Examples
+
+```yql
+SELECT DictCreate(String, Tuple<String,Double?>);
+```
+
+```yql
+SELECT DictCreate(Tuple<Int32?,String>, OptionalType(DataType("String")));
+```
+
+## SetCreate {#setcreate}
+
+Construct an empty set. An argument is passed: the key type that can be built by [type functions](types.md). There are no sets with an unknown key type in YQL. As a key, you can set a [primitive data type](../types/primitive.md), except for `Yson` and `Json` that may be [optional](../types/optional.md) or a tuple of them of a length of at least two.
+
+[Documentation for the type definition format](../types/type_string.md).
+
+### Examples
+
+```yql
+SELECT SetCreate(String);
+```
+
+```yql
+SELECT SetCreate(Tuple<Int32?,String>);
+```
+
+## DictLength {#dictlength}
+
+The count of items in the dictionary.
+
+### Examples
+
+```yql
+SELECT DictLength(AsDict(AsTuple(1, AsList("foo", "bar"))));
+```
+
+```yql
+SELECT DictLength(dict_column) FROM my_table;
+```
+
+## DictHasItems {#dicthasitems}
+
+Check that the dictionary contains at least one item.
+
+### Examples
+
+```yql
+SELECT DictHasItems(AsDict(AsTuple(1, AsList("foo", "bar")))) FROM my_table;
+```
+
+```yql
+SELECT DictHasItems(dict_column) FROM my_table;
+```
+
+
+## DictItems {#dictitems}
+
+Get dictionary contents as a list of tuples including key-value pairs (`List<Tuplekey_type,value_type>`).
+
+### Examples
+
+```yql
+SELECT DictItems(AsDict(AsTuple(1, AsList("foo", "bar"))));
+-- [ ( 1, [ "foo", "bar" ] ) ]
+```
+
+
+```yql
+SELECT DictItems(dict_column)
+FROM my_table;
+```
+
+
+## DictKeys {#dictkeys}
+
+Get a list of dictionary keys.
+
+### Examples
+
+```yql
+SELECT DictKeys(AsDict(AsTuple(1, AsList("foo", "bar"))));
+-- [ 1 ]
+```
+
+
+```yql
+SELECT DictKeys(dict_column)
+FROM my_table;
+```
+
+
+## DictPayloads {#dictpayloads}
+
+Get a list of dictionary values.
+
+### Examples
+
+```yql
+SELECT DictPayloads(AsDict(AsTuple(1, AsList("foo", "bar"))));
+-- [ [ "foo", "bar" ] ]
+```
+
+```yql
+SELECT DictPayloads(dict_column)
+FROM my_table;
+```
+
+## DictLookup {#dictlookup}
+
+Get a dictionary element by its key.
+
+### Examples
+
+```yql
+SELECT DictLookup(AsDict(
+ AsTuple(1, AsList("foo", "bar")),
+ AsTuple(2, AsList("bar", "baz"))
+), 1);
+-- [ "foo", "bar" ]
+```
+
+```yql
+SELECT DictLookup(dict_column, "foo")
+FROM my_table;
+```
+
+## DictContains {#dictcontains}
+
+Checking if an element in the dictionary using its key. Returns true or false.
+
+### Examples
+
+```yql
+SELECT DictContains(AsDict(
+ AsTuple(1, AsList("foo", "bar")),
+ AsTuple(2, AsList("bar", "baz"))
+), 42);
+-- false
+```
+
+```yql
+SELECT DictContains(dict_column, "foo")
+FROM my_table;
+```
+
+
+## DictAggregate {#dictaggregate}
+
+Apply [aggregation factory](basic.md#aggregationfactory) to the passed dictionary where each value is a list. The factory is applied separately inside each key.
+If the list is empty, the aggregation result is the same as for an empty table: 0 for the `COUNT` function and `NULL` for other functions.
+If the list under a certain key is empty in the passed dictionary, such a key is removed from the result.
+If the passed dictionary is optional and contains `NULL`, the result is also `NULL`.
+
+Arguments:
+
+1. Dictionary.
+2. [Aggregation factory](basic.md#aggregationfactory).
+
+### Examples
+
+```yql
+SELECT DictAggregate(AsDict(
+ AsTuple(1, AsList("foo", "bar")),
+ AsTuple(2, AsList("baz", "qwe"))),
+ AggregationFactory("Max"));
+-- {1 : "foo", 2 : "qwe" }
+```
+
+## SetIsDisjoint {#setisjoint}
+
+Check that the dictionary doesn't intersect by keys with a list or another dictionary.
+
+So there are two options to make a call:
+
+* With the `Dict<K,V1>` and `List<K>` arguments.
+* With the `Dict<K,V1>` and `Dict<K,V2>` arguments.
+
+### Examples
+
+```yql
+SELECT SetIsDisjoint(ToSet(AsList(1, 2, 3)), AsList(7, 4)); -- true
+SELECT SetIsDisjoint(ToSet(AsList(1, 2, 3)), ToSet(AsList(3, 4))); -- false
+```
+
+## SetIntersection {#setintersection}
+
+Construct intersection between two dictionaries based on keys.
+
+Arguments:
+
+* Two dictionaries: `Dict<K,V1>` and `Dict<K,V2>`.
+* An optional function that combines the values from the source dictionaries to construct the values of the output dictionary. If such a function has the `(K,V1,V2) -> U` type, the result type is `Dict<K,U>`. If the function is not specified, the result type is `Dict<K,Void>`, and the values from the source dictionaries are ignored.
+
+### Examples
+
+```yql
+SELECT SetIntersection(ToSet(AsList(1, 2, 3)), ToSet(AsList(3, 4))); -- { 3 }
+SELECT SetIntersection(
+ AsDict(AsTuple(1, "foo"), AsTuple(3, "bar")),
+ AsDict(AsTuple(1, "baz"), AsTuple(2, "qwe")),
+ ($k, $a, $b) -> { RETURN AsTuple($a, $b) });
+-- { 1 : ("foo", "baz") }
+```
+
+## SetIncludes {#setincludes}
+
+Checking that the keys of the specified dictionary include all the elements of the list or the keys of the second dictionary.
+
+So there are two options to make a call:
+
+* With the `Dict<K,V1>` and `List<K>` arguments.
+* With the `Dict<K,V1>` and `Dict<K,V2>` arguments.
+
+### Examples
+
+```yql
+SELECT SetIncludes(ToSet(AsList(1, 2, 3)), AsList(3, 4)); -- false
+SELECT SetIncludes(ToSet(AsList(1, 2, 3)), ToSet(AsList(2, 3))); -- true
+```
+
+## SetUnion {#setunion}
+
+Constructs a union of two dictionaries based on keys.
+
+Arguments:
+
+* Two dictionaries: `Dict<K,V1>` and `Dict<K,V2>`.
+* An optional function that combines the values from the source dictionaries to construct the values of the output dictionary. If such a function has the `(K,V1?,V2?) -> U` type, the result type is `Dict<K,U>`. If the function is not specified, the result type is `Dict<K,Void>`, and the values from the source dictionaries are ignored.
+
+### Examples
+
+```yql
+SELECT SetUnion(ToSet(AsList(1, 2, 3)), ToSet(AsList(3, 4))); -- { 1, 2, 3, 4 }
+SELECT SetUnion(
+ AsDict(AsTuple(1, "foo"), AsTuple(3, "bar")),
+ AsDict(AsTuple(1, "baz"), AsTuple(2, "qwe")),
+ ($k, $a, $b) -> { RETURN AsTuple($a, $b) });
+-- { 1 : ("foo", "baz"), 2 : (null, "qwe"), 3 : ("bar", null) }
+```
+
+## SetDifference {#setdifference}
+
+Construct a dictionary containing all the keys with their values in the first dictionary with no matching key in the second dictionary.
+
+### Examples
+
+```yql
+SELECT SetDifference(ToSet(AsList(1, 2, 3)), ToSet(AsList(3, 4))); -- { 1, 2 }
+SELECT SetDifference(
+ AsDict(AsTuple(1, "foo"), AsTuple(2, "bar")),
+ ToSet(AsList(2, 3)));
+-- { 1 : "foo" }
+```
+
+## SetSymmetricDifference {#setsymmetricdifference}
+
+Construct a symmetric difference between two dictionaries based on keys.
+
+Arguments:
+
+* Two dictionaries: `Dict<K,V1>` and `Dict<K,V2>`.
+* An optional function that combines the values from the source dictionaries to construct the values of the output dictionary. If such a function has the `(K,V1?,V2?) -> U` type, the result type is `Dict<K,U>`. If the function is not specified, the result type is `Dict<K,Void>`, and the values from the source dictionaries are ignored.
+
+### Examples
+
+```yql
+SELECT SetSymmetricDifference(ToSet(AsList(1, 2, 3)), ToSet(AsList(3, 4))); -- { 1, 2, 4 }
+SELECT SetSymmetricDifference(
+ AsDict(AsTuple(1, "foo"), AsTuple(3, "bar")),
+ AsDict(AsTuple(1, "baz"), AsTuple(2, "qwe")),
+ ($k, $a, $b) -> { RETURN AsTuple($a, $b) });
+-- { 2 : (null, "qwe"), 3 : ("bar", null) }
+```
+
diff --git a/yql/essentials/docs/en/builtins/index.md b/yql/essentials/docs/en/builtins/index.md
new file mode 100644
index 0000000000..5c303e16d0
--- /dev/null
+++ b/yql/essentials/docs/en/builtins/index.md
@@ -0,0 +1,12 @@
+# Built-in YQL functions
+
+- [Basic](basic.md)
+- [Aggregate](aggregation.md)
+- [Window](window.md)
+- [For lists](list.md)
+- [For dictionaries](dict.md)
+- [For structures](struct.md)
+- [For types](types.md)
+- [For code generation](codegen.md)
+- [For JSON](json.md)
+- [C++ libraries](../udf/list/index.md)
diff --git a/yql/essentials/docs/en/builtins/json.md b/yql/essentials/docs/en/builtins/json.md
new file mode 100644
index 0000000000..d9168fa6d1
--- /dev/null
+++ b/yql/essentials/docs/en/builtins/json.md
@@ -0,0 +1,1170 @@
+# Functions for JSON
+
+<!-- markdownlint-disable no-trailing-punctuation -->
+
+**JSON** is a lightweight [data-interchange format](https://www.json.org). In YQL, it's represented by the `Json` type. Unlike relational tables, JSON can store data with no schema defined. Here is an example of a valid JSON object:
+
+```json
+[
+ {
+ "name": "Jim Holden",
+ "age": 30
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": "twenty years old"
+ }
+]
+```
+
+Despite the fact that the `age` field in the first object is of the `Number` type (`"age": 21`) and in the second object its type is `String` (`"age": "twenty years old"`), this is a fully valid JSON object.
+
+To work with JSON, YQL implements a subset of the [SQL support for JavaScript Object Notation (JSON)](https://www.iso.org/standard/67367.html) standard, which is part of the common ANSI SQL standard.
+
+## JsonPath
+
+Values inside JSON objects are accessed using a query language called JsonPath. All functions for JSON accept a JsonPath query as an argument.
+
+Let's look at an example. Suppose we have a JSON object like:
+
+```json
+{
+ "comments": [
+ {
+ "id": 123,
+ "text": "A whisper will do, if it's all that you can manage."
+ },
+ {
+ "id": 456,
+ "text": "My life has become a single, ongoing revelation that I haven’t been cynical enough."
+ }
+ ]
+}
+```
+
+Then, to get the text of the second comment, we can write the following JsonPath query:
+
+```yql
+$.comments[1].text
+```
+
+In this query:
+
+1. `$` is a way to access the entire JSON object.
+2. `$.comments` accesses the `comments` key of the JSON object.
+3. `$.comments[1]` accesses the second element of the JSON array (element numbering starts from 0).
+4. `$.comments[1].text` accesses the `text` key of the JSON object.
+5. Query execution result: `"My life has become a single, ongoing revelation that I haven’t been cynical enough."`
+
+### Quick reference
+
+| Operation | Example |
+| --------------------------------------- | ------------------------------------------------- |
+| Retrieving a JSON object key | `$.key` |
+| Retrieving all JSON object keys | `$.*` |
+| Accessing an array element | `$[25]` |
+| Retrieving an array subsegment | `$[2 to 5]` |
+| Accessing the last array element | `$[last]` |
+| Accessing all array elements | `$[*]` |
+| Unary operations | `- 1` |
+| Binary operations | `(12 * 3) % 4 + 8` |
+| Accessing a variable | `$variable` |
+| Logical operations | `(1 > 2) &#124;&#124; (3 <= 4) && ("string" == "another")&#124; |
+| Matching a regular expression | `$.name like_regex "^[A-Za-z]+$"` |
+| Checking the string prefix | `$.name starts with "Bobbie"` |
+| Checking if a path exists | `exists ($.profile.name)` |
+| Checking a Boolean expression for null | `($.age > 20) is unknown` |
+| Filtering values | `$.friends ? (@.age >= 18 && @.gender == "male")` |
+| Getting the value type | `$.name.type()` |
+| Getting the array size | `$.friends.size()` |
+| Converting a string to a number | `$.number.double()` |
+| Rounding up a number | `$.number.ceiling()` |
+| Rounding down a number | `$.number.floor()` |
+| Returning the absolute value | `$.number.abs()` |
+| Getting key-value pairs from an object | `$.profile.keyvalue()` |
+
+### Data model
+
+The result of executing all JsonPath expressions is a sequence of JSON values. For example:
+
+- The result of executing the `"Bobbie"` expression is a sequence with the only element `"Bobbie"`. Its length is 1.
+- The result of executing the `$` expression (that takes the entire JSON object) in JSON `[1, 2, 3]` is `[1, 2, 3]`. A sequence of 1 element of the array `[1, 2, 3]`
+- The result of executing the `$[*]` expression (retrieving all array elements) in JSON `[1, 2, 3]` is `1, 2, 3`. A sequence of three items:`1`, `2`, and `3`
+
+If the input sequence consists of multiple values, some operations are performed for each element (for example, accessing a JSON object key). However, other operations require a sequence of one element as input (for example, binary arithmetic operations).
+
+The behavior of a specific operation is described in the corresponding section of the documentation.
+
+### Execution mode
+
+JsonPath supports two execution modes, `lax` and `strict`. Setting the mode is optional. By default, `lax`. The mode is specified at the beginning of a query. For example, `strict $.key`.
+
+The behavior for each mode is described in the corresponding sections with JsonPath operations.
+
+#### Auto unpacking of arrays
+
+When accessing a JSON object key in `lax` mode, arrays are automatically unpacked.
+
+##### Example
+
+```json
+[
+ {
+ "key": 123
+ },
+ {
+ "key": 456
+ }
+]
+```
+
+The `lax $.key` query is successful and returns `123, 456`. As `$` is an array, it's automatically unpacked and accessing the key of the `$.key` JSON object is executed for each element in the array.
+
+The `strict $.key` query returns an error. In `strict` mode, there is no support for auto unpacking of arrays. Since `$` is an array and not an object, accessing the `$.key` object key is impossible. You can fix this by writing `strict $[*].key`.
+
+Unpacking is only 1 level deep. In the event of nested arrays, only the outermost one is unpacked.
+
+#### Wrapping values in arrays
+
+When accessing an array element in `lax` mode, JSON values are automatically wrapped in an array.
+
+##### Example
+
+```json
+{
+ "name": "Avasarala"
+}
+```
+
+The `lax $[0].name` query is successful and returns `"Avasarala"`. As `$` isn't an array, it's automatically wrapped in an array of length 1. Accessing the first element `$[0]` returns the source JSON object where the `name` key is taken.
+
+The `strict $[0].name` query returns an error. In `strict` mode, values aren't wrapped in an array automatically. Since `$` is an object and not an array, accessing the `$[0]` element is impossible. You can fix this by writing `strict $.name`.
+
+#### Handling errors
+
+Some errors are converted to an empty result when a query is executed in `lax` mode.
+
+### Literals
+
+Values of some types can be specified in a JsonPath query using literals:
+
+| Type | Example |
+| ------------------ | ---------------- |
+| Numbers | `42`, `-1.23e-5` |
+| Boolean values | `false`, `true` |
+| Null | `Null` |
+| Stings | `"Belt"` |
+
+### Accessing JSON object keys
+
+JsonPath supports accessing JSON object keys, such as `$.session.user.name`.
+
+{% note info %}
+
+Accessing keys without quotes is only supported for keys that start with an English letter or underscore and only contain English letters, underscores, numbers, and a dollar sign. Use quotes for all other keys. For example, `$.profile."this string has spaces"` or `$.user."42 is the answer"`
+
+{% endnote %}
+
+For each value from the input sequence:
+
+1. If the value is an array, it's automatically unpacked in `lax` mode.
+2. If the value isn't a JSON object or if it is and the specified key is missing from this JSON object, a query executed in `strict` mode fails. In `lax` mode, an empty result is returned for this value.
+
+The expression execution result is the concatenation of the results for each value from the input sequence.
+
+#### Example
+
+```json
+{
+ "name": "Amos",
+ "friends": [
+ {
+ "name": "Jim"
+ },
+ {
+ "name": "Alex"
+ }
+ ]
+}
+```
+
+| | `lax` | `strict` |
+| ---------------- | ---------------- | -------- |
+| `$.name` | `"Amos"` | `"Amos"` |
+| `$.surname` | Empty result | Error |
+| `$.friends.name` | `"Jim", "Alex"` | Error |
+
+### Accessing all JSON object keys
+
+JsonPath supports accessing all JSON object keys at once: `$.*`.
+
+For each value from the input sequence:
+
+1. If the value is an array, it's automatically unpacked in `lax` mode.
+2. If the value isn't a JSON object, a query executed in `strict` mode fails. In `lax` mode, an empty result is returned for this value.
+
+The expression execution result is the concatenation of the results for each value from the input sequence.
+
+#### Example
+
+```json
+{
+ "profile": {
+ "id": 123,
+ "name": "Amos"
+ },
+ "friends": [
+ {
+ "name": "Jim"
+ },
+ {
+ "name": "Alex"
+ }
+ ]
+}
+```
+
+| | `lax` | `strict` |
+| ------------- | --------------- | ------------- |
+| `$.profile.*` | `123, "Amos"` | `123, "Amos"` |
+| `$.friends.*` | `"Jim", "Alex"` | Error |
+
+### Accessing an array element
+
+JsonPath supports accessing array elements: `$.friends[1, 3 to last - 1]`.
+
+For each value from the input sequence:
+
+1. If the value isn't an array, a query executed in `strict` mode fails. In `lax` mode, values are automatically wrapped in an array.
+2. The `last` keyword is replaced with the array's last index. Using `last` outside of accessing the array is an error in both modes.
+3. The specified indexes are calculated. Each of them must be a single number, otherwise the query fails in both modes.
+4. If the index is a fractional number, it's rounded down.
+5. If the index goes beyond the array boundaries, the query executed in `strict` mode fails. In `lax` mode, this index is ignored.
+6. If a segment is specified and its start index is greater than the end index (for example, `$[20 to 1]`), the query fails in `strict` mode. In `lax` mode, this segment is ignored.
+7. All elements by the specified indexes are added to the result. Segments include **both ends**.
+
+#### Examples
+
+```json
+[
+ {
+ "name": "Camina",
+ "surname": "Drummer"
+ },
+ {
+ "name": "Josephus",
+ "surname": "Miller"
+ },
+ {
+ "name": "Bobbie",
+ "surname": "Draper"
+ },
+ {
+ "name": "Julie",
+ "surname": "Mao"
+ }
+]
+```
+
+| | `lax` | `strict` |
+| ----------------------------- | ------------------------------- | ------------------------------- |
+| `$[0].name` | `"Camina"` | `"Camina"` |
+| `$[1, 2 to 3].name` | `"Josephus", "Bobbie", "Julie"` | `"Josephus", "Bobbie", "Julie"` |
+| `$[last - 2].name` | `"Josephus"` | `"Josephus"` |
+| `$[2, last + 200 to 50].name` | `"Bobbie"` | Error |
+| `$[50].name` | Empty result | Error |
+
+### Accessing all array elements
+
+JsonPath supports accessing all array elements at once: `$[*]`.
+
+For each value from the input sequence:
+
+1. If the value isn't an array, a query executed in `strict` mode fails. In `lax` mode, values are automatically wrapped in an array.
+2. All elements of the current array are added to the result.
+
+#### Examples
+
+```json
+[
+ {
+ "class": "Station",
+ "title": "Medina"
+ },
+ {
+ "class": "Corvette",
+ "title": "Rocinante"
+ }
+]
+```
+
+| | `lax` | `strict` |
+| ------------------- | ------------------------- | ----------------------- |
+| `$[*].title` | `"Medina", "Rocinante"` | `"Medina", "Rocinante"` |
+| `lax $[0][*].class` | `"Station"` | Error |
+
+Let's analyze the last example step by step:
+
+1. `$[0]` returns the first element of the array, that is `{"class": "Station", "title": "Medina"}`
+2. `$[0][*]` expects an array for input, but an object was input instead. It's automatically wrapped in an array as `[ {"class": "Station", "title": "Medina"} ]`
+3. Now, `$[0][*]` can be executed and returns all elements of the array, that is `{"class": "Station", "title": "Medina"}`
+4. `$[0][*].class` returns the `class` field value: `"Station"`.
+
+### Arithmetic operations
+
+{% note info %}
+
+All arithmetic operations work with numbers as with Double. Calculations are made with potential [loss of accuracy](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html).
+
+{% endnote %}
+
+#### Unary operations
+
+JsonPath supports unary `+` and `-`.
+
+A unary operation applies to all values from the input sequence. If a unary operation's input is a value that isn't a number, a query fails in both modes.
+
+##### Example
+
+```json
+[1, 2, 3, 4]
+```
+
+The `strict -$[*]` query is successful and returns `-1, -2, -3, -4`.
+
+The `lax -$` query fails as `$` is an array and not a number.
+
+#### Binary operations
+
+JsonPath supports binary arithmetic operations (in descending order of priority):
+
+1. Multiplication `*`, dividing floating-point numbers `/`, and taking the remainder `%` (works as the `MOD` function in `SQL`).
+2. Addition `+`, subtraction `-`.
+
+You can change the order of operations using parentheses.
+
+If each argument of a binary operation is not a single number or a number is divided by 0, the query fails in both modes.
+
+##### Examples
+
+- `(1 + 2) * 3` returns `9`
+- `1 / 2` returns `0.5`
+- `5 % 2` returns `1`
+- `1 / 0` fails
+- If JSON is `[-32.4, 5.2]`, the `$[0] % $[1]` query returns `-1.2`
+- If JSON is `[1, 2, 3, 4]`, the `lax $[*] + $[*]` query fails as the `$[*]` expression execution result is `1, 2, 3, 4`, that is multiple numbers. A binary operation only requires one number for each of its arguments.
+
+### Boolean values
+
+Unlike some other programming languages, Boolean values in JsonPath are not only `true` and `false`, but also `null` (uncertainty).
+
+JsonPath considers any values received from a JSON document to be non-Boolean. For example, a query like `! $.is_valid_user` (a logical negation applied to the `is_valid_user`) field is syntactically invalid because the `is_valid_user` field value is not Boolean (even when it actually stores `true` or `false`). The correct way to write this kind of query is to explicitly use a comparison with a Boolean value, such as `$.is_valid_user == false`.
+
+### Logical operations
+
+JsonPath supports some logical operations for Boolean values.
+
+The arguments of any logical operation must be a single Boolean value.
+All logical operations return a Boolean value.
+
+#### Logical negation, !
+
+Truth table:
+
+| `x` | `!x` |
+| ------- | ------- |
+| `true` | `false` |
+| `false` | `true` |
+| `Null` | `Null` |
+
+#### Logical AND, &&
+
+In the truth table, the first column is the left argument, the first row is the right argument, and each cell is the result of using the Logical AND both with the left and right arguments:
+
+| `&&` | `true` | `false` | `Null` |
+| ------- | ------- | ------- | ------- |
+| `true` | `true` | `false` | `Null` |
+| `false` | `false` | `false` | `false` |
+| `Null` | `Null` | `false` | `Null` |
+
+#### Logical OR, ||
+
+In the truth table, the first column is the left argument, the first row is the right argument, and each cell is the result of using the logical OR with both the left and right arguments:
+
+| `\|\|` | `true` | `false` | `Null` |
+| ------- | ------- | ------- | ------- |
+| `true` | `true` | `true` | `true` |
+| `false` | `true` | `false` | `Null` |
+| `Null` | `true` | `Null` | `Null` |
+
+##### Examples
+
+- `! (true == true)`, the result is `false`
+- `(true == true) && (true == false)`, the result is `false`
+- `(true == true) || (true == false)`, the result is `true`
+
+### Comparison operators
+
+JsonPath implements comparison operators for values:
+
+- Equality, `==`
+- Inequality, `!=`and `<>`
+- Less than and less than or equal to, `<` and `=`
+- Greater than and greater than or equal to, `>` and `>=`
+
+All comparison operators return a Boolean value. Both operator arguments support multiple values.
+
+If an error occurs when calculating the operator arguments, it returns `null`. In this case, the JsonPath query execution continues.
+
+The arrays of each of the arguments are automatically unpacked. After that, for each pair where the first element is taken from the sequence of the left argument and the second one from the sequence of the right argument:
+
+1. The elements of the pair are compared
+2. If an error occurs during the comparison, the `ERROR` flag is set.
+3. If the comparison result is true, the flag set is `FOUND`
+4. If either the `ERROR` or `FOUND` flag is set and the query is executed in `lax` mode, no more pairs are analyzed.
+
+If the pair analysis results in:
+
+1. The `ERROR` flag is set, the operator returns `null`
+2. The `FOUND` flag is set, the operator returns `true`
+3. Otherwise, it returns `false`
+
+We can say that this algorithm considers all pairs from the Cartesian product of the left and right arguments, trying to find the pair whose comparison returns true.
+
+Elements in a pair are compared according to the following rules:
+
+1. If the left or right argument is an array or object, the comparison fails.
+2. `null == null` returns true
+3. In all other cases, if one of the arguments is `null`, false is returned.
+4. If the left and right arguments are of different types, the comparison fails.
+5. Strings are compared byte by byte.
+6. `true` is considered greater than `false`
+7. Numbers are compared with the accuracy of `1e-20`
+
+#### Example
+
+Let's take a JSON document as an example
+
+```json
+{
+ "left": [1, 2],
+ "right": [4, "Inaros"]
+}
+```
+
+and analyze the steps for executing the `lax $.left < $.right` query:
+
+1. Auto unpacking of arrays in the left and right arguments. As a result, the left argument is the sequence `1, 2` and the right argument is `4, "Iranos"`
+2. Let's take the pair `(1, 4)`. The comparison is successful as `1 < 4` is true. Set the flag `FOUND`
+3. Since the query is executed in `lax` mode and the `FOUND` flag is set, we aren't analyzing any more pairs.
+4. Since we have the `FOUND` flag set, the operator returns true.
+
+Let's take the same query in a different execution mode: `strict $.left < $.right`:
+
+1. Auto unpacking of arrays in the left and right arguments. As a result, the left argument is the sequence `1, 2` and the right argument is `4, "Iranos"`
+2. Let's take the pair `(1, 4)`. The comparison is successful as `1 < 4` is true. Set the flag `FOUND`
+3. Let's take the pair `(2, 4)`. The comparison is successful as `2 < 4` is true. Set the flag `FOUND`
+4. Let's take the pair `(1, "Iranos")`. The comparison fails as a number can't be compared with a string. Set the flag `ERROR`
+5. Let's take the pair `(2, "Iranos")`. The comparison fails as a number can't be compared with a string. Set the flag `ERROR`
+6. Since we have the `ERROR` flag set, the operator returns `null`
+
+### Predicates
+
+JsonPath supports predicates which are expressions that return a Boolean value and check a certain condition. You can use them, for example, in filters.
+
+#### `like_regex`
+
+The `like_regex` predicate lets you check if a string matches a regular expression. The syntax of regular expressions is the same as in [Hyperscan UDF](../udf/list/hyperscan.md) and [REGEXP](../syntax/expressions.md#regexp).
+
+##### Syntax
+
+```yql
+<expression> like_regex <regexp string> [flag <flag string>]
+```
+
+Where:
+
+1. `<expression>` is a JsonPath expression with strings to be checked for matching the regular expression.
+2. `<regexp string>` is a string with the regular expression.
+3. `flag <flag string>` is an optional section where `<flag string>` is a string with regular expression execution flags.
+
+Supported flags:
+
+- `i`: Disable the case sensitivity.
+
+##### Execution
+
+Before the check, the input sequence arrays are automatically unpacked.
+
+After that, for each element of the input sequence:
+
+1. A check is made to find out if a string matches a regular expression.
+2. If the element isn't a string, the `ERROR` flag is set.
+3. If the check result is true, the `FOUND` flag is set.
+4. If either the `ERROR` or `FOUND` flag is set and the query is executed in `lax` mode, no more pairs are analyzed.
+
+If the pair analysis results in:
+
+1. Setting the `ERROR` flag, the predicate returns `null`
+2. Setting the `FOUND` flag, the predicate returns `true`
+3. Otherwise, the predicate returns `false`
+
+##### Examples
+
+1. `"123456" like_regex "^[0-9]+$"` returns `true`
+2. `"123abcd456" like_regex "^[0-9]+$"` returns `false`
+3. `"Naomi Nagata" like_regex "nag"` returns `false`
+4. `"Naomi Nagata" like_regex "nag" flag "i"` returns `true`
+
+#### `starts with`
+
+The `starts with` predicate lets you check if one string is a prefix of another.
+
+##### Syntax
+
+```yql
+<string expression> starts with <prefix expression>
+```
+
+Where:
+
+1. `<string expression>` is a JsonPath expression with the string to check.
+2. `<prefix expression>` is a JsonPath expression with a prefix string.
+
+This means that the predicate will check that the `<string expression>` starts with the `<prefix expression>` string.
+
+##### Execution
+
+The first argument of the predicate must be a single string.
+
+The second argument of the predicate must be a sequence of (possibly, multiple) strings.
+
+For each element in a sequence of prefix strings:
+
+1. A check is made for whether "an element is a prefix of an input string"
+2. If the element isn't a string, the `ERROR` flag is set.
+3. If the check result is true, the `FOUND` flag is set.
+4. If either the `ERROR` or `FOUND` flag is set and the query is executed in `lax` mode, no more pairs are analyzed.
+
+If the pair analysis results in:
+
+1. Setting the `ERROR` flag, the predicate returns `null`
+2. Setting the `FOUND` flag, the predicate returns `true`
+3. Otherwise, the predicate returns `false`
+
+##### Examples
+
+1. `"James Holden" starts with "James"` returns `true`
+2. `"James Holden" starts with "Amos"` returns `false`
+
+#### `exists`
+
+The `exists` predicate lets you check whether a JsonPath expression returns at least one element.
+
+##### Syntax
+
+```yql
+exists (<expression>)
+```
+
+Where `<expression>` is the JsonPath expression to be checked. Parentheses around the expression are required.
+
+##### Execution
+
+1. The passed JsonPath expression is executed
+2. If an error occurs, the predicate returns `null`
+3. If an empty sequence is obtained as a result of the execution, the predicate returns `false`
+4. Otherwise, the predicate returns `true`
+
+##### Examples
+
+Let's take a JSON document:
+
+```json
+{
+ "profile": {
+ "name": "Josephus",
+ "surname": "Miller"
+ }
+}
+```
+
+1. `exists ($.profile.name)` returns `true`
+2. `exists ($.friends.profile.name)` returns `false`
+3. `strict exists ($.friends.profile.name)` returns `null`, because accessing non-existent object keys in `strict` mode is an error.
+
+#### `is unknown`
+
+The `is unknown` predicate lets you check if a Boolean value is `null`.
+
+##### Syntax
+
+```yql
+(<expression>) is unknown
+```
+
+Where `<expression>` is the JsonPath expression to be checked. Only expressions that return a Boolean value are allowed. Parentheses around the expression are required.
+
+##### Execution
+
+1. If the passed expression returns `null`, the predicate returns `true`
+2. Otherwise, the predicate returns `false`
+
+##### Examples
+
+1. `(1 == 2) is unknown` returns `false`. The `1 == 2` expression returned `false`, which is not `null`
+2. `(1 == "string") is unknown` returns `true`. The `1 == "string"` expression returned `null`, because strings and numbers can't be compared in JsonPath.
+
+### Filters
+
+JsonPath lets you filter values obtained during query execution.
+
+An expression in a filter must return a Boolean value.
+Before filtering, the input sequence arrays are automatically unpacked.
+
+For each element of the input sequence:
+
+1. The value of the current filtered `@` object becomes equal to the current element of the input sequence.
+2. Executing the expression in the filter
+3. If an error occurs during the expression execution, the current element of the input sequence is skipped.
+4. If the expression execution result is the only `true` value, the current element is added to the filter result.
+
+#### Example
+
+Suppose we have a JSON document describing the user's friends
+
+```json
+{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35,
+ "money": 500
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30,
+ "money": 345
+ }
+ ]
+}
+```
+
+and we want to get a list of friends who are over 32 years old using a JsonPath query. To do this, you can write the following query:
+
+```yql
+$.friends ? (@.age > 32)
+```
+
+Let's analyze the query in parts:
+
+- `$.friends` accesses the `friends` array in the JSON document.
+- `? ( ... )` is the filter syntax. An expression inside the parentheses is called a predicate.
+- `` accesses the currently filtered object. In our example, it's the object describing a friend of the user.
+- `.age` accesses the `age` field of the currently filtered object.
+- `.age > 32` compares the `age` field with the value 32. As a result of the query, only the values for which this predicate returned true remain.
+
+The query only returns the first friend from the array of user's friends.
+
+Like many other JsonPath operators, filters can be arranged in chains. Let's take a more complex query that selects the names of friends who are older than 20 and have less than 400 currency units:
+
+```yql
+$.friends ? (@.age > 20) ? (@.money < 400) . name
+```
+
+Let's analyze the query in parts:
+
+- `$.friends` accesses the `friends` array in the JSON document.
+- `? (@.age > 20)` is the first filter. Since all friends are over 20, it just returns all the elements of the `friends` array.
+- `? (@.money < 400)` is the second filter. It only returns the second element of the `friends` array, since only its `money` field value is less than 400.
+- `.name` accesses the `name` field of filtered objects.
+
+The query returns a sequence of a single element: `"Naomi Nagata"`.
+
+In practice, it's recommended to combine multiple filters into one if possible. The above query is equivalent to `$.friends ? (@.age > 20 && @.money < 400) . name`.
+
+### Methods
+
+JsonPath supports methods that are functions converting one sequence of values to another. The syntax for calling a method is similar to accessing the object key:
+
+```yql
+$.friends.size()
+```
+
+Just like in the case of accessing object keys, method calls can be arranged in chains:
+
+```yql
+$.numbers.double().floor()
+```
+
+#### `type`
+
+The `type` method returns a string with the type of the passed value.
+
+For each element of the input sequence, the method adds this string to the output sequence according to the table below:
+
+| Value type | String with type |
+| ------------------ | ------------------------ |
+| Null | `"null"` |
+| Boolean value | `"boolean"` |
+| Number | `"number"` |
+| String | `"string"` |
+| Array | `"array"` |
+| Object | `"object"` |
+
+##### Examples
+
+1. `"Naomi".type()` returns `"string"`
+2. `false.type()` returns `"boolean"`
+
+#### `size`
+
+The `size` method returns the size of the array.
+
+For each element of the input sequence, the method adds the following to the output sequence:
+
+1. The size of the array if the element type is an array.
+2. For all other types (including objects), it adds `1`
+
+##### Examples
+
+Let's take a JSON document:
+
+```json
+{
+ "array": [1, 2, 3],
+ "object": {
+ "a": 1,
+ "b": 2
+ },
+ "scalar": "string"
+}
+```
+
+And queries to it:
+
+1. `$.array.size()` returns `3`
+2. `$.object.size()` returns `1`
+3. `$.scalar.size()` returns `1`
+
+#### `Double`
+
+The `double` method converts strings to numbers.
+
+Before its execution, the input sequence arrays are automatically unpacked.
+
+All elements in the input sequence must be strings that contain decimal numbers. It's allowed to specify the fractional part and exponent.
+
+##### Examples
+
+1. `"125".double()` returns `125`
+2. `"125.456".double()` returns `125.456`
+3. `"125.456e-3".double()` returns `0.125456`
+
+#### `ceiling`
+
+The `ceiling` method rounds up a number.
+
+Before its execution, the input sequence arrays are automatically unpacked.
+
+All elements in the input sequence must be numbers.
+
+##### Examples
+
+1. `(1.3).ceiling()` returns `2`
+2. `(1.8).ceiling()` returns `2`
+3. `(1.5).ceiling()` returns `2`
+4. `(1.0).ceiling()` returns `1`
+
+#### `floor`
+
+The `floor` method rounds down a number.
+
+Before its execution, the input sequence arrays are automatically unpacked.
+
+All elements in the input sequence must be numbers.
+
+##### Examples
+
+1. `(1.3).floor()` returns `1`
+2. `(1.8).floor()` returns `1`
+3. `(1.5).floor()` returns `1`
+4. `(1.0).floor()` returns `1`
+
+#### `abs`
+
+The `abs` method calculates the absolute value of a number (removes the sign).
+
+Before its execution, the input sequence arrays are automatically unpacked.
+
+All elements in the input sequence must be numbers.
+
+##### Examples
+
+1. `(0.0).abs()` returns `0`
+2. `(1.0).abs()` returns `1`
+3. `(-1.0).abs()` returns `1`
+
+#### `keyvalue`
+
+The `keyvalue` method converts an object to a sequence of key-value pairs.
+
+Before its execution, the input sequence arrays are automatically unpacked.
+
+All elements in the input sequence must be objects.
+
+For each element of the input sequence:
+
+1. Each key-value pair in the element is analyzed.
+2. For each key-value pair, an object is generated with the keys `name` and `value`.
+3. `name` stores a string with the name of the key from the pair.
+4. `value` stores the value from the pair.
+5. All objects for this element are added to the output sequence.
+
+##### Examples
+
+Let's take a JSON document:
+
+```json
+{
+ "name": "Chrisjen",
+ "surname": "Avasarala",
+ "age": 70
+}
+```
+
+The `$.keyvalue()` query returns the following sequence for it:
+
+```json
+{
+ "name": "age",
+ "value": 70
+},
+{
+ "name": "name",
+ "value": "Chrisjen"
+},
+{
+ "name": "surname",
+ "value": "Avasarala"
+}
+```
+
+### Variables
+
+Functions using JsonPath can pass values into a query. They are called variables. To access a variable, write the `$` character and the variable name: `$variable`.
+
+#### Example
+
+Let the `planet` variable be equal to
+
+```json
+{
+ "name": "Mars",
+ "gravity": 0.376
+}
+```
+
+Then the `strict $planet.name` query returns `"Mars"`.
+
+Unlike many programming languages, JsonPath doesn't support creating new variables or modifying existing ones.
+
+## Common arguments
+
+All functions for JSON accept:
+
+1. A JSON value (can be an arbitrary `Json` or `Json?` expression)
+2. A JsonPath query (must be explicitly specified with a string literal)
+3. **(Optional)** `PASSING` section
+
+### PASSING section
+
+Lets you pass values to a JsonPath query as variables.
+
+#### Syntax
+
+```yql
+PASSING
+ <expression 1> AS <variable name 1>,
+ <expression 2> AS <variable name 2>,
+ ...
+```
+
+`<expression>` can have the following types:
+
+- Numbers, `Date`, `DateTime`, and `Timestamp` (a `CAST` into `Double` will be made before passing a value to JsonPath)
+- `Utf8`, `Bool`, and `Json`
+
+You can set a `<variable name>` in several ways:
+
+- As an SQL name like `variable`
+- In quotes, for example, `"variable"`
+
+##### Example
+
+```yql
+JSON_VALUE(
+ $json,
+ "$.timestamp - $Now + $Hour"
+ PASSING
+ 24 * 60 as Hour,
+ CurrentUtcTimestamp() as "Now"
+)
+```
+
+## JSON_EXISTS {#json_exists}
+
+The `JSON_EXISTS` function checks if a JSON value meets the specified JsonPath.
+
+### Syntax
+
+```yql
+JSON_EXISTS(
+ <JSON expression>,
+ <JsonPath query>,
+ [<PASSING clause>]
+ [{TRUE | FALSE | UNKNOWN | ERROR} ON ERROR]
+)
+```
+
+Return value: `Bool?`
+
+Default value: If the `ON ERROR` section isn't specified, the used section is `FALSE ON ERROR`
+
+Behavior
+
+1. If `<JSON expression>` is `NULL` or an empty `Json?`, it returns an empty `Bool?`
+2. If an error occurs during JsonPath execution, the returned value depends on the `ON ERROR` section:
+
+ - `TRUE`: Return `True`
+ - `FALSE`: Return `False`
+ - `UNKNOWN`: Return an empty `Bool?`
+ - `ERROR`: Abort the entire query
+
+3. If the result of JsonPath execution is one or more values, the return value is `True`.
+4. Otherwise, `False` is returned.
+
+#### Examples
+
+```yql
+$json = CAST(@@{
+ "title": "Rocinante",
+ "crew": [
+ "James Holden",
+ "Naomi Nagata",
+ "Alex Kamai",
+ "Amos Burton"
+ ]
+}@@ as Json);
+
+SELECT
+ JSON_EXISTS($json, "$.title"), -- True
+ JSON_EXISTS($json, "$.crew[*]"), -- True
+ JSON_EXISTS($json, "$.nonexistent"); -- False, as JsonPath returns an empty result
+
+SELECT
+ -- JsonPath error, False is returned because the default section used is FALSE ON ERROR
+ JSON_EXISTS($json, "strict $.nonexistent");
+
+SELECT
+ -- JsonPath error, the entire YQL query fails.
+ JSON_EXISTS($json, "strict $.nonexistent" ERROR ON ERROR);
+```
+
+## JSON_VALUE {#json_value}
+
+The `JSON_VALUE` function retrieves a scalar value from JSON (anything that isn't an array or object).
+
+### Syntax
+
+```yql
+JSON_VALUE(
+ <JSON expression>,
+ <JsonPath query>,
+ [<PASSING clause>]
+ [RETURNING <type>]
+ [{ERROR | NULL | DEFAULT <expr>} ON EMPTY]
+ [{ERROR | NULL | DEFAULT <expr>} ON ERROR]
+)
+```
+
+Return value: `<type>?`
+
+Default values:
+
+1. If the `ON EMPTY` section isn't specified, the section used is `NULL ON EMPTY`
+2. If the `ON ERROR` section isn't specified, the section used is `NULL ON ERROR`
+3. If the `RETURNING` section isn't specified, then for `<type>`, the type used is `Utf8`
+
+Behavior:
+
+1. If `<JSON expression>` is `NULL` or an empty `Json?`, it returns an empty `<type>?`
+2. If an error occurs, the returned value depends on the `ON ERROR` section:
+
+ - `NULL`: Return an empty `<type>?`
+ - `ERROR`: Abort the entire query
+ - `DEFAULT <expr>`: Return `<expr>` after running the `CAST` function to convert the data type to `<type>?`. If the `CAST` fails, the entire query fails, too.
+
+3. If the JsonPath execution result is empty, the returned value depends on the `ON EMPTY` section:
+
+ - `NULL`: Return an empty `<type>?`
+ - `ERROR`: Abort the entire query
+ - `DEFAULT <expr>`: Return `<expr>` after running the `CAST` function to convert the data type to `<type>?`. If the `CAST` fails, the behavior matches the `ON ERROR` section.
+
+4. If the result of JsonPath execution is a single value, then:
+
+ - If the `RETURNING` section isn't specified, the value is converted to `Utf8`.
+ - Otherwise, the `CAST` function is run to convert the value to `<type>`. If the `CAST` fails, the behavior matches the `ON ERROR` section. In this case, the value from JSON must match the `<type>` type.
+
+5. Return the result
+
+Correlation between JSON and YQL types:
+
+- JSON Number: Numeric types, `Date`, `DateTime`, and `Timestamp`
+- JSON Bool: `Bool`
+- JSON String: `Utf8` and `String`
+
+Errors executing `JSON_VALUE` are as follows:
+
+- Errors evaluating JsonPath
+- The result of JsonPath execution is a number of values or a non-scalar value.
+- The type of value returned by JSON doesn't match the expected one.
+
+`The RETURNING` section supports such types as numbers, `Date`, `DateTime`, `Timestamp`, `Utf8`, `String`, and `Bool`.
+
+### Examples
+
+```yql
+$json = CAST(@@{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30
+ }
+ ]
+}@@ as Json);
+
+SELECT
+ JSON_VALUE($json, "$.friends[0].age"), -- "35" (type Utf8?)
+ JSON_VALUE($json, "$.friends[0].age" RETURNING Uint64), -- 35 (type Uint64?)
+ JSON_VALUE($json, "$.friends[0].age" RETURNING Utf8); -- an empty Utf8? due to an error. The JSON's Number type doesn't match the string Utf8 type.
+
+SELECT
+ -- "empty" (type String?)
+ JSON_VALUE(
+ $json,
+ "$.friends[50].name"
+ RETURNING String
+ DEFAULT "empty" ON EMPTY
+ );
+
+SELECT
+ -- 20 (type Uint64?). The result of JsonPath execution is empty, but the
+ -- default value from the ON EMPTY section can't be cast to Uint64.
+ -- That's why the value from ON ERROR is used.
+ JSON_VALUE(
+ $json,
+ "$.friends[50].age"
+ RETURNING Uint64
+ DEFAULT -1 ON EMPTY
+ DEFAULT 20 ON ERROR
+ );
+```
+
+## JSON_QUERY {#json_query}
+
+The `JSON_QUERY` function lets you retrieve arrays and objects from JSON.
+
+### Syntax
+
+```yql
+JSON_QUERY(
+ <JSON expression>,
+ <JsonPath query>,
+ [<PASSING clause>]
+ [WITHOUT [ARRAY] | WITH [CONDITIONAL | UNCONDITIONAL] [ARRAY] WRAPPER]
+ [{ERROR | NULL | EMPTY ARRAY | EMPTY OBJECT} ON EMPTY]
+ [{ERROR | NULL | EMPTY ARRAY | EMPTY OBJECT} ON ERROR]
+)
+```
+
+Return value: `Json?`
+
+Default values:
+
+1. If the `ON EMPTY` section isn't specified, the section used is `NULL ON EMPTY`
+2. If the `ON ERROR` section isn't specified, the section used is `NULL ON ERROR`
+3. If the `WRAPPER` section isn't specified, the section used is `WITHOUT WRAPPER`
+4. If the `WITH WRAPPER` section is specified but `CONDITIONAL` or `UNCONDITIONAL` is omitted, then the section used is `UNCONDITIONAL`
+
+Behavior:
+
+{% note info %}
+
+You can't specify the `WITH ... WRAPPER` and `ON EMPTY` sections at the same time.
+
+{% endnote %}
+
+1. If `<JSON expression>` is `NULL` or an empty `Json?`, it returns an empty `Json?`
+2. If the `WRAPPER` section is specified, then:
+
+ - `WITHOUT WRAPPER` or `WITHOUT ARRAY WRAPPER`: Don't convert the result of JsonPath execution in any way.
+ - `WITH UNCONDITIONAL WRAPPER` or `WITH UNCONDITIONAL ARRAY WRAPPER`: Wrap the result of JsonPath execution in an array.
+ - `WITH CONDITIONAL WRAPPER` or `WITH CONDITIONAL ARRAY WRAPPER`: Wrap the result of JsonPath execution in an array if it isn't the only array or object.
+
+3. If the JsonPath execution result is empty, the returned value depends on the `ON EMPTY` section:
+
+ - `NULL`: Return an empty `Json?`
+ - `ERROR`: Abort the entire query
+ - `EMPTY ARRAY`: Return an empty JSON array, `[]`
+ - `EMPTY OBJECT`: Return an empty JSON object, `{}`
+
+4. If an error occurs, the returned value depends on the `ON ERROR` section:
+
+ - `NULL`: Return an empty `Json?`
+ - `ERROR`: Abort the entire query
+ - `EMPTY ARRAY`: Return an empty JSON array, `[]`
+ - `EMPTY OBJECT`: Return an empty JSON object, `{}`
+
+5. Return the result
+
+Errors running a `JSON_QUERY`:
+
+- Errors evaluating JsonPath
+- The result of JsonPath execution is a number of values (even after using the `WRAPPER` section) or a scalar value.
+
+#### Examples
+
+```yql
+$json = CAST(@@{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30
+ }
+ ]
+}@@ as Json);
+
+SELECT
+ JSON_QUERY($json, "$.friends[0]"); -- {"name": "James Holden", "age": 35}
+
+SELECT
+ JSON_QUERY($json, "$.friends.name" WITH UNCONDITIONAL WRAPPER); -- ["James Holden", "Naomi Nagata"]
+
+SELECT
+ JSON_QUERY($json, "$.friends[0]" WITH CONDITIONAL WRAPPER), -- {"name": "James Holden", "age": 35}
+ JSON_QUERY($json, "$.friends.name" WITH CONDITIONAL WRAPPER); -- ["James Holden", "Naomi Nagata"]
+```
+
+## See also
+
+* [{#T}](../recipes/accessing-json.md)
+* [{#T}](../recipes/modifying-json.md)
diff --git a/yql/essentials/docs/en/builtins/list.md b/yql/essentials/docs/en/builtins/list.md
new file mode 100644
index 0000000000..af8e48283a
--- /dev/null
+++ b/yql/essentials/docs/en/builtins/list.md
@@ -0,0 +1,602 @@
+# Functions for lists
+
+## ListCreate {#list-create}
+
+Construct an empty list. The only argument specifies a string describing the data type of the list cell, or the type itself obtained using [relevant functions](types.md). YQL doesn't support lists with an unknown cell type.
+
+[Documentation for the type definition format](../types/type_string.md).
+
+### Examples
+
+```yql
+SELECT ListCreate(Tuple<String,Double?>);
+```
+
+```yql
+SELECT ListCreate(OptionalType(DataType("String")));
+```
+
+## AsList and AsListStrict {#aslist}
+
+Construct a list based on one or more arguments. The argument types must be compatible in the case of `AsList` and strictly match in the case of `AsListStrict`.
+
+### Examples
+
+```yql
+SELECT AsList(1, 2, 3, 4, 5);
+```
+
+## ListLength {#listlength}
+
+The count of items in the list.
+
+### Examples
+
+```yql
+SELECT ListLength(list_column) FROM my_table;
+```
+
+## ListHasItems
+
+Check that the list contains at least one item.
+
+### Examples
+
+```yql
+SELECT ListHasItems(list_column) FROM my_table;
+```
+
+## ListCollect {#listcollect}
+
+Convert a lazy list (it can be built by such functions as [ListFilter](#listmap), [ListMap](#listmap), [ListFlatMap](#listmap)) to an eager list. In contrast to a lazy list, where each new pass re-calculates the list contents, in an eager list the content is built at once by consuming more memory.
+
+### Examples
+
+```yql
+SELECT ListCollect(list_column) FROM my_table;
+```
+
+## ListSort, ListSortAsc, and ListSortDesc {#listsort}
+
+Sort the list. By default, the ascending sorting order is applied (`ListSort` is an alias for `ListSortAsc`).
+
+Arguments:
+
+1. List.
+2. An optional expression to get the sort key from a list element (it's the element itself by default).
+
+### Examples
+
+```yql
+SELECT ListSortDesc(list_column) FROM my_table;
+```
+
+```yql
+$list = AsList(
+ AsTuple("x", 3),
+ AsTuple("xx", 1),
+ AsTuple("a", 2)
+);
+
+SELECT ListSort($list, ($x) -> {
+ RETURN $x.1;
+});
+```
+
+{% note info %}
+
+The example used a [lambda function](../syntax/expressions.md#lambda).
+
+{% endnote %}
+
+## ListExtend and ListExtendStrict {#listextend}
+
+Sequentially join lists (concatenation of lists). The arguments can be lists, optional lists, and `NULL`.
+The types of list items must be compatible in the case of `ListExtend` and strictly match in the case of `ListExtendStrict`.
+If at least one of the lists is optional, then the result is also optional.
+If at least one argument is `NULL`, then the result type is `NULL`.
+
+
+### Examples
+
+```yql
+SELECT ListExtend(
+ list_column_1,
+ list_column_2,
+ list_column_3
+) FROM my_table;
+```
+
+## ListUnionAll {#listunionall}
+
+Sequentially join lists of structures (concatenation of lists). A field is added to the output list of structures if it exists in at least one source list, but if there is no such field in any list, it is added as NULL. In the case when a field is present in two or more lists, the output field is cast to the common type.
+
+If at least one of the lists is optional, then the result is also optional.
+
+### Examples
+
+```yql
+SELECT ListUnionAll(
+ list_column_1,
+ list_column_2,
+ list_column_3
+) FROM my_table;
+```
+
+## ListZip and ListZipAll {#listzip}
+
+Based on the input lists, build a list of pairs containing the list items with matching indexes (`List<Tuplefirst_list_element_type,second_list_element_type>`).
+
+The length of the returned list is determined by the shortest list for ListZip and the longest list for ListZipAll.
+When the shorter list is exhausted, a `NULL` value of a relevant [optional type](../types/optional.md) is paired with the elements of the longer list.
+
+### Examples
+
+```yql
+SELECT
+ ListZip(list_column_1, list_column_2, list_column_3),
+ ListZipAll(list_column_1, list_column_2)
+FROM my_table;
+```
+
+## ListEnumerate {#listenumerate}
+
+Build a list of pairs (Tuple) containing the element number and the element itself (`List<TupleUint64,list_element_type>`).
+
+### Examples
+
+```yql
+SELECT ListEnumerate(list_column) FROM my_table;
+```
+
+## ListReverse {#listreverse}
+
+Reverse the list.
+
+### Examples
+
+```yql
+SELECT ListReverse(list_column) FROM my_table;
+```
+## ListSkip {#listskip}
+
+Returns a copy of the list, skipping the specified number of its first elements.
+
+The first argument specifies the source list and the second argument specifies how many elements to skip.
+
+### Examples
+
+```yql
+SELECT
+ ListSkip(list_column, 3)
+FROM my_table;
+```
+
+## ListTake {#listtake}
+
+Returns a copy of the list containing a limited number of elements from the second list.
+
+The first argument specifies the source list and the second argument specifies the maximum number of elements to be taken from the beginning of the list.
+
+### Examples
+
+```yql
+SELECT ListTake(list_column, 3) FROM my_table;
+```
+
+## ListSample and ListSampleN {#listsample}
+
+Returns a sample without replacement from the list.
+
+- `ListSample` chooses elements independently with the specified probability.
+
+- `ListSampleN` chooses a sample of the specified size (if the length of the list is less than the sample size, returns the original list).
+
+If the probability/sample size is NULL, returns the original list.
+
+An optional argument is used to control randomness, see [documentation for `Random`](basic.md#random).
+
+### Examples
+
+```yql
+ListSample(List<T>, Double?[, U])->List<T>
+ListSample(List<T>?, Double?[, U])->List<T>?
+
+ListSampleN(List<T>, Uint64?[, U])->List<T>
+ListSampleN(List<T>?, Uint64?[, U])->List<T>?
+```
+
+```yql
+$list = AsList(1, 2, 3, 4, 5);
+
+SELECT ListSample($list, 0.5); -- [1, 2, 5]
+SELECT ListSampleN($list, 2); -- [4, 2]
+```
+
+## ListShuffle {#listshuffle}
+
+Returns a shuffled copy of the list. An optional argument is used to control randomness, see [documentation for `Random`](basic.md#random).
+
+### Examples
+
+```yql
+ListShuffle(List<T>[, U])->List<T>
+ListShuffle(List<T>?[, U])->List<T>?
+```
+
+```yql
+$list = AsList(1, 2, 3, 4, 5);
+
+SELECT ListShuffle($list); -- [1, 3, 5, 2, 4]
+```
+
+## ListIndexOf {#listindexof}
+
+Searches the list for an element with the specified value and returns its index at the first occurrence. Indexes count from 0. If such element is missing, it returns `NULL`.
+
+### Examples
+
+```yql
+SELECT
+ ListIndexOf(list_column, 123)
+FROM my_table;
+```
+
+## ListMap, ListFilter, and ListFlatMap {#listmap}
+
+Apply the function specified as the second argument to each list element. The functions differ in their returned result:
+
+* `ListMap` returns a list with results.
+* `ListFlatMap` returns a list with results, combining and expanding the first level of results (lists or optional values) for each item.
+* `ListFilter` leaves only those elements where the function returned `true`.
+
+{% note info %}
+
+In `ListFlatMap`, using optional values in function results is deprecated, use the combination of [`ListNotNull`](#listnotnull) and `ListMap` instead.
+
+{% endnote %}
+
+Arguments:
+
+1. Source list.
+2. Functions for processing list elements, such as:
+
+ * [Lambda function](../syntax/expressions.md#lambda).
+ * `Module::Function` - C++ UDF.
+
+If the source list is optional, then the output list is also optional.
+
+### Examples
+
+```yql
+$callable = Python::test(Callable<(Int64)->Bool>, "defMyFavouriteCrutchtest(i): return i % 2");
+SELECT
+ ListMap(list_column, ($x) -> { RETURN $x > 2; }),
+ ListFlatMap(list_column, My::Udf),
+ ListFilter(list_column, $callable)
+FROM my_table;
+```
+
+## ListNotNull {#listnotnull}
+
+Applies transformation to the source list, skipping empty optional items and strengthening the item type to non-optional. For a list with non-optional items, it returns the unchanged source list.
+
+If the source list is optional, then the output list is also optional.
+
+### Examples
+
+```yql
+SELECT ListNotNull([1,2]), -- [1,2]
+ ListNotNull([3,null,4]); -- [3,4]
+```
+
+## ListFlatten {#listflatten}
+
+Expands the list of lists into a flat list, preserving the order of items. As the top-level list item you can use an optional list that is interpreted as an empty list in the case of `NULL`.
+
+If the source list is optional, then the output list is also optional.
+
+### Examples
+
+```yql
+SELECT ListFlatten([[1,2],[3,4]]), -- [1,2,3,4]
+ ListFlatten([null,[3,4],[5,6]]); -- [3,4,5,6]
+```
+
+## ListUniq {#listuniq}
+
+Returns a copy of the list containing only distinct elements.
+
+### Examples
+
+```yql
+SELECT
+ ListUniq(list_column)
+FROM my_table;
+```
+
+## ListAny and ListAll {#listany}
+
+Returns `true` for a list of Boolean values, if:
+
+* `ListAny`: At least one element is `true`.
+* `ListAll`: All elements are `true`.
+
+Otherwise, it returns false.
+
+### Examples
+
+```yql
+SELECT
+ ListAll(bool_column),
+ ListAny(bool_column)
+FROM my_table;
+```
+
+## ListHas {#listhas}
+
+Show whether the list contains the specified element. In this case, `NULL` values are considered equal to each other, and with a `NULL` input list, the result is always `false`.
+
+### Examples
+
+```yql
+SELECT
+ ListHas(list_column, "my_needle")
+FROM my_table;
+```
+
+## ListHead, ListLast {#listheadlast}
+
+Returns the first and last item of the list.
+
+### Examples
+
+```yql
+SELECT
+ ListHead(numeric_list_column) AS head,
+ ListLast(numeric_list_column) AS last
+FROM my_table;
+```
+
+## ListMin, ListMax, ListSum and ListAvg {#listminy}
+
+Apply the appropriate aggregate function to all elements of the numeric list.
+
+### Examples
+
+```yql
+SELECT
+ ListMax(numeric_list_column) AS max,
+ ListMin(numeric_list_column) AS min,
+ ListSum(numeric_list_column) AS sum,
+ ListAvg(numeric_list_column) AS avg
+FROM my_table;
+```
+
+## ListFold, ListFold1 {#listfold}
+
+Folding a list.
+
+Arguments:
+
+1. List
+2. Initial state `U` for `ListFold`, `initLambda(item:T)->U` for `ListFold1`
+3. `updateLambda(item:T, state:U)->U`
+
+Type returned:
+`U` for `ListFold`, `U?` for `ListFold1`.
+
+```yql
+$l = [1, 4, 7, 2];
+$y = ($x, $y) -> { RETURN $x + $y; };
+$z = ($x) -> { RETURN 4 * $x; };
+
+SELECT
+ ListFold($l, 6, $y) AS fold, -- 20
+ ListFold([], 3, $y) AS fold_empty, -- 3
+ ListFold1($l, $z, $y) AS fold1, -- 17
+ ListFold1([], $z, $y) AS fold1_empty; -- Null
+```
+
+## ListFoldMap, ListFold1Map {#listfoldmap}
+
+Converts each list item i by calling the handler(i, state).
+
+Arguments:
+
+1. List
+2. Initial state `S` for `ListFoldMap`, `initLambda(item:T)->tuple (U S)` for `ListFold1Map`
+3. `handler(item:T, state:S)->tuple (U S)`
+
+Type returned: `List` of `U` items.
+
+### Examples
+
+```yql
+$l = [1, 4, 7, 2];
+$x = ($i, $s) -> { RETURN ($i * $s, $i + $s); };
+$t = ($i) -> { RETURN ($i + 1, $i + 2); };
+
+SELECT
+ ListFoldMap([], 1, $x), -- []
+ ListFoldMap($l, 1, $x), -- [1, 8, 42, 26]
+ ListFold1Map([], $t, $x), -- []
+ ListFold1Map($l, $t, $x); -- [2, 12, 49, 28]
+```
+
+## ListFromRange {#listfromrange}
+
+Generate a sequence of numbers with the specified step. It's similar to `xrange` in Python 2, but additionally supports floats.
+
+Arguments:
+
+1. Start
+2. End
+3. Step (optional, 1 by default)
+
+Specifics:
+
+* The end is not included, i.e. `ListFromRange(1,3) == AsList(1,2)`.
+* The type for the resulting elements is selected as the broadest from the argument types. For example, `ListFromRange(1, 2, 0.5)` results in a `Double` list.
+* If the start and the end is one of the date representing type, the step has to be `Interval`.
+* The list is "lazy", but if it's used incorrectly, it can still consume a lot of RAM.
+* If the step is positive and the end is less than or equal to the start, the result list is empty.
+* If the step is negative and the end is greater than or equal to the start, the result list is empty.
+* If the step is neither positive nor negative (0 or NaN), the result list is empty.
+* If any of the parameters is optional, the result list is optional.
+* If any of the parameters is `NULL`, the result is `NULL`.
+
+### Examples
+
+```yql
+SELECT
+ ListFromRange(-2, 2), -- [-2, -1, 0, 1]
+ ListFromRange(2, 1, -0.5); -- [2.0, 1.5]
+```
+
+### Signature
+
+```yql
+ListFromRange(T{Flags:AutoMap}, T{Flags:AutoMap}, T?)->LazyList<T> -- T — numeric type
+ListFromRange(T{Flags:AutoMap}, T{Flags:AutoMap}, I?)->LazyList<T> -- T — type, representing date/time, I — interval
+```
+
+## ListReplicate {#listreplicate}
+
+Creates a list containing multiple copies of the specified value.
+
+Required arguments:
+
+1. Value.
+2. Number of copies.
+
+### Examples
+
+```yql
+SELECT ListReplicate(true, 3); -- [true, true, true]
+```
+
+## ListConcat {#listconcat}
+
+Concatenates a list of strings into a single string.
+You can set a separator as the second parameter.
+
+### Examples
+
+```yql
+SELECT
+ ListConcat(string_list_column),
+ ListConcat(string_list_column, "; ")
+FROM my_table;
+```
+
+## ListExtract {#listextract}
+
+For a list of structures, it returns a list of contained fields having the specified name.
+
+### Examples
+
+```yql
+SELECT
+ ListExtract(struct_list_column, "MyMember")
+FROM my_table;
+```
+
+## ListTakeWhile, ListSkipWhile {#listtakewhile}
+
+`ListTakeWhile` returns a list from the beginning while the predicate is true, then the list ends.
+
+`ListSkipWhile` skips the list segment from the beginning while the predicate is true, then returns the rest of the list ignoring the predicate.
+`ListTakeWhileInclusive` returns a list from the beginning while the predicate is true. Then the list ends, but it also includes the item on which the stopping predicate triggered.
+`ListSkipWhileInclusive` skips a list segment from the beginning while the predicate is true, then returns the rest of the list disregarding the predicate, but excluding the element that matched the predicate and starting with the next element after it.
+
+Required arguments:
+
+1. List.
+2. Predicate.
+
+If the input list is optional, then the result is also optional.
+
+### Examples
+
+```yql
+$data = AsList(1, 2, 5, 1, 2, 7);
+
+SELECT
+ ListTakeWhile($data, ($x) -> {return $x <= 3}), -- [1, 2]
+ ListSkipWhile($data, ($x) -> {return $x <= 3}), -- [5, 1, 2, 7]
+ ListTakeWhileInclusive($data, ($x) -> {return $x <= 3}), -- [1, 2, 5]
+ ListSkipWhileInclusive($data, ($x) -> {return $x <= 3}); -- [1, 2, 7]
+```
+
+## ListAggregate {#listaggregate}
+
+Apply the [aggregation factory](basic.md#aggregationfactory) to the passed list.
+If the passed list is empty, the aggregation result is the same as for an empty table: 0 for the `COUNT` function and `NULL` for other functions.
+If the passed list is optional and `NULL`, the result is also `NULL`.
+
+Arguments:
+
+1. List.
+2. [Aggregation factory](basic.md#aggregationfactory).
+
+### Examples
+
+```yql
+SELECT ListAggregate(AsList(1, 2, 3), AggregationFactory("Sum")); -- 6
+```
+
+## ToDict and ToMultiDict {#todict}
+
+Convert a list of tuples containing key-value pairs to a dictionary. In case of conflicting keys in the input list, `ToDict` leaves the first value and `ToMultiDict` builds a list of all the values.
+
+It means that:
+
+* `ToDict` converts `List<TupleK, V="">` to `Dict<K, V="">`
+* `ToMultiDict` converts `List<TupleK, V>` to `Dict<K, List<V>>`
+
+Optional lists are also supported, resulting in an optional dictionary.
+
+### Examples
+
+```yql
+SELECT
+ ToDict(tuple_list_column)
+FROM my_table;
+```
+
+## ToSet {#toset}
+
+Converts a list to a dictionary where the keys are unique elements of this list, and values are omitted and have the type `Void`. For the `List<T>` list, the result type is `Dict<T, Void="">`.
+An optional list is also supported, resulting in an optional dictionary.
+
+Inverse function: get a list of keys for the [DictKeys](dict.md#dictkeys) dictionary.
+
+### Examples
+
+```yql
+SELECT
+ ToSet(list_column)
+FROM my_table;
+```
+
+## ListTop, ListTopAsc, ListTopDesc, ListTopSort, ListTopSortAsc и ListTopSortDesc {#listtop}
+
+Select top values from the list. `ListTopSort*` additionally sorts the returned values. The smallest values are selected by default. Thus, the functions without a suffix are the aliases to `*Asc` functions, while `*Desc` functions return the largest values.
+
+`ListTopSort` is more effective than consecutive `ListTop` and `ListSort` because `ListTop` can partially sort the list to find needed values. However, `ListTop` is more effective than `ListTopSort` when the result order is unimportant.
+
+Arguments:
+
+1. List.
+2. Size of selection.
+3. An optional expression to get the sort key from a list element (it's the element itself by default).
+
+### Examples
+
+```yql
+ListTop(List<T>{Flags:AutoMap}, N)->List<T>
+ListTop(List<T>{Flags:AutoMap}, N, (T)->U)->List<T>
+```
+
+The signatures of other functions are the same.
diff --git a/yql/essentials/docs/en/builtins/struct.md b/yql/essentials/docs/en/builtins/struct.md
new file mode 100644
index 0000000000..9ab3442d72
--- /dev/null
+++ b/yql/essentials/docs/en/builtins/struct.md
@@ -0,0 +1,359 @@
+# Functions for structures
+
+## TryMember {#trymember}
+
+Trying to get a field from the structure. If it's not found among the fields or null in the structure value, use the default value.
+
+Arguments:
+
+1. Structure.
+2. Field name.
+3. Default value.
+
+```yql
+$struct = <|a:1|>;
+SELECT
+ TryMember(
+ $struct,
+ "a",
+ 123
+ ) AS a, -- 1
+ TryMember(
+ $struct,
+ "b",
+ 123
+ ) AS b; -- 123
+```
+
+## ExpandStruct {#expandstruct}
+
+Adding one or more new fields to the structure.
+
+If the field set contains duplicate values, an error is returned.
+
+Arguments:
+
+* The first argument passes the source structure to be expanded.
+* All the other arguments must be named, each argument adds a new field and the argument's name is used as the field's name (as in [AsStruct](basic.md#asstruct)).
+
+### Examples
+
+```yql
+$struct = <|a:1|>;
+SELECT
+ ExpandStruct(
+ $struct,
+ 2 AS b,
+ "3" AS c
+ ) AS abc;
+```
+
+## AddMember {#addmember}
+
+Adding one new field to the structure. If you need to add multiple fields, better use [ExpandStruct](#expandstruct).
+
+If the field set contains duplicate values, an error is returned.
+
+Arguments:
+
+1. Source structure.
+2. Name of the new field.
+3. Value of the new field.
+
+### Examples
+
+```yql
+$struct = <|a:1|>;
+SELECT
+ AddMember(
+ $struct,
+ "b",
+ 2
+ ) AS ab;
+```
+
+## RemoveMember {#removemember}
+
+Removing a field from the structure.
+
+If the entered field hasn't existed, an error is returned.
+
+Arguments:
+
+1. Source structure.
+2. Field name.
+
+### Examples
+
+```yql
+$struct = <|a:1, b:2|>;
+SELECT
+ RemoveMember(
+ $struct,
+ "b"
+ ) AS a;
+```
+
+## ForceRemoveMember {#forceremovemember}
+
+Removing a field from the structure.
+
+If the entered field hasn't existed, unlike [RemoveMember](#removemember), the error is not returned.
+
+Arguments:
+
+1. Source structure.
+2. Field name.
+
+### Examples
+
+```yql
+$struct = <|a:1, b:2|>;
+SELECT
+ ForceRemoveMember(
+ $struct,
+ "c"
+ ) AS ab;
+```
+
+## ChooseMembers {#choosemembers}
+
+Selecting fields with specified names from the structure.
+
+If any of the fields haven't existed, an error is returned.
+
+Arguments:
+
+1. Source structure.
+2. List of field names.
+
+### Examples
+
+```yql
+$struct = <|a:1, b:2, c:3|>;
+SELECT
+ ChooseMembers(
+ $struct,
+ ["a", "b"]
+ ) AS ab;
+```
+
+## RemoveMembers {#removemembers}
+
+Excluding fields with specified names from the structure.
+
+If any of the fields haven't existed, an error is returned.
+
+Arguments:
+
+1. Source structure.
+2. List of field names.
+
+### Examples
+
+```yql
+$struct = <|a:1, b:2, c:3|>;
+SELECT
+ RemoveMembers(
+ $struct,
+ ["a", "b"]
+ ) AS c;
+```
+
+## ForceRemoveMembers {#forceremovemembers}
+
+Excluding fields with specified names from the structure.
+
+If any of the fields haven't existed, it is ignored.
+
+Arguments:
+
+1. Source structure.
+2. List of field names.
+
+### Examples
+
+```yql
+$struct = <|a:1, b:2, c:3|>;
+SELECT
+ ForceRemoveMembers(
+ $struct,
+ ["a", "b", "z"]
+ ) AS c;
+```
+
+## CombineMembers {#combinemembers}
+
+Combining the fields from multiple structures into a new structure.
+
+If the resulting field set contains duplicate values, an error is returned.
+
+Arguments: two or more structures.
+
+### Examples
+
+```yql
+$struct1 = <|a:1, b:2|>;
+$struct2 = <|c:3|>;
+SELECT
+ CombineMembers(
+ $struct1,
+ $struct2
+ ) AS abc;
+```
+
+## FlattenMembers {#flattenmembers}
+
+Combining the fields from multiple new structures into another new structure with prefix support.
+
+If the resulting field set contains duplicate values, an error is returned.
+
+Arguments: two or more tuples of two items: prefix and structure.
+
+### Examples
+
+```yql
+$struct1 = <|a:1, b:2|>;
+$struct2 = <|c:3|>;
+SELECT
+ FlattenMembers(
+ AsTuple("foo", $struct1), -- fooa, foob
+ AsTuple("bar", $struct2) -- barc
+ ) AS abc;
+```
+
+## StructMembers {#structmembers}
+
+Returns an unordered list of field names (possibly removing one Optional level) for a single argument that is a structure. For the `NULL` argument, an empty list of strings is returned.
+
+Argument: structure
+
+### Examples
+
+```yql
+$struct = <|a:1, b:2|>;
+SELECT
+ StructMembers($struct); -- ['a', 'b']
+```
+
+## RenameMembers {#renamemembers}
+
+Renames the fields in the structure passed. In this case, you can rename a source field into multiple target fields. All fields not mentioned in the renaming as source names are moved to the result structure. If some source field is omitted in the rename list, an error is returned. For an Optional structure or `NULL`, the result has the same type.
+
+Arguments:
+
+1. Source structure.
+2. A tuple of field names: the original name, the new name.
+
+### Examples
+
+```yql
+$struct = <|a:1, b:2|>;
+SELECT
+ RenameMembers($struct, [('a', 'c'), ('a', 'e')]); -- (b:2, c:1, e:1)
+```
+
+## ForceRenameMembers {#forecerenamemembers}
+
+Renames the fields in the structure passed. In this case, you can rename a source field into multiple target fields. All fields not mentioned in the renaming as source names are moved to the result structure. If some source field is omitted in the rename list, the name is ignored. For an Optional structure or `NULL`, the result has the same type.
+
+Arguments:
+
+1. Source structure.
+2. A tuple of field names: the original name, the new name.
+
+### Examples
+
+```yql
+$struct = <|a:1, b:2|>;
+SELECT
+ ForceRenameMembers($struct, [('a', 'c'), ('d', 'e')]); -- (b:2, c:1)
+```
+
+## GatherMembers {#gathermembers}
+
+Returns an unordered list of tuples including the field name and value. For the `NULL` argument, `EmptyList` is returned. It can be used only in the cases when the types of items in the structure are the same or compatible. Returns an optional list for an optional structure.
+
+Argument: structure
+
+### Examples
+
+```yql
+$struct = <|a:1, b:2|>;
+SELECT
+ GatherMembers($struct); -- [('a', 1), ('b', 2)]
+```
+
+## SpreadMembers {#spreadmembers}
+
+Creates a structure with a specified list of fields and applies a specified list of edits to it in the format (field name, field value). All types of fields in the resulting structure are the same and equal to the type of values in the update list with added Optional (unless they are optional already). If the field wasn't mentioned among the list of updated fields, it's returned as `NULL`. Among all updates for a field, the latest one is written. If the update list is Optional or `NULL`, the result has the same type. If the list of edits includes a field that is not in the list of expected fields, an error is returned.
+
+Arguments:
+
+1. List of tuples: field name, field value.
+2. A list of all possible field names in the structure.
+
+### Examples
+
+```yql
+SELECT
+ SpreadMembers([('a',1),('a',2)],['a','b']); -- (a: 2, b: null)
+```
+
+## ForceSpreadMembers {#forcespreadmembers}
+
+Creates a structure with a specified list of fields and applies to it the specified list of updates in the format (field name, field value). All types of fields in the resulting structure are the same and equal to the type of values in the update list with added Optional (unless they are optional already). If the field wasn't mentioned among the list of updated fields, it's returned as `NULL`. Among all updates for a field, the latest one is written. If the update list is optional or equal to `NULL`, the result has the same type. If the list of updates includes a field that is not in the list of expected fields, this edit is ignored.
+
+Arguments:
+
+1. List of tuples: field name, field value.
+2. A list of all possible field names in the structure.
+
+### Examples
+
+```yql
+SELECT
+ ForceSpreadMembers([('a',1),('a',2),('c',100)],['a','b']); -- (a: 2, b: null)
+```
+
+## StructUnion, StructIntersection, StructDifference, StructSymmetricDifference
+
+Combine two structures using one of the four methods (using the provided lambda to merge fields with the same name):
+
+* `StructUnion` adds all fields of both of the structures to the result.
+* `StructIntersection` adds only the fields which are present in both of the structures.
+* `StructDifference` adds only the fields of `left`, which are absent in `right`.
+* `StructSymmetricDifference` adds all fields that are present in exactly one of the structures.
+
+### Signatures
+
+```yql
+StructUnion(left:Struct<...>, right:Struct<...>[, mergeLambda:(name:String, l:T1?, r:T2?)->T])->Struct<...>
+StructIntersection(left:Struct<...>, right:Struct<...>[, mergeLambda:(name:String, l:T1?, r:T2?)->T])->Struct<...>
+StructDifference(left:Struct<...>, right:Struct<...>)->Struct<...>
+StructSymmetricDifference(left:Struct<...>, right:Struct<...>)->Struct<...>
+```
+
+Arguments:
+
+1. `left` - first structure.
+2. `right` - second structure.
+3. `mergeLambda` - _(optional)_ function to merge fields with the same name (arguments: field name, `Optional` field value of the first struct, `Optional` field value of the second struct - arguments are `Nothing<T?>` in case of absence of the corresponding struct field). By default, if present, the first structure's field value is used; otherwise, the second one's value is used.
+
+### Examples
+
+```yql
+$merge = ($name, $l, $r) -> {
+ return ($l ?? 0) + ($r ?? 0);
+};
+$left = <|a: 1, b: 2, c: 3|>;
+$right = <|c: 1, d: 2, e: 3|>;
+
+SELECT
+ StructUnion($left, $right), -- <|a: 1, b: 2, c: 3, d: 2, e: 3|>
+ StructUnion($left, $right, $merge), -- <|a: 1, b: 2, c: 4, d: 2, e: 3|>
+ StructIntersection($left, $right, $merge), -- <|c: 4|>
+ StructDifference($left, $right), -- <|a: 1, b: 1|>
+ StructSymmetricDifference($left, $right) -- <|a: 1, b: 2, d: 2, e: 3|>
+;
+```
diff --git a/yql/essentials/docs/en/builtins/toc_i.yaml b/yql/essentials/docs/en/builtins/toc_i.yaml
new file mode 100644
index 0000000000..45c83c7fc0
--- /dev/null
+++ b/yql/essentials/docs/en/builtins/toc_i.yaml
@@ -0,0 +1,13 @@
+items:
+- { name: Overview, href: index.md }
+- { name: Basic, href: basic.md }
+- { name: Aggregate, href: aggregation.md }
+- { name: Window, href: window.md }
+- { name: For lists, href: list.md }
+- { name: For dictionaries, href: dict.md }
+- { name: For structures, href: struct.md }
+- { name: For types, href: types.md }
+- { name: For code generation, href: codegen.md }
+- { name: For JSON, href: json.md }
+- name: C++ libraries
+ include: { mode: link, path: ../udf/list/toc_i.yaml }
diff --git a/yql/essentials/docs/en/builtins/types.md b/yql/essentials/docs/en/builtins/types.md
new file mode 100644
index 0000000000..2b66d5528e
--- /dev/null
+++ b/yql/essentials/docs/en/builtins/types.md
@@ -0,0 +1,637 @@
+# Functions for data types
+
+## FormatType {#formattype}
+
+Serializing a type or a handle type to a human-readable string. This helps at debugging and will also be used in the next examples of this section. [Documentation for the format](../types/type_string.md).
+
+## ParseType {#parsetype}
+
+Building a type from a string with description. [Documentation for its format](../types/type_string.md).
+
+### Examples
+
+```yql
+SELECT FormatType(ParseType("List<Int32>")); -- List<int32>
+```
+
+## TypeOf {#typeof}
+
+Getting the type of value passed to the argument.
+
+### Examples
+
+```yql
+SELECT FormatType(TypeOf("foo")); -- String
+```
+
+```yql
+SELECT FormatType(TypeOf(AsTuple(1, 1u))); -- Tuple<Int32,Uint32>
+```
+
+## InstanceOf {#instanceof}
+
+Returns an instance of the specified type that can only be used to get the type of the result of an expression that uses this type.
+
+If this instance remains in the computation graph by the end of optimization, the operation fails.
+
+### Examples
+
+```yql
+SELECT FormatType(TypeOf(
+ InstanceOf(ParseType("Int32")) +
+ InstanceOf(ParseType("Double"))
+)); -- Double, because "Int32 + Double" returns Double
+```
+
+## DataType {#datatype}
+
+Returns a type for [primitive data types](../types/primitive.md) based on type name.
+
+### Examples
+
+```yql
+SELECT FormatType(DataType("Bool")); -- Bool
+SELECT FormatType(DataType("Decimal","5","1")); -- Decimal(5,1)
+```
+
+## OptionalType {#optionaltype}
+
+Adds the option to assign `NULL` to the passed type.
+
+### Examples
+
+```yql
+SELECT FormatType(OptionalType(DataType("Bool"))); -- Bool?
+```
+
+## ListType and StreamType {#listtype}
+
+Builds a list type or stream type based on the passed element type.
+
+### Examples
+
+```yql
+SELECT FormatType(ListType(DataType("Bool"))); -- List<Bool>
+```
+
+## DictType {#dicttype}
+
+Builds a dictionary type based on the passed key types (first argument) and value types (second argument).
+
+### Examples
+
+```yql
+SELECT FormatType(DictType(
+ DataType("String"),
+ DataType("Double")
+)); -- Dict<String,Double>
+```
+
+## TupleType {#tupletype}
+
+Builds the tuple type from the passed element types.
+
+### Examples
+
+```yql
+SELECT FormatType(TupleType(
+ DataType("String"),
+ DataType("Double"),
+ OptionalType(DataType("Bool"))
+)); -- Tuple<String,Double,Bool?>
+```
+
+## StructType {#structtype}
+
+Builds the structure type based on the passed element types. The standard syntax of named arguments is used to specify the element names.
+
+### Examples
+
+```yql
+SELECT FormatType(StructType(
+ DataType("Bool") AS MyBool,
+ ListType(DataType("String")) AS StringList
+)); -- Struct<'MyBool':Bool,'StringList':List<String>>
+```
+
+## VariantType {#varianttype}
+
+Returns the type of a variant based on the underlying type (structure or tuple).
+
+### Examples
+
+```yql
+SELECT FormatType(VariantType(
+ ParseType("Struct<foo:Int32,bar:Double>")
+)); -- Variant<'bar':Double,'foo':Int32>
+```
+
+## ResourceType {#resourcetype}
+
+Returns the type of the [resource](../types/special.md) based on the passed string label.
+
+### Examples
+
+```yql
+SELECT FormatType(ResourceType("Foo")); -- Resource<'Foo'>
+```
+
+## CallableType {#callabletype}
+
+Constructs the type of the called value using the following arguments:
+
+1. Number of optional arguments (if all arguments are required — 0).
+2. Result type.
+3. All the next arguments of CallableType are treated as types of arguments of the callable value, but with a shift for two required arguments (for example, the third argument of the CallableType describes the type of the first argument in the callable value).
+
+### Examples
+
+```yql
+SELECT FormatType(CallableType(
+ 1, -- optional args count
+ DataType("Double"), -- result type
+ DataType("String"), -- arg #1 type
+ OptionalType(DataType("Int64")) -- arg #2 type
+)); -- Callable<(String,[Int64?])->Double>
+```
+
+## GenericType, UnitType, and VoidType {#generictype}
+
+Return the same-name [special data types](../types/special.md). They have no arguments because they are not parameterized.
+
+### Examples
+
+```yql
+SELECT FormatType(VoidType()); -- Void
+```
+
+## OptionalItemType, ListItemType and StreamItemType {#optionalitemtype}
+
+If a type is passed to these functions, then they perform the action reverse to [OptionalType](#optionaltype), [ListType](#listtype), and [StreamType](#listtype): return the item type based on its container type.
+
+If a type handle is passed to these functions, then they perform the action reverse to [OptionalTypeHandle](#optionaltypehandle), [ListTypeHandle](#list-stream-typehandle), and [StreamTypeHandle](#list-stream-typehandle): they return the handle of the element type based on the type handle of its container.
+
+### Examples
+
+```yql
+SELECT FormatType(ListItemType(
+ ParseType("List<Int32>")
+)); -- Int32
+```
+
+```yql
+SELECT FormatType(ListItemType(
+ ParseTypeHandle("List<Int32>")
+)); -- Int32
+```
+
+## DictKeyType and DictPayloadType {#dictkeytype}
+
+Returns the type of the key or value based on the dictionary type.
+
+### Examples
+
+```yql
+SELECT FormatType(DictKeyType(
+ ParseType("Dict<Int32,String>")
+)); -- Int32
+```
+
+## TupleElementType {#tupleelementtype}
+
+Returns the tuple's element type based on the tuple type and the element index (index starts from zero).
+
+### Examples
+
+```yql
+SELECT FormatType(TupleElementType(
+ ParseType("Tuple<Int32,Double>"), "1"
+)); -- Double
+```
+
+## StructMemberType {#structmembertype}
+
+Returns the type of the structure element based on the structure type and element name.
+
+### Examples
+
+```yql
+SELECT FormatType(StructMemberType(
+ ParseType("Struct<foo:Int32,bar:Double>"), "foo"
+)); -- Int32
+```
+
+## CallableResultType and CallableArgumentType {#callableresulttype}
+
+`CallableResultType` returns the result type based on the type of the called value. `CallableArgumentType` returns the argument type based on the called value type and its index (index starts from zero).
+
+### Examples
+
+```yql
+$callable_type = ParseType("(String,Bool)->Double");
+
+SELECT FormatType(CallableResultType(
+ $callable_type
+)), -- Double
+FormatType(CallableArgumentType(
+ $callable_type, 1
+)); -- Bool
+```
+
+## VariantUnderlyingType {#variantunderlyingtype}
+
+If a type is passed to this function, then it performs an action reverse to [VariantType](#varianttype): it returns the underlying type based on the variant type.
+
+If a type handle is passed to this function, it performs the action reverse to [VariantTypeHandle](#varianttypehandle): returns the handle of the underlying type based on the handle of the variant type.
+
+### Examples
+
+```yql
+SELECT FormatType(VariantUnderlyingType(
+ ParseType("Variant<foo:Int32,bar:Double>")
+)), -- Struct<'bar':Double,'foo':Int32>
+FormatType(VariantUnderlyingType(
+ ParseType("Variant<Int32,Double>")
+)); -- Tuple<Int32,Double>
+```
+
+```yql
+SELECT FormatType(VariantUnderlyingType(
+ ParseTypeHandle("Variant<foo:Int32,bar:Double>")
+)), -- Struct<'bar':Double,'foo':Int32>
+FormatType(VariantUnderlyingType(
+ ParseTypeHandle("Variant<Int32,Double>")
+)); -- Tuple<Int32,Double>
+```
+
+## Functions for data types during calculations
+
+To work with data types during calculations, use handle types: these are [resources](../types/special.md) that contain an opaque type definition. After constructing the type handle, you can revert to the regular type using the [EvaluateType](#evaluatetype) function. For debug purposes, you can convert a handle type to a string using the [FormatType](#formattype) function.
+
+### TypeHandle
+
+Getting a type handle from the type passed to the argument.
+
+#### Examples
+
+```yql
+SELECT FormatType(TypeHandle(TypeOf("foo"))); -- String
+```
+
+### EvaluateType
+
+Getting the type from the type handle passed to the argument. The function is evaluated before the start of the main calculation, as well as [EvaluateExpr](basic.md#evaluate_expr_atom).
+
+#### Examples
+
+```yql
+SELECT FormatType(EvaluateType(TypeHandle(TypeOf("foo")))); -- String
+```
+
+### ParseTypeHandle
+
+Building a type handle from a string with description. [Documentation for its format](../types/type_string.md).
+
+#### Examples
+
+```yql
+SELECT FormatType(ParseTypeHandle("List<Int32>")); -- List<int32>
+```
+
+### TypeKind
+
+Getting the top-level type name from the type handle passed to the argument.
+
+#### Examples
+
+```yql
+SELECT TypeKind(TypeHandle(TypeOf("foo"))); -- Data
+SELECT TypeKind(ParseTypeHandle("List<Int32>")); -- List
+```
+
+### DataTypeComponents
+
+Getting the name and parameters for a [primitive data type](../types/primitive.md) from the primitive type handle passed to the argument. Reverse function: [DataTypeHandle](#datatypehandle).
+
+#### Examples
+
+```yql
+SELECT DataTypeComponents(TypeHandle(TypeOf("foo"))); -- ["String"]
+SELECT DataTypeComponents(ParseTypeHandle("Decimal(4,1)")); -- ["Decimal", "4", "1"]
+```
+
+### DataTypeHandle
+
+Constructing a handle for a [primitive data type](../types/primitive.md) from its name and parameters passed to the argument as a list. Reverse function: [DataTypeComponents](#datatypecomponents).
+
+#### Examples
+
+```yql
+SELECT FormatType(DataTypeHandle(
+ AsList("String")
+)); -- String
+
+SELECT FormatType(DataTypeHandle(
+ AsList("Decimal", "4", "1")
+)); -- Decimal(4,1)
+```
+
+### OptionalTypeHandle
+
+Adds the option to assign `NULL` to the passed type handle.
+
+#### Examples
+
+```yql
+SELECT FormatType(OptionalTypeHandle(
+ TypeHandle(DataType("Bool"))
+)); -- Bool?
+```
+
+### PgTypeName
+
+Getting the name of the PostgreSQL type from the type handle passed to the argument. Inverse function: [PgTypeHandle](#pgtypehandle).
+
+#### Examples
+
+```yql
+SELECT PgTypeName(ParseTypeHandle("pgint4")); -- int4
+```
+
+### PgTypeHandle
+
+Builds a type handle based on the passed name of the PostgreSQL type. Inverse function: [PgTypeName](#pgtypename).
+
+#### Examples
+
+```yql
+SELECT FormatType(PgTypeHandle("int4")); -- pgint4
+```
+
+### ListTypeHandle and StreamTypeHandle {#list-stream-typehandle}
+
+Builds a list type handle or stream type handle based on the passed element type handle.
+
+#### Examples
+
+```yql
+SELECT FormatType(ListTypeHandle(
+ TypeHandle(DataType("Bool"))
+)); -- List<Bool>
+```
+
+### EmptyListTypeHandle and EmptyDictTypeHandle
+
+Constructs a handle for an empty list or dictionary.
+
+#### Examples
+
+```yql
+SELECT FormatType(EmptyListTypeHandle()); -- EmptyList
+```
+
+### TupleTypeComponents
+
+Getting a list of element type handles from the tuple type handle passed to the argument. Inverse function: [TupleTypeHandle](#tupletypehandle).
+
+#### Examples
+
+```yql
+SELECT ListMap(
+ TupleTypeComponents(
+ ParseTypeHandle("Tuple<Int32, String>")
+ ),
+ ($x)->{
+ return FormatType($x)
+ }
+); -- ["Int32", "String"]
+```
+
+### TupleTypeHandle
+
+Building a tuple type handle from handles of element types passed as a list to the argument. Inverse function: [TupleTypeComponents](#tupletypecomponents).
+
+#### Examples
+
+```yql
+SELECT FormatType(
+ TupleTypeHandle(
+ AsList(
+ ParseTypeHandle("Int32"),
+ ParseTypeHandle("String")
+ )
+ )
+); -- Tuple<Int32,String>
+```
+
+### StructTypeComponents
+
+Getting a list of element type handles and their names from the structure type handle passed to the argument. Inverse function: [StructTypeHandle](#structtypehandle).
+
+#### Examples
+
+```yql
+SELECT ListMap(
+ StructTypeComponents(
+ ParseTypeHandle("Struct<a:Int32, b:String>")
+ ),
+ ($x) -> {
+ return AsTuple(
+ FormatType($x.Type),
+ $x.Name
+ )
+ }
+); -- [("Int32","a"), ("String","b")]
+```
+
+### StructTypeHandle
+
+Building a structure type handle from handles of element types and names passed as a list to the argument. Inverse function: [StructTypeComponents](#structtypecomponents).
+
+#### Examples
+
+```yql
+SELECT FormatType(
+ StructTypeHandle(
+ AsList(
+ AsStruct(ParseTypeHandle("Int32") as Type,"a" as Name),
+ AsStruct(ParseTypeHandle("String") as Type, "b" as Name)
+ )
+ )
+); -- Struct<'a':Int32,'b':String>
+```
+
+### DictTypeComponents
+
+Getting a key-type handle and a value-type handle from the dictionary-type handle passed to the argument. Inverse function: [DictTypeHandle](#dicttypehandle).
+
+#### Examples
+
+```yql
+$d = DictTypeComponents(ParseTypeHandle("Dict<Int32,String>"));
+
+SELECT
+ FormatType($d.Key), -- Int32
+ FormatType($d.Payload); -- String
+```
+
+### DictTypeHandle
+
+Building a dictionary-type handle from a key-type handle and a value-type handle passed to arguments. Inverse function: [DictTypeComponents](#dicttypecomponents).
+
+#### Examples
+
+```yql
+SELECT FormatType(
+ DictTypeHandle(
+ ParseTypeHandle("Int32"),
+ ParseTypeHandle("String")
+ )
+); -- Dict<Int32, String>
+```
+
+### ResourceTypeTag
+
+Getting the tag from the resource type handle passed to the argument. Inverse function: [ResourceTypeHandle](#resourcetypehandle).
+
+#### Examples
+
+```yql
+SELECT ResourceTypeTag(ParseTypeHandle("Resource<foo>")); -- foo
+```
+
+### ResourceTypeHandle
+
+Building a resource-type handle from the tag value passed to the argument. Inverse function: [ResourceTypeTag](#resourcetypetag).
+
+#### Examples
+
+```yql
+SELECT FormatType(ResourceTypeHandle("foo")); -- Resource<'foo'>
+```
+
+### TaggedTypeComponents
+
+Getting the tag and the basic type from the decorated type handle passed to the argument. Inverse function: [TaggedTypeHandle](#taggedtypehandle).
+
+#### Examples
+
+```yql
+$t = TaggedTypeComponents(ParseTypeHandle("Tagged<Int32,foo>"));
+
+SELECT FormatType($t.Base), $t.Tag; -- Int32, foo
+```
+
+### TaggedTypeHandle
+
+Constructing a decorated type handle based on the base type handle and the tag name passed in arguments. Inverse function: [TaggedTypeComponents](#taggedtypecomponents).
+
+#### Examples
+
+```yql
+SELECT FormatType(TaggedTypeHandle(
+ ParseTypeHandle("Int32"), "foo"
+)); -- Tagged<Int32, 'foo'>
+```
+
+### VariantTypeHandle
+
+Building a variant-type handle from the handle of the underlying type passed to the argument. Inverse function: [VariantUnderlyingType](#variantunderlyingtype).
+
+#### Examples
+
+```yql
+SELECT FormatType(VariantTypeHandle(
+ ParseTypeHandle("Tuple<Int32, String>")
+)); -- Variant<Int32, String>
+```
+
+### VoidTypeHandle and NullTypeHandle
+
+Constructing a handle for Void and Null types, respectively.
+
+#### Examples
+
+```yql
+SELECT FormatType(VoidTypeHandle()); -- Void
+SELECT FormatType(NullTypeHandle()); -- Null
+```
+
+### CallableTypeComponents
+
+Getting the handle description for the type of callable value passed to the argument. Inverse function: [CallableTypeHandle](#callabletypehandle).
+
+#### Examples
+
+```yql
+$formatArgument = ($x) -> {
+ return AsStruct(
+ FormatType($x.Type) as Type,
+ $x.Name as Name,
+ $x.Flags as Flags
+ )
+};
+
+$formatCallable = ($x) -> {
+ return AsStruct(
+ $x.OptionalArgumentsCount as OptionalArgumentsCount,
+ $x.Payload as Payload,
+ FormatType($x.Result) as Result,
+ ListMap($x.Arguments, $formatArgument) as Arguments
+ )
+};
+
+SELECT $formatCallable(
+ CallableTypeComponents(
+ ParseTypeHandle("(Int32,[bar:Double?{Flags:AutoMap}])->String")
+ )
+); -- (OptionalArgumentsCount: 1, Payload: "", Result: "String", Arguments: [
+ -- (Type: "Int32", Name: "", Flags: []),
+ -- (Type: "Double?", Name: "bar", Flags: ["AutoMap"]),
+ -- ])
+```
+
+### CallableArgument
+
+Packing the description of the argument of the callable value into the structure to be passed to the [CallableTypeHandle](#callabletypehandle) function with the following arguments:
+
+1. Argument type handle.
+2. Optional argument name. The default value is an empty string.
+3. A list of strings with optional argument flags. The default value is an empty list. Supported flags are "AutoMap".
+
+### CallableTypeHandle
+
+Constructing the type handle of the called value using the following arguments:
+
+1. Handle of the return value type.
+2. List of descriptions of arguments received using the [CallableArgument](#callableargument) function.
+3. Optional number of optional arguments in the callable value. The default value is 0.
+4. An optional label for the called value type. The default value is an empty string.
+
+Inverse function: [CallableTypeComponents](#callabletypecomponents).
+
+#### Examples
+
+```yql
+SELECT FormatType(
+ CallableTypeHandle(
+ ParseTypeHandle("String"),
+ AsList(
+ CallableArgument(ParseTypeHandle("Int32")),
+ CallableArgument(ParseTypeHandle("Double?"), "bar", AsList("AutoMap"))
+ ),
+ 1
+ )
+); -- Callable<(Int32,['bar':Double?{Flags:AutoMap}])->String>
+```
+
+### LambdaArgumentsCount
+
+Getting the number of arguments in a lambda function.
+
+#### Examples
+
+```yql
+SELECT LambdaArgumentsCount(($x, $y)->($x+$y))
+; -- 2
+```
diff --git a/yql/essentials/docs/en/builtins/window.md b/yql/essentials/docs/en/builtins/window.md
new file mode 100644
index 0000000000..f9a670167b
--- /dev/null
+++ b/yql/essentials/docs/en/builtins/window.md
@@ -0,0 +1,247 @@
+
+# List of window functions in YQL
+
+The syntax for calling window functions is detailed in a [separate article](../syntax/window.md).
+
+
+
+## Aggregate functions {#aggregate-functions}
+
+All [aggregate functions](aggregation.md) can also be used as window functions.
+In this case, each row includes an aggregation result obtained on a set of rows from the [window frame](../syntax/window.md#frame).
+
+### Examples
+
+```yql
+SELECT
+ SUM(int_column) OVER w1 AS running_total,
+ SUM(int_column) OVER w2 AS total,
+FROM my_table
+WINDOW
+ w1 AS (ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW),
+ w2 AS ();
+```
+
+
+
+## ROW_NUMBER {#row_number}
+
+Row number within a [partition](../syntax/window.md#partition). No arguments.
+
+### Signature
+
+```yql
+ROW_NUMBER()->Uint64
+```
+
+### Examples
+
+```yql
+SELECT
+ ROW_NUMBER() OVER w AS row_num
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+
+
+## LAG / LEAD {#lag-lead}
+
+Accessing a value from a row in the [section](../syntax/window.md#partition) that lags behind (`LAG`) or leads (`LEAD`) the current row by a fixed number. The first argument specifies the expression to be accessed, and the second argument specifies the offset in rows. You may omit the offset. By default, the neighbor row is used: the previous or next, respectively (hence, 1 is assumed by default). For the rows having no neighbors at a given distance (for example, `LAG(expr, 3)` `NULL` is returned in the first and second rows of the section).
+
+### Signature
+
+```yql
+LEAD(T[,Int32])->T?
+LAG(T[,Int32])->T?
+```
+
+### Examples
+
+```yql
+SELECT
+ int_value - LAG(int_value) OVER w AS int_value_diff
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+```yql
+SELECT item, odd, LAG(item, 1) OVER w as lag1 FROM (
+ SELECT item, item % 2 as odd FROM (
+ SELECT AsList(1, 2, 3, 4, 5, 6, 7) as item
+ )
+ FLATTEN BY item
+)
+WINDOW w As (
+ PARTITION BY odd
+ ORDER BY item
+);
+
+/* Output:
+item odd lag1
+--------------------
+2 0 NULL
+4 0 2
+6 0 4
+1 1 NULL
+3 1 1
+5 1 3
+7 1 5
+*/
+```
+
+
+## FIRST_VALUE / LAST_VALUE
+
+Access values from the first and last rows (using the `ORDER BY` clause for the window) of the [window frame](../syntax/window.md#frame). The only argument is the expression that you need to access.
+
+Optionally, `OVER` can be preceded by the additional modifier `IGNORE NULLS`. It changes the behavior of functions to the first or last **non-empty** (i.e., non-`NULL`) value among the window frame rows. The antonym of this modifier is `RESPECT NULLS`: it's the default behavior that can be omitted.
+
+### Signature
+
+```yql
+FIRST_VALUE(T)->T?
+LAST_VALUE(T)->T?
+```
+
+### Examples
+
+```yql
+SELECT
+ FIRST_VALUE(my_column) OVER w
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+```yql
+SELECT
+ LAST_VALUE(my_column) IGNORE NULLS OVER w
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+
+
+## NTH_VALUE
+
+Access a value from a row specified by position in the window's `ORDER BY` order within [window frame](../syntax/window.md#frame). Arguments - the expression to access and the row number, starting with 1.
+
+Optionally, the `IGNORE NULLS` modifier can be specified before `OVER`, which causes rows with `NULL` in the first argument's value to be skipped. The antonym of this modifier is `RESPECT NULLS`, which is the default behavior and may be skipped.
+
+### Signature
+
+```yql
+NTH_VALUE(T,N)->T?
+```
+
+### Examples
+
+```yql
+SELECT
+ NTH_VALUE(my_column, 2) OVER w
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+```yql
+SELECT
+ NTH_VALUE(my_column, 3) IGNORE NULLS OVER w
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+
+
+
+## RANK / DENSE_RANK / PERCENT_RANK {#rank}
+
+Number the groups of neighboring rows in the [partition](../syntax/window.md#partition) with the same expression value in the argument. `DENSE_RANK` numbers the groups one by one, and `RANK` skips `(N - 1)` values, with `N` being the number of rows in the previous group. `PERCENT_RANK` returns the relative rank of the current row: $(RANK - 1)/(number of rows in the partition - 1)$.
+
+If there is no argument, it uses the order specified in the `ORDER BY` section in the window definition.
+If the argument is omitted and `ORDER BY` is not specified, then all rows are considered equal to each other.
+
+{% note info %}
+
+Passing an argument to `RANK`/`DENSE_RANK`/`PERCENT_RANK` is a non-standard extension in YQL.
+
+{% endnote %}
+
+### Signature
+
+```text
+RANK([T])->Uint64
+DENSE_RANK([T])->Uint64
+PERCENT_RANK([T])->Double
+```
+
+### Examples
+
+```yql
+SELECT
+ RANK(my_column) OVER w
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+```yql
+SELECT
+ DENSE_RANK() OVER w
+FROM my_table
+WINDOW w AS (ORDER BY my_column);
+```
+
+```yql
+SELECT
+ PERCENT_RANK() OVER w
+FROM my_table
+WINDOW w AS (ORDER BY my_column);
+```
+
+
+
+## NTILE
+
+Distributes the rows of an ordered [partition](../syntax/window.md#partition) into a specified number of groups. The groups are numbered starting with one. For each row, the `NTILE` function returns the number of the group to which the row belongs.
+
+### Signature
+
+```yql
+NTILE(Uint64)->Uint64
+```
+
+### Examples
+
+```yql
+SELECT
+ NTILE(10) OVER w AS group_num
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+
+
+## CUME_DIST
+
+Returns the relative position (> 0 and <= 1) of a row within a [partition](../syntax/window.md#partition). No arguments.
+
+### Signature
+
+```yql
+CUME_DIST()->Double
+```
+
+### Examples
+
+```yql
+SELECT
+ CUME_DIST() OVER w AS dist
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+
+## SessionState() {#session-state}
+
+A non-standard window function `SessionState()` (without arguments) lets you get the session calculation status from [SessionWindow](../syntax/group_by.md#session-window) for the current row.
+It's allowed only if `SessionWindow()` is present in the `PARTITION BY` section in the window definition.
+
diff --git a/yql/essentials/docs/en/index.md b/yql/essentials/docs/en/index.md
new file mode 100644
index 0000000000..77431a8793
--- /dev/null
+++ b/yql/essentials/docs/en/index.md
@@ -0,0 +1,10 @@
+# YQL - Overview
+
+*YQL* (Yandex Query Language) — is a universal declarative query language for distributed systems of data storage and processing, a dialect of SQL.
+
+This documentation section contains the YQL reference that includes the sections:
+
+- [Data types](types/index.md) with a description of data types used in YQL
+- [Syntax](syntax/index.md) with a full list of YQL commands
+- [Built-in functions](builtins/index.md) with a description of the available built-in functions
+- [Recipes](recipes/index.md) with a description of recipes for various tasks
diff --git a/yql/essentials/docs/en/recipes/accessing-json.md b/yql/essentials/docs/en/recipes/accessing-json.md
new file mode 100644
index 0000000000..c18412d95b
--- /dev/null
+++ b/yql/essentials/docs/en/recipes/accessing-json.md
@@ -0,0 +1,103 @@
+# Accessing values inside JSON with YQL
+
+YQL provides two main ways to retrieve values from JSON:
+
+- Using [**JSON functions from the SQL standard**](../builtins/json.md). This approach is recommended for simple cases and for teams that are familiar with them from other DBMSs.
+- Using [**Yson UDF**](../udf/list/yson.md), [list](../builtins/list.md) and [dict](../builtins/dict.md) builtins, and [lambdas](../syntax/expressions.md#lambda). This approach is more flexible and tightly integrated with YQL's data type system, thus recommended for complex cases.
+
+Below are the recipes that will use the same input JSON to demonstrate how to use each option to check whether a key exists, get a specific value, and retrieve a subtree.
+
+## JSON functions
+
+```yql
+$json = @@{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30
+ }
+ ]
+}@@j;
+
+SELECT
+ JSON_EXISTS($json, "$.friends[*].name"), -- True
+ CAST(JSON_VALUE($json, "$.friends[0].age") AS Int32), -- 35
+ JSON_QUERY($json, "$.friends[0]"); -- {"name": "James Holden", "age": 35}
+```
+
+`JSON_*` functions expect the `Json` data type as an input to run. In this example, the string literal has the suffix `j`, marking it as `Json`. In tables, data could be stored in either JSON format or as a string representation. To convert data from `String` to `JSON` data type, use the `CAST` function, such as `CAST(my_string AS JSON)`.
+
+## Yson UDF
+
+This approach typically combines multiple functions and expressions, so a query might leverage different specific strategies.
+
+### Convert the whole JSON to YQL containers
+
+```yql
+$json = @@{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30
+ }
+ ]
+}@@j;
+
+$containers = Yson::ConvertTo($json, Struct<friends:List<Struct<name:String?,age:Int32?>>>);
+$has_name = ListAny(
+ ListMap($containers.friends, ($friend) -> {
+ return $friend.name IS NOT NULL;
+ })
+);
+$get_age = $containers.friends[0].age;
+$get_first_friend = Yson::SerializeJson(Yson::From($containers.friends[0]));
+
+SELECT
+ $has_name, -- True
+ $get_age, -- 35
+ $get_first_friend; -- {"name": "James Holden", "age": 35}
+```
+
+It is **not** necessary to convert the whole JSON object to a structured combination of containers. Some fields can be omitted if not used, while some subtrees could be left in an unstructured data type like `Json`.
+
+### Work with in-memory representation
+
+```yql
+$json = @@{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30
+ }
+ ]
+}@@j;
+
+$has_name = ListAny(
+ ListMap(Yson::ConvertToList($json.friends), ($friend) -> {
+ return Yson::Contains($friend, "name");
+ })
+);
+$get_age = Yson::ConvertToInt64($json.friends[0].age);
+$get_first_friend = Yson::SerializeJson($json.friends[0]);
+
+SELECT
+ $has_name, -- True
+ $get_age, -- 35
+ $get_first_friend; -- {"name": "James Holden", "age": 35}
+```
+
+## See also
+
+- [{#T}](modifying-json.md)
diff --git a/yql/essentials/docs/en/recipes/index.md b/yql/essentials/docs/en/recipes/index.md
new file mode 100644
index 0000000000..904887e254
--- /dev/null
+++ b/yql/essentials/docs/en/recipes/index.md
@@ -0,0 +1,9 @@
+# YQL recipes
+
+This section contains query recipes for various tasks that can be solved with YQL.
+
+Table of contents:
+
+* [{#T}](accessing-json.md)
+* [{#T}](modifying-json.md)
+
diff --git a/yql/essentials/docs/en/recipes/modifying-json.md b/yql/essentials/docs/en/recipes/modifying-json.md
new file mode 100644
index 0000000000..3619aa1137
--- /dev/null
+++ b/yql/essentials/docs/en/recipes/modifying-json.md
@@ -0,0 +1,23 @@
+# Modifying JSON with YQL
+
+In memory, YQL operates on immutable values. Thus, when a query needs to change something inside a JSON value, the mindset should be about constructing a new value from pieces of the old one.
+
+This example query takes an input JSON named `$fields`, parses it, substitutes key `a` with 0, drops key `d`, and adds a key `c` with value 3:
+
+```yql
+$fields = '{"a": 1, "b": 2, "d": 4}'j;
+$pairs = DictItems(Yson::ConvertToInt64Dict($fields));
+$result_pairs = ListExtend(ListNotNull(ListMap($pairs, ($item) -> {
+ $item = if ($item.0 == "a", ("a", 0), $item);
+ return if ($item.0 == "d", null, $item);
+})), [("c", 3)]);
+$result_dict = ToDict($result_pairs);
+SELECT Yson::SerializeJson(Yson::From($result_dict));
+```
+
+## See also
+
+- [{#T}](../udf/list/yson.md)
+- [{#T}](../builtins/list.md)
+- [{#T}](../builtins/dict.md)
+- [{#T}](accessing-json.md)
diff --git a/yql/essentials/docs/en/recipes/toc_i.yaml b/yql/essentials/docs/en/recipes/toc_i.yaml
new file mode 100644
index 0000000000..70ad056eef
--- /dev/null
+++ b/yql/essentials/docs/en/recipes/toc_i.yaml
@@ -0,0 +1,7 @@
+items:
+- name: Overview
+ href: index.md
+- name: Accessing JSON
+ href: accessing-json.md
+- name: Modifying JSON
+ href: modifying-json.md \ No newline at end of file
diff --git a/yql/essentials/docs/en/syntax/_assets/join-YQL-06.png b/yql/essentials/docs/en/syntax/_assets/join-YQL-06.png
new file mode 100644
index 0000000000..aae84322b7
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/_assets/join-YQL-06.png
Binary files differ
diff --git a/yql/essentials/docs/en/syntax/action.md b/yql/essentials/docs/en/syntax/action.md
new file mode 100644
index 0000000000..6ec0f0f71f
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/action.md
@@ -0,0 +1,145 @@
+# ACTION
+
+## DEFINE ACTION {#define-action}
+
+Specifies a named action that is a parameterizable block of multiple top-level expressions.
+
+### Syntax
+
+1. `DEFINE ACTION`: action definition.
+1. [Action name](expressions.md#named-nodes) that will be used to access the defined action further in the query.
+1. The values of parameter names are listed in parentheses.
+1. `AS` keyword.
+1. List of top-level expressions.
+1. `END DEFINE`: The marker of the last expression inside the action.
+
+One or more of the last parameters can be marked with a question mark `?` as optional. If they are omitted during the call, they will be assigned the `NULL` value.
+
+## DO {#do}
+
+Executes an `ACTION` with the specified parameters.
+
+### Syntax
+
+1. `DO`: Executing an action.
+1. The named expression for which the action is defined.
+1. The values to be used as parameters are listed in parentheses.
+
+`EMPTY_ACTION`: An action that does nothing.
+
+{% note info %}
+
+In large queries, you can use separate files for action definition and include them to the main query using [EXPORT](export_import.md#export) + [IMPORT](export_import.md#import) so that instead of one long text you can have several logical parts that are easier to navigate. An important nuance: the `USE my_cluster;` directive in the import query does not affect behavior of actions declared in other files.
+
+{% endnote %}
+
+### Example
+
+```yql
+DEFINE ACTION $hello_world($name, $suffix?) AS
+ $name = $name ?? ($suffix ?? "world");
+ SELECT "Hello, " || $name || "!";
+END DEFINE;
+
+DO EMPTY_ACTION();
+DO $hello_world(NULL);
+DO $hello_world("John");
+DO $hello_world(NULL, "Earth");
+```
+
+## BEGIN .. END DO {#begin}
+
+Performing an action without declaring it (anonymous action).
+
+### Syntax
+
+1. `BEGIN`.
+1. List of top-level expressions.
+1. `END DO`.
+
+An anonymous action can't include any parameters.
+
+### Example
+
+```yql
+DO BEGIN
+ SELECT 1;
+ SELECT 2 -- here and in the previous example, you might omit ';' before END
+END DO
+```
+
+## EVALUATE IF {#evaluate-if}
+
+`EVALUATE IF`: Executing an action depending on the condition. It's followed by:
+
+1. Condition.
+2. [DO](#do) with the name and parameters of the action or an anonymous action.
+3. An optional `ELSE` followed by the second `DO` for a situation where the condition is not met.
+
+## EVALUATE FOR {#evaluate-for}
+
+`EVALUATE FOR`: Executing an action for each item in the list. It's followed by:
+
+1. [A named expression](expressions.md#named-nodes) applied to each next element in the list.
+2. `IN` keyword.
+3. The above-declared named expression applied to the list the action is executed on.
+4. [DO](#do) with the name and parameters of an action or an anonymous action. In the parameters, you can use both the current element from the first paragraph and any named expressions declared above, including the list itself.
+5. An optional `ELSE` followed by the second `DO` for the situation when the list is empty.
+
+### Examples
+
+```yql
+DEFINE ACTION $hello() AS
+ SELECT "Hello!";
+END DEFINE;
+
+DEFINE ACTION $bye() AS
+ SELECT "Bye!";
+END DEFINE;
+
+EVALUATE IF RANDOM(0) > 0.5
+ DO $hello()
+ELSE
+ DO $bye();
+
+EVALUATE IF RANDOM(0) > 0.1 DO BEGIN
+ SELECT "Hello!";
+END DO;
+
+EVALUATE FOR $i IN AsList(1, 2, 3) DO BEGIN
+ SELECT $i;
+END DO;
+```
+
+```yql
+-- copy the $input table to $count of new tables
+$count = 3;
+$input = "my_input";
+$inputs = ListReplicate($input, $count);
+$outputs = ListMap(
+ ListFromRange(0, $count),
+ ($i) -> {
+ RETURN "tmp/out_" || CAST($i as String)
+ }
+);
+$pairs = ListZip($inputs, $outputs);
+
+DEFINE ACTION $copy_table($pair) as
+ $input = $pair.0;
+ $output = $pair.1;
+ INSERT INTO $output WITH TRUNCATE
+ SELECT * FROM $input;
+END DEFINE;
+
+EVALUATE FOR $pair IN $pairs
+ DO $copy_table($pair)
+ELSE
+ DO EMPTY_ACTION (); -- you may omit this ELSE,
+ -- do nothing is implied by default
+```
+
+{% note info %}
+
+Note that `EVALUATE` is run before the operation starts.
+
+{% endnote %}
diff --git a/yql/essentials/docs/en/syntax/commit.md b/yql/essentials/docs/en/syntax/commit.md
new file mode 100644
index 0000000000..eace340a5c
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/commit.md
@@ -0,0 +1,17 @@
+# COMMIT
+
+By default, the entire YQL query is executed within a single transaction, and independent parts inside it are executed in parallel, if possible.
+Using the `COMMIT;` keyword you can add a barrier to the execution process to delay execution of expressions that follow until all the preceding expressions have completed.
+
+To commit in the same way automatically after each expression in the query, you can use `PRAGMA autocommit;`.
+
+## Examples
+
+```yql
+INSERT INTO result1 SELECT * FROM my_table;
+INSERT INTO result2 SELECT * FROM my_table;
+COMMIT;
+-- result2 will already include the SELECT contents from the second line:
+INSERT INTO result3 SELECT * FROM result2;
+```
+
diff --git a/yql/essentials/docs/en/syntax/declare.md b/yql/essentials/docs/en/syntax/declare.md
new file mode 100644
index 0000000000..93cd978cd4
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/declare.md
@@ -0,0 +1,36 @@
+# DECLARE
+
+Declares a typed [named expression](expressions.md#named-nodes) whose value will be passed separately from the query text. With parameterization, you can separately develop an analytical solution and then launch it sequentially with different input values.
+
+In the case of transactional load, parameters let you avoid recompilation of queries when repeating calls of the same type. This way you can reduce server utilization and exclude compilation time from the total time of query execution.
+
+Passing of parameters is supported in the SDK, CLI, and graphical interfaces.
+
+## Syntax
+
+```yql
+DECLARE $named-node AS data_type;
+```
+
+1. `DECLARE` keyword.
+1. `$named-node`: The name by which you can access the passed value. It must start with `$`.
+1. `AS` keyword.
+1. `data_type` is the data type [represented as a string in the accepted format](../types/type_string.md).
+
+Only serializable data types are allowed:
+
+* [Primitive types](../types/primitive.md).
+* [Optional types](../types/optional.md).
+* [Containers](../types/containers.md), except `Stream<Type>`.
+* `Void` and `Null` are the supported [special types](../types/special.md).
+
+## Example
+
+```yql
+DECLARE $x AS String;
+DECLARE $y AS String?;
+DECLARE $z AS List<String>;
+
+SELECT $x, $y, $z;
+```
+
diff --git a/yql/essentials/docs/en/syntax/discard.md b/yql/essentials/docs/en/syntax/discard.md
new file mode 100644
index 0000000000..83364abd8b
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/discard.md
@@ -0,0 +1,29 @@
+# DISCARD
+
+Calculates [`SELECT`](select/index.md), [`REDUCE`](reduce.md), or [`PROCESS`](process.md) without returning the result neither to the client or table. You can't use it along with [INTO RESULT](into_result.md).
+
+It's good to combine it with [`Ensure`](../builtins/basic.md#ensure) to check the final calculation result against the user's criteria.
+
+
+## Examples
+
+```yql
+DISCARD SELECT 1;
+```
+
+```yql
+INSERT INTO result_table WITH TRUNCATE
+SELECT * FROM
+my_table
+WHERE value % 2 == 0;
+
+COMMIT;
+
+DISCARD SELECT Ensure(
+ 0, -- will discard result anyway
+ COUNT(*) > 1000,
+ "Too small result table, got only " || CAST(COUNT(*) AS String) || " rows"
+) FROM result_table;
+```
+
+
diff --git a/yql/essentials/docs/en/syntax/export_import.md b/yql/essentials/docs/en/syntax/export_import.md
new file mode 100644
index 0000000000..ddebe256be
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/export_import.md
@@ -0,0 +1,63 @@
+# Putting part of the query into a separate file
+
+Here's the mechanism for putting part of the query into a separate attached file:
+
+* [PRAGMA Library](pragma.md#library) marks the attached file as available for import.
+
+## `Export`
+
+* `EXPORT $my_symbol1, $my_symbol2, ...;` lists the names of named expressions in the library that are available for import.
+
+## `Import`
+
+* `IMPORT my_library SYMBOLS $my_symbol1, $my_symbol2, ...;` makes the listed named expressions available for further use.
+
+{% note info %}
+
+You can use the library to include [lambdas](expressions.md#lambda), [actions](action.md), [named subqueries](subquery.md), constants and expressions, but **not subqueries or aggregate functions**.
+
+{% endnote %}
+
+{% note warning %}
+
+The file linked by the [PRAGMA Library](pragma.md#library) must be attached to the query. **You can't use a [PRAGMA File](pragma.md#file) for this purpose**.
+
+{% endnote %}
+
+### Examples
+
+my_lib.sql:
+
+```yql
+$Square = ($x) -> { RETURN $x * $x; };
+$Sqrt = ($x) -> { RETURN Math::Sqrt($x); };
+
+-- Aggregate functions created by
+-- AggregationFactory, it makes sense to add it to the library
+$Agg_sum = AggregationFactory("SUM");
+$Agg_max = AggregationFactory("MAX");
+
+EXPORT $Square, $Sqrt, $Agg_sum, $Agg_max;
+```
+
+Query:
+
+```yql
+PRAGMA Library("my_lib.sql");
+IMPORT my_lib SYMBOLS $Square, $Sqrt, $Agg_sum, $Agg_max;
+SELECT
+ $Square(2), -- 4
+ $Sqrt(4); -- 2
+
+SELECT
+ AGGREGATE_BY(x, $Agg_sum), -- 5
+ AGGREGATE_BY(x, $Agg_max) -- 3
+FROM (
+ SELECT 2 AS x
+ UNION ALL
+ SELECT 3 AS x
+)
+```
+
+
+
diff --git a/yql/essentials/docs/en/syntax/expressions.md b/yql/essentials/docs/en/syntax/expressions.md
new file mode 100644
index 0000000000..02ba8372dd
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/expressions.md
@@ -0,0 +1,550 @@
+# Expressions
+
+<!-- markdownlint-disable blanks-around-fences -->
+
+## String concatenation {#concatenation}
+
+Executed using the binary operator `||`.
+
+As with other binary operators, if the data on either side is `NULL`, the result is also `NULL`.
+
+Don't confuse this operator with a logical "or": in SQL, it's denoted by the `OR` keyword. It's also not worth doing concatenation using `+`.
+
+### Examples
+
+```yql
+SELECT "fo" || "o";
+```
+
+
+
+## Matching a string by pattern {#check-match}
+
+`REGEXP` and `RLIKE` are aliases used to call [Re2::Grep](../udf/list/re2.md#match). `MATCH`: Same for [Re2::Match](../udf/list/re2.md#match).
+
+`LIKE` works as follows:
+
+* Patterns can include two special characters:
+
+ * `%`: Zero or more of any characters.
+ * `_`: Exactly one of any character.
+
+All other characters are literals that represent themselves.
+
+* As opposed to `REGEXP`, `LIKE` must be matched exactly. For example, to search a substring, add `%` at the beginning and end of the pattern.
+* `ILIKE` is a case-insensitive version of `LIKE`.
+* If `LIKE` is applied to the key column of the sorted table and the pattern doesn't start with a special character, filtering by prefix drills down directly to the cluster level, which in some cases lets you avoid the full table scan. This optimization is disabled for `ILIKE`.
+* To escape special characters, specify the escaped character after the pattern using the `ESCAPE '?'` keyword. Instead of `?` you can use any character except `%`, `_` and `\`. For example, if you use a question mark as an escape character, the expressions `?%`, `?_` and `??` will match their second character in the template: percent, underscore, and question mark, respectively. The escape character is undefined by default.
+
+The most popular way to use the `LIKE` and `REGEXP` keywords is to filter a table using the statements with the `WHERE` clause. However, there are no restrictions on using templates in this context: you can use them in most of contexts involving strings, for example, with concatenation by using `||`.
+
+### Examples
+
+```yql
+SELECT * FROM my_table
+WHERE string_column REGEXP '\\d+';
+-- the second slash is required because
+-- all the standard string literals in SQL
+-- can accept C-escaped strings
+```
+
+```yql
+SELECT
+ string_column LIKE '___!_!_!_!!!!!!' ESCAPE '!'
+ -- searches for a string of exactly 9 characters:
+ -- 3 arbitrary characters
+ -- followed by 3 underscores
+ -- and 3 exclamation marks
+FROM my_table;
+```
+
+```yql
+SELECT * FROM my_table
+WHERE key LIKE 'foo%bar';
+-- if the table is sorted by key, it will only scan the keys,
+-- starting with "foo", and then, among them,
+-- will leave only those that end in "bar"
+```
+
+
+
+## Operators
+
+### Arithmetic operators {#math-operators}
+
+The operators `+`, `-`, `*`, `/`, `%` are defined for [primitive data types](../types/primitive.md) that are variations of numbers.
+
+For the Decimal data type, bankers rounding is used (to the nearest even integer).
+
+#### Examples
+
+```yql
+SELECT 2 + 2;
+```
+
+```yql
+SELECT 0.0 / 0.0;
+```
+
+### Comparison operators {#comparison-operators}
+
+The operators `=`, `==`, `!=`, `<>`, `>`, `<` are defined for:
+
+* Primitive data types except Yson and Json.
+* Tuples and structures with the same set of fields. No order is defined for structures, but you can check for (non-)equality. Tuples are compared element-by-element left to right.
+
+#### Examples
+
+```yql
+SELECT 2 > 1;
+```
+
+### Logical operators {#logic-operators}
+
+Use the operators `AND`, `OR`, `XOR` for logical operations on Boolean values (`Bool`).
+
+#### Examples*
+
+```yql
+SELECT 3 > 0 AND false;
+```
+
+### Bitwise operators {#bit-operators}
+
+Bitwise operations on numbers:
+
+* `&`, `|`, `^`: AND, OR, and XOR, respectively. Don't confuse bitwise operations with the related keywords. The keywords `AND`, `OR`, and `XOR` are used *for Boolean values only*, but not for numbers.
+* ` ~ `: A negation.
+* `<`, `>`: Left or right shifts.
+* `|<`, `>|`: Circular left or right shifts.
+
+#### Examples
+
+```yql
+SELECT
+ key << 10 AS key,
+ ~value AS value
+FROM my_table;
+```
+
+### Precedence and associativity of operators {#operator-priority}
+
+Operator precedence determines the order of evaluation of an expression that contains different operators.
+For example, the expression `1 + 2 * 3` is evaluated as `1 + (2 * 3)` because the multiplication operator has a higher precedence than the addition operator.
+
+Associativity determines the order of evaluating expressions containing operators of the same type.
+For example, the expression `1 + 2 + 3` is evaluated as `(1 + 2) + 3` because the addition operator is left-associative.
+On the other hand, the expression `a ?? b ?? c` is evaluated as `a ?? (b ?? c)` because the `??` operator is right-associative
+
+The table below shows precedence and associativity of YQL operators.
+The operators in the table are listed in descending order of precedence.
+
+| Priority | Operator | Description | Associativity |
+| --- | --- | --- | --- |
+| 1 | `a[], a.foo, a()` | Accessing a container item, calling a function | Left |
+| 2 | `+a, -a, ~a, NOT a` | Unary operators: plus, minus, bitwise and logical negation | Right |
+| 3 | `a\|\|b` | [String concatenation](#concatenation) | Left |
+| 4 | `a*b, a/b, a%b` | Multiplication, division, remainder of division | Left |
+| 5 | `a+b, a-b` | Addition/Subtraction | Left |
+| 6 | `a ?? b` | Operator notation for [NVL/COALESCE](../builtins/basic.md#coalesce) | Right |
+| 7 | `a<b, a>b, a\|<b, a>\|b,` `a\|b, a^b, a&b` | Shift operators and logical bit operators | Left |
+| 8 | `a<b, a=b, a=b, a>b` | Comparison | Left |
+| 9 | `a IN b` | Occurrence of an element in a set | Left |
+| 9 | `a==b, a=b, a!=b, a<>b,` `a is (not) distinct from b` | Comparison for (non-)equality | Left |
+| 10 | `a XOR b` | Logical XOR | Left |
+| 11 | `a AND b` | Logical AND | Left |
+| 12 | `a OR b` | Logical OR | Left |
+
+
+
+## IS \[NOT\] NULL {#is-null}
+
+Matching an empty value (`NULL`). Since `NULL` is a special value [equal to nothing](../types/optional.md#null_expr), the ordinary [comparison operators](#comparison-operators) can't be used to match it.
+
+### Examples
+
+```yql
+SELECT key FROM my_table
+WHERE value IS NOT NULL;
+```
+
+
+
+## IS \[NOT\] DISTINCT FROM {#is-distinct-from}
+
+Comparing of two values. Unlike the regular [comparison operators](#comparison-operators), NULLs are treated as equal to each other.
+More precisely, the comparison is carried out according to the following rules:
+
+1. The operators `IS DISTINCT FROM`/`IS NOT DISTINCT FROM` are defined for those and only for those arguments for which the operators `!=` and `=` are defined.
+2. The result of `IS NOT DISTINCT FROM` is equal to the logical negation of the `IS DISTINCT FROM` result for these arguments.
+3. If the result of the `==` operator is not equal to zero for some arguments, then it is equal to the result of the `IS NOT DISTINCT FROM` operator for the same arguments.
+4. If both arguments are empty `Optional` or `NULL`s, then the value of `IS NOT DISTINCT FROM` is `True`.
+5. The result of `IS NOT DISTINCT FROM` for an empty `Optional` or `NULL` and filled-in `Optional` or non-`Optional` value is `False`.
+
+For values of composite types, these rules are used recursively.
+
+
+## BETWEEN {#between}
+
+Checking whether a value is in a range. It's equivalent to two conditions with `>=` and `<=` (range boundaries are included). Can be used with the `NOT` prefix to support inversion.
+
+### Examples
+
+```yql
+SELECT * FROM my_table
+WHERE key BETWEEN 10 AND 20;
+```
+
+
+
+## IN {#in}
+
+Checking whether a value is inside of a set of values. It's logically equivalent to a chain of equality comparisons using `OR` but implemented more efficiently.
+
+{% note warning "Warning" %}
+
+Unlike a similar keyword in Python, in YQL `IN` **DOES NOT** search for a substring inside a string. To search for a substring, use the function [String::Contains](../udf/list/string.md) or [LIKE/REGEXP](#check-match) mentioned above.
+
+{% endnote %}
+
+Immediately after `IN`, you can specify the `COMPACT` modifier.
+If `COMPACT` is not specified, then `IN` with a subquery is executed as a relevant `JOIN` (`LEFT SEMI` for `IN` and `LEFT ONLY` for `NOT IN`), if possible.
+Using the `COMPACT` modifier forces the in-memory execution strategy: a hash table is immediately built from the contents of the right `IN` part in-memory, and then the left part is filtered.
+
+The `COMPACT` modifier must be used with care. Since the hash table is built in-memory, the query may fail if the right part of `IN` contains many large or different elements.
+
+It is prefirable to add large lists of values to your query by URLs and use the [ParseFile](../builtins/basic.md#parsefile) function.
+
+### Examples
+
+```yql
+SELECT column IN (1, 2, 3)
+FROM my_table;
+```
+
+```yql
+SELECT * FROM my_table
+WHERE string_column IN ("a", "b", "c");
+```
+
+```yql
+$foo = AsList(1, 2, 3);
+SELECT 1 IN $foo;
+```
+
+```yql
+$values = (SELECT column + 1 FROM table);
+SELECT * FROM my_table WHERE
+ -- filtering by an in-memory hash table for one_table
+ column1 IN COMPACT $values AND
+ -- followed by LEFT ONLY JOIN with other_table
+ column2 NOT IN (SELECT other_column FROM other_table);
+```
+
+
+
+## AS {#as}
+
+Can be used in the following scenarios:
+
+* Adding a short name (alias) for columns or tables within the query.
+* Using named arguments in function calls.
+* To specify the target type in the case of explicit type casting, see [CAST](#cast).
+
+### Examples
+
+```yql
+SELECT key AS k FROM my_table;
+```
+
+```yql
+SELECT t.key FROM my_table AS t;
+```
+
+```yql
+SELECT
+ MyFunction(key, 123 AS my_optional_arg)
+FROM my_table;
+```
+
+## CAST {#cast}
+
+<!-- markdownlint-disable blanks-around-fences -->
+
+Tries to cast the value to the specified type. The attempt may fail and return `NULL`. When used with numbers, it may lose precision or most significant bits.
+For lists and dictionaries, it can either delete or replace with `NULL` the elements whose conversion failed.
+For structures and tuples, it deletes elements that are omitted in the target type.
+For more information about casting rules, see [here](../types/cast.md).
+
+{% include [decimal_args](../_includes/decimal_args.md) %}
+
+### Examples
+
+{% include [cast_examples](../_includes/cast_examples.md) %}
+
+
+## BITCAST {#bitcast}
+
+Performs a bitwise conversion of an integer value to the specified integer type. The conversion is always successful, but may lose precision or high-order bits.
+
+### Examples
+
+```yql
+SELECT
+ BITCAST(100000ul AS Uint32), -- 100000
+ BITCAST(100000ul AS Int16), -- -31072
+ BITCAST(100000ul AS Uint16), -- 34464
+ BITCAST(-1 AS Int16), -- -1
+ BITCAST(-1 AS Uint16); -- 65535
+```
+
+## CASE {#case}
+
+Conditional expressions and branching. It's similar to `if`, `switch` and ternary operators in the imperative programming languages.
+If the result of the `WHEN` expression is `true`, the value of the `CASE` expression becomes the result following the condition, and the rest of the `CASE` expression isn't calculated. If the condition is not met, all the `WHEN` clauses that follow are checked. If none of the `WHEN` clauses are met, the `CASE` value is assigned the result from the `ELSE` clause.
+The `ELSE` branch is mandatory in the `CASE` expression. Expressions in `WHEN` are checked sequentially, from top to bottom.
+
+Since its syntax is quite sophisticated, it's often more convenient to use the built-in function [IF](../builtins/basic.md#if).
+
+### Examples
+
+```yql
+SELECT
+ CASE
+ WHEN value > 0
+ THEN "positive"
+ ELSE "negative"
+ END
+FROM my_table;
+```
+
+```yql
+SELECT
+ CASE value
+ WHEN 0 THEN "zero"
+ WHEN 1 THEN "one"
+ ELSE "not zero or one"
+ END
+FROM my_table;
+```
+
+
+
+## Named expressions {#named-nodes}
+
+Complex queries may be sophisticated, containing lots of nested levels and/or repeating parts. In YQL, you can use named expressions to assign a name to an arbitrary expression or subquery. Named expressions can be referenced in other expressions or subqueries. In this case, the original expression/subquery is actually substituted at point of use.
+
+A named expression is defined as follows:
+
+```yql
+<named-expr> = <expression> | <subquery>;
+```
+
+Here `<named-expr>` consists of a $ character and an arbitrary non-empty identifier (for example, `$foo`).
+
+If the expression on the right is a tuple, you can automatically unpack it by specifying several named expressions separated by commas on the left:
+
+```yql
+<named-expr1>, <named-expr2>, <named-expr3> ... = <expression-returning-tuple>;
+```
+
+In this case, the number of expressions must match the tuple size.
+
+Each named expression has a scope. It starts immediately after the definition of a named expression and ends at the end of the nearest enclosed namescope (for example, at the end of the query or at the end of the body of the [lambda function](#lambda), [ACTION](action.md#define-action), [SUBQUERY](subquery.md#define-subquery), or the cycle [EVALUATE FOR](action.md#evaluate-for)).
+Redefining a named expression with the same name hides the previous expression from the current scope.
+
+If the named expression has never been used, a warning is issued. To avoid such a warning, use the underscore as the first character in the ID (for example, `$_foo`).
+The named expression `$_` is called an anonymous named expression and is processed in a special way: it works as if `$_` would be automatically replaced by `$_<some_uniq_name>`.
+Anonymous named expressions are convenient when you don't need the expression value. For example, to fetch the second element from a tuple of three elements, you can write:
+
+```yql
+$_, $second, $_ = AsTuple(1, 2, 3);
+select $second;
+```
+
+An attempt to reference an anonymous named expression results in an error:
+
+```yql
+$_ = 1;
+select $_; --- error: Unable to reference anonymous name $_
+export $_; --- An error: Can not export anonymous name $_
+```
+
+Moreover, you can't import a named expression with an anonymous alias:
+
+```yql
+import utils symbols $sqrt as $_; --- error: Can not import anonymous name $_
+```
+
+Anonymous argument names are also supported for [lambda functions](#lambda), [ACTION](action.md#define-action), [SUBQUERY](subquery.md#define-subquery), and in [EVALUATE FOR](action.md#evaluate-for).
+
+{% note info %}
+
+If named expression substitution results in completely identical subgraphs in the query execution graph, the graphs are combined to execute a subgraph only once.
+
+{% endnote %}
+
+### Examples
+
+```yql
+$multiplier = 712;
+SELECT
+ a * $multiplier, -- $multiplier is 712
+ b * $multiplier,
+ (a + b) * $multiplier
+FROM abc_table;
+$multiplier = c;
+SELECT
+ a * $multiplier -- $multiplier is column c
+FROM abc_table;
+```
+
+```yql
+$intermediate = (
+ SELECT
+ value * value AS square,
+ value
+ FROM my_table
+);
+SELECT a.square * b.value
+FROM $intermediate AS a
+INNER JOIN $intermediate AS b
+ON a.value == b.square;
+```
+
+```yql
+$a, $_, $c = AsTuple(1, 5u, "test"); -- unpack a tuple
+SELECT $a, $c;
+```
+
+```yql
+$x, $y = AsTuple($y, $x); -- swap expression values
+```
+
+## Table expressions {#table-contexts}
+
+A table expression is an expression that returns a table. Table expressions in YQL are as follows:
+
+* Subqueries: `(SELECT key, subkey FROM T)`
+* [Named subqueries](#named-nodes): `$foo = SELECT * FROM T;` (in this case, `$foo` is also a table expression)
+* [Subquery templates](subquery.md#define-subquery): `DEFINE SUBQUERY $foo($name) AS ... END DEFINE;` (`$foo("InputTable")` is a table expression).
+
+Semantics of a table expression depends on the context where it is used. In YQL, table expressions can be used in the following contexts:
+
+* Table context: after [FROM](select/from.md). In this case, table expressions work as expected: for example, `$input = SELECT a, b, c FROM T; SELECT * FROM $input` returns a table with three columns. The table context also occurs after [UNION ALL](select/union.md#unionall), [JOIN](join.md#join), [PROCESS](process.md#process), [REDUCE](reduce.md#reduce);
+* Vector context: after [IN](#in). In this context, the table expression must contain exactly one column (the name of this column doesn't affect the expression result in any way). A table expression in a vector context is typed as a list (the type of the list element is the same as the column type in this case). Example: `SELECT * FROM T WHERE key IN (SELECT k FROM T1)`;
+* A scalar context arises *in all the other cases*. As in a vector context, a table expression must contain exactly one column, but the value of the table expression is a scalar, that is, an arbitrarily selected value of this column (if no rows are returned, the result is `NULL`). Example: `$count = SELECT COUNT(*) FROM T; SELECT * FROM T ORDER BY key LIMIT $count / 2`;
+
+The order of rows in a table context, the order of elements in a vector context, and the rule for selecting a value from a scalar context (if multiple values are returned), aren't defined. This order also cannot be affected by `ORDER BY`: `ORDER BY` without `LIMIT` is ignored in table expressions with a warning, and `ORDER BY` with `LIMIT` defines a set of elements rather than the order within that set.
+
+There is an exception to this rule. Named expression with [PROCESS](process.md#process), if used in a scalar context, behaves as in a table context:
+
+```yql
+$input = SELECT 1 AS key, 2 AS value;
+$process = PROCESS $input;
+
+SELECT FormatType(TypeOf($process)); -- $process is used in a scalar context,
+ -- but the SELECT result in this case is List<Struct'key':Int32,'value':Int32>
+
+SELECT $process[0].key; -- that returns 1
+
+SELECT FormatType(TypeOf($input)); -- throws an error: $input in a scalar context must contain one column
+```
+
+{% note warning %}
+
+A common error is to use an expression in a scalar context rather than a table context or vector context. For example:
+
+```yql
+$dict = SELECT key, value FROM T1;
+
+DEFINE SUBQUERY $merge_dict($table, $dict) AS
+SELECT * FROM $table LEFT JOIN $dict USING(key);
+END DEFINE;
+
+SELECT * FROM $merge_dict("Input", $dict); -- $dict is used in a scalar context in this case.
+ -- an error: exactly one column is expected in a scalar context
+```
+
+A correct notation in this case is:
+
+```yql
+DEFINE SUBQUERY $dict() AS
+SELECT key, value FROM T1;
+END DEFINE;
+
+DEFINE SUBQUERY $merge_dict($table, $dict) AS
+SELECT * FROM $table LEFT JOIN $dict() USING(key); -- Using the table expression $dict()
+ -- (Calling a subquery template) in a table context
+END DEFINE;
+
+SELECT * FROM $merge_dict("Input", $dict); -- $dict - is a subquery template (rather than a table expression)
+ -- that is passed as an argument of a table expression
+```
+
+{% endnote %}
+
+## Lambda functions {#lambda}
+
+Let you combine multiple expressions into a single callable value.
+
+List arguments in round brackets, following them by the arrow and lambda function body. The lambda function body includes either an expression in round brackets or curly brackets around an optional chain of [named expressions](#named-nodes) assignments and the call result after the `RETURN` keyword in the last expression.
+
+The scope for the lambda body: first the local named expressions, then arguments, then named expressions defined above by the lambda function at the top level of the query.
+
+Only use pure expressions inside the lambda body (those might also be other lambdas, possibly passed through arguments). However, you can't use [SELECT](select/index.md), [INSERT INTO](insert_into.md), or other top-level expressions.
+
+One or more of the last lambda parameters can be marked with a question mark as optional: if they haven't been specified when calling lambda, they are assigned the `NULL` value.
+
+### Examples
+
+```yql
+$f = ($y) -> {
+ $prefix = "x";
+ RETURN $prefix || $y;
+};
+
+$g = ($y) -> ("x" || $y);
+
+$h = ($x, $y?) -> ($x + ($y ?? 0));
+
+SELECT $f("y"), $g("z"), $h(1), $h(2, 3); -- "xy", "xz", 1, 5
+```
+
+```yql
+-- if the lambda result is calculated by a single expression, then you can use a more compact syntax:
+$f = ($x, $_) -> ($x || "suffix"); -- the second argument is not used
+SELECT $f("prefix_", "whatever");
+```
+
+
+
+## Accessing containers {#items-access}
+
+For accessing the values inside containers:
+
+* `Struct<>`, `Tuple<>` and `Variant<>`, use a **dot**. The set of keys (for the tuple and the corresponding variant — indexes) is known at the query compilation time. The key is **validated** before beginning the query execution.
+* `List<>` and `Dict<>`, use **square brackets**. The set of keys (set of indexes for keys) is known only at the query execution time. The key is **not validated** before beginning the query execution. If no value is found, an empty value (NULL) is returned.
+
+[Description and list of available containers](../types/containers.md).
+
+When using this syntax to access containers within table columns, be sure to specify the full column name, including the table name or table alias separated by a dot (see the first example below).
+
+### Examples
+
+```yql
+SELECT
+ t.struct.member,
+ t.tuple.7,
+ t.dict["key"],
+ t.list[7]
+FROM my_table AS t;
+```
+
+```yql
+SELECT
+ Sample::ReturnsStruct().member;
+```
+
+
+
diff --git a/yql/essentials/docs/en/syntax/flatten.md b/yql/essentials/docs/en/syntax/flatten.md
new file mode 100644
index 0000000000..b99f59ef49
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/flatten.md
@@ -0,0 +1,145 @@
+# FLATTEN
+
+## FLATTEN BY {#flatten-by}
+
+Converts rows in the source table using vertical unpacking of [containers](../types/containers.md) of variable length (lists or dictionaries).
+
+For example:
+
+* Source table:
+
+ |[a, b, c]|1|
+ | --- | --- |
+ |[d]|2|
+ |[]|3|
+
+* The table resulting from `FLATTEN BY` on the left column:
+
+ |a|1|
+ | --- | --- |
+ |b|1|
+ |c|1|
+ |d|2|
+
+
+### Example
+
+```yql
+$sample = AsList(
+ AsStruct(AsList('a','b','c') AS value, CAST(1 AS Uint32) AS id),
+ AsStruct(AsList('d') AS value, CAST(2 AS Uint32) AS id),
+ AsStruct(AsList() AS value, CAST(3 AS Uint32) AS id)
+);
+
+SELECT value, id FROM as_table($sample) FLATTEN BY (value);
+```
+
+This conversion can be convenient in the following cases:
+
+* When it is necessary to output statistics by cells from a container column (for example, via [`GROUP BY`](group_by.md)).
+
+* When the cells in a container column store IDs from another table that you want to join with [`JOIN`](join.md).
+
+### Syntax
+
+* `FLATTEN BY` is specified after `FROM`, but before `GROUP BY`, if `GROUP BY` is present in the query.
+* The type of the result column depends on the type of the source column:
+
+| Container type | Result type | Comments |
+| --- | --- | --- |
+| `List<X>` | `X` | List cell type |
+| `Dict<X,Y>` | `Tuple<X,Y>` | Tuple of two elements containing key-value pairs |
+| `Optional<X>` | `X` | The result is almost equivalent to the clause `WHERE foo IS NOT NULL`, but the `foo` column type is changed to `X` |
+
+* By default, the result column replaces the source column. Use `FLATTEN BY foo AS bar` to keep the source container. As a result, the source container is still available as `foo` and the output container is available as `bar`.
+* To build a Cartesian product of multiple container columns, use the clause `FLATTEN BY (a, b, c)`. Parentheses are mandatory to avoid grammar conflicts.
+* Inside `FLATTEN BY`, you can only use column names from the input table. To apply `FLATTEN BY` to the calculation result, use a subquery.
+* In `FLATTEN BY` you can use both columns and arbitrary named expressions (unlike columns, `AS` is required in this case). To avoid grammatical ambiguities of the expression after `FLATTEN BY`, make sure to use parentheses with the following: `... FLATTEN BY (ListSkip(col, 1) AS col) ...`
+* If the source column had nested containers, for example, `List<DictX,Y>`, `FLATTEN BY` unpacks only the outer level. To completely unpack the nested containers, use a subquery.
+
+{% note info %}
+
+`FLATTEN BY` interprets [optional data types](../types/optional.md) as lists of length 0 or 1. The table rows with `NULL` are skipped, and the column type changes to a similar non-optional type.
+
+`FLATTEN BY` makes only one conversion at a time, so use `FLATTEN LIST BY` or `FLATTEN OPTIONAL BY` on optional containers, for example, `Optional<List<String>>`.
+
+{% endnote %}
+
+
+
+### Specifying the container type {#flatten-by-specific-type}
+
+To specify the type of container to convert to, you can use:
+
+* `FLATTEN LIST BY`
+
+ For `Optional<List<T>>`, `FLATTEN LIST BY` will unpack the list, treating `NULL` as an empty list.
+
+* `FLATTEN DICT BY`
+
+ For `Optional<Dict<T>>`, `FLATTEN DICT BY` will unpack the dictionary, interpreting `NULL` as an empty dictionary.
+
+* `FLATTEN OPTIONAL BY`
+
+ To filter the `NULL` values without serialization, specify the operation by using `FLATTEN OPTIONAL BY`.
+
+### Examples
+
+```yql
+SELECT
+ t.item.0 AS key,
+ t.item.1 AS value,
+ t.dict_column AS original_dict,
+ t.other_column AS other
+FROM my_table AS t
+FLATTEN DICT BY dict_column AS item;
+```
+
+```yql
+SELECT * FROM (
+ SELECT
+ AsList(1, 2, 3) AS a,
+ AsList("x", "y", "z") AS b
+) FLATTEN LIST BY (a, b);
+```
+
+```yql
+SELECT * FROM (
+ SELECT
+ "1;2;3" AS a,
+ AsList("x", "y", "z") AS b
+) FLATTEN LIST BY (String::SplitToList(a, ";") as a, b);
+```
+
+
+
+### Analogues of FLATTEN BY in other DBMS {#flatten-other-dmb}
+
+* PostgreSQL: `unnest`
+* Hive: `LATERAL VIEW`
+* MongoDB: `unwind`
+* Google BigQuery: `FLATTEN`
+* ClickHouse: `ARRAY JOIN / arrayJoin`
+
+
+
+## FLATTEN COLUMNS {#flatten-columns}
+
+Converts a table where all columns must be structures to a table with columns corresponding to each element of each structure from the source columns.
+
+The names of the source column structures are not used and not returned in the result. Be sure that the structure element names aren't repeated in the source columns.
+
+### Example
+
+```yql
+SELECT x, y, z
+FROM (
+ SELECT
+ AsStruct(
+ 1 AS x,
+ "foo" AS y),
+ AsStruct(
+ false AS z)
+) FLATTEN COLUMNS;
+```
+
diff --git a/yql/essentials/docs/en/syntax/group_by.md b/yql/essentials/docs/en/syntax/group_by.md
new file mode 100644
index 0000000000..5740cc6380
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/group_by.md
@@ -0,0 +1,267 @@
+## GROUP BY
+
+Group the `SELECT` results by the values of the specified columns or expressions. `GROUP BY` is often combined with [aggregate functions](../builtins/aggregation.md) (`COUNT`, `MAX`, `MIN`, `SUM`, `AVG`) to perform calculations in each group.
+
+### Syntax
+
+```yql
+SELECT -- In SELECT, you can use:
+ column1, -- key columns specified in GROUP BY
+ key_n, -- named expressions specified in GROUP BY
+ column1 + key_n, -- arbitrary non-aggregate functions on them
+ Aggr_Func1( column2 ), -- aggregate functions containing any columns as arguments,
+ Aggr_Func2( key_n + column2 ), -- including named expressions specified in GROUP BY
+ ...
+FROM table
+GROUP BY
+ column1, column2, ...,
+ <expr> AS key_n -- When grouping by expression, you can set a name for it using AS,
+ -- and use it in SELECT
+```
+
+The query in the format `SELECT * FROM table GROUP BY k1, k2, ...` returns all columns listed in GROUP BY, i.e., is equivalent to `SELECT DISTINCT k1, k2, ... FROM table`.
+
+An asterisk can also be used as an argument for the `COUNT` aggregate function. `COUNT(*)` means "the count of rows in the group".
+
+{% note info %}
+
+Aggregate functions ignore `NULL` in their arguments, except for `COUNT`.
+
+{% endnote %}
+
+YQL also provides aggregation factories implemented by the functions [`AGGREGATION_FACTORY`](../builtins/basic.md#aggregationfactory) and [`AGGREGATE_BY`](../builtins/aggregation.md#aggregateby).
+
+### Examples
+
+```yql
+SELECT key, COUNT(*) FROM my_table
+GROUP BY key;
+```
+
+```yql
+SELECT double_key, COUNT(*) FROM my_table
+GROUP BY key + key AS double_key;
+```
+
+```yql
+SELECT
+ double_key, -- OK: A key column
+ COUNT(*) AS group_size, -- OK: COUNT(*)
+ SUM(key + subkey) AS sum1, -- OK: An aggregate function
+ CAST(SUM(1 + 2) AS String) AS sum2, -- OK: An aggregate function with a constant argument
+ SUM(SUM(1) + key) AS sum3, -- ERROR: Nested aggregations are not allowed
+ key AS k1, -- ERROR: Using a non-key column named key without aggregation
+ key * 2 AS dk1, -- ERROR in YQL: using a non-key column named key without aggregation
+FROM my_table
+GROUP BY
+ key * 2 AS double_key,
+ subkey as sk,
+```
+
+{% note warning %}
+
+Specifying a name for a column or expression in `GROUP BY .. AS foo` it is an extension on top of YQL. Such a name becomes visible in `WHERE` despite the fact that filtering by `WHERE` is executed [before](select/where.md) the grouping. For example, if the `T` table includes two columns, `foo` and `bar`, then the query `SELECT foo FROM T WHERE foo > 0 GROUP BY bar AS foo` would actually filter data by the `bar` column from the source table.
+
+{% endnote %}
+
+
+
+## GROUP BY ... SessionWindow() {#session-window}
+
+YQL supports grouping by session. To standard expressions in `GROUP BY`, you can add a special `SessionWindow` function:
+
+```yql
+SELECT
+ user,
+ session_start,
+ SessionStart() AS same_session_start, -- It's same as session_start
+ COUNT(*) AS session_size,
+ SUM(value) AS sum_over_session,
+FROM my_table
+GROUP BY user, SessionWindow(<time_expr>, <timeout_expr>) AS session_start
+```
+
+The following happens in this case:
+
+1. The input table is partitioned by the grouping keys specified in `GROUP BY`, ignoring SessionWindow (in this case, it's based on `user`).
+
+ If `GROUP BY` includes nothing more than SessionWindow, then the input table gets into one partition.
+
+2. Each partition is split into disjoint subsets of rows (sessions).
+
+ For this, the partition is sorted in the ascending order of the `time_expr` expression.
+ The session limits are drawn between neighboring items of the partition, that differ in their `time_expr` values by more than `timeout_expr`.
+
+3. The sessions obtained in this way are the final partitions on which aggregate functions are calculated.
+
+The `SessionWindow()` key column (in the example, it's `session_start`) has the value "the minimum `time_expr` in the session".
+If `GROUP BY` includes SessionWindow(), you can use a special aggregate function
+[SessionStart](../builtins/aggregation.md#session-start).
+
+An extended version of SessionWindow with four arguments is also supported:
+
+`SessionWindow(<order_expr>, <init_lambda>, <update_lambda>, <calculate_lambda>)`
+
+Where:
+
+* `<order_expr>`: An expression used to sort the source partition
+* `<init_lambda>`: A lambda function to initialize the state of session calculation. It has the signature `(TableRow())->State`. It's called once for the first (following the sorting order) element of the source partition
+* `<update_lambda>`: A lambda function to update the status of session calculation and define the session limits. It has the signature `(TableRow(), State)->Tuple<Bool, State>`. It's called for every item of the source partition, except the first one. The new value of state is calculated based on the current row of the table and the previous state. If the first item in the return tuple is `True`, then a new session starts from the _current_ row. The key of the new session is obtained by applying `<calculate_lambda>` to the second item in the tuple.
+* `<calculate_lambda>`: A lambda function for calculating the session key (the "value" of SessionWindow() that is also accessible via SessionStart()). The function has the signature `(TableRow(), State)->SessionKey`. It's called for the first item in the partition (after `<init_lambda>`) and those items for which `<update_lambda>` has returned `True` in the first item in the tuple. Please note that to start a new session, you should make sure that `<calculate_lambda>` has returned a value different from the previous session key. Sessions having the same keys are not merged. For example, if `<calculate_lambda>` returns the sequence `0, 1, 0, 1`, then there will be four different sessions.
+
+Using the extended version of SessionWindow, you can, for example, do the following: divide a partition into sessions, as in the SessionWindow use case with two arguments, but with the maximum session length limited by a certain constant:
+
+### Example
+
+```yql
+$max_len = 1000; -- is the maximum session length.
+$timeout = 100; -- is the timeout (timeout_expr in a simplified version of SessionWindow).
+
+$init = ($row) -> (AsTuple($row.ts, $row.ts)); -- is the session status: tuple from 1) value of the temporary column ts in the session's first line and 2) in the current line
+$update = ($row, $state) -> {
+ $is_end_session = $row.ts - $state.0 > $max_len OR $row.ts - $state.1 > $timeout;
+ $new_state = AsTuple(IF($is_end_session, $row.ts, $state.0), $row.ts);
+ return AsTuple($is_end_session, $new_state);
+};
+$calculate = ($row, $state) -> ($row.ts);
+SELECT
+ user,
+ session_start,
+ SessionStart() AS same_session_start, -- It's same as session_start
+ COUNT(*) AS session_size,
+ SUM(value) AS sum_over_session,
+FROM my_table
+GROUP BY user, SessionWindow(ts, $init, $update, $calculate) AS session_start
+```
+
+You can use `SessionWindow` in `GROUP BY` only once.
+
+## ROLLUP, CUBE, and GROUPING SETS {#rollup}
+
+The results of calculating the aggregate function as subtotals for the groups and overall totals over individual columns or whole table.
+
+### Syntax
+
+```yql
+SELECT
+ c1, c2, -- the columns to group by
+
+AGGREGATE_FUNCTION(c3) AS outcome_c -- an aggregate function (SUM, AVG, MIN, MAX, COUNT)
+
+FROM table_name
+
+GROUP BY
+ GROUP_BY_EXTENSION(c1, c2) -- an extension of GROUP BY: ROLLUP, CUBE, or GROUPING SETS
+```
+
+* `ROLLUP` groups the column values in the order they are listed in the arguments (strictly from left to right), generates subtotals for each group and the overall total.
+* `CUBE` groups the values for every possible combination of columns, generates the subtotals for each group and the overall total.
+* `GROUPING SETS` sets the groups for subtotals.
+
+You can combine `ROLLUP`, `CUBE` and `GROUPING SETS`, separating them by commas.
+
+### GROUPING {#grouping}
+
+The values of columns not used in calculations are replaced with `NULL` in the subtotal. In the overall total, the values of all columns are replaced by `NULL`. `GROUPING`: A function that allows you to distinguish the source `NULL` values from the `NULL` values added while calculating subtotals and overall totals.
+
+`GROUPING` returns a bit mask:
+
+* `0`: If `NULL` is used for the original empty value.
+* `1`: If `NULL` is added for a subtotal or overall total.
+
+### Example
+
+```yql
+SELECT
+ column1,
+ column2,
+ column3,
+
+ CASE GROUPING(
+ column1,
+ column2,
+ column3,
+ )
+ WHEN 1 THEN "Subtotal: column1 and column2"
+ WHEN 3 THEN "Subtotal: column1"
+ WHEN 4 THEN "Subtotal: column2 and column3"
+ WHEN 6 THEN "Subtotal: column3"
+ WHEN 7 THEN "Grand total"
+ ELSE "Individual group"
+ END AS subtotal,
+
+ COUNT(*) AS rows_count
+
+FROM my_table
+
+GROUP BY
+ ROLLUP(
+ column1,
+ column2,
+ column3
+ ),
+ GROUPING SETS(
+ (column2, column3),
+ (column3)
+ -- if you add here (column2) as well, then together
+ -- the ROLLUP and GROUPING SETS would produce a result
+ -- similar to CUBE
+ )
+;
+```
+
+## DISTINCT {#distinct}
+
+Applying [aggregate functions](../builtins/aggregation.md) only to distinct values of the column.
+
+{% note info %}
+
+Applying `DISTINCT` to calculated values is not currently implemented. For this purpose, you can use a [subquery](select/from.md) or the expression `GROUP BY ... AS ...`.
+
+{% endnote %}
+
+### Example
+
+```yql
+SELECT
+ key,
+ COUNT (DISTINCT value) AS count -- top 3 keys by the number of unique values
+FROM my_table
+GROUP BY key
+ORDER BY count DESC
+LIMIT 3;
+```
+
+You can also use `DISTINCT` to fetch distinct rows using [`SELECT DISTINCT`](select/distinct.md).
+
+## GROUP COMPACT BY
+
+Improves aggregation efficiency if the query author knows in advance that none of aggregation keys finds large amounts of data (i.e., with the order of magnitude exceeding a gigabyte or a million of rows). If this assumption fails to materialize, then the operation may fail with Out of Memory error or start running much slower compared to the non-COMPACT version.
+
+Unlike the usual GROUP BY, the Map-side combiner stage and additional Reduce are disabled for each field with [DISTINCT](../syntax/group_by.md#distinct) aggregation.
+
+### Example
+
+```yql
+SELECT
+ key,
+ COUNT (DISTINCT value) AS count -- top 3 keys by the number of unique values
+FROM my_table
+GROUP COMPACT BY key
+ORDER BY count DESC
+LIMIT 3;
+```
+
+## HAVING {#having}
+
+Filtering a `SELECT` based on the calculation results of [aggregate functions](../builtins/aggregation.md). The syntax is similar to [WHERE](select/where.md).
+
+### Example
+
+```yql
+SELECT
+ key
+FROM my_table
+GROUP BY key
+HAVING COUNT(value) > 100;
+```
diff --git a/yql/essentials/docs/en/syntax/index.md b/yql/essentials/docs/en/syntax/index.md
new file mode 100644
index 0000000000..cd9ca6d592
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/index.md
@@ -0,0 +1,22 @@
+# List of articles on YQL syntax
+
+* [Lexical structure](lexer.md)
+* [Expressions](expressions.md)
+* [ACTION](action.md)
+* [COMMIT](commit.md)
+* [DECLARE](declare.md)
+* [DISCARD](discard.md)
+* [EXPORT and IMPORT](export_import.md)
+* [FLATTEN](flatten.md)
+* [GROUP BY](group_by.md)
+* [INSERT](insert_into.md)
+* [INTO RESULT](into_result.md)
+* [JOIN](join.md)
+* [PRAGMA](pragma.md)
+* [PROCESS](process.md)
+* [REDUCE](reduce.md)
+* [SELECT](select/index.md)
+* [SUBQUERY](subquery.md)
+* [USE](use.md)
+* [VALUES](values.md)
+* [WINDOW](window.md)
diff --git a/yql/essentials/docs/en/syntax/insert_into.md b/yql/essentials/docs/en/syntax/insert_into.md
new file mode 100644
index 0000000000..36b1287cdd
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/insert_into.md
@@ -0,0 +1,33 @@
+# INSERT INTO
+
+Adds rows to the table.
+
+The table is searched by name in the database specified by the [USE](use.md) operator.
+
+`INSERT INTO` lets you perform the following operations:
+
+* Adding constant values using [`VALUES`](values.md).
+
+ ```yql
+ INSERT INTO my_table (Key1, Key2, Value1, Value2)
+ VALUES (345987,'ydb', 'Pied piper', 1414);
+ COMMIT;
+ ```
+
+ ```yql
+ INSERT INTO my_table (key, value)
+ VALUES ("foo", 1), ("bar", 2);
+ ```
+
+* Saving the `SELECT` result.
+
+ ```yql
+ INSERT INTO my_table
+ SELECT Key AS Key1, "Empty" AS Key2, Value AS Value1
+ FROM my_table1;
+ ```
+
+Inserts can be made with one or more modifiers. A modifier is specified after the `WITH` keyword following the table name: `INSERT INTO ... WITH SOME_HINT`.
+If a modifier has a value, it's indicated after the `=` sign: `INSERT INTO ... WITH SOME_HINT=value`.
+If necessary, specify multiple modifiers, they should be enclosed in parentheses: `INSERT INTO ... WITH (SOME_HINT1=value, SOME_HINT2, SOME_HINT3=value)`.
+
diff --git a/yql/essentials/docs/en/syntax/into_result.md b/yql/essentials/docs/en/syntax/into_result.md
new file mode 100644
index 0000000000..bb79ec7dae
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/into_result.md
@@ -0,0 +1,16 @@
+# INTO RESULT
+
+Lets you set a custom label for [SELECT](select/index.md), [PROCESS](process.md), or [REDUCE](reduce.md). It can't be used along with [DISCARD](discard.md).
+
+## Examples
+
+```yql
+SELECT 1 INTO RESULT foo;
+```
+
+```yql
+SELECT * FROM
+my_table
+WHERE value % 2 == 0
+INTO RESULT `Result name`;
+```
diff --git a/yql/essentials/docs/en/syntax/join.md b/yql/essentials/docs/en/syntax/join.md
new file mode 100644
index 0000000000..14ec1ce566
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/join.md
@@ -0,0 +1,143 @@
+# JOIN
+
+It lets you combine multiple data sources (subqueries or tables) by equality of values in the specified columns or expressions (the `JOIN` keys).
+
+## Syntax
+
+```yql
+SELECT ... FROM table_1
+-- first JOIN step:
+ <Join_Type> JOIN table_2 <Join_Condition>
+ -- left subquery -- entries in table_1
+ -- right subquery -- entries in table_2
+-- next JOIN step:
+ <Join_Type> JOIN table_n <Join_Condition>
+ -- left subquery -- JOIN result in the previous step
+ -- right subquery -- entries in table_n
+-- JOIN can include the following steps
+...
+WHERE ...
+```
+
+At each JOIN step, rules are used to establish correspondences between rows in the left and right data subqueries, creating a new subquery that includes every combination of rows that meet the JOIN conditions.
+
+{% note warning "Attention!" %}
+
+Since columns in YQL are identified by their names, and you can't have two columns with the same name in the subquery, `SELECT * FROM ... JOIN ...` can't be executed if there are columns with identical names in the joined tables.
+
+{% endnote %}
+
+## Types of join
+
+* `INNER` <span style="color: gray;">(default)</span>: Rows from joined subqueries that don't match any rows on the other side won't be included in the result.
+* `LEFT`: If there's no value in the right subquery, it adds a row to the result with column values from the left subquery, using `NULL` in columns from the right subquery
+* `RIGHT`: If there's no value in the left subquery, it adds the row to the result, including column values from the right subquery, but using `NULL` in columns from the left subquery
+* `FULL` = `LEFT` + `RIGHT`
+* `LEFT/RIGHT SEMI`: One side of the subquery is a whitelist of keys, its values are not available. The result includes columns from one table only, no Cartesian product is created.
+* `LEFT/RIGHT ONLY`: Subtracting the sets by keys (blacklist). It's almost the same as adding `IS NULL` to the key on the opposite side in the regular `LEFT/RIGHT` JOIN, but with no access to values: the same as `SEMI` JOIN.
+* `CROSS`: A full Cartesian product of two tables without specifying key columns and no explicit `ON/USING`.
+* `EXCLUSION`: Both sides minus the intersection.
+
+![JOIN](_assets/join-YQL-06.png)
+
+{% note info %}
+
+`NULL` is a special value to denote nothing. Hence, `NULL` values on both sides are not treated as equal to each other. This eliminates ambiguity in some types of `JOIN` and avoids a giant Cartesian product otherwise created.
+
+{% endnote %}
+
+## Conditions for joining
+
+For `CROSS JOIN`, no join condition is specified. The result includes the Cartesian product of the left and right subquery, meaning it combines everything with everything. The number of rows in the resulting subquery is the product of the number of rows in the left and right subqueries.
+
+For any other JOIN types, specify the condition using one of the two methods:
+
+1. `USING (column_name)`. Used if both the left and right subqueries share a column whose equality of values is a join condition.
+2. `ON (equality_conditions)`. Lets you set a condition of equality for column values or expressions over columns in the left and right subqueries or use several such conditions combined by `and`.
+
+### Examples
+
+```yql
+SELECT a.value as a_value, b.value as b_value
+FROM a_table AS a
+FULL JOIN b_table AS b USING (key);
+```
+
+```yql
+SELECT a.value as a_value, b.value as b_value
+FROM a_table AS a
+FULL JOIN b_table AS b ON a.key = b.key;
+```
+
+```yql
+SELECT a.value as a_value, b.value as b_value, c.column2
+FROM a_table AS a
+CROSS JOIN b_table AS b
+LEFT JOIN c_table AS c ON c.ref = a.key and c.column1 = b.value;
+```
+
+To make sure no full scan of the right joined table is required, a secondary index can be applied to the columns included in the Join condition. Accessing a secondary index should be specified explicitly in `JOIN table_name VIEW index_name AS table_alias` format.
+
+For example, creating an index to use in the Join condition:
+
+```yql
+ALTER TABLE b_table ADD INDEX b_index_ref GLOBAL ON(ref);
+```
+
+Using the created index:
+
+```yql
+SELECT a.value as a_value, b.value as b_value
+FROM a_table AS a
+INNER JOIN b_table VIEW b_index_ref AS b ON a.ref = b.ref;
+```
+
+If the statement filters data in addition to `JOIN`, we recommend wrapping the criteria that would return `true` for most of the rows in the `LIKELY(...)` function call. If your assumption that positive values prevail for the criteria is correct, such a hint might speed up your subquery. `LIKELY` can be useful when the predicate calculation is a resource-intensive operation and JOIN significantly reduces the number of rows.
+
+In front of any data source for `JOIN`, you can add the `ANY` keyword to suppress duplicate `JOIN` keys on the given side. In this case, only one row is left from the set of rows with the same `JOIN` key value (no matter which one, that's why the keyword is called `ANY`).
+This syntax is different from that used in [ClickHouse](https://clickhouse.com/docs/en/sql-reference/statements/select/join/), where `ANY` is placed before the `JOIN` type and applies to the right side only.
+
+Query:
+
+```yql
+$t1 = AsList(
+ AsStruct("1" AS key, "v111" AS value),
+ AsStruct("2" AS key, "v121" AS value),
+ AsStruct("2" AS key, "v122" AS value),
+ AsStruct("3" AS key, "v131" AS value),
+ AsStruct("3" AS key, "v132" AS value));
+
+$t2 = AsList(
+ AsStruct("2" AS key, "v221" AS value),
+ AsStruct("2" AS key, "v222" AS value),
+ AsStruct("3" AS key, "v231" AS value),
+ AsStruct("3" AS key, "v232" AS value),
+ AsStruct("4" AS key, "v241" AS value));
+
+SELECT
+ a.key, a.value, b.value
+FROM ANY AS_TABLE($t1) AS a
+JOIN ANY AS_TABLE($t2) AS b
+ON a.key == b.key;
+```
+
+results in:
+
+| a.key | a.value | b.value |
+| --- | --- | --- |
+| "3" | "v131" | "v231" |
+| "2" | "v121" | "v221" |
+
+and without `ANY` it would result in:
+
+| a.key | a.value | b.value |
+| --- | --- | --- |
+| "3" | "v131" | "v231" |
+| "3" | "v131" | "v232" |
+| "3" | "v132" | "v231" |
+| "3" | "v132" | "v232" |
+| "2" | "v121" | "v221" |
+| "2" | "v121" | "v222" |
+| "2" | "v122" | "v221" |
+| "2" | "v122" | "v222" |
+
diff --git a/yql/essentials/docs/en/syntax/lexer.md b/yql/essentials/docs/en/syntax/lexer.md
new file mode 100644
index 0000000000..9e57b15d64
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/lexer.md
@@ -0,0 +1,235 @@
+
+# Lexical structure
+
+The query in the YQL language is a valid UTF-8 text consisting of **statements** separated by semicolons (`;`).
+The last semicolon can be omitted.
+Each command is a sequence of **tokens** that are valid for this command.
+Tokens can be **keywords**, **identifiers**, **literals**, and so on.
+Tokens are separated by whitespace characters (space, tab, line feed) or **comments**. The comment is not a part of the command and is syntactically equivalent to a space character.
+
+## Syntax compatibility modes {#lexer-modes}
+
+Two syntax compatibility modes are supported:
+
+* Advanced C++ (default)
+* ANSI SQL
+
+ANSI SQL mode is enabled with a special comment `--!ansi_lexer`, which must be in the beginning of the query.
+
+Specifics of interpretation of lexical elements in different compatibility modes are described below.
+
+## Comments {#comments}
+
+The following types of comments are supported:
+
+* Single-line comment: starts with `--` (two minus characters following one another) and continues to the end of the line
+* Multiline comment: starts with `/*` and ends with `*/`
+
+```yql
+SELECT 1; -- A single-line comment
+/*
+ Some multi-line comment
+*/
+```
+
+In C++ syntax compatibility mode (default), a multiline comment ends with the **nearest** `*/`.
+The ANSI SQL syntax compatibility mode accounts for nesting of multiline comments:
+
+```yql
+--!ansi_lexer
+SELECT * FROM T; /* this is a comment /* this is a nested comment, without ansi_lexer it raises an error */ */
+```
+
+## Keywords and identifiers {#keywords-and-ids}
+
+**Keywords** are tokens that have a fixed value in the YQL language. Examples of keywords: `SELECT`, `INSERT`, `FROM`, `ACTION`, and so on. Keywords are case-insensitive, that is, `SELECT` and `SeLEcT` are equivalent to each other.
+The list of keywords is not fixed and is going to expand as the language develops. A keyword can't contain numbers and begin or end with an underscore.
+
+**Identifiers** are tokens that identify the names of tables, columns, and other objects in YQL. Identifiers in YQL are always case-sensitive.
+An identifier can be written in the body of the program without any special formatting, if the identifier:
+
+* Is not a keyword
+* Begins with a Latin letter or underscore
+* Is followed by a Latin letter, an underscore, or a number
+
+```yql
+SELECT my_column FROM my_table; -- my_column and my_table are identifiers
+```
+
+To include an arbitrary ID in the body of a query, the ID is enclosed in backticks:
+
+```yql
+SELECT `column with space` from T;
+SELECT * FROM `my_dir/my_table`
+```
+
+IDs in backticks are never interpreted as keywords:
+
+```yql
+SELECT `select` FROM T; -- select - Column name in the T table
+```
+
+When using backticks, you can use the standard C escaping:
+
+```yql
+SELECT 1 as `column with\n newline, \x0a newline and \` backtick `;
+```
+
+In ANSI SQL syntax compatibility mode, arbitrary IDs can also be enclosed in double quotes. To include a double quote in a quoted ID, use two double quotes:
+
+```yql
+--!ansi_lexer
+SELECT 1 as "column with "" double quote"; -- column name will be: column with " double quote
+```
+
+## SQL hints {#sql-hints}
+
+SQL hints are special settings with which a user can modify a query execution plan
+(for example, enable/disable specific optimizations or force the JOIN execution strategy).
+Unlike [PRAGMA](pragma.md), SQL hints act locally – they are linked to a specific point in the YQL query (normally, after the keyword)
+and affect only the corresponding statement or even a part of it.
+SQL hints are a set of settings "name-value list" and defined inside special comments —
+comments with SQL hints must have `+` as the first character:
+
+```yql
+--+ Name1(Value1 Value2 Value3) Name2(Value4) ...
+```
+
+An SQL hint name must be comprised of ASCII alphanumeric characters and start with a letter. Hint names are case insensitive.
+A hint name must be followed by a custom number of space-separated values. A value can be a custom set of characters.
+If there's a space or parenthesis in a set of characters, single quotation marks must be used:
+
+```yql
+--+ foo('value with space and paren)')
+```
+
+```yql
+--+ foo('value1' value2)
+-- equivalent to
+--+ foo(value1 value2)
+```
+
+To escape a single quotation within a value, double it:
+
+```yql
+--+ foo('value with single quote '' inside')
+```
+
+If there're two or more hints with the same name in the list, the latter is used:
+
+```yql
+--+ foo(v1 v2) bar(v3) foo()
+-- equivalent to
+--+ bar(v3) foo()
+```
+
+Unknown SQL hint names (or syntactically incorrect hints) never result in errors, they're simply ignored:
+
+```yql
+--+ foo(value1) bar(value2 baz(value3)
+-- due to a missing closing parenthesis in bar, is equivalent to
+--+ foo(value1)
+```
+
+Thanks to this behavior, previous valid YQL queries with comments that look like hints remain intact.
+Syntactically correct SQL hints in a place unexpected for YQL result in a warning:
+
+```yql
+-- presently, hints after SELECT are not supported
+SELECT /*+ foo(123) */ 1; -- warning 'Hint foo will not be used'
+```
+
+What's important is that SQL hints are hints for an optimizer, so:
+
+* Hints never affect search results.
+* As YQL optimizers improve, a situation is possible when a hint becomes outdated and is ignored (for example, the algorithm based on a given hint completely changes or the optimizer becomes so sophisticated that it can be expected to choose the best solution, so some manual settings are likely to interfere).
+
+## String literals {#string-literals}
+
+A string literal (constant) is expressed as a sequence of characters enclosed in single quotes. Inside a string literal, you can use the C-style escaping rules:
+
+```yql
+SELECT 'string with\n newline, \x0a newline and \' backtick ';
+```
+
+In the C++ syntax compatibility mode (default), you can use double quotes instead of single quotes:
+
+```yql
+SELECT "string with\n newline, \x0a newline and \" backtick ";
+```
+
+In ASNI SQL compatibility mode, double quotes are used for IDs, and the only escaping that can be used for string literals is a pair of single quotes:
+
+```yql
+--!ansi_lexer
+SELECT 'string with '' quote'; -- result: string with ' quote
+```
+
+Based on string literals, [simple literals](builtins/basic#data-type-literals) can be obtained.
+
+### Multi-line string literals {#multiline-string-literals}
+
+A multiline string literal is expressed as an arbitrary set of characters enclosed in double at signs `@@`:
+
+```yql
+$text = @@some
+multiline
+text@@;
+SELECT LENGTH($text);
+```
+
+If you need to use double at signs in your text, duplicate them:
+
+```yql
+$text = @@some
+multiline with double at: @@@@
+text@@;
+SELECT $text;
+```
+
+### Typed string literals {#typed-string-literals}
+
+* For string literals, including [multi-string](#multiline-string-literals) ones, the `String` type is used by default (see also [PRAGMA UnicodeLiterals](pragma.md#UnicodeLiterals)).
+* You can use the following suffixes to explicitly control the literal type:
+
+ * `s` — `String`
+ * `u` — `Utf8`
+ * `y` — `Yson`
+ * `j` — `Json`
+
+#### Example
+
+```yql
+SELECT "foo"u, '[1;2]'y, @@{"a":null}@@j;
+```
+
+## Numeric literals {#literal-numbers}
+
+* Integer literals have the default type `Int32`, if they fit within the Int32 range. Otherwise, they automatically expand to `Int64`.
+* You can use the following suffixes to explicitly control the literal type:
+
+ * `l`: `Int64`
+ * `s`: `Int16`
+ * `t`: `Int8`
+
+* Add the suffix `u` to convert a type to its corresponding unsigned type:
+
+ * `ul`: `Uint64`
+ * `u`: `Uint32`
+ * `us`: `Uint16`
+ * `ut`: `Uint8`
+
+* You can also use hexadecimal, octal, and binary format for integer literals using the prefixes `0x`, `0o` and `0b`, respectively. You can arbitrarily combine them with the above-mentioned suffixes.
+* Floating point literals have the `Double` type by default, but you can use the suffix `f` to narrow it down to `Float`.
+
+```yql
+SELECT
+ 123l AS `Int64`,
+ 0b01u AS `Uint32`,
+ 0xfful AS `Uint64`,
+ 0o7ut AS `Uint8`,
+ 456s AS `Int16`,
+ 1.2345f AS `Float`;
+```
+
+
diff --git a/yql/essentials/docs/en/syntax/not_yet_supported.md b/yql/essentials/docs/en/syntax/not_yet_supported.md
new file mode 100644
index 0000000000..f6ebbc1d59
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/not_yet_supported.md
@@ -0,0 +1,14 @@
+# Classic SQL constructs not supported yet
+
+## \[NOT\] \[EXISTS|INTERSECT\|EXCEPT] {#not-exists}
+
+A syntactically available alternative is `EXISTS`, but it's not very useful as it doesn't support correlated subqueries. You can also rewrite it using `JOIN`.
+
+## NATURAL JOIN {#natural-join}
+
+An alternative is to explicitly list the matching columns on both sides.
+
+## NOW() / CURRENT_TIME() {#now}
+
+An alternative is to use the functions [CurrentUtcDate, CurrentUtcDatetime and CurrentUtcTimestamp](../builtins/basic.md#current-utc).
+
diff --git a/yql/essentials/docs/en/syntax/pragma.md b/yql/essentials/docs/en/syntax/pragma.md
new file mode 100644
index 0000000000..afbfe50227
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/pragma.md
@@ -0,0 +1,421 @@
+# PRAGMA
+
+## Definition
+
+Redefinition of settings.
+
+### Syntax
+
+`PRAGMA x.y = "z";` or `PRAGMA x.y("z", "z2", "z3");`:
+
+* `x`: (optional) The category of the setting.
+* `y`: The name of the setting.
+* `z`: (optional for flags) The value of the setting. The following suffixes are acceptable:
+
+ * `Kb`, `Mb`, `Gb`: For the data amounts.
+ * `sec`, `min`, `h`, `d`: For the time values.
+
+### Examples
+
+```yql
+PRAGMA AutoCommit;
+```
+
+```yql
+PRAGMA TablePathPrefix = "home/yql";
+```
+
+```yql
+PRAGMA Warning("disable", "1101");
+```
+
+With some exceptions, you can return the settings values to their default states using `PRAGMA my_pragma = default;`.
+
+For the full list of available settings, [see the table below](pragma.md#pragmas).
+
+### Scope {#pragmascope}
+
+Unless otherwise specified, a pragma affects all the subsequent expressions up to the end of the module where it's used. If necessary and logically possible, you can change the value of this setting several times within a given query to make it different at different execution steps.
+
+There are also special scoped pragmas with the scope defined by the same rules as the scope of [named expressions](expressions.md#named-nodes). Unlike scoped pragmas, regular pragmas can only be used in the global scope (not inside lambda functions, `ACTION`, `SUBQUERY`, etc.).
+
+
+
+## Global {#pragmas}
+
+### AutoCommit {#autocommit}
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+Automatically run [COMMIT](commit.md) after every statement.
+
+### TablePathPrefix {#table-path-prefix}
+
+| Value type | Default |
+| --- | --- |
+| String | — |
+
+Add the specified prefix to the cluster table paths. It uses standard file system path concatenation, supporting parent folder `..` referencing and requiring no trailing slash. For example,
+
+`PRAGMA TablePathPrefix = "home/yql";
+SELECT * FROM test;`
+
+The prefix is not added if the table name is an absolute path (starts with /).
+
+### UseTablePrefixForEach {#use-table-prefix-for-each}
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+EACH uses [TablePathPrefix](#table-path-prefix) for each list item.
+
+### Warning {#warning}
+
+| Value type | Default |
+| --- | --- |
+| 1. Action<br/>2. Warning code or "*" | — |
+
+Action:
+
+* `disable`: Disable.
+* `error`: Treat as an error.
+* `default`: Revert to the default behavior.
+
+The warning code is returned with the text itself (it's displayed on the right side of the web interface).
+
+#### Example
+
+`PRAGMA Warning("error", "*");`
+`PRAGMA Warning("disable", "1101");`
+`PRAGMA Warning("default", "4503");`
+
+In this case, all the warnings are treated as errors, except for the warning `1101` (that will be disabled) and `4503` (that will be processed by default, that is, remain a warning). Since warnings may be added in new YQL releases, use `PRAGMA Warning("error", "*");` with caution (at least cover such queries with autotests).
+
+### SimpleColumns {#simplecolumns}
+
+`SimpleColumns` / `DisableSimpleColumns`
+
+| Value type | Default |
+| --- | --- |
+| Flag | true |
+
+When you use `SELECT foo.* FROM ... AS foo`, remove the `foo.` prefix from the names of the result columns.
+
+It can be also used with a [JOIN](join.md), but in this case it may fail in the case of a name conflict (that can be resolved by using [WITHOUT](select/without.md) and renaming columns). For JOIN in SimpleColumns mode, an implicit Coalesce is made for key columns: the query `SELECT * FROM T1 AS a JOIN T2 AS b USING(key)` in the SimpleColumns mode works same as `SELECT a.key ?? b.key AS key, ... FROM T1 AS a JOIN T2 AS b USING(key)`.
+
+### CoalesceJoinKeysOnQualifiedAll
+
+`CoalesceJoinKeysOnQualifiedAll` / `DisableCoalesceJoinKeysOnQualifiedAll`
+
+| Value type | Default |
+| --- | --- |
+| Flag | true |
+
+Controls implicit Coalesce for the key `JOIN` columns in the SimpleColumns mode. If the flag is set, the Coalesce is made for key columns if there is at least one expression in the format `foo.*` or `*` in SELECT: for example, `SELECT a.* FROM T1 AS a JOIN T2 AS b USING(key)`. If the flag is not set, then Coalesce for JOIN keys is made only if there is an asterisk '*' after `SELECT`
+
+### StrictJoinKeyTypes
+
+`StrictJoinKeyTypes` / `DisableStrictJoinKeyTypes`
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+If the flag is set, then [JOIN](join.md) will require strict matching of key types.
+By default, JOIN preconverts keys to a shared type, which might result in performance degradation.
+StrictJoinKeyTypes is a [scoped](pragma.md#pragmascope) setting.
+
+### AnsiInForEmptyOrNullableItemsCollections
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+This pragma brings the behavior of the `IN` operator in accordance with the standard when there's `NULL` in the left or right side of `IN`. The behavior of `IN` when on the right side there is a Tuple with elements of different types also changed. Examples:
+
+`1 IN (2, 3, NULL) = NULL (was Just(False))`
+`NULL IN () = Just(False) (was NULL)`
+`(1, null) IN ((2, 2), (3, 3)) = Just(False) (was NULL)`
+
+For more information about the `IN` behavior when operands include `NULL`s, see [here](expressions.md#in). You can explicitly select the old behavior by specifying the pragma `DisableAnsiInForEmptyOrNullableItemsCollections`. If no pragma is set, then a warning is issued and the old version works.
+
+### AnsiRankForNullableKeys
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+Aligns the RANK/DENSE_RANK behavior with the standard if there are optional types in the window sort keys or in the argument of such window functions. It means that:
+
+* The result type is always Uint64 rather than Uint64?.
+* NULLs in keys are treated as equal to each other (the current implementation returns NULL).
+
+You can explicitly select the old behavior by using the `DisableAnsiRankForNullableKeys` pragma. If no pragma is set, then a warning is issued and the old version works.
+
+### AnsiCurrentRow
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+Aligns the implicit setting of a window frame with the standard if there is ORDER BY.
+If AnsiCurrentRow is not set, then the `(ORDER BY key)` window is equivalent to `(ORDER BY key ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)`.
+The standard also requires that this window behave as `(ORDER BY key RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)`.
+The difference is in how `CURRENT ROW` is interpreted. In `ROWS` mode `CURRENT ROW` is interpreted literally: the current row in a partition.
+In `RANGE` mode, the end of the `CURRENT ROW` frame means "the last row in a partition with a sort key equal to the current row".
+
+### AnsiOrderByLimitInUnionAll
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+Aligns the UNION ALL behavior with the standard if there is `ORDER BY/LIMIT/DISCARD/INSERT INTO` in the combined subqueries. It means that:
+
+* `ORDER BY/LIMIT/INSERT INTO` are allowed only after the last subquery.
+* `DISCARD` is allowed only before the first subquery.
+* The specified operators apply to the `UNION ALL` result (unlike the current behavior when they apply only to the subquery).
+* To apply an operator to a subquery, enclose the subquery in parentheses.
+
+You can explicitly select the old behavior by using the `DisableAnsiOrderByLimitInUnionAll` pragma. If no pragma is set, then a warning is issued and the old version works.
+
+### OrderedColumns {#orderedcolumns}
+
+`OrderedColumns`/`DisableOrderedColumns`
+
+Output the [column order](select/order_by.md) in SELECT/JOIN/UNION ALL and preserve it when writing the results. The order of columns is undefined by default.
+
+### PositionalUnionAll {#positionalunionall}
+
+Enable the standard column-by-column execution for [UNION ALL](select/union.md#unionall). This automatically enables
+[ordered columns](#orderedcolumns).
+
+### RegexUseRe2
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+Use Re2 UDF instead of Pcre to execute SQL the `REGEX`,`MATCH`,`RLIKE` statements. Re2 UDF can properly handle Unicode characters, unlike the default Pcre UDF.
+
+### ClassicDivision
+
+| Value type | Default |
+| --- | --- |
+| Flag | true |
+
+In the classical version, the result of integer division remains integer (by default).
+If disabled, the result is always Double.
+ClassicDivision is a [scoped](pragma.md#pragmascope) setting.
+
+### UnicodeLiterals
+
+`UnicodeLiterals`/`DisableUnicodeLiterals`
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+When this mode is enabled, string literals without suffixes like "foo"/'bar'/@@multiline@@ will be of type `Utf8`, when disabled - `String`.
+UnicodeLiterals is a [scoped](pragma.md#pragmascope) setting.
+
+### WarnUntypedStringLiterals
+
+`WarnUntypedStringLiterals`/`DisableWarnUntypedStringLiterals`
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+When this mode is enabled, a warning will be generated for string literals without suffixes like "foo"/'bar'/@@multiline@@. It can be suppressed by explicitly choosing the suffix `s` for the `String` type, or `u` for the `Utf8` type.
+WarnUntypedStringLiterals is a [scoped](pragma.md#pragmascope) setting.
+
+### AllowDotInAlias
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+Enable dot in names of result columns. This behavior is disabled by default, since the further use of such columns in JOIN is not fully implemented.
+
+### WarnUnnamedColumns
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+Generate a warning if a column name was automatically generated for an unnamed expression in `SELECT` (in the format `column[0-9]+`).
+
+### GroupByLimit
+
+| Value type | Default |
+| --- | --- |
+| Positive number | 32 |
+
+Increasing the limit on the number of dimensions in [GROUP BY](group_by.md).
+
+### GroupByCubeLimit
+
+| Value type | Default |
+| --- | --- |
+| Positive number | 5 |
+
+Increasing the limit on the number of dimensions in [GROUP BY](group_by.md#rollup-cube-group-sets).
+
+Use this option with care, because the computational complexity of the query grows exponentially with the number of dimensions.
+
+
+## Yson
+
+Managing the default behavior of Yson UDF, for more information, see the [documentation](../udf/list/yson.md) and, in particular, [Yson::Options](../udf/list/yson.md#ysonoptions).
+
+### `yson.AutoConvert`
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+Automatic conversion of values to the required data type in all Yson UDF calls, including implicit calls.
+
+### `yson.Strict`
+
+| Value type | Default |
+| --- | --- |
+| Flag | true |
+
+Strict mode control in all Yson UDF calls, including implicit calls. If the value is omitted or is `"true"`, it enables the strict mode. If the value is `"false"`, it disables the strict mode.
+
+### `yson.DisableStrict`
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+An inverted version of `yson.Strict`. If the value is omitted or is `"true"`, it disables the strict mode. If the value is `"false"`, it enables the strict mode.
+
+
+## Working with files
+
+### File
+
+| Value type | Default | Static/<br/>dynamic |
+| --- | --- | --- |
+| Two string arguments: alias and URL | — | Static |
+
+Attach a file to the query by URL. For attaching files you can use the built-in functions [FilePath and FileContent](../builtins/basic.md#filecontent).
+
+### Folder
+
+| Value type | Default | Static/<br/>dynamic |
+| --- | --- | --- |
+| Two string arguments: prefix and URL | — | Static |
+
+Attach a set of files to the query by URL. Works similarly to adding multiple files via [`PRAGMA File`](#file) by direct links to files with aliases obtained by combining a prefix with a file name using `/`.
+
+### Library
+
+| Value type | Default | Static/<br/>dynamic |
+| --- | --- | --- |
+| One or two arguments: the file name and an optional URL | — | Static |
+
+Treat the specified attached file as a library from which you can do [IMPORT](export_import.md). The syntax type for the library is determined from the file extension:
+
+* `.sql`: For the YQL dialect of SQL <span style="color: green;">(recommended)</span>.
+* `.yql`: For [s-expressions](/docs/s_expressions).
+
+Example with a file attached to the query:
+
+```yql
+PRAGMA library("a.sql");
+IMPORT a SYMBOLS $x;
+SELECT $x;
+```
+
+If the URL is specified, the library is downloaded from the URL rather than from the pre-attached file as in the following example:
+
+```yql
+PRAGMA library("a.sql","http://intranet.site/5618566/text");
+IMPORT a SYMBOLS $x;
+SELECT $x;
+```
+
+In this case, you can use text parameter value substitution in the URL:
+
+```yql
+DECLARE $_ver AS STRING; -- "5618566"
+PRAGMA library("a.sql","http://intranet.site/{$_ver}/text");
+IMPORT a SYMBOLS $x;
+SELECT $x;
+```
+
+### Package
+
+| Value type | Default | Static /<br/>dynamic |
+| --- | --- | --- |
+| Two or three arguments: package name, URL and optional token | — | Static |
+
+Attach a hierarchical set of files to the query by URL, treating them as a package with a given name - an interconnected set of libraries.
+
+Package name is expected to be given as ``project_name.package_name``; from package's libraries you can do [IMPORT](export_import.md) with a module name like ``pkg.project_name.package_name.maybe.nested.module.name``.
+
+Example for a package with flat hierarchy which consists of two libraries - foo.sql and bar.sql:
+
+```yql
+PRAGMA package("project.package", "http://intranet.site/path/to/package");
+IMPORT pkg.project.package.foo SYMBOLS $foo;
+IMPORT pkg.project.package.bar SYMBOLS $bar;
+SELECT $foo, $bar;
+```
+
+You can also use text parameter value substitution in the URL:
+
+```yql
+DECLARE $_path AS STRING; -- "path"
+PRAGMA package("project.package","http://intranet.site/{$_path}/to/package");
+IMPORT pkg.project.package.foo SYMBOLS $foo;
+IMPORT pkg.project.package.bar SYMBOLS $bar;
+SELECT $foo, $bar;
+```
+
+### OverrideLibrary
+
+| Value type | Default | Static/<br/>dynamic |
+| --- | --- | --- |
+| One argument: the file name | — | Static |
+
+Treat the specified attached file as a library and override with it one of package's libraries.
+
+File name is expected to be given as ``project_name/package_name/maybe/nested/module/name.EXTENSION``, extensions analagous to [PRAGMA Library](#library) are supported.
+
+Example:
+
+```yql
+PRAGMA package("project.package", "http://intranet.site/path/to/package");
+PRAGMA override_library("project/package/maybe/nested/module/name.sql");
+
+IMPORT pkg.project.package.foo SYMBOLS $foo;
+SELECT $foo;
+```
+
+## Debugging and auxiliary settings {#debug}
+
+
+### `config.flags("ValidateUdf", "Lazy")`
+
+| Value type | Default |
+| --- | --- |
+| String: None/Lazy/Greedy | None |
+
+Validating whether UDF results match the declared signature. The Greedy mode enforces materialization of lazy containers, although the Lazy mode doesn't.
+
+### `config.flags("Diagnostics")`
+
+| Value type | Default |
+| --- | --- |
+| Flag | false |
+
+Getting diagnostic information from YQL as an additional result of a query.
+
diff --git a/yql/essentials/docs/en/syntax/process.md b/yql/essentials/docs/en/syntax/process.md
new file mode 100644
index 0000000000..e6f18e07f9
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/process.md
@@ -0,0 +1,78 @@
+# PROCESS
+
+Convert the input table using a UDF or a [lambda function](expressions.md#lambda) that is applied sequentially to each input row and can create zero to create one or more result row for each input row (similarly to Map in MapReduce terms).
+
+The parameters of the function call after the `USING` keyword explicitly specify the values of columns from which to pass values for each input row and in which order.
+
+You can use functions that return the result of one of three composite types derived from `OutputType` (supported `OutputType` options are described below):
+
+* `OutputType`: Each input row must always have an output row with the schema determined by the structure type.
+* `OutputType?`: The function may skip rows, returning empty values (`TUnboxedValue()` in C++, `None` in Python, or `null` in JavaScript).
+* `Stream<OutputType>` or `List<OutputType>`: An option to return multiple rows.
+
+Regardless of the option selected above, the result is converted to a flat table with columns defined by the `OutputType` type.
+
+As `OutputType`, you can use one of the types:
+
+* `Struct<...>`: `PROCESS` has exactly one output with entries of a given structure that is a flat table with columns corresponding to the fields `Struct<...>`
+* `Variant<Struct...>,...>`: `PROCESS` will have the number of outputs equal to the number of variants in `Variant`. The entries of each output are represented by a flat table with columns based on fields from the relevant variant. In this case, you can access the set of `PROCESS` outputs as a `Tuple` of lists that can be unpacked into separate [named expressions](expressions.md#named-nodes) and used independently.
+
+In the list of function arguments after the `USING` keyword, you can pass one of the two special named expressions:
+
+* `TableRow()`: The entire current row in the form of a structure.
+* `TableRows()`: A lazy iterator by strings, in terms of the types `Stream<Struct...>>`. In this case, the output type of the function can only be `Stream<OutputType>` or `List<OutputType>`.
+
+{% note info %}
+
+After executing `PROCESS`, within the same query, on the resulting table (or tables), you can perform [SELECT](select/index.md), [REDUCE](reduce.md), other `PROCESS` and so on, depending on the intended result.
+
+{% endnote %}
+
+The `USING` keyword and the function are optional: if you omit them, the source table is returned. This can be convenient for using a [subquery template](subquery.md).
+
+In `PROCESS` you can pass multiple inputs (the input here means a table, a [range of tables](select/concat.md), a subquery, a [named expression](expressions.md#named-nodes)), separated by commas. To the function from `USING`, you can only pass in this case special named expressions `TableRow()` or `TableRows()` that will have the following type:
+
+* `TableRow()`: A `Variant` where each element has an entry structure type from the relevant input. For each input row in the Variant, the element corresponding to the occurrence ID for this row is non-empty
+* `TableRows()`: A lazy iterator by Variants, in terms of the types `Stream<Variant...>>`. The alternative has the same semantics as for `TableRow()`
+
+After `USING` in `PROCESS` you can optionally specify `ASSUME ORDER BY` with a list of columns. The result of such a `PROCESS` statement is treated as sorted, but without actually running a sort. Sort check is performed at the query execution stage. It supports setting the sort order using the keywords `ASC` (ascending order) and `DESC` (descending order). Expressions are not supported in `ASSUME ORDER BY`.
+
+## Examples
+
+```yql
+PROCESS my_table
+USING MyUdf::MyProcessor(value)
+```
+
+```yql
+$udfScript = @@
+def MyFunc(my_list):
+ return [(int(x.key) % 2, x) for x in my_list]
+@@;
+
+-- The function returns an iterator of Variants
+$udf = Python3::MyFunc(Callable<(Stream<Struct<...>>) -> Stream<Variant<Struct<...>, Struct<...>>>>,
+ $udfScript
+);
+
+-- The output of the PROCESS produces a tuple of lists
+$i, $j = (PROCESS my_table USING $udf(TableRows()));
+
+SELECT * FROM $i;
+SELECT * FROM $j;
+```
+
+```yql
+$udfScript = @@
+def MyFunc(stream):
+ for r in stream:
+ yield {"alt": r[0], "key": r[1].key}
+@@;
+
+-- The function accepts an iterator of Variants as input
+$udf = Python::MyFunc(Callable<(Stream<Variant<Struct<...>, Struct<...>>>) -> Stream<Struct<...>>>,
+ $udfScript
+);
+
+PROCESS my_table1, my_table2 USING $udf(TableRows());
+```
diff --git a/yql/essentials/docs/en/syntax/reduce.md b/yql/essentials/docs/en/syntax/reduce.md
new file mode 100644
index 0000000000..e7c579c7ee
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/reduce.md
@@ -0,0 +1,108 @@
+# REDUCE
+
+Groups the input by the specified key columns, then passes the current keys and a lazy iterator over their corresponding values from the remaining columns to the specified UDF for processing. Similarly to `PROCESS`, the UDF can return an arbitrary number of result rows per call and also return `Variants` to create multiple outputs. In terms of MapReduce, it's very similar to Reduce.
+
+Keywords that can follow:
+
+* `PRESORT` <span style="color: gray;">(optional)</span>: Specifying the order within each group, the syntax is similar to [ORDER BY](select/order_by.md);
+* `ON` <span style="color: gray;">(required)</span>: Specifying key columns.
+* `USING` or `USING ALL` <span style="color: gray;">(required)</span>: A UDF call, see more about the rules below.
+
+Rules for passing UDF arguments:
+
+* If `TableRows()` is specified as a UDF argument, then the UDF must accept one argument: a lazy iterator over strings, with the type `Stream<Struct...>>`. In this case, the output type of the function can only be `Stream<OutputType>` or `List<OutputType>`. It's guaranteed that the data in the input iterator is grouped by the key and, if necessary, sorted according to the `PRESORT` section. With `TableRows()`, you can only use `USING ALL`.
+* With `USING`:
+
+ * The UDF must accept two arguments: the current key is passed to the first argument, and a lazy iterator with values corresponding to this key is passed to the second argument.
+
+* With `USING ALL`:
+
+ * The UDF must accept one argument: a lazy iterator over `Tuples`, where the first item in the tuple is a key, and the second item is a lazy iterator with values corresponding to this key.
+
+* The key to be passed to the UDF follows the rule below. If there is only one key column, then only its value is used in the key. If there are multiple columns (columns are listed similarly to `GROUP BY` separated by commas), then the key is a `Tuple` with values from the listed columns in the specified order.
+* When you call `REDUCE` from a query, only the expression whose values will be passed as iterator items follows the UDF name in parentheses (the second UDF argument for `USING` or the second item of the tuple for `USING ALL`).
+
+The result is built in the same way as for [PROCESS](process.md). You can also use the `TableRow()` keyword to get the whole string as a structure.
+
+In `REDUCE`, you can pass multiple inputs (the input here means a table, a [range of tables](select/concat.md), a subquery, a [named expression](expressions.md#named-nodes)), separated by commas. All inputs must have the key columns of the matching type specified in `ON`. To the function from `USING` in this case, you can only pass a special named expression `TableRow()`. The second argument (or the second element of the tuple for `USING ALL`) will include a lazy iterator over variants with a populated element that corresponds to the occurrence ID for the current entry.
+
+After `USING`, in `REDUCE` you can optionally specify `ASSUME ORDER BY` with a list of columns. The result of such a `REDUCE` statement is treated as sorted, but without actually running a sort. Sort check is performed at the query execution stage. It supports setting the sort order using the keywords `ASC` (ascending order) and `DESC` (descending order). Expressions are not supported in `ASSUME ORDER BY`.
+
+## Examples
+
+```yql
+REDUCE my_table
+ON key, subkey
+USING MyUdf::MyReducer(TableRow());
+```
+
+```yql
+REDUCE my_table
+ON key, subkey
+USING ALL MyUDF::MyStreamReducer(TableRow()); -- MyUDF::MyStreamReducer accepts a lazy list of tuples (key, list of entries for the key) as its input
+```
+
+```yql
+REDUCE my_table
+PRESORT LENGTH(subkey) DESC
+ON key
+USING MyUdf::MyReducer(
+ AsTuple(subkey, value)
+);
+```
+
+```yql
+REDUCE my_table
+ON key
+USING ALL MyUDF::MyFlatStreamReducer(TableRows()); -- MyUDF::MyFlatStreamReducer accepts a single lazy list of entries as its input
+```
+
+```yql
+-- The function returns Variants
+$udf = Python::MyReducer(Callable<(String, Stream<Struct<...>>) -> Variant<Struct<...>, Struct<...>>>,
+ $udfScript
+);
+
+-- The output of REDUCE produces a tuple of lists
+$i, $j = (REDUCE my_table ON key USING $udf(TableRow()));
+
+SELECT * FROM $i;
+SELECT * FROM $j;
+```
+
+```yql
+$script = @@
+def MyReducer(key, values):
+ state = None, 0
+ for name, last_visit_time in values:
+ if state[1] < last_visit_time:
+ state = name, last_visit_time
+ return {
+ 'region':key,
+ 'last_visitor':state[0],
+ }
+@@;
+
+$udf = Python::MyReducer(Callable<(
+ Int64?,
+ Stream<Tuple<String?, Uint64?>>
+) -> Struct<
+ region:Int64?,
+ last_visitor:String?
+>>,
+ $script
+);
+
+REDUCE my_table
+ON region USING $udf((name, last_visit_time));
+```
+
+```yql
+-- The function accepts a key and iterator of Variants as input
+$udf = Python::MyReducer(Callable<(String, Stream<Variant<Struct<...>,Struct<...>>>) -> Struct<...>>,
+ $udfScript
+);
+
+REDUCE my_table1, my_table2 ON key USING $udf(TableRow());
+```
+
diff --git a/yql/essentials/docs/en/syntax/select/assume_order_by.md b/yql/essentials/docs/en/syntax/select/assume_order_by.md
new file mode 100644
index 0000000000..61c9e24196
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/assume_order_by.md
@@ -0,0 +1,14 @@
+# ASSUME ORDER BY
+
+Checking that the `SELECT` result is sorted by the value in the specified column or multiple columns. The result of such a `SELECT` statement is treated as sorted, but without actually running a sort. Sort check is performed at the query execution stage.
+
+As in case of `ORDER BY`, it supports setting the sort order using the keywords `ASC` (ascending order) and `DESC` (descending order). Expressions are not supported in `ASSUME ORDER BY`.
+
+## Examples
+
+```yql
+SELECT key || "suffix" as key, -CAST(subkey as Int32) as subkey
+FROM my_table
+ASSUME ORDER BY key, subkey DESC;
+```
+
diff --git a/yql/essentials/docs/en/syntax/select/concat.md b/yql/essentials/docs/en/syntax/select/concat.md
new file mode 100644
index 0000000000..e1170e7287
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/concat.md
@@ -0,0 +1,44 @@
+## Accessing multiple tables in a single query {#concat} {#each} {#range} {#like} {#filter} {#regexp}
+
+Standard SQL uses [UNION ALL](union.md#union-all) to execute a query across multiple tables and combine the results of two or more `SELECT` statements. This is not very convenient for the use case of running the same query on multiple tables (for example, if they contain data for different dates). To make this more convenient, in YQL `SELECT` statements, after `FROM`, you can specify not only a table or a subquery, but also call built-in functions letting you combine data from multiple tables.
+
+The following functions are defined for these purposes:
+
+```CONCAT(`table1`, `table2`, `table3` VIEW view_name, ...)``` combines all the tables listed in the arguments.
+
+```EACH($list_of_strings) or EACH($list_of_strings VIEW view_name)``` combines all tables whose names are listed in the list of strings. Optionally, you can pass multiple lists in separate arguments similar to `CONCAT`.
+
+{% note warning %}
+
+All of the above functions don't guarantee the order of the table union.
+
+The list of tables is calculated **before** executing the query. Therefore, the tables created during the query execution won't be included in the function results.
+
+{% endnote %}
+
+By default, the schemas of all the unioned tables are combined using the [UNION ALL](union.md#union-all) rules. If you don't want to combine schemas, then you can use functions with the `_STRICT` suffix, for example `CONCAT_STRICT`, that are totally similar to the original functions, but treat any difference in table schemas as an error.
+
+To specify a cluster of unioned tables, add it before the function name.
+
+All arguments of the functions described above can be declared separately using [named expressions](../expressions.md#named-nodes). In this case, you can also use simple expressions in them by implicitly calling [EvaluateExpr](../../builtins/basic.md#evaluate_expr_atom).
+
+To get the name of the source table from which you originally obtained each row, use [TablePath()](../../builtins/basic.md#tablepath).
+
+### Examples
+
+```yql
+USE some_cluster;
+SELECT * FROM CONCAT(
+ `table1`,
+ `table2`,
+ `table3`);
+```
+
+```yql
+USE some_cluster;
+$indices = ListFromRange(1, 4);
+$tables = ListMap($indices, ($index) -> {
+ RETURN "table" || CAST($index AS String);
+});
+SELECT * FROM EACH($tables); -- Identical to the previous example
+```
diff --git a/yql/essentials/docs/en/syntax/select/distinct.md b/yql/essentials/docs/en/syntax/select/distinct.md
new file mode 100644
index 0000000000..ae3eec3685
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/distinct.md
@@ -0,0 +1,19 @@
+# DISTINCT
+
+Selecting unique rows.
+
+{% note info %}
+
+Applying `DISTINCT` to calculated values is not currently implemented. For this purpose, use a subquery or the clause [`GROUP BY ... AS ...`](../group_by.md).
+
+{% endnote %}
+
+## Example
+
+```yql
+SELECT DISTINCT value -- only unique values from the table
+FROM my_table;
+```
+
+The `DISTINCT` keyword can also be used to apply [aggregate functions](../../builtins/aggregation.md) only to distinct values. For more information, see the documentation for [GROUP BY](../group_by.md).
+
diff --git a/yql/essentials/docs/en/syntax/select/from.md b/yql/essentials/docs/en/syntax/select/from.md
new file mode 100644
index 0000000000..924790d9de
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/from.md
@@ -0,0 +1,22 @@
+## FROM {#from}
+
+Data source for `SELECT`. The argument can accept the table name, the result of another `SELECT`, or a [named expression](../expressions.md#named-nodes). Between `SELECT` and `FROM`, list the comma-separated column names from the source (or `*` to select all columns).
+
+The table is searched by name in the database specified by the operator [USE](../use.md).
+
+### Examples
+
+```yql
+SELECT key FROM my_table;
+```
+
+```yql
+SELECT * FROM
+ (SELECT value FROM my_table);
+```
+
+```yql
+$table_name = "my_table";
+SELECT * FROM $table_name;
+```
+
diff --git a/yql/essentials/docs/en/syntax/select/from_as_table.md b/yql/essentials/docs/en/syntax/select/from_as_table.md
new file mode 100644
index 0000000000..459cd51b04
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/from_as_table.md
@@ -0,0 +1,17 @@
+## FROM AS_TABLE {#as-table}
+
+Accessing named expressions as tables using the `AS_TABLE` function.
+
+`AS_TABLE($variable)` lets you use the value of `$variable` as the data source for the query. In this case, the variable `$variable` must have the type `List<Struct<...>>`.
+
+### Example
+
+```yql
+$data = AsList(
+ AsStruct(1u AS Key, "v1" AS Value),
+ AsStruct(2u AS Key, "v2" AS Value),
+ AsStruct(3u AS Key, "v3" AS Value));
+
+SELECT Key, Value FROM AS_TABLE($data);
+```
+
diff --git a/yql/essentials/docs/en/syntax/select/from_select.md b/yql/essentials/docs/en/syntax/select/from_select.md
new file mode 100644
index 0000000000..76373ca251
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/from_select.md
@@ -0,0 +1,17 @@
+## FROM ... SELECT ... {#from-select}
+
+An inverted format, first specifying the data source and then the operation.
+
+### Examples
+
+```yql
+FROM my_table SELECT key, value;
+```
+
+```yql
+FROM a_table AS a
+JOIN b_table AS b
+USING (key)
+SELECT *;
+```
+
diff --git a/yql/essentials/docs/en/syntax/select/index.md b/yql/essentials/docs/en/syntax/select/index.md
new file mode 100644
index 0000000000..656e2bfba4
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/index.md
@@ -0,0 +1,102 @@
+<!-- markdownlint-disable blanks-around-fences -->
+
+# SELECT
+
+Returns the result of evaluating the expressions specified after `SELECT`.
+
+It can be used in combination with other operations to obtain other effect.
+
+## Examples
+
+```yql
+SELECT "Hello, world!";
+```
+
+```yql
+SELECT 2 + 2;
+```
+
+## SELECT execution procedure {#selectexec}
+
+The `SELECT` query result is calculated as follows:
+
+* Determine the set of input tables by evaluating the [FROM](from.md) clauses.
+* Apply [SAMPLE](sample.md)/[TABLESAMPLE](sample.md) to input tables.
+* Execute [FLATTEN COLUMNS](../flatten.md#flatten-columns) or [FLATTEN BY](../flatten.md); aliases set in `FLATTEN BY` become visible after this point.
+* Execute every [JOIN](../join.md).
+* Add to (or replace in) the data the columns listed in [GROUP BY ... AS ...](../group_by.md).
+* Execute [WHERE](where.md) - discard all the data mismatching the predicate.
+* Execute [GROUP BY](../group_by.md), evaluate aggregate functions.
+* Apply the filter [HAVING](../group_by.md#having).
+* Evaluate [window functions](../window.md);
+* Evaluate expressions in `SELECT`.
+* Assign names set by aliases to expressions in `SELECT`.
+* Apply top-level [DISTINCT](distinct.md) to the resulting columns.
+* Execute similarly every subquery inside [UNION ALL](union.md#union-all), combine them (see [PRAGMA AnsiOrderByLimitInUnionAll](../pragma.md#pragmas)).
+* Perform sorting with [ORDER BY](order_by.md).
+* Apply [OFFSET and LIMIT](limit_offset.md) to the result.
+
+
+## Column order in YQL {#orderedcolumns}
+
+The standard SQL is sensitive to the order of columns in projections (that is, in `SELECT`). While the order of columns must be preserved in the query results or when writing data to a new table, some SQL constructs use this order.
+This applies, for example, to [UNION ALL](union.md#union-all) and positional [ORDER BY](order_by.md) (ORDER BY ordinal).
+
+The column order is ignored in YQL by default:
+
+* The order of columns in the output tables and query results is undefined
+* The data scheme of the `UNION ALL` result is output by column names rather than positions
+
+If you enable `PRAGMA OrderedColumns;`, the order of columns is preserved in the query results and is derived from the order of columns in the input tables using the following rules:
+
+* `SELECT`: an explicit column enumeration dictates the result order.
+* `SELECT` with an asterisk (`SELECT * FROM ...`) inherits the order from its input.
+* The order of columns after [JOIN](../join.md): First output the left-hand columns, then the right-hand ones. If the column order in any of the sides in the `JOIN` output is undefined, the column order in the result is also undefined.
+* The order in `UNION ALL` depends on the [UNION ALL](union.md#union-all) execution mode.
+* The column order for [AS_TABLE](from_as_table.md) is undefined.
+
+
+### Combining queries {#combining-queries}
+
+Results of several SELECT statements (or subqueries) can be combined using `UNION` and `UNION ALL` keywords.
+
+```yql
+query1 UNION [ALL] query2 (UNION [ALL] query3 ...)
+```
+
+Union of more than two queries is interpreted as a left-associative operation, that is
+
+```yql
+query1 UNION query2 UNION ALL query3
+```
+
+is interpreted as
+
+```yql
+(query1 UNION query2) UNION ALL query3
+```
+
+If the underlying queries have one of the `ORDER BY/LIMIT/DISCARD/INTO RESULT` operators, the following rules apply:
+
+* `ORDER BY/LIMIT/INTO RESULT` is only allowed after the last query
+* `DISCARD` is only allowed before the first query
+* the operators apply to the `UNION [ALL]` as a whole, instead of referring to one of the queries
+* to apply the operator to one of the queries, enclose the query in parantheses
+
+## Clauses supported in SELECT
+
+* [FROM](from.md)
+* [FROM AS_TABLE](from_as_table.md)
+* [FROM SELECT](from_select.md)
+* [DISTINCT](distinct.md)
+* [UNIQUE DISTINCT](unique_distinct_hints.md)
+* [UNION](union.md)
+* [WITH](with.md)
+* [WITHOUT](without.md)
+* [WHERE](where.md)
+* [ORDER BY](order_by.md)
+* [ASSUME ORDER BY](assume_order_by.md)
+* [LIMIT OFFSET](limit_offset.md)
+* [SAMPLE](sample.md)
+* [TABLESAMPLE](sample.md)
+* [CONCAT](concat.md)
diff --git a/yql/essentials/docs/en/syntax/select/limit_offset.md b/yql/essentials/docs/en/syntax/select/limit_offset.md
new file mode 100644
index 0000000000..45e5bd1866
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/limit_offset.md
@@ -0,0 +1,22 @@
+# LIMIT and OFFSET
+
+`LIMIT`: limits the output to the specified number of rows. By default, the output is not restricted.
+
+`OFFSET`: specifies the offset from the beginning (in rows). By default, it's zero.
+
+## Examples
+
+```yql
+SELECT key FROM my_table
+LIMIT 7;
+```
+
+```yql
+SELECT key FROM my_table
+LIMIT 7 OFFSET 3;
+```
+
+```yql
+SELECT key FROM my_table
+LIMIT 3, 7; -- equivalent to the previous example
+```
diff --git a/yql/essentials/docs/en/syntax/select/order_by.md b/yql/essentials/docs/en/syntax/select/order_by.md
new file mode 100644
index 0000000000..e33deeecc0
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/order_by.md
@@ -0,0 +1,20 @@
+# ORDER BY
+
+Sorting the `SELECT` result using a comma-separated list of sorting criteria. As a criteria, you can use a column value or an expression on columns. Ordering by column sequence number is not supported (`ORDER BY N` where `N` is a number).
+
+Each criteria can be followed by the sorting direction:
+
+- `ASC`: Sorting in the ascending order. Applied by default.
+- `DESC`: Sorting in the descending order.
+
+Multiple sorting criteria will be applied left-to-right.
+
+## Example
+
+```yql
+SELECT key, string_column
+FROM my_table
+ORDER BY key DESC, LENGTH(string_column) ASC;
+```
+
+You can also use `ORDER BY` for [window functions](../window.md).
diff --git a/yql/essentials/docs/en/syntax/select/sample.md b/yql/essentials/docs/en/syntax/select/sample.md
new file mode 100644
index 0000000000..efe493fa18
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/sample.md
@@ -0,0 +1,38 @@
+# TABLESAMPLE and SAMPLE
+
+Building a random sample from the data source specified in `FROM`.
+
+`TABLESAMPLE` is part of the SQL standard and works as follows:
+
+* The operating mode is specified:
+
+ * `BERNOULLI` means "slowly, straightforwardly going through all the data, but in a truly random way".
+ * `SYSTEM` uses knowledge about the physical data storage of data to avoid full data scans, but somewhat sacrificing randomness of the sample.
+
+The data is split into sufficiently large blocks, and the whole data blocks are sampled. For applied calculations on sufficiently large tables, the result may well be consistent.
+
+* The size of the random sample is indicated as a percentage after the operating mode, in parentheses.
+* Optionally, it can be followed by the `REPEATABLE` keyword and an integer in parentheses to be used as a seed for a pseudorandom number generator.
+
+`SAMPLE` is a shorter alias without sophisticated settings and sample size specified as a fraction. It currently corresponds to the `BERNOULLI` mode.
+
+## Examples
+
+```yql
+SELECT *
+FROM my_table
+TABLESAMPLE BERNOULLI(1.0) REPEATABLE(123); -- one percent of the table
+```
+
+```yql
+SELECT *
+FROM my_table
+TABLESAMPLE SYSTEM(1.0); -- about one percent of the table
+```
+
+```yql
+SELECT *
+FROM my_table
+SAMPLE 1.0 / 3; -- one-third of the table
+```
+
diff --git a/yql/essentials/docs/en/syntax/select/toc_i.yaml b/yql/essentials/docs/en/syntax/select/toc_i.yaml
new file mode 100644
index 0000000000..0c63de3ff2
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/toc_i.yaml
@@ -0,0 +1,17 @@
+items:
+- { name: Overview, href: index.md }
+- { name: FROM, href: from.md }
+- { name: FROM AS_TABLE, href: from_as_table.md }
+- { name: FROM SELECT, href: from_select.md }
+- { name: DISTINCT, href: distinct.md }
+- { name: UNIQUE DISTINCT, href: unique_distinct_hints.md }
+- { name: UNION, href: union.md }
+- { name: CONCAT, href: concat.md }
+- { name: WITH, href: with.md }
+- { name: WITHOUT, href: without.md }
+- { name: WHERE, href: where.md }
+- { name: ORDER BY, href: order_by.md }
+- { name: ASSUME ORDER BY, href: assume_order_by.md }
+- { name: LIMIT OFFSET, href: limit_offset.md }
+- { name: SAMPLE, href: sample.md }
+- { name: TABLESAMPLE, href: sample.md }
diff --git a/yql/essentials/docs/en/syntax/select/toc_p.yaml b/yql/essentials/docs/en/syntax/select/toc_p.yaml
new file mode 100644
index 0000000000..5bfec4365d
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/toc_p.yaml
@@ -0,0 +1,2 @@
+items:
+- include: { mode: link, path: toc_i.yaml } \ No newline at end of file
diff --git a/yql/essentials/docs/en/syntax/select/union.md b/yql/essentials/docs/en/syntax/select/union.md
new file mode 100644
index 0000000000..32b5ee1875
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/union.md
@@ -0,0 +1,63 @@
+# Combining subquery results (UNION)
+
+## UNION {#union}
+
+Union of the results of the underlying queries, with duplicates removed.
+Behavior is identical to using `UNION ALL` followed by `SELECT DISTINCT *`.
+Refer to [UNION ALL](#union-all) for more details.
+
+### Examples
+
+```yql
+SELECT key FROM T1
+UNION
+SELECT key FROM T2 -- returns the set of distinct keys in the tables
+```
+
+
+## UNION ALL {#union-all}
+
+Concatenating results of multiple `SELECT` statements (or subqueries).
+
+Two `UNION ALL` modes are supported: by column names (the default mode) and by column positions (corresponds to the ANSI SQL standard and is enabled by the [PRAGMA](../pragma.md#positionalunionall)).
+
+In the "by name" mode, the output of the resulting data schema uses the following rules:
+
+* The resulting table includes all columns that were found in at least one of the input tables.
+* If a column wasn't present in all the input tables, then it's automatically assigned the [optional data type](../../types/optional.md) (that can accept `NULL`).
+* If a column in different input tables had different types, then the shared type (the broadest one) is output.
+* If a column in different input tables had a heterogeneous type, for example, string and numeric, an error is raised.
+
+
+The order of output columns in this mode is equal to the largest common prefix of the order of inputs, followed by all other columns in the alphabetic order.
+If the largest common prefix is empty (for example, if the order isn't specified for one of the inputs), then the output order is undefined.
+
+In the "by position" mode, the output of the resulting data schema uses the following rules:
+
+* All inputs must have equal number of columns
+* The order of columns must be defined for all inputs
+* The names of the resulting columns must match the names of columns in the first table
+* The type of the resulting columns is output as a common (widest) type of input column types having the same positions
+
+The order of the output columns in this mode is the same as the order of columns in the first input.
+
+### Examples
+
+```yql
+SELECT 1 AS x
+UNION ALL
+SELECT 2 AS y
+UNION ALL
+SELECT 3 AS z;
+```
+
+In the default mode, this query returns a selection with three columns x, y, and z. When `PRAGMA PositionalUnionAll;` is enabled, the selection only includes the x column.
+
+```yql
+PRAGMA PositionalUnionAll;
+
+SELECT 1 AS x, 2 as y
+UNION ALL
+SELECT * FROM AS_TABLE([<|x:3, y:4|>]); -- error: the order of columns in AS_TABLE is undefined
+```
+
diff --git a/yql/essentials/docs/en/syntax/select/unique_distinct_hints.md b/yql/essentials/docs/en/syntax/select/unique_distinct_hints.md
new file mode 100644
index 0000000000..1e0f310aa1
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/unique_distinct_hints.md
@@ -0,0 +1,10 @@
+# UNIQUE DISTINCT hints
+
+Directly after `SELECT`, it is possible to add [SQL hints](../lexer.md#sql-hints) `unique` or `distinct`, which declare that this projection generates data containing unique values in the specified set of columns of a row-based or columnar table. This can be used to optimize subsequent subqueries executed on this projection, or for writing to table meta-attributes during `INSERT`.
+
+* Columns are specified in the hint values, separated by spaces.
+* If the set of columns is not specified, uniqueness applies to the entire set of columns in this projection.
+* `unique` - indicates unique or `null` values. According to the SQL standard, each null is unique: `NULL = NULL` -> `NULL`.
+* `distinct` - indicates completely unique values including null: `NULL IS DISTINCT FROM NULL` -> `FALSE`.
+* Multiple sets of columns can be specified in several hints for a single projection.
+* If the hint contains a column that is not in the projection, it will be ignored.
diff --git a/yql/essentials/docs/en/syntax/select/where.md b/yql/essentials/docs/en/syntax/select/where.md
new file mode 100644
index 0000000000..e522ab82d6
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/where.md
@@ -0,0 +1,11 @@
+# WHERE
+
+Filtering rows in the `SELECT` result based on a condition in tables.
+
+## Example
+
+```yql
+SELECT key FROM my_table
+WHERE value > 0;
+```
+
diff --git a/yql/essentials/docs/en/syntax/select/with.md b/yql/essentials/docs/en/syntax/select/with.md
new file mode 100644
index 0000000000..861dc1a7be
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/with.md
@@ -0,0 +1,32 @@
+# WITH
+
+It's set after the data source in `FROM` and is used for additional hints for tables. You can't use hints for subqueries and [named expressions](../expressions.md#named-nodes).
+
+The following values are supported:
+
+* `INLINE`: Hints that the table contents is small and you need to use its in-memory view to process the query. The actual size of the table is not controlled in this case, and if it's large, the query might fail with an out-of-memory error.
+* `UNORDERED`: Suppresses original table sorting.
+* `SCHEMA` type: Hints that the specified table schema must be used entirely, ignoring the schema in the metadata.
+* `COLUMNS` type: Hints that the specified types should be used for columns whose names match the table's column names in the metadata, as well as which columns are additionally present in the table.
+
+When setting the `SCHEMA` and `COLUMNS` hints, the type must be a [structure](../../types/containers.md).
+
+If you use the `SCHEMA` hint, then with the table functions like [EACH](concat.md#each) you can use an empty list of tables that is treated as an empty table with columns defined in the `SCHEMA`.
+
+## Examples
+
+```yql
+SELECT key FROM my_table WITH INLINE;
+```
+
+```yql
+SELECT key, value FROM my_table WITH SCHEMA Struct<key:String, value:Int32>;
+```
+
+```yql
+SELECT key, value FROM my_table WITH COLUMNS Struct<value:Int32?>;
+```
+
+```yql
+SELECT key, value FROM EACH($my_tables) WITH SCHEMA Struct<key:String, value:List<Int32>>;
+```
diff --git a/yql/essentials/docs/en/syntax/select/without.md b/yql/essentials/docs/en/syntax/select/without.md
new file mode 100644
index 0000000000..7f85fab3bc
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/select/without.md
@@ -0,0 +1,16 @@
+# WITHOUT
+
+Excluding columns from the result of `SELECT *`.
+
+## Examples
+
+```yql
+SELECT * WITHOUT foo, bar FROM my_table;
+```
+
+```yql
+PRAGMA simplecolumns;
+SELECT * WITHOUT t.foo FROM my_table AS t
+CROSS JOIN (SELECT 1 AS foo) AS v;
+```
+
diff --git a/yql/essentials/docs/en/syntax/subquery.md b/yql/essentials/docs/en/syntax/subquery.md
new file mode 100644
index 0000000000..10767ed07d
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/subquery.md
@@ -0,0 +1,190 @@
+# Subquery templates
+
+## DEFINE SUBQUERY {#define-subquery}
+
+`DEFINE SUBQUERY` lets you declare a subquery template that is a parameterizable block of several top-level expressions (statements), and then use it repeatedly in the `FROM` section of [SELECT](select/index.md) statements or as input data in [PROCESS](process.md)/[REDUCE](reduce.md) with parameters.
+As opposed to [actions](action.md), the subquery template must end with the `SELECT`/`PROCESS`/`REDUCE` statement whose result is the subquery's return value. Keep in mind that you can't use the top-level `SELECT`/`PROCESS`/`REDUCE` statement and the modifying expressions (for example, `INSERT`) more than once.
+
+After `DEFINE SUBQUERY`, specify:
+
+1. [A named expression](expressions.md#named-nodes) that will be used to access the declared template further in the query.
+2. The round brackets contain a list of named expressions you can use to access parameters inside the subquery template.
+3. `AS` keyword.
+4. The list of top-level expressions.
+5. `END DEFINE` acts as a marker of the last expression inside the subquery template.
+
+One or more of the last subquery parameters can be marked with a question as optional: unless they haven't been specified when calling subquery, they will be assigned the `NULL` value.
+
+{% note info %}
+
+In large queries, you can use separate files for action definition and include them to the main query using [EXPORT](export_import.md#export) + [IMPORT](export_import.md#import) so that instead of one long text you can have several logical parts that are easier to navigate. An important nuance: the `USE my_cluster;` directive in the import query doesn't affect behavior of actions declared in other subquery files.
+
+{% endnote %}
+
+Even if the list of parameters in the subquery template definition is empty, when using it in `FROM`, specify the parentheses `()`. This may help to limit the scope of named expressions used in only one subquery.
+
+In some cases, instead of `DEFINE SUBQUERY` it's more convenient to use an equivalent [lambda function](expressions.md#lambda).
+In this case, the lambda function must accept, as the first argument, the special object called `world` that passes dependencies to make certain PRAGMA or COMMIT statements visible at the query template's point of use. Also, make sure to pass this object as the first argument along with the other arguments (if any) to other query templates, if you use them in your lambda function.
+The return value of the lambda function must have the structure list type (output table) or a list of variants over a tuple of structures (multiple output tables). In the latter case, the following unpacking is usually used at the query template's point of use:
+
+```yql
+$out1, $out2 = PROCESS $mySubquery($myParam1, $myParam2);
+-- next we use $out1 and $out2 as separate tables.
+```
+
+### Examples
+
+```yql
+DEFINE SUBQUERY $hello_world($name, $suffix?) AS
+ $name = $name ?? ($suffix ?? "world");
+ SELECT "Hello, " || $name || "!";
+END DEFINE;
+
+SELECT * FROM $hello_world(NULL); -- Hello, world!
+SELECT * FROM $hello_world("John"); -- Hello, John!
+SELECT * FROM $hello_world(NULL, "Earth"); -- Hello, Earth!
+```
+
+```yql
+DEFINE SUBQUERY $dup($x) AS
+ SELECT * FROM $x(1) -- apply the passed query template with one argument
+ UNION ALL
+ SELECT * FROM $x(2); -- ... and with other argument
+END DEFINE;
+
+DEFINE SUBQUERY $sub($n) AS
+ SELECT $n * 10;
+END DEFINE;
+
+SELECT * FROM $dup($sub); -- pass the query template $sub as a parameter
+-- Result:
+-- 10
+-- 20
+```
+
+```yql
+/* Hide the named expressions $a and $b inside a separate scope */
+DEFINE SUBQUERY $clean() AS
+ $a = 10;
+ $b = $a * $a;
+ SELECT $a AS a, $b AS b;
+END DEFINE;
+
+SELECT * FROM $clean(); -- a: 10, b: 100
+```
+
+```yql
+USE my_cluster;
+
+DEFINE SUBQUERY $input() as
+ SELECT * FROM `home/yql/tutorial/users`;
+END DEFINE;
+
+DEFINE SUBQUERY $myProcess1($nestedQuery, $lambda) AS
+ PROCESS $nestedQuery() -- the parentheses () are mandatory here
+ USING $lambda(TableRow());
+END DEFINE;
+
+$myProcess2 = ($world, $nestedQuery, $lambda) -> {
+ -- If you use ListFlatMap or YQL::OrderedFlatMap, you get an Ordered YT Map operation
+ return YQL::FlatMap($nestedQuery($world), $lambda);
+};
+
+-- With such use, the implementations of $myProcess1 and $myProcess2 are identical
+SELECT * FROM $myProcess1($input, ($x) -> { RETURN AsList($x, $x) });
+SELECT * FROM $myProcess2($input, ($x) -> { RETURN AsList($x, $x) });
+```
+
+```yql
+USE my_cluster;
+
+DEFINE SUBQUERY $runPartition($table) AS
+ $paritionByAge = ($row) -> {
+ $recordType = TypeOf($row);
+ $varType = VariantType(TupleType($recordType, $recordType));
+ RETURN If($row.age % 2 == 0,
+ Variant($row, "0", $varType),
+ Variant($row, "1", $varType),
+ );
+ };
+
+ PROCESS $table USING $paritionByAge(TableRow());
+END DEFINE;
+
+-- Unpacking two results
+$i, $j = (PROCESS $runPartition("home/yql/tutorial/users"));
+
+SELECT * FROM $i;
+
+SELECT * FROM $j;
+```
+
+## Combining the subquery templates: SubqueryExtend, SubqueryUnionAll, SubqueryMerge, SubqueryUnionMerge {#subquery-extend} {#subquery-unionall} {#subquery-merge} {#subquery-unionmerge}
+
+These functions combine the results of one or more subquery templates passed by arguments. The number of parameters in such subquery templates must be the same.
+
+* `SubqueryExtend` requires matching of subquery schemas.
+* `SubqueryUnionAll` follows the same rules as [ListUnionAll](../builtins/list.md#ListUnionAll).
+* `SubqueryMerge` uses the same constraints as `SubqueryExtend` and also outputs a sorted result if all subqueries have the same sort order.
+* `SubqueryUnionMerge` uses the same constraints as `SubqueryUnionAll` and also outputs a sorted result if all subqueries have the same sort order.
+
+### Examples
+
+```yql
+DEFINE SUBQUERY $sub1() as
+ SELECT 1 as x;
+END DEFINE;
+
+DEFINE SUBQUERY $sub2() as
+ SELECT 2 as x;
+END DEFINE;
+
+$s = SubqueryExtend($sub1,$sub2);
+PROCESS $s();
+```
+
+## Combining subquery templates after substituting list items: SubqueryExtendFor, SubqueryUnionAllFor, SubqueryMergeFor, SubqueryUnionMergeFor {#subquery-extend-for} {#subquery-unionall-for} {#subquery-merge-for} {#subquery-unionmerge-for}
+
+The functions take the following arguments:
+
+* A non-empty list of values.
+* A subquery template that must have exactly one parameter.
+
+They substitute each item from the list into the subquery template as a parameter and then combine the obtained subqueries.
+
+* `SubqueryExtendFor` requires matching of subquery schemas.
+* `SubqueryUnionAllFor` follows the same rules as [ListUnionAll](../builtins/list.md#ListUnionAll).
+* `SubqueryMergeFor` uses the same constraints as `SubqueryExtendFor` and also outputs a sorted result if all subqueries have the same sort order.
+* `SubqueryUnionMergeFor` uses the same constraints as `SubqueryUnionAllFor` and also outputs a sorted result if all subqueries have the same sort order.
+
+### Examples
+
+```yql
+DEFINE SUBQUERY $sub($i) as
+ SELECT $i as x;
+END DEFINE;
+
+$s = SubqueryExtendFor([1,2,3],$sub);
+PROCESS $s();
+```
+
+## Adding sorting to the SubqueryOrderBy template or indicating the presence of this SubqueryAssumeOrderBy
+
+The functions take the following arguments:
+
+* A subquery template without parameters.
+* A list of pairs (string indicating the column name and Boolean value: True for sorting in ascending order or False for sorting in descending order).
+
+And they build a new query template without parameters where sorting is performed or a comment on the use of sorting is added to the result. To use the resulting query template, call the `PROCESS` function, since, when using a `SELECT`, sorting is ignored.
+
+### Examples
+
+```yql
+DEFINE SUBQUERY $sub() as
+ SELECT * FROM (VALUES (1,'c'), (1,'a'), (3,'b')) AS a(x,y);
+end define;
+
+$sub2 = SubqueryOrderBy($sub, [('x',false), ('y',true)]);
+
+PROCESS $sub2();
+```
diff --git a/yql/essentials/docs/en/syntax/toc_i.yaml b/yql/essentials/docs/en/syntax/toc_i.yaml
new file mode 100644
index 0000000000..f91c0f3e1e
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/toc_i.yaml
@@ -0,0 +1,23 @@
+items:
+- { name: Overview, href: index.md }
+- { name: Lexical structure, href: lexer.md }
+- { name: Expressions, href: expressions.md }
+- { name: ACTION, href: action.md }
+- { name: COMMIT, href: commit.md }
+- { name: DECLARE, href: declare.md }
+- { name: DISCARD, href: discard.md }
+- { name: GROUP BY, href: group_by.md }
+- { name: EXPORT and IMPORT, href: export_import.md }
+- { name: FLATTEN, href: flatten.md }
+- { name: INSERT, href: insert_into.md }
+- { name: INTO RESULT, href: into_result.md }
+- { name: JOIN, href: join.md }
+- { name: PRAGMA, href: pragma.md }
+- { name: PROCESS, href: process.md }
+- { name: REDUCE, href: reduce.md }
+- { name: SELECT, include: { mode: link, path: select/toc_p.yaml } }
+- { name: SUBQUERY, href: subquery.md }
+- { name: USE, href: use.md }
+- { name: VALUES, href: values.md }
+- { name: WINDOW, href: window.md }
+- { name: Unsupported statements, href: not_yet_supported.md }
diff --git a/yql/essentials/docs/en/syntax/use.md b/yql/essentials/docs/en/syntax/use.md
new file mode 100644
index 0000000000..913c36744f
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/use.md
@@ -0,0 +1,24 @@
+# USE
+
+Specifying the "database". As a rule, one of the backend clusters is used as a database. This database will be used by default to search for tables whenever the database hasn't been specified explicitly.
+
+If the query doesn't include `USE`, then the cluster must be specified at the beginning of the table path in the format ``` cluster.`path/to/table` ```, for example ```cluster.`home/yql/test` ```. Backticks are used to automatically escape special characters (in this case, slashes).
+
+Usually the cluster name is specified explicitly, but you can use an expression for it. For example, this will let you use the parameters declared by [DECLARE](declare.md).
+In this case, `USE` must have the notation `USE yt:$cluster_name`, where `$cluster_name` is the [named expression](expressions.md#named-nodes) of the `String` type.
+Alternatively, you can specify the cluster right at the beginning of the table path in the format ```yt:$cluster_name.`path/to/table` ```.
+
+As far as `USE` is concerned, you can add it inside [actions](action.md) or [subquery templates](subquery.md). The value of the current cluster is inherited by declarations of nested actions or subqueries. The scope of `USE` is terminated at the end of the action or subquery template where it has been declared.
+
+## Examples
+
+```yql
+USE my_cluster;
+```
+
+{% note info %}
+
+`USE` **doesn't** guarantee that the query will be executed against the specified cluster. The query might be executed against other cluster if it doesn't use any input data (for example, `USE foo; SELECT 2 + 2;` ) or if the full path to the table on other cluster has been specified (for example, `USE foo; SELECT * FROM bar.``path/to/table``;`).
+
+{% endnote %}
+
diff --git a/yql/essentials/docs/en/syntax/values.md b/yql/essentials/docs/en/syntax/values.md
new file mode 100644
index 0000000000..c39805312c
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/values.md
@@ -0,0 +1,45 @@
+# Basic VALUES syntax in YQL
+
+## VALUES as a top-level operator
+
+It lets you create a table from specified values. For example, this statement creates a table of k columns and n rows:
+
+```yql
+VALUES (expr_11, expr_12, ..., expr_1k),
+ (expr_21, expr_22, ..., expr_2k),
+ ....
+ (expr_n1, expr_n2, ..., expr_nk);
+```
+
+This statement is totally equivalent to the following one:
+
+```yql
+SELECT expr_11, expr_12, ..., expr_1k UNION ALL
+SELECT expr_21, expr_22, ..., expr_2k UNION ALL
+....
+SELECT expr_n1, expr_n2, ..., expr_nk;
+```
+
+### Example
+
+```yql
+VALUES (1,2), (3,4);
+```
+
+## VALUES after FROM
+
+VALUES can also be used in a subquery, after FROM. For example, the following two queries are equivalent:
+
+```yql
+VALUES (1,2), (3,4);
+SELECT * FROM (VALUES (1,2), (3,4));
+```
+
+In all the examples above, column names are assigned by YQL and have the format `column0 ... columnN`. To assign arbitrary column names, you can use the following construct:
+
+```yql
+SELECT * FROM (VALUES (1,2), (3,4)) as t(x,y);
+```
+
+In this case, the columns will get the names `x`, `y`.
+
diff --git a/yql/essentials/docs/en/syntax/window.md b/yql/essentials/docs/en/syntax/window.md
new file mode 100644
index 0000000000..7c7d9e7df8
--- /dev/null
+++ b/yql/essentials/docs/en/syntax/window.md
@@ -0,0 +1,153 @@
+# OVER, PARTITION BY, and WINDOW
+
+Window functions were introduced in the SQL:2003 standard and expanded in the SQL:2011 standard. They let you run calculations on a set of table rows that are related to the current row in some way.
+
+Unlike [aggregate functions](../builtins/aggregation.md), window functions don't group rows into one output row: the number of rows in the resulting table is always the same as in the source table.
+
+If a query contains both aggregate and window functions, grouping is performed and aggregate function values are calculated first. The calculated values of aggregate functions can be used as window function arguments (but not the other way around).
+
+## Syntax {#syntax}
+
+General syntax for calling a window function is as follows
+
+```yql
+function_name([expression [, expression ...]]) OVER (window_definition)
+```
+
+or
+
+```yql
+function_name([expression [, expression ...]]) OVER window_name
+```
+
+Here, window name (`window_name`) is an arbitrary ID that is unique within the query and `expression` is an arbitrary expression that contains no window function calls.
+
+In the query, each window name must be mapped to the window definition (`window_definition`):
+
+```yql
+SELECT
+ F0(...) OVER (window_definition_0),
+ F1(...) OVER w1,
+ F2(...) OVER w2,
+ ...
+FROM my_table
+WINDOW
+ w1 AS (window_definition_1),
+ ...
+ w2 AS (window_definition_2)
+;
+```
+
+Here, the `window_definition` is written as
+
+```yql
+[ PARTITION BY (expression AS column_identifier | column_identifier) [, ...] ]
+[ ORDER BY expression [ASC | DESC] ]
+[ frame_definition ]
+```
+
+You can set an optional *frame definition* (`frame_definition`) one of two ways:
+
+* `ROWS frame_begin`
+* `ROWS BETWEEN frame_begin AND frame_end`
+
+*The frame start* (`frame_begin`) and *frame end* (`frame_end`) are set one of the following ways:
+
+* `UNBOUNDED PRECEDING`
+* `offset PRECEDING`
+* `CURRENT ROW`
+* `offset FOLLOWING`
+* `UNBOUNDED FOLLOWING`
+
+Here, the *frame* `offset` is a non-negative numeric literal. If the frame end isn't set, the `CURRENT ROW` is assumed.
+
+There should be no window function calls in any of the expressions inside the window definition.
+
+## Calculation algorithm
+
+### Partitioning {#partition}
+
+If `PARTITION BY` is set, the source table rows are grouped into *partitions*, which are then handled independently of each other.
+If `PARTITION BY` isn't set, all rows in the source table are put in the same partition. If `ORDER BY` is set, it determines the order of rows in a partition.
+Both in `PARTITION BY` and [GROUP BY](group_by.md) you can use aliases and [SessionWindow](group_by.md#session-window).
+
+If `ORDER BY` is omitted, the order of rows in the partition is undefined.
+
+### Frame {#frame}
+
+The `frame_definition` specifies a set of partition rows that fall into the *window frame* associated with the current row.
+
+In `ROWS` mode (the only one that YQL currently supports), the window frame contains rows with the specified offsets relative to the current row in the partition. For example, if `ROWS BETWEEN 3 PRECEDING AND 5 FOLLOWING` is used, the window frame contains 3 rows preceding the current one, the current row, and 5 rows following it.
+
+The set of rows in the window frame may change depending on which row is the current one. For example, for the first row in the partition, the `ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING` window frame will have no rows.
+
+Setting `UNBOUNDED PRECEDING` as the frame start means "from the first partition row" and `UNBOUNDED FOLLOWING` as the frame end — "up to the last partition row". Setting `CURRENT ROW` means "from/to the current row".
+
+If no `frame_definition` is specified, a set of rows to be included in the window frame depends on whether there is `ORDER BY` in the `window_definition`.
+Namely, if there is `ORDER BY`, then `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW` is implicitly assumed. If none, then `ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING`.
+
+Further, depending on the specific window function, it's calculated either based on the set of rows in the partition or the set of rows in the window frame.
+
+[List of available window functions](../builtins/window.md)
+
+#### Examples
+
+```yql
+SELECT
+ COUNT(*) OVER w AS rows_count_in_window,
+ some_other_value -- access the current row
+FROM `my_table`
+WINDOW w AS (
+ PARTITION BY partition_key_column
+ ORDER BY int_column
+);
+```
+
+```yql
+SELECT
+ LAG(my_column, 2) OVER w AS row_before_previous_one
+FROM `my_table`
+WINDOW w AS (
+ PARTITION BY partition_key_column
+);
+```
+
+```yql
+SELECT
+ -- AVG (like all aggregate functions used as window functions)
+ -- is calculated on the window frame
+ AVG(some_value) OVER w AS avg_of_prev_current_next,
+ some_other_value -- access the current row
+FROM my_table
+WINDOW w AS (
+ PARTITION BY partition_key_column
+ ORDER BY int_column
+ ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
+);
+```
+
+```yql
+SELECT
+ -- LAG doesn't depend on the window frame position
+ LAG(my_column, 2) OVER w AS row_before_previous_one
+FROM my_table
+WINDOW w AS (
+ PARTITION BY partition_key_column
+ ORDER BY my_column
+);
+```
+
+## Implementation specifics
+
+* Functions calculated on the `ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING` or `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW` window frame are implemented efficiently (do not require additional memory and their computation runs on a partition in O(partition size) time).
+* For the `ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING` window frame, you can choose the execution strategy in RAM by specifying the `COMPACT` hint after the `PARTITION` keyword.
+
+ For example, `PARTITION COMPACT BY key` or `PARTITION COMPACT BY ()` (if `PARTITION BY` was missing initially).
+
+ If the `COMPACT` hint is specified, this requires additional memory equal to O(partition size), but then no extra `JOIN` operation is made.
+
+* If the window frame doesn't start with `UNBOUNDED PRECEDING`, calculating window functions on this window requires additional memory equal to O(the maximum number of rows from the window boundaries to the current row), while the computation time is equal to O(number_of_partition_rows * window_size).
+* For the window frame starting with `UNBOUNDED PRECEDING` and ending with `N`, where `N` is neither `CURRENT ROW` nor `UNBOUNDED FOLLOWING`, additional memory equal to O(N) is required and the computation time is equal to O(N * number_of_partition_rows).
+* The `LEAD(expr, N)` and `LAG(expr, N)` functions always require O(N) of RAM.
+
+Given the above, a query with `ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING` should, if possible, be changed to `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW` by reversing the `ORDER BY` sorting order.
diff --git a/yql/essentials/docs/en/toc.yaml b/yql/essentials/docs/en/toc.yaml
new file mode 100644
index 0000000000..5bfec4365d
--- /dev/null
+++ b/yql/essentials/docs/en/toc.yaml
@@ -0,0 +1,2 @@
+items:
+- include: { mode: link, path: toc_i.yaml } \ No newline at end of file
diff --git a/yql/essentials/docs/en/toc_i.yaml b/yql/essentials/docs/en/toc_i.yaml
new file mode 100644
index 0000000000..7396a17141
--- /dev/null
+++ b/yql/essentials/docs/en/toc_i.yaml
@@ -0,0 +1,11 @@
+title: YQL core reference
+href: index.md
+items:
+- name: Data types
+ include: { mode: link, path: types/toc_i.yaml }
+- name: Syntax
+ include: { mode: link, path: syntax/toc_i.yaml }
+- name: Built-in functions
+ include: { mode: link, path: builtins/toc_i.yaml }
+- name: Recipes
+ include: { mode: link, path: recipes/toc_i.yaml }
diff --git a/yql/essentials/docs/en/types/cast.md b/yql/essentials/docs/en/types/cast.md
new file mode 100644
index 0000000000..6136c2f580
--- /dev/null
+++ b/yql/essentials/docs/en/types/cast.md
@@ -0,0 +1,74 @@
+# Rules for type casting using the operator [CAST](../syntax/expressions.md#cast)
+
+## Rules for casting primitive data types
+
+* When casting primitive data types, some of the source information may be discarded unless contained in the target type. For example:
+
+ * The `Float`/`Double` fractional part, when casting to integer types.
+ * The `Datetime`/`Timestamp` time, when casting to `Date`.
+ * The timezone, when casting from timezone types to date/time types without a timezone.
+
+* If, in a certain combination of the source and target type, casting can't be performed for all possible values of the source type, then, if the casting fails, `CAST` returns `NULL`. In such cases, one `Optional` level is added to the return value type, unless already present. For example, the constructs: `CAST("3.14" AS Float?)` and `CAST("3.14" AS Float)` are fully equivalent and return `Float?`.
+* If casting is possible for all values of the source type, then adding '?' works the same way as `Just` on top: `CAST(3.14 AS Utf8?)` is same as `Just(CAST(3.14 AS Utf8))`.
+
+All combinations of primitive data types for which `CAST` can be used are described [here](primitive.md).
+
+## Casting rules for containers
+
+### Rules for Optional
+
+* If a higher `Optional` level is set for the target type than for the source type, it's same as adding `Just` on top of `CAST` with a lower `Optional` level.
+* If the source type has a higher level of `Optional` for the source type, then `NULL` at any level higher than the target level results in `NULL`.
+* At equal levels of `Optional`, the `NULL` value preserves the same level.
+
+```yql
+SELECT
+ CAST(1 AS Int32?), -- is equivalent to Just(1)
+ CAST(Just(2/1) AS Float??), -- [2]
+ CAST(Just(3/0) AS Float??) IS NULL; -- false: the result is Just(NULL)
+```
+
+### Rules for List/Dict
+
+* To create a list, `CAST` is applied to each item in the source list to cast it to the target type.
+* If the target item type is non-optional and `CAST` on the item might fail, then such casting is discarded. In this case, the resulting list might be shorter or even empty if every casting failed.
+* For dictionaries, the casting is totally similar to lists, with `CAST` being applied to keys and values.
+
+```yql
+SELECT
+ CAST([-1, 0, 1] AS List<Uint8?>), -- [null, 0, 1]
+ CAST(["3.14", "bad", "42"] AS List<Float>), -- [3.14, 42]
+
+ CAST({-1:3.14, 7:1.6} AS Dict<Uint8, Utf8>), -- {7: "1.6"}
+ CAST({-1:3.14, 7:1.6} AS Dict<Uint8?, Utf8>); -- {7: "1.6", null:"3.14"}
+```
+
+### Rules for Struct/Tuple
+
+* A structure or tuple is created by applying `CAST` to each item of the source type to cast it to an item with the same name or target type index.
+* If some field is missing in the target type, it's simply discarded.
+* If some field is missing in the source value type, then it can be added only if it's optional and accepts the `NULL` value.
+* If some field is non-optional in the target type, but its casting might fail, then `CAST` adds Optional to the structure or tuple level and might return `NULL` for the entire result.
+
+```yql
+SELECT
+ CAST((-1, 0, 1) AS Tuple<Uint16?, Uint16?, Utf8>), -- (null, 0, "1")
+ CAST((-2, 0) AS Tuple<Uint16, Utf8>), -- null
+ CAST((3, 4) AS Tuple<Uint16, String>), -- (3, "4"): the type is Tuple<Uint16, String>?
+ CAST(("4",) AS Tuple<Uint16, String?>), -- (4, null)
+ CAST((5, 6, null) AS Tuple<Uint8?>); -- (5,): the items were removed.
+
+SELECT -- One field was removed and one field was added: ("three":null, "two": "42")
+ CAST(<|one:"8912", two:42|> AS Struct<two:Utf8, three:Date?>);
+```
+
+### Rules for Variant
+
+* A variant with a specific name or index is cast to a variant with the same name or index.
+* If casting of a variant might fail and the type of this variant is non-optional, then `CAST` adds Optional to the top level and can return `NULL`.
+* If some variant is missing in the target type, then `CAST` adds Optional to the top level and returns `NULL` for such a value.
+
+### Nested containers
+
+* All of the above rules are applied recursively for nested containers.
+
diff --git a/yql/essentials/docs/en/types/containers.md b/yql/essentials/docs/en/types/containers.md
new file mode 100644
index 0000000000..523fa31313
--- /dev/null
+++ b/yql/essentials/docs/en/types/containers.md
@@ -0,0 +1,26 @@
+# Containers
+
+YQL supports container types to define complex data structures organized in various ways.
+Values of container types can be passed to YQL queries as input parameters or returned from YQL queries as columns of the set of results.
+
+| Type | Declaration,<br/>example | Description |
+| ------------ | ---------------- | ------------- |
+| List | `List<Type>`,<br/>`List<Int32>` | A variable-length sequence consisting of same-type elements. |
+| Dictionary | `Dict<KeyType, ValueType>`,<br/>`Dict<String,Int32>` | Set of key-value pairs with a fixed type of keys and values. |
+| Set | `Set<KeyType>`,<br/>`Set<String>` | A set of elements with a fixed type is a special case of a dictionary with the `Void` value type. |
+| Tuple | `Tuple<Type1, ..., TypeN>`,<br/>`Tuple<Int32,Double>` | Set of unnamed fixed-length elements with types specified for all elements. |
+| Structure | `Struct<Name1:Type1, ..., NameN:TypeN>`,<br/> `Struct<Name:String,Age:Int32>` | A set of named fields with specified value types, fixed at query start (must be data-independent). |
+| Stream | `Stream<Type>`,<br/> `Stream<Int32>` | Single-pass iterator by same-type values, not serializable |
+| Variant on tuple | `Variant<Type1, Type2>`,<br/> `Variant<Int32,String>` | A tuple known to have exactly one element filled |
+| Variant on structure | `Variant<Name1:Type1, Name2:Type2>`,<br/>`Variant<value:Int32,error:String>` | A structure known to have exactly one element filled |
+| Enumeration | `Enum<Name1, Name2>`,<br/>`Enum<value,error>` | A container with exactly one enumeration element selected and defined only by its name. |
+
+If necessary, you can nest containers in any combination, for example, `List<Tuple<Int32,Int32>>`.
+
+In certain contexts, [optional values](optional.md) can also be considered a container type (`Optional<Type>`) that behaves like a list of length 0 or 1.
+
+To create literals of list containers, dictionary containers, set containers, tuple containers, or structure containers, you can use the [operator notation](../builtins/basic.md#containerliteral).
+To create a variant literal over a tuple or structure, use the function [Variant](../builtins/basic.md#variant).
+To create an enumeration literal, use the function [Enum](../builtins/basic.md#enum).
+
+To access the container elements, use a [dot or square brackets](../syntax/expressions.md#items-access), depending on the container type.
diff --git a/yql/essentials/docs/en/types/index.md b/yql/essentials/docs/en/types/index.md
new file mode 100644
index 0000000000..f1c2fbab3b
--- /dev/null
+++ b/yql/essentials/docs/en/types/index.md
@@ -0,0 +1,12 @@
+# YQL data types
+
+This section contains articles on YQL data types:
+
+- [Simple/Primitive types](primitive.md)
+- [Optional types](optional.md)
+- [Containers](containers.md)
+- [Special types](special.md)
+- [Type casting](cast.md)
+- [Text representation of data types](type_string.md)
+- [Data representation in JSON format](json.md)
+
diff --git a/yql/essentials/docs/en/types/json.md b/yql/essentials/docs/en/types/json.md
new file mode 100644
index 0000000000..115dc7c0d5
--- /dev/null
+++ b/yql/essentials/docs/en/types/json.md
@@ -0,0 +1,187 @@
+# Data representation in JSON format
+
+## Bool {#bool}
+
+Boolean value.
+
+* Type in JSON: `bool`.
+* Value example: `true`.
+* Sample JSON value: `true`.
+
+## Int8, Int16, Int32, Int64 {#int}
+
+Signed integer types.
+
+* Type in JSON: `number`.
+* Value example: `123456`, `-123456`.
+* Sample JSON value: `123456`, `-123456`.
+
+## Uint8, Uint16, Uint32, Uint64 {#uint}
+
+Unsigned integer types.
+
+* Type in JSON: `number`.
+* Value example: `123456`.
+* Sample JSON value: `123456`.
+
+## Float {#float}
+
+Real 4-byte number.
+
+* Type in JSON: `number`.
+* Value example: `0.12345679`.
+* Sample JSON value: `0.12345679`.
+
+## Double {#double}
+
+Real 8-byte number.
+
+* Type in JSON: `number`.
+* Value example: `0.12345678901234568`.
+* Sample JSON value: `0.12345678901234568`.
+
+## Decimal {#decimal}
+
+Fixed-precision number. Only Decimal(22, 9) is supported.
+
+* Type in JSON: `string`.
+* Value example: `-320.789`.
+* Sample JSON value: `"-320.789"`.
+
+## String, Yson {#string}
+
+Binary strings. Encoding algorithm depending on the byte value:
+
+* [0-31] — `\u00XX` (6 characters denoting the Unicode character code).
+* [32-126] — as is. These are readable single-byte characters that don't need to be escaped.
+* [127-255] — `\u00XX`.
+
+Decoding is a reverse process. Character codes in `\u00XX`, maximum 255.
+
+* Type in JSON: `string`.
+* Value example: A sequence of 4 bytes:
+
+ * 5 `0x05`: A control character.
+ * 10 `0x0a`: The `\n` newline character.
+ * 107 `0x6b`: The `k` character.
+ * 255 `0xff`: The `ÿ` character in Unicode.
+
+* Sample JSON value: `"\u0005\nk\u00FF"`.
+
+## Utf8, Json, Uuid {#utf}
+
+String types in UTF-8. Such strings are represented in JSON as strings with JSON characters escaped: `\\`, `\"`, `\n`, `\r`, `\t`, `\f`.
+
+* Type in JSON: `string`.
+
+* Value example: C++ code:
+
+ ```c++
+ "Escaped characters: "
+ "\\ \" \f \b \t \r\n"
+ "Non-escaped characters: "
+ "/ ' < > & []() ".
+ ```
+
+* Sample JSON value: `"Escaped characters: \\ \" \f \b \t \r\nNon-escaped characters: / ' < > & []() "`.
+
+## Date {#date}
+
+Date. Uint64, unix time days.
+
+* Type in JSON: `string`.
+* Value example: `18367`.
+* Sample JSON value: `"2020-04-15"`.
+
+## Datetime {#datetime}
+
+Date and time. Uint64, unix time seconds.
+
+* Type in JSON: `string`.
+* Value example: `1586966302`.
+* Sample JSON value: `"2020-04-15T15:58:22Z"`.
+
+## Timestamp {#timestamp}
+
+Date and time. Uint64, unix time microseconds.
+
+* Type in JSON: `string`.
+* Value example: `1586966302504185`.
+* Sample JSON value: `"2020-04-15T15:58:22.504185Z"`.
+
+## Interval {#interval}
+
+Time interval. Int64, precision to the microsecond, the interval values must not exceed 24 hours.
+
+* Type in JSON: `number`.
+* Value example: `123456`, `-123456`.
+* Sample JSON value: `123456`, `-123456`.
+
+## Optional {#optional}
+
+Means that the value can be `null`. If the value is `null`, then in JSON it's also `null`. If the value is not `null`, then the JSON value is expressed as if the type isn't `Optional`.
+
+* Type in JSON is missing.
+* Value example: `null`.
+* Sample JSON value: `null`.
+
+## List {#list}
+
+List. An ordered set of values of a given type.
+
+* Type in JSON: `array`.
+* Value example:
+
+ * Type: `List<Int32>`.
+ * Value: `1, 10, 100`.
+
+* Sample JSON value: `[1,10,100]`.
+
+## Stream {#stream}
+
+Stream. Single-pass iterator by same-type values,
+
+* Type in JSON: `array`.
+* Value example:
+
+ * Type: `Stream<Int32>`.
+ * Value: `1, 10, 100`.
+
+* Sample JSON value: `[1,10,100]`.
+
+## Struct {#struct}
+
+Structure. An unordered set of values with the specified names and type.
+
+* Type in JSON: `object`.
+* Value example:
+
+ * Type: `Struct<'Id':Uint32,'Name':String,'Value':Int32,'Description':Utf8?>`;
+ * Value: `"Id":1,"Name":"Anna","Value":-100,"Description":null`.
+
+* Sample JSON value: `{"Id":1,"Name":"Anna","Value":-100,"Description":null}`.
+
+## Tuple {#tuple}
+
+Tuple. An ordered set of values of the set types.
+
+* Type in JSON: `array`.
+* Value example:
+
+ * Type: `Tuple<Int32??,Int64???,String??,Utf8???>`;
+ * Value: `10,-1,null,"Some string"`.
+
+* Sample JSON value: `[10,-1,null,"Some string"]`.
+
+## Dict {#dict}
+
+Dictionary. An unordered set of key-value pairs. The type is set both for the key and the value. It's written in JSON to an array of arrays including two items.
+
+* Type in JSON: `array`.
+* Value example:
+
+ * Type: `Dict<Int64,String>`.
+ * Value: `1:"Value1",2:"Value2"`.
+
+* Sample JSON value: `[[1,"Value1"],[2,"Value2"]]`.
+
diff --git a/yql/essentials/docs/en/types/optional.md b/yql/essentials/docs/en/types/optional.md
new file mode 100644
index 0000000000..d1e1f69cef
--- /dev/null
+++ b/yql/essentials/docs/en/types/optional.md
@@ -0,0 +1,50 @@
+## Data types accepting NULL
+
+Any typed data in YQL, including table columns, can be either non-nullable (guaranteed value) or nullable (empty value denoted as `NULL`). Data types that can include `NULL` values are called *optional* or, in SQL terms, *nullable*.
+
+Optional data types in the [text format](type_string.md) use the question mark at the end (for example, `String?`) or the notation `Optional<...>`.
+The following operations are most often performed on optional data types:
+
+* [IS NULL](../syntax/expressions.md#is-null): Matching an empty value
+* [COALESCE](../builtins/basic.md#coalesce): Leave the filled values unchanged and replace `NULL` with the default value that follows
+* [UNWRAP](../builtins/basic.md#optional-ops): Extract the value of the original type from the optional data type, `T?`. is converted to `T`
+* [JUST](../builtins/basic#optional-ops): Add optionality to the current type, `T` is converted to `T?`.
+* [NOTHING](../builtins/basic.md#optional-ops): Create an empty value with the specified type.
+
+`Optional` (nullable) isn't a property of a data type or column, but a container type where [containers](containers.md) can be arbitrarily nested into each other. For example, a column with the type `Optional<Optional<Boolean>>` can accept 4 values: `NULL` of the whole container, `NULL` of the inner container, `TRUE`, and `FALSE`. The above-declared type differs from `List<List<Boolean>>`, because it uses `NULL` as an empty list, and you can't put more than one non-null element in it. In addition, `Optional<Optional<T>>` type values are returned as results when searching by the key in the `Dict(k,v)` dictionary with `Optional<T>` type values. Using this type of result data, you can distinguish between a `NULL` value in the dictionary and a situation when the key is missing.
+
+### Example
+
+```yql
+$dict = {"a":1, "b":null};
+$found = $dict["b"];
+select if($found is not null, unwrap($found), -1);
+```
+
+Result:
+
+```text
+# column0
+null
+```
+
+## Logical and arithmetic operations with NULL {#null_expr}
+
+The `NULL` literal has a separate singular `Null` type and can be implicitly converted to any optional type (for example, the nested type `Optional<Optional<...Optional<T>...>>`). In ANSI SQL, `NULL` means "an unknown value", that's why logical and arithmetic operations involving `NULL` or empty `Optional` have certain specifics.
+
+### Examples
+
+```yql
+SELECT
+ True OR NULL, -- Just(True) (works the same way as True OR <unknown value of type Bool>)
+ False AND NULL, -- Just(False)
+ True AND NULL, -- NULL (more precise than Nothing<Bool?> – <unknown value of type Bool>)
+ NULL OR NOT NULL, -- NULL (all NULLs are "different")
+ 1 + NULL, -- NULL (Nothing<Int32?>) - the result of adding 1 together with
+ -- unknown value of type Int)
+ 1 == NULL, -- NULL (the result of adding 1 together with unknown value of type Int)
+ (1, NULL) == (1, 2), -- NULL (composite elements are compared by component
+ -- through `AND`)
+ (2, NULL) == (1, 3), -- Just(False) (expression is equivalent to 2 == 1 AND NULL == 3)
+
+```
diff --git a/yql/essentials/docs/en/types/primitive.md b/yql/essentials/docs/en/types/primitive.md
new file mode 100644
index 0000000000..24857a2f64
--- /dev/null
+++ b/yql/essentials/docs/en/types/primitive.md
@@ -0,0 +1,188 @@
+# Primitive data types
+
+<!-- markdownlint-disable blanks-around-fences -->
+
+The terms "simple", "primitive", and "elementary" data types are used synonymously.
+
+## Numeric types {#numeric}
+
+| Type | Description | Notes |
+| ----- | ----- | ----- |
+| `Bool` | Boolean value. |
+| `Int8` | A signed integer.<br/>Acceptable values: from -2<sup>7</sup> to 2<sup>7</sup>–1. | |
+| `Int16` | A signed integer.<br/>Acceptable values: from –2<sup>15</sup> to 2<sup>15</sup>–1. | |
+| `Int32` | A signed integer.<br/>Acceptable values: from –2<sup>31</sup> to 2<sup>31</sup>–1. | |
+| `Int64` | A signed integer.<br/>Acceptable values: from –2<sup>63</sup> to 2<sup>63</sup>–1. | |
+| `Uint8` | An unsigned integer.<br/>Acceptable values: from 0 to 2<sup>8</sup>–1. | |
+| `Uint16` | An unsigned integer.<br/>Acceptable values: from 0 to 2<sup>16</sup>–1. | |
+| `Uint32` | An unsigned integer.<br/>Acceptable values: from 0 to 2<sup>32</sup>–1. | |
+| `Uint64` | An unsigned integer.<br/>Acceptable values: from 0 to 2<sup>64</sup>–1. | |
+| `Float` | A real number with variable precision, 4 bytes in size. | |
+| `Double` | A real number with variable precision, 8 bytes in size. | |
+| `Decimal` | A real number with the specified precision, up to 35 decimal digits | |
+|`DyNumber` | A binary representation of a real number with an accuracy of up to 38 digits.<br/>Acceptable values: positive numbers from 1×10<sup>-130</sup> up to 1×10<sup>126</sup>–1, negative numbers from -1×10<sup>126</sup>–1 to -1×10<sup>-130</sup>, and 0.<br/>Compatible with the `Number` type in AWS DynamoDB. | |
+
+
+## String types {#string}
+
+| Type | Description | Notes |
+| ----- | ----- | ----- |
+| `String` | A string that can contain any binary data |
+| `Utf8` | Text encoded in [UTF-8](https://en.wikipedia.org/wiki/UTF-8) |
+| `Json` | [JSON](https://en.wikipedia.org/wiki/JSON) represented as text | Doesn't support matching |
+| `JsonDocument` | [JSON](https://en.wikipedia.org/wiki/JSON) in an indexed binary representation | Doesn't support matching |
+| `Yson` | [YSON](../udf/list/yson.md) in a textual or binary representation. | Doesn't support matching |
+| `Uuid` | Universally unique identifier [UUID](https://tools.ietf.org/html/rfc4122) |
+
+
+Unlike the `JSON` data type that stores the original text representation passed by the user, `JsonDocument` uses an indexed binary representation. An important difference from the point of view of semantics is that `JsonDocument` doesn't preserve formatting, the order of keys in objects, or their duplicates.
+
+Thanks to the indexed view, `JsonDocument` lets you bypass the document model using `JsonPath` without the need to parse the full content. This helps efficiently perform operations from the [JSON API](../builtins/json.md), reducing delays and cost of user queries. Execution of `JsonDocument` queries can be up to several times more efficient depending on the type of load.
+
+Due to the added redundancy, `JsonDocument` is less effective in storage. The additional storage overhead depends on the specific content, but is 20-30% of the original volume on average. Saving data in `JsonDocument` format requires additional conversion from the textual representation, which makes writing it less efficient. However, for most read-intensive scenarios that involve processing data from JSON, this data type is preferred and recommended.
+
+{% note warning %}
+
+To store numbers (JSON Number) in `JsonDocument`, as well as for arithmetic operations on them in the [JSON API](../builtins/json.md), the [Double](https://en.wikipedia.org/wiki/Double-precision_floating-point_format) type is used. Precision might be lost when non-standard representations of numbers are used in the source JSON document.
+
+{% endnote %}
+
+
+
+## Date and time {#datetime}
+
+| Type | Description | Notes |
+| ----- | ----- | ----- |
+| `Date` | Date, precision to the day | Range of values for all time types except `Interval`: From 00:00 01.01.1970 to 00:00 01.01.2106. Internal `Date` representation: Unsigned 16-bit integer |
+| `Datetime` | Date/time, precision to the second | Internal representation: Unsigned 32-bit integer |
+| `Timestamp` | Date/time, precision to the microsecond | Internal representation: Unsigned 64-bit integer |
+| `Interval` | Time interval (signed), precision to microseconds | Value range: From -136 years to +136 years. Internal representation: Signed 64-bit integer. |
+| `TzDate` | Date with time zone label, precision to the day | Not supported in table columns |
+| `TzDateTime` | Date/time with time zone label, precision to the second | Not supported in table columns |
+| `TzTimestamp` | Date/time with time zone label, precision to the microsecond | Not supported in table columns |
+
+
+
+### Supporting types with a time zone label
+
+Time zone label for the `TzDate`, `TzDatetime`, `TzTimestamp` types is an attribute that is used:
+
+* When converting ([CAST](../syntax/expressions.md#cast), [DateTime::Parse](../udf/list/datetime.md#parse), [DateTime::Format](../udf/list/datetime.md#format)) to a string and from a string.
+* In [DateTime::Split](../udf/list/datetime.md#split), a timezone component is added to `Resource<TM>`.
+
+The point in time for these types is stored in UTC, and the timezone label doesn't participate in any other calculations in any way. For example:
+
+```yql
+SELECT -- these expressions are always true for any timezones: the timezone doesn't affect the point in time.
+ AddTimezone(CurrentUtcDate(), "Europe/Moscow") ==
+ AddTimezone(CurrentUtcDate(), "America/New_York"),
+ AddTimezone(CurrentUtcDatetime(), "Europe/Moscow") ==
+ AddTimezone(CurrentUtcDatetime(), "America/New_York");
+```
+
+Keep in mind that when converting between `TzDate` and `TzDatetime`, or `TzTimestamp` the date's midnight doesn't follow the local time zone, but midnight in UTC for the date in UTC.
+
+
+
+## Casting between data types {#cast}
+
+### Explicit casting {#explicit-cast}
+
+Explicit casting using [CAST](../syntax/expressions.md#cast):
+
+#### Casting to numeric types
+
+| Type | Bool | Int | Uint | Float | Double | Decimal |
+| --- | --- | --- | --- | --- | --- | --- |
+| **Bool** | — | Yes<sup>1</sup> | Yes<sup>1</sup> | Yes<sup>1</sup> | Yes<sup>1</sup> | No | Yes | No |
+| **INT** | Yes<sup>2</sup> | — | Yes<sup>3</sup> | Yes | Yes | Yes |
+| **Uint** | Yes<sup>2</sup> | Yes | — | Yes | Yes | Yes |
+| **Float** | Yes<sup>2</sup> | Yes | Yes | — | Yes | No |
+| **Double** | Yes<sup>2</sup> | Yes | Yes | Yes | — | No |
+| **Decimal** | No | Yes | Yes | Yes | Yes | — |
+| **String** | Yes | Yes | Yes | Yes | Yes | Yes |
+| **Utf8** | Yes | Yes | Yes | Yes | Yes | Yes |
+| **Json** | No | No | No | No | No | No |
+| **Yson** | Yes<sup>4</sup> | Yes<sup>4</sup> | Yes<sup>4</sup> | Yes<sup>4</sup> | Yes<sup>4</sup> | Yes<sup>4</sup> |
+| **Uuid** | No | No | No | No | No | No |
+| **Date** | No | Yes | Yes | Yes | Yes | No | Yes |
+| **Datetime** | No | Yes | Yes | Yes | Yes | No |
+| **Timestamp** | No | Yes | Yes | Yes | Yes | No |
+| **Interval** | No | Yes | Yes | Yes | Yes | No |
+
+<sup>1</sup> `True` is converted to `1` and `False` to `0`.
+<sup>2</sup> Any value other than `0` is converted to `True`, `0` is converted to `False`.
+<sup>3</sup> Possible only in the case of a non-negative value.
+<sup>4</sup> Using the built-in function [Yson::ConvertTo](../udf/list/yson.md#ysonconvertto).
+
+#### Converting to date and time data types
+
+| Type | Date | Datetime | Timestamp | Interval |
+| --- | --- | --- | --- | --- |
+| **Bool** | No | No | No | No |
+| **INT** | Yes | Yes | Yes | Yes |
+| **Uint** | Yes | Yes | Yes | Yes |
+| **Float** | No | No | No | No |
+| **Double** | No | No | No | No |
+| **Decimal** | No | No | No | No |
+| **String** | Yes | Yes | Yes | Yes |
+| **Utf8** | Yes | Yes | Yes | Yes |
+| **Json** | No | No | No | No |
+| **Yson** | No | No | No | No |
+| **Uuid** | No | No | No | No |
+| **Date** | — | Yes | Yes | No |
+| **Datetime** | Yes | — | Yes | No |
+| **Timestamp** | Yes | Yes | — | No |
+| **Interval** | No | No | No | — | — |
+
+#### Conversion to other data types
+
+| Type | String | Utf8 | Json | Yson | Uuid |
+| --- | --- | --- | --- | --- | --- |
+| **Bool** | Yes | No | No | No | No |
+| **INT** | Yes | No | No | No | No |
+| **Uint** | Yes | No | No | No | No |
+| **Float** | Yes | No | No | No | No |
+| **Double** | Yes | No | No | No | No |
+| **Decimal** | Yes | No | No | No | No |
+| **String** | — | Yes | Yes | Yes | Yes |
+| **Utf8** | Yes | — | No | No | No |
+| **Json** | Yes | Yes | — | No | No |
+| **Yson** | Yes<sup>4</sup> | No | No | No | No |
+| **Uuid** | Yes | Yes | No | No | — |
+| **Date** | Yes | Yes | No | No | No |
+| **Datetime** | Yes | Yes | No | No | No |
+| **Timestamp** | Yes | Yes | No | No | No |
+| **Interval** | Yes | Yes | No | No | No |
+
+<sup>4</sup> Using the built-in function [Yson::ConvertTo](../udf/list/yson.md#ysonconvertto).
+
+##### Examples
+
+{% include [x](../_includes/cast_examples.md) %}
+
+### Implicit casting {#implicit-cast}
+
+Implicit type casting that occurs in basic operations ( +-\*/) between different data types. The table cells specify the operation result type, if the operation is possible:
+
+#### Numeric types
+
+| Type | Int | Uint | Float | Double |
+| --- | --- | --- | --- | --- |
+| **INT** | — | `INT` | `Float` | `Double` |
+| **Uint** | `INT` | — | `Float` | `Double` |
+| **Float** | `Float` | `Float` | — | `Double` |
+| **Double** | `Double` | `Double` | `Double` | — |
+
+#### Date and time types
+
+| Type | Date | Datetime | Timestamp | Interval | TzDate | TzDatetime | TzTimestamp |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| **Date** | — | — | — | `Date` | — | — | — |
+| **Datetime** | — | — | — | `Datetime` | — | — | — |
+| **Timestamp** | — | — | — | `Timestamp` | — | — | — |
+| **Interval** | `Date` | `Datetime` | `Timestamp` | — | `TzDate` | `TzDatetime` | `TzTimestamp` |
+| **TzDate** | — | — | — | `TzDate` | — | — | — |
+| **TzDatetime** | — | — | — | `TzDatetime` | — | — | — |
+| **TzTimestamp** | — | — | — | `TzTimestamp` | — | — | — |
+
diff --git a/yql/essentials/docs/en/types/special.md b/yql/essentials/docs/en/types/special.md
new file mode 100644
index 0000000000..16a8cc7e01
--- /dev/null
+++ b/yql/essentials/docs/en/types/special.md
@@ -0,0 +1,14 @@
+# Special data types
+
+| Type | Description |
+| ----- | ----- |
+| `Callable` | A callable value that can be executed by passing arguments in parentheses in YQL SQL syntax or using the `Apply` function with the [s-expressions](/docs/s_expressions) syntax. |
+| `Resource` | Resource is an opaque pointer to a resource you can pass between the user defined functions (UDF). The type of the returned and accepted resource is declared inside a function using a string label. When passing a resource, YQL checks for label matching to prevent passing of resources between incompatible functions. If the labels mismatch, a type error occurs. |
+| `Tagged` | Tagged is the option to assign an application name to any other type. |
+| `Generic` | The data type used for data types. |
+| `Unit` | Unit is the data type used for non-enumerable entities (data sources and data sinks, atoms, etc.&nbsp;). |
+| `Null` | Void is a singular data type with the only possible null value. It's the type of the `NULL` literal and can be converted to any `Optional` type. |
+| `Void` | Void is a singular data type with the only possible `"null"` value. |
+| `EmptyList` | A singular data type with the only possible [] value. It's the type of the `[]` literal and can be converted to any `List` type. |
+| `EmptyDict` | A singular data type with the only possible {} value. It's a type of the `{}` literal and can be converted to any `Dict` or `Set` type. |
+
diff --git a/yql/essentials/docs/en/types/toc_i.yaml b/yql/essentials/docs/en/types/toc_i.yaml
new file mode 100644
index 0000000000..060dd02891
--- /dev/null
+++ b/yql/essentials/docs/en/types/toc_i.yaml
@@ -0,0 +1,17 @@
+items:
+- name: Overview
+ href: index.md
+- name: Simple
+ href: primitive.md
+- name: Optional
+ href: optional.md
+- name: Containers
+ href: containers.md
+- name: Special
+ href: special.md
+- name: Type casting
+ href: cast.md
+- name: Text representation of data types
+ href: type_string.md
+- name: JSON
+ href: json.md \ No newline at end of file
diff --git a/yql/essentials/docs/en/types/type_string.md b/yql/essentials/docs/en/types/type_string.md
new file mode 100644
index 0000000000..e8a0c54d7d
--- /dev/null
+++ b/yql/essentials/docs/en/types/type_string.md
@@ -0,0 +1,70 @@
+# Text representation of data types
+
+## Introduction {#intro}
+
+Since YQL is a strongly typed language, the data type is important for many of its aspects. To make data type management easy, YQL has a data type definition convention in text format. It's mentioned in many places in the documentation. There's also a library that provides functions for building a data type based on a text description (for example, when manually defining the signature for the called value) or for serializing the data type into a string for debugging purposes.
+
+Functions for data types are [described in the article](../builtins/types.md). Below is the format of text representation of data types.
+
+## General conventions {#rules}
+
+* [Primitive data types](primitive.md) are represented in text format simply by referencing their name.
+* A complex data type is composed of other data types. If you depict this structure as a tree, it has [primitive data types](primitive.md) as leaves and [containers](containers.md) as other nodes. [You may treat special data types](special.md) as exceptions, because they can function as both.
+* The text representation repeats the structure of this tree from the root to the leaves: each node of the tree specifies the name of the current data type, and proceeding to a deeper level is denoted by different types of brackets.
+* Feel free to use spaces and line breaks if they improve readability.
+* If the ID contains something else except the Latin letters and numbers, put it in single quotes and use C-escaping.
+
+## Containers {#containers}
+
+* Use angle brackets to specify the types of container elements.
+
+ Example: `List<Int32>`.
+
+* If a container can hold multiple heterogeneous elements, they are listed inside angle brackets with a comma.
+
+ Example: `Tuple<Int32, String>`.
+
+* If a container can hold named elements, use comma-separated name-type pairs with a colon in-between instead of comma-separated data types.
+
+ Example: `Struct<a:Int32, b:String>`.
+
+* The underlying `Variant` container type is chosen based on the presence of names in arguments.
+
+ Example: `Variant<Int32, String>` is a variant on tuple, `Variant<a:Int32, b:String>` is a variant on structure.
+
+## Types that allow NULL {#optional}
+
+* They are called `Optional` in YQL terms, or nullable in the classic SQL terms.
+
+* Formally, this type is a container. So, you may declare it as `Optional<...>`, but the shortcut notation of a question mark suffix is usually used instead.
+
+ Example: `String?`.
+
+## Called values {#callable}
+
+* The basic form of the called values looks as follows: `(arg1, arg2, ...) -> result`.
+
+ An example of declaring a function signature that accepts two strings and returns a number: `(String, String) -> Int64`.
+
+* The called values can return the called values: in this case, they make up a chain of the required length.
+
+ Example: `(String, String) -> (String, String) -> Int64`.
+
+* Optional arguments must have the `Optional` type at the top level and be enclosed in square brackets.
+
+ Example: `(String, [String?, Double?]) -> Int64`.
+
+* The arguments of the called values can contain flags.
+
+ Currently, the only possible flag is `AutoMap`. It means that if NULL is passed to this argument, the result must also be set to NULL without running the function.
+
+ Example: `(String{Flags: AutoMap}) -> Int64`.
+
+* Use this particular format if you need `Optional<Callable...>`, because the trailing question mark refers to the result of the called value.
+
+## Resources {#resources}
+
+* Unlike containers, a resource isn't parameterized by the element type (it's a pointer in memory and YQL knows nothing about its contents). Instead, a resource is parameterized by a string label that can safeguard against passing resources between incompatible functions.
+
+ Example: `Resource<Foo>`.
+
diff --git a/yql/essentials/docs/en/udf/list/datetime.md b/yql/essentials/docs/en/udf/list/datetime.md
new file mode 100644
index 0000000000..c18380d408
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/datetime.md
@@ -0,0 +1,501 @@
+# DateTime
+
+In the DateTime module, the main internal representation format is `Resource<TM>`, which stores the following date components:
+
+* Year (12 bits).
+* Month (4 bits).
+* Day (5 bits).
+* Hour (5 bits).
+* Minute (6 bits).
+* Second (6 bits).
+* Microsecond (20 bits).
+* TimezoneId (16 bits).
+* DayOfYear (9 bits): Day since the beginning of the year.
+* WeekOfYear (6 bits): Week since the beginning of the year, January 1 is always in week 1.
+* WeekOfYearIso8601 (6 bits): Week of the year according to ISO 8601 (the first week is the one that includes January 4).
+* DayOfWeek (3 bits): Day of the week.
+
+If the timezone is not GMT, the components store the local time for the relevant timezone.
+
+## Split {#split}
+
+Conversion from a primitive type to an internal representation. It's always successful on a non-empty input.
+
+### List of functions
+
+* `DateTime::Split(Date{Flags:AutoMap}) -> Resource<TM>`
+* `DateTime::Split(Datetime{Flags:AutoMap}) -> Resource<TM>`
+* `DateTime::Split(Timestamp{Flags:AutoMap}) -> Resource<TM>`
+* `DateTime::Split(TzDate{Flags:AutoMap}) -> Resource<TM>`
+* `DateTime::Split(TzDatetime{Flags:AutoMap}) -> Resource<TM>`
+* `DateTime::Split(TzTimestamp{Flags:AutoMap}) -> Resource<TM>`
+
+Functions that accept `Resource<TM>` as input, can be called directly from the primitive date/time type. An implicit conversion will be made in this case by calling a relevant `Split` function.
+
+## Make... {#make}
+
+Making a primitive type from an internal representation. It's always successful on a non-empty input.
+
+### List of functions
+
+* `DateTime::MakeDate(Resource<TM>{Flags:AutoMap}) -> Date`
+* `DateTime::MakeDatetime(Resource<TM>{Flags:AutoMap}) -> Datetime`
+* `DateTime::MakeTimestamp(Resource<TM>{Flags:AutoMap}) -> Timestamp`
+* `DateTime::MakeTzDate(Resource<TM>{Flags:AutoMap}) -> TzDate`
+* `DateTime::MakeTzDatetime(Resource<TM>{Flags:AutoMap}) -> TzDatetime`
+* `DateTime::MakeTzTimestamp(Resource<TM>{Flags:AutoMap}) -> TzTimestamp`
+
+### Examples
+
+```yql
+SELECT
+ DateTime::MakeTimestamp(DateTime::Split(Datetime("2019-01-01T15:30:00Z"))),
+ -- 2019-01-01T15:30:00.000000Z
+ DateTime::MakeDate(Datetime("2019-01-01T15:30:00Z")),
+ -- 2019-01-01
+ DateTime::MakeTimestamp(DateTime::Split(TzDatetime("2019-01-01T00:00:00,Europe/Moscow"))),
+ -- 2018-12-31T21:00:00Z (conversion to UTC)
+ DateTime::MakeDate(TzDatetime("2019-01-01T12:00:00,GMT"))
+ -- 2019-01-01 (Datetime -> Date with implicit Split)>
+```
+
+## Get... {#get}
+
+Extracting a component from an internal representation.
+
+### List of functions
+
+* `DateTime::GetYear(Resource<TM>{Flags:AutoMap}) -> Uint16`
+* `DateTime::GetDayOfYear(Resource<TM>{Flags:AutoMap}) -> Uint16`
+* `DateTime::GetMonth(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetMonthName(Resource<TM>{Flags:AutoMap}) -> String`
+* `DateTime::GetWeekOfYear(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetWeekOfYearIso8601(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetDayOfMonth(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetDayOfWeek(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetDayOfWeekName(Resource<TM>{Flags:AutoMap}) -> String`
+* `DateTime::GetHour(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetMinute(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetSecond(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetMillisecondOfSecond(Resource<TM>{Flags:AutoMap}) -> Uint32`
+* `DateTime::GetMicrosecondOfSecond(Resource<TM>{Flags:AutoMap}) -> Uint32`
+* `DateTime::GetTimezoneId(Resource<TM>{Flags:AutoMap}) -> Uint16`
+* `DateTime::GetTimezoneName(Resource<TM>{Flags:AutoMap}) -> String`
+
+### Examples
+
+```yql
+$tm = DateTime::Split(TzDatetime("2019-01-09T00:00:00,Europe/Moscow"));
+
+SELECT
+ DateTime::GetDayOfMonth($tm) as Day, -- 9
+ DateTime::GetMonthName($tm) as Month, -- "January"
+ DateTime::GetYear($tm) as Year, -- 2019
+ DateTime::GetTimezoneName($tm) as TzName, -- "Europe/Moscow"
+ DateTime::GetDayOfWeekName($tm) as WeekDay; -- "Wednesday"
+```
+
+## Update {#update}
+
+Updating one or more components in the internal representation. Returns either an updated copy or NULL, if an update produces an invalid date or other inconsistencies.
+
+### List of functions
+
+```yql
+DateTime::Update( Resource<TM>{Flags:AutoMap}, [ Year:Uint16?, Month:Uint8?, Day:Uint8?, Hour:Uint8?, Minute:Uint8?, Second:Uint8?, Microsecond:Uint32?, Timezone:String? ]) -> Resource<TM>?
+```
+
+### Examples
+
+```yql
+$tm = DateTime::Split(Timestamp("2019-01-01T01:02:03.456789Z"));
+
+SELECT
+ DateTime::MakeDate(DateTime::Update($tm, 2012)), -- 2012-01-01
+ DateTime::MakeDate(DateTime::Update($tm, 2000, 6, 6)), -- 2000-06-06
+ DateTime::MakeDate(DateTime::Update($tm, NULL, 2, 30)), -- NULL (February 30)
+ DateTime::MakeDatetime(DateTime::Update($tm, NULL, NULL, 31)), -- 2019-01-31T01:02:03Z
+ DateTime::MakeDatetime(DateTime::Update($tm, 15 as Hour, 30 as Minute)), -- 2019-01-01T15:30:03Z
+ DateTime::MakeTimestamp(DateTime::Update($tm, 999999 as Microsecond)), -- 2019-01-01T01:02:03.999999Z
+ DateTime::MakeTimestamp(DateTime::Update($tm, "Europe/Moscow" as Timezone)), -- 2018-12-31T22:02:03.456789Z (conversion to UTC)
+ DateTime::MakeTzTimestamp(DateTime::Update($tm, "Europe/Moscow" as Timezone)); -- 2019-01-01T01:02:03.456789,Europe/Moscow
+```
+
+## From... {#from}
+
+Getting a Timestamp from the number of seconds/milliseconds/microseconds since the UTC epoch. When the Timestamp limits are exceeded, NULL is returned.
+
+### List of functions
+
+* `DateTime::FromSeconds(Uint32{Flags:AutoMap}) -> Timestamp`
+* `DateTime::FromMilliseconds(Uint64{Flags:AutoMap}) -> Timestamp`
+* `DateTime::FromMicroseconds(Uint64{Flags:AutoMap}) -> Timestamp`
+
+## To... {#to}
+
+Getting a number of seconds/milliseconds/microseconds since the UTC Epoch from a primitive type.
+
+### List of functions
+
+* `DateTime::ToSeconds(Date/DateTime/Timestamp/TzDate/TzDatetime/TzTimestamp{Flags:AutoMap}) -> Uint32`
+* `DateTime::ToMilliseconds(Date/DateTime/Timestamp/TzDate/TzDatetime/TzTimestamp{Flags:AutoMap}) -> Uint64`
+* `DateTime::ToMicroseconds(Date/DateTime/Timestamp/TzDate/TzDatetime/TzTimestamp{Flags:AutoMap}) -> Uint64`
+
+### Examples
+
+```yql
+SELECT
+ DateTime::FromSeconds(1546304523), -- 2019-01-01T01:02:03.000000Z
+ DateTime::ToMicroseconds(Timestamp("2019-01-01T01:02:03.456789Z")); -- 1546304523456789
+```
+
+## Interval... {#interval}
+
+Conversions between `Interval` and various time units.
+
+### List of functions
+
+* `DateTime::ToDays(Interval{Flags:AutoMap}) -> Int16`
+* `DateTime::ToHours(Interval{Flags:AutoMap}) -> Int32`
+* `DateTime::ToMinutes(Interval{Flags:AutoMap}) -> Int32`
+* `DateTime::ToSeconds(Interval{Flags:AutoMap}) -> Int32`
+* `DateTime::ToMilliseconds(Interval{Flags:AutoMap}) -> Int64`
+* `DateTime::ToMicroseconds(Interval{Flags:AutoMap}) -> Int64`
+* `DateTime::IntervalFromDays(Int16{Flags:AutoMap}) -> Interval`
+* `DateTime::IntervalFromHours(Int32{Flags:AutoMap}) -> Interval`
+* `DateTime::IntervalFromMinutes(Int32{Flags:AutoMap}) -> Interval`
+* `DateTime::IntervalFromSeconds(Int32{Flags:AutoMap}) -> Interval`
+* `DateTime::IntervalFromMilliseconds(Int64{Flags:AutoMap}) -> Interval`
+* `DateTime::IntervalFromMicroseconds(Int64{Flags:AutoMap}) -> Interval`
+
+AddTimezone doesn't affect the output of ToSeconds() in any way, because ToSeconds() always returns GMT time.
+
+You can also create an Interval from a string literal in the format [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601%23Durations).
+
+### Examples
+
+```yql
+SELECT
+ DateTime::ToDays(Interval("PT3000M")), -- 2
+ DateTime::IntervalFromSeconds(1000000), -- 11 days 13 hours 46 minutes 40 seconds
+ DateTime::ToDays(cast('2018-01-01' as date) - cast('2017-12-31' as date)); --1
+```
+
+## StartOf... / EndOf... / TimeOfDay {#startof}
+
+Get the start (end) of the period including the date/time. If the result is invalid, NULL is returned. If the timezone is different from GMT, then the period start (end) is in the specified time zone.
+
+### List of functions
+
+* `DateTime::StartOfYear(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::EndOfYear(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::StartOfQuarter(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::EndOfQuarter(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::StartOfMonth(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::EndOfMonth(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::StartOfWeek(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::EndOfWeek(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::StartOfDay(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::EndOfDay(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::StartOf(Resource<TM>{Flags:AutoMap}, Interval{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::EndOf(Resource<TM>{Flags:AutoMap}, Interval{Flags:AutoMap}) -> Resource<TM>?`
+
+The `StartOf`/`EndOf` functions are intended for grouping by an arbitrary period within a day. The result differs from the input value only by time components. A period exceeding one day is treated as a day (an equivalent of `StartOfDay`/`EndOfDay`). If a day doesn't include an integer number of periods, the number is rounded to the nearest time from the beginning of the day that is a multiple of the specified period. When the interval is zero, the output is same as the input. A negative interval is treated as a positive one.
+
+The `EndOf...` functions are intended for obtaining the latest moment in the same period of time as the specified one.
+
+The functions treat periods longer than one day in a different manner than the same-name functions in the old library. The time components are always reset to zero (this makes sense, because these functions are mainly used for grouping by the period). You can also specify a time period within a day:
+
+* `DateTime::TimeOfDay(Resource<TM>{Flags:AutoMap}) -> Interval`
+
+### Examples
+
+```yql
+SELECT
+ DateTime::MakeDate(DateTime::StartOfYear(Date("2019-06-06"))),
+ -- 2019-01-01 (implicit Split here and below)
+ DateTime::MakeDatetime(DateTime::StartOfQuarter(Datetime("2019-06-06T01:02:03Z"))),
+ -- 2019-04-01T00:00:00Z (time components are reset to zero)
+ DateTime::MakeDate(DateTime::StartOfMonth(Timestamp("2019-06-06T01:02:03.456789Z"))),
+ -- 2019-06-01
+ DateTime::MakeDate(DateTime::StartOfWeek(Date("1970-01-01"))),
+ -- NULL (the beginning of the epoch is Thursday, the beginning of the week is 1969-12-29 that is beyond the limits)
+ DateTime::MakeTimestamp(DateTime::StartOfWeek(Date("2019-01-01"))),
+ -- 2018-12-31T00:00:00Z
+ DateTime::MakeDatetime(DateTime::StartOfDay(Datetime("2019-06-06T01:02:03Z"))),
+ -- 2019-06-06T00:00:00Z
+ DateTime::MakeTzDatetime(DateTime::StartOfDay(TzDatetime("1970-01-01T05:00:00,Europe/Moscow"))),
+ -- NULL (beyond the epoch in GMT)
+ DateTime::MakeTzTimestamp(DateTime::StartOfDay(TzTimestamp("1970-01-02T05:00:00.000000,Europe/Moscow"))),
+ -- 1970-01-02T00:00:00,Europe/Moscow (the beginning of the day in Moscow)
+ DateTime::MakeDatetime(DateTime::StartOf(Datetime("2019-06-06T23:45:00Z"), Interval("PT7H"))),
+ -- 2019-06-06T21:00:00Z
+ DateTime::MakeDatetime(DateTime::StartOf(Datetime("2019-06-06T23:45:00Z"), Interval("PT20M"))),
+ -- 2019-06-06T23:40:00Z
+ DateTime::TimeOfDay(Timestamp("2019-02-14T01:02:03.456789Z"));
+ -- 1 hour 2 minutes 3 seconds 456789 microseconds
+```
+
+## Shift... {#shift}
+
+Add/subtract the specified number of units to/from the component in the internal representation and update the other fields.
+Returns either an updated copy or NULL, if an update produces an invalid date or other inconsistencies.
+
+### List of functions
+
+* `DateTime::ShiftYears(Resource<TM>{Flags:AutoMap}, Int32) -> Resource<TM>?`
+* `DateTime::ShiftQuarters(Resource<TM>{Flags:AutoMap}, Int32) -> Resource<TM>?`
+* `DateTime::ShiftMonths(Resource<TM>{Flags:AutoMap}, Int32) -> Resource<TM>?`
+
+If the resulting number of the day in the month exceeds the maximum allowed, then the `Day` field will accept the last day of the month without changing the time (see examples).
+
+### Examples
+
+```yql
+$tm1 = DateTime::Split(DateTime("2019-01-31T01:01:01Z"));
+$tm2 = DateTime::Split(TzDatetime("2049-05-20T12:34:50,Europe/Moscow"));
+
+SELECT
+ DateTime::MakeDate(DateTime::ShiftYears($tm1, 10)), -- 2029-01-31T01:01:01
+ DateTime::MakeDate(DateTime::ShiftYears($tm2, -10000)), -- NULL (beyond the limits)
+ DateTime::MakeDate(DateTime::ShiftQuarters($tm2, 0)), -- 2049-05-20T12:34:50,Europe/Moscow
+ DateTime::MakeDate(DateTime::ShiftQuarters($tm1, -3)), -- 2018-04-30T01:01:01
+ DateTime::MakeDate(DateTime::ShiftMonths($tm1, 1)), -- 2019-02-28T01:01:01
+ DateTime::MakeDate(DateTime::ShiftMonths($tm1, -35)), -- 2016-02-29T01:01:01
+```
+
+## Format {#format}
+
+Get a string representation of a time using an arbitrary formatting string.
+
+### List of functions
+
+* `DateTime::Format(String, alwaysWriteFractionalSeconds:Bool?) -> (Resource<TM>{Flags:AutoMap}) -> String`
+
+A set of specifiers is implemented for the formatting string:
+
+* `%%`: % character.
+* `%Y`: 4-digit year.
+* `%m`: 2-digit month.
+* `%d`: 2-digit day.
+* `%H`: 2-digit hour.
+* `%M`: 2-digit minutes.
+* `%S`: 2-digit seconds -- or xx.xxxxxx in the case of non-empty microseconds (only if `alwaysWriteFractionalSeconds` is not set to `True`).
+* `%z`: +hhmm or -hhmm.
+* `%Z`: IANA name of the timezone.
+* `%b`: A short three-letter English name of the month (Jan).
+* `%B`: A full English name of the month (January).
+
+All other characters in the format string are passed on without changes.
+
+### Examples
+
+```yql
+$format = DateTime::Format("%Y-%m-%d %H:%M:%S %Z");
+
+SELECT
+ $format(DateTime::Split(TzDatetime("2019-01-01T01:02:03,Europe/Moscow")));
+ -- "2019-01-01 01:02:03 Europe/Moscow"
+```
+
+## Parse {#parse}
+
+Parse a string into an internal representation using an arbitrary formatting string. Default values are used for empty fields. If errors are raised, NULL is returned.
+
+### List of functions
+
+* `DateTime::Parse(String) -> (String{Flags:AutoMap}) -> Resource<TM>?`
+
+Implemented specifiers:
+
+* `%%`: the % character.
+* `%Y`: 4-digit year (1970).
+* `%m`: 2-digit month (1).
+* `%d`: 2-digit day (1).
+* `%H`: 2-digit hour (0).
+* `%M`: 2-digit minutes (0).
+* `%S`: Seconds (0), can also accept microseconds in the formats from xx. up to xx.xxxxxx
+* `%Z`: The IANA name of the timezone (GMT).
+* `%b`: A short three-letter case-insensitive English name of the month (Jan).
+* `%B`: A full case-insensitive English name of the month (January).
+
+### Examples
+
+```yql
+$parse1 = DateTime::Parse("%H:%M:%S");
+$parse2 = DateTime::Parse("%S");
+$parse3 = DateTime::Parse("%m/%d/%Y");
+$parse4 = DateTime::Parse("%Z");
+
+SELECT
+ DateTime::MakeDatetime($parse1("01:02:03")), -- 1970-01-01T01:02:03Z
+ DateTime::MakeTimestamp($parse2("12.3456")), -- 1970-01-01T00:00:12.345600Z
+ DateTime::MakeTimestamp($parse3("02/30/2000")), -- NULL (Feb 30)
+ DateTime::MakeTimestamp($parse4("Canada/Central")); -- 1970-01-01T06:00:00Z (conversion to UTC)
+```
+
+For the common formats, wrappers around the corresponding util methods are supported. You can only get TM with components in the UTC timezone.
+
+## Parse specific formats
+
+### List of functions
+
+* `DateTime::ParseRfc822(String{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::ParseIso8601(String{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::ParseHttp(String{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::ParseX509(String{Flags:AutoMap}) -> Resource<TM>?`
+
+### Examples
+
+```yql
+SELECT
+ DateTime::MakeTimestamp(DateTime::ParseRfc822("Fri, 4 Mar 2005 19:34:45 EST")),
+ -- 2005-03-05T00:34:45Z
+ DateTime::MakeTimestamp(DateTime::ParseIso8601("2009-02-14T02:31:30+0300")),
+ -- 2009-02-13T23:31:30Z
+ DateTime::MakeTimestamp(DateTime::ParseHttp("Sunday, 06-Nov-94 08:49:37 GMT")),
+ -- 1994-11-06T08:49:37Z
+ DateTime::MakeTimestamp(DateTime::ParseX509("20091014165533Z"))
+ -- 2009-10-14T16:55:33Z
+```
+
+## Standard scenarios
+
+### Conversions between strings and seconds
+
+Converting a string date (in the Moscow timezone) to seconds (in GMT timezone):
+
+```yql
+$datetime_parse = DateTime::Parse("%Y-%m-%d %H:%M:%S");
+$datetime_parse_tz = DateTime::Parse("%Y-%m-%d %H:%M:%S %Z");
+
+SELECT
+ DateTime::ToSeconds(TzDateTime("2019-09-16T00:00:00,Europe/Moscow")) AS md_us1, -- 1568581200
+ DateTime::ToSeconds(DateTime::MakeDatetime($datetime_parse_tz("2019-09-16 00:00:00" || " Europe/Moscow"))), -- 1568581200
+ DateTime::ToSeconds(DateTime::MakeDatetime(DateTime::Update($datetime_parse("2019-09-16 00:00:00"), "Europe/Moscow" as Timezone))), -- 1568581200
+
+ -- INCORRECT (Date imports time as GMT, but AddTimezone has no effect on ToSeconds that always returns GMT time)
+ DateTime::ToSeconds(AddTimezone(Date("2019-09-16"), 'Europe/Moscow')) AS md_us2, -- 1568592000
+```
+
+Converting a string date (in the Moscow timezone) to seconds (in the Moscow timezone). DateTime::ToSeconds() exports only to GMT. That's why we should put timezones aside for a while and use only GMT (as if we assumed for a while that Moscow is in GMT):
+
+```yql
+$date_parse = DateTime::Parse("%Y-%m-%d");
+$datetime_parse = DateTime::Parse("%Y-%m-%d %H:%M:%S");
+$datetime_parse_tz = DateTime::Parse("%Y-%m-%d %H:%M:%S %Z");
+
+SELECT
+ DateTime::ToSeconds(Datetime("2019-09-16T00:00:00Z")) AS md_ms1, -- 1568592000
+ DateTime::ToSeconds(Date("2019-09-16")) AS md_ms2, -- 1568592000
+ DateTime::ToSeconds(DateTime::MakeDatetime($date_parse("2019-09-16"))) AS md_ms3, -- 1568592000
+ DateTime::ToSeconds(DateTime::MakeDatetime($datetime_parse("2019-09-16 00:00:00"))) AS md_ms4, -- 1568592000
+ DateTime::ToSeconds(DateTime::MakeDatetime($datetime_parse_tz("2019-09-16 00:00:00 GMT"))) AS md_ms5, -- 1568592000
+
+ -- INCORRECT (imports the time in the Moscow timezone, but RemoveTimezone doesn't affect ToSeconds in any way)
+ DateTime::ToSeconds(RemoveTimezone(TzDatetime("2019-09-16T00:00:00,Europe/Moscow"))) AS md_ms6, -- 1568581200
+ DateTime::ToSeconds(DateTime::MakeDatetime($datetime_parse_tz("2019-09-16 00:00:00 Europe/Moscow"))) AS md_ms7 -- 1568581200
+```
+
+Converting seconds (in the GMT timezone) to a string date (in the Moscow timezone):
+
+```yql
+$date_format = DateTime::Format("%Y-%m-%d %H:%M:%S %Z");
+SELECT
+ $date_format(AddTimezone(DateTime::FromSeconds(1568592000), 'Europe/Moscow')) -- "2019-09-16 03:00:00 Europe/Moscow"
+```
+
+Converting seconds (in the Moscow timezone) to a string date (in the Moscow timezone). In this case, the %Z timezone is output for reference: usually, it's not needed because it's "GMT" and might mislead you.
+
+```yql
+$date_format = DateTime::Format("%Y-%m-%d %H:%M:%S %Z");
+SELECT
+ $date_format(DateTime::FromSeconds(1568592000)) -- "2019-09-16 00:00:00 GMT"
+```
+
+Converting seconds (in the GMT timezone) to three-letter days of the week (in the Moscow timezone):
+
+```yql
+SELECT
+ SUBSTRING(DateTime::GetDayOfWeekName(AddTimezone(DateTime::FromSeconds(1568581200), "Europe/Moscow")), 0, 3) -- "Mon"
+```
+
+### Date and time formatting
+
+Usually a separate named expression is used to format time, but you can do without it:
+
+```yql
+$date_format = DateTime::Format("%Y-%m-%d %H:%M:%S %Z");
+
+SELECT
+
+ -- A variant with a named expression
+
+ $date_format(AddTimezone(DateTime::FromSeconds(1568592000), 'Europe/Moscow')),
+
+ -- A variant without a named expression
+
+ DateTime::Format("%Y-%m-%d %H:%M:%S %Z")
+ (AddTimezone(DateTime::FromSeconds(1568592000), 'Europe/Moscow'))
+;
+```
+
+### Converting types
+
+This way, you can convert only constants:
+
+```yql
+SELECT
+ TzDateTime("2019-09-16T00:00:00,Europe/Moscow"), -- 2019-09-16T00:00:00,Europe/Moscow
+ Date("2019-09-16") -- 2019-09-16
+```
+
+But this way, you can convert a constant, a named expression, or a table field:
+
+```yql
+SELECT
+ CAST("2019-09-16T00:00:00,Europe/Moscow" AS TzDateTime), -- 2019-09-16T00:00:00,Europe/Moscow
+ CAST("2019-09-16" AS Date) -- 2019-09-16
+```
+
+### Converting time to date
+
+A CAST to Date or TzDate outputs a GMT date for a midnight, local time (for example, for Moscow time 2019-10-22 00:00:00, the date 2019-10-21 is returned). To get a date in the local timezone, you can use DateTime::Format.
+
+```yql
+$x = DateTime("2019-10-21T21:00:00Z");
+SELECT
+ AddTimezone($x, "Europe/Moscow"), -- 2019-10-22T00:00:00,Europe/Moscow
+ cast($x as TzDate), -- 2019-10-21,GMT
+ cast(AddTimezone($x, "Europe/Moscow") as TzDate), -- 2019-10-21,Europe/Moscow
+ cast(AddTimezone($x, "Europe/Moscow") as Date), -- 2019-10-21
+ DateTime::Format("%Y-%m-%d %Z")(AddTimezone($x, "Europe/Moscow")), -- 2019-10-22 Europe/Moscow
+```
+
+It's worth mentioning that several `TzDatetime` or `TzTimestamp` values with a positive timezone offset cannot be cast to `TzDate`. Consider the example below:
+
+```yql
+SELECT CAST(TzDatetime("1970-01-01T23:59:59,Europe/Moscow") as TzDate);
+/* Fatal: Timestamp 1970-01-01T23:59:59.000000,Europe/Moscow cannot be casted to TzDate */
+```
+
+Starting from the Unix epoch, there is no valid value representing midnight on 01/01/1970 for the Europe/Moscow timezone. As a result, such a cast is impossible and fails at runtime.
+
+At the same time, values with a negative timezone offset are converted correctly:
+
+```yql
+SELECT CAST(TzDatetime("1970-01-01T23:59:59,America/Los_Angeles") as TzDate);
+/* 1970-01-01,America/Los_Angeles */
+```
+
+### Daylight saving time
+
+Please note that daylight saving time depends on the year:
+
+```yql
+SELECT
+ RemoveTimezone(TzDatetime("2019-09-16T10:00:00,Europe/Moscow")) as DST1, -- 2019-09-16T07:00:00Z
+ RemoveTimezone(TzDatetime("2008-12-03T10:00:00,Europe/Moscow")) as DST2, -- 2008-12-03T07:00:00Z
+ RemoveTimezone(TzDatetime("2008-07-03T10:00:00,Europe/Moscow")) as DST3, -- 2008-07-03T06:00:00Z (DST)
+```
+
diff --git a/yql/essentials/docs/en/udf/list/digest.md b/yql/essentials/docs/en/udf/list/digest.md
new file mode 100644
index 0000000000..2acd4de863
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/digest.md
@@ -0,0 +1,43 @@
+# Digest
+
+A set of commonly used hash functions.
+
+## List of functions
+
+* `Digest::Crc32c(String{Flags::AutoMap}) -> Uint32`
+* `Digest::Crc64(String{Flags::AutoMap}) -> Uint64`
+* `Digest::Fnv32(String{Flags::AutoMap}) -> Uint32`
+* `Digest::Fnv64(String{Flags::AutoMap}) -> Uint64`
+* `Digest::MurMurHash(String{Flags:AutoMap}) -> Uint64`
+* `Digest::MurMurHash32(String{Flags:AutoMap}) -> Uint32`
+* `Digest::MurMurHash2A(String{Flags:AutoMap}) -> Uint64`
+* `Digest::MurMurHash2A32(String{Flags:AutoMap}) -> Uint32`
+* `Digest::CityHash(String{Flags:AutoMap}, [Uint64?]) -> Uint64`: The second optional argument is seed
+* `Digest::CityHash128(String{Flags:AutoMap}) -> Tuple<Uint64,Uint64>`
+* `Digest::NumericHash(Uint64{Flags:AutoMap}) -> Uint64`
+* `Digest::Md5Hex(String{Flags:AutoMap}) -> String`
+* `Digest::Md5Raw(String{Flags:AutoMap}) -> String`
+* `Digest::Md5HalfMix(String{Flags:AutoMap}) -> Uint64`: MD5 coarsening option (yabs_md5)
+* `Digest::Argon2(String{Flags:AutoMap},String{Flags:AutoMap}) -> String`: The second argument is the salt
+* `Digest::Blake2B(String{Flags:AutoMap},[String?]) -> String`: The second optional argument is the key
+* `Digest::SipHash(Uint64,Uint64,String{Flags:AutoMap}) -> Uint64`
+* `Digest::HighwayHash(Uint64,Uint64,Uint64,Uint64,String{Flags:AutoMap}) -> Uint64`
+* `Digest::FarmHashFingerprint(Uint64{Flags:AutoMap}) -> Uint64`
+* `Digest::FarmHashFingerprint2(Uint64{Flags:AutoMap}, Uint64{Flags:AutoMap}) -> Uint64`
+* `Digest::FarmHashFingerprint32(String{Flags:AutoMap}) -> Uint32`
+* `Digest::FarmHashFingerprint64(String{Flags:AutoMap}) -> Uint64`
+* `Digest::FarmHashFingerprint128(String{Flags:AutoMap}) -> Tuple<Uint64,Uint64>`
+* `Digest::SuperFastHash(String{Flags:AutoMap}) -> Uint32`
+* `Digest::Sha1(String{Flags:AutoMap}) -> String`
+* `Digest::Sha256(String{Flags:AutoMap}) -> String`
+* `Digest::IntHash64(Uint64{Flags:AutoMap}) -> Uint64`
+* `Digest::XXH3(String{Flags:AutoMap}) -> Uint64`
+* `Digest::XXH3_128(String{Flags:AutoMap}) -> Tuple<Uint64,Uint64>`
+
+### Examples
+
+```yql
+SELECT Digest::Md5Hex("YQL"); -- "1a0c1b56e9d617688ee345da4030da3c"
+SELECT Digest::NumericHash(123456789); -- 1734215268924325803
+```
+
diff --git a/yql/essentials/docs/en/udf/list/histogram.md b/yql/essentials/docs/en/udf/list/histogram.md
new file mode 100644
index 0000000000..94ac054c79
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/histogram.md
@@ -0,0 +1,19 @@
+# Histogram
+
+Set of auxiliary functions for the [HISTOGRAM aggregate function](../../builtins/aggregation.md). In the signature description below, HistogramStruct refers to the result of the aggregate function `HISTOGRAM`, `LinearHistogram` or `LogarithmicHistogram` being a structure of a certain type.
+
+## List of functions
+
+* `Histogram::Print(HistogramStruct{Flags:AutoMap}, Byte?) -> String`
+* `Histogram::Normalize(HistogramStruct{Flags:AutoMap}, [Double?]) -> HistogramStruct`: The second argument specifies the desired area of the histogram, 100 by default.
+* `Histogram::ToCumulativeDistributionFunction(HistogramStruct{Flags:AutoMap}) -> HistogramStruct`
+* `Histogram::GetSumAboveBound(HistogramStruct{Flags:AutoMap}, Double) -> Double`
+* `Histogram::GetSumBelowBound(HistogramStruct{Flags:AutoMap}, Double) -> Double`
+* `Histogram::GetSumInRange(HistogramStruct{Flags:AutoMap}, Double, Double) -> Double`
+* `Histogram::CalcUpperBound(HistogramStruct{Flags:AutoMap}, Double) -> Double`
+* `Histogram::CalcLowerBound(HistogramStruct{Flags:AutoMap}, Double) -> Double`
+* `Histogram::CalcUpperBoundSafe(HistogramStruct{Flags:AutoMap}, Double) -> Double`
+* `Histogram::CalcLowerBoundSafe(HistogramStruct{Flags:AutoMap}, Double) -> Double`
+
+`Histogram::Print` has an optional numeric argument that sets the maximum length of the histogram columns (the length is in characters, since the histogram is rendered in ASCII art). Default: 25. This function is primarily intended for viewing histograms in the console.
+
diff --git a/yql/essentials/docs/en/udf/list/hyperscan.md b/yql/essentials/docs/en/udf/list/hyperscan.md
new file mode 100644
index 0000000000..9bb32a078d
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/hyperscan.md
@@ -0,0 +1,108 @@
+# Hyperscan
+
+[Hyperscan](https://www.hyperscan.io) is an opensource library for regular expression matching developed by Intel.
+
+The library includes 4 implementations that use different sets of processor instructions (SSE3, SSE4.2, AVX2, and AVX512), with the needed instruction automatically selected based on the current processor.
+
+By default, all functions work in the single-byte mode. However, if the regular expression is a valid UTF-8 string but is not a valid ASCII string, the UTF-8 mode is enabled automatically.
+
+## List of functions
+
+* `Hyperscan::Grep(pattern:String) -> (string:String?) -> Bool`
+* `Hyperscan::Match(pattern:String) -> (string:String?) -> Bool`
+* `Hyperscan::BacktrackingGrep(pattern:String) -> (string:String?) -> Bool`
+* `Hyperscan::BacktrackingMatch(pattern:String) -> (string:String?) -> Bool`
+* `Hyperscan::MultiGrep(pattern:String) -> (string:String?) -> Tuple<Bool, Bool, ...>`
+* `Hyperscan::MultiMatch(pattern:String) -> (string:String?) -> Tuple<Bool, Bool, ...>`
+* `Hyperscan::Capture(pattern:String) -> (string:String?) -> String?`
+* `Hyperscan::Replace(pattern:String) -> (string:String?, replacement:String) -> String?`
+
+## Call syntax {#syntax}
+
+To avoid compiling a regular expression at each table row at direct call, wrap the function call by [a named expression](../../syntax/expressions.md#named-nodes):
+
+```yql
+$re = Hyperscan::Grep("\\d+"); -- create a callable value to match a specific regular expression
+SELECT * FROM table WHERE $re(key); -- use it to filter the table
+```
+
+{% note info %}
+
+Please note escaping of special characters in regular expressions. Be sure to use the second slash, since all the standard string literals in SQL can accept C-escaped strings, and the `\d` sequence is not valid sequence (even if it were, it wouldn't search for numbers as intended).
+
+{% endnote %}
+
+You can enable the case-insensitive mode by specifying, at the beginning of the regular expression, the flag `(?i)`.
+
+## Grep {#grep}
+
+Matches the regular expression with a **part of the string** (arbitrary substring).
+
+## Match {#match}
+
+Matches **the whole string** against the regular expression.
+
+To get a result similar to `Grep` (where substring matching is included), enclose the regular expression in `.*` (`.*foo.*` instead of `foo`). However, in terms of code readability, it's usually better to change the function.
+
+## BacktrackingGrep/BacktrackingMatch {#backtrackinggrep}
+
+The functions are identical to the same-name functions without the `Backtracking` prefix. However, they support a broader range of regular expressions. This is due to the fact that if a specific regular expression is not fully supported by Hyperscan, the library switches to the prefilter mode. In this case, it responds not by "Yes" or "No", but by "Definitely not" or "Maybe yes". The "Maybe yes" responses are then automatically rechecked using a slower, but more functional, library [libpcre](https://www.pcre.org).
+
+## MultiGrep/MultiMatch {#multigrep}
+
+Hyperscan lets you match against multiple regular expressions in a single pass through the text, and get a separate response for each match.
+
+However, if you want to match a string against any of the listed expressions (the results would be joined with "or"), it would be more efficient to combine the query parts in a single regular expression with `|` and match it with regular `Grep` or `Match`.
+
+When you call `MultiGrep`/`MultiMatch`, regular expressions are passed one per line using [multiline string literals](../../syntax/expressions.md#named-nodes):
+
+### Example
+
+```yql
+$multi_match = Hyperscan::MultiMatch(@@a.*
+.*x.*
+.*axa.*@@);
+
+SELECT
+ $multi_match("a") AS a, -- (true, false, false)
+ $multi_match("axa") AS axa; -- (true, true, true)
+```
+
+## Capture and Replace {#capture}
+
+`Hyperscan::Capture` if a string matches the specified regular expression, it returns the last substring matching the regular expression. `Hyperscan::Replace` replaces all occurrences of the specified regular expression with the specified string.
+
+Hyperscan doesn't support advanced functionality for such operations. Although `Hyperscan::Capture` and `Hyperscan::Replace` are implemented for consistency, it's better to use the same-name functions from the Re2 library for any non-trivial capture and replace:
+
+* [Re2::Capture](re2.md#capture);
+* [Re2::Replace](re2.md#replace).
+
+## Usage example
+
+```yql
+$value = "xaaxaaXaa";
+
+$match = Hyperscan::Match("a.*");
+$grep = Hyperscan::Grep("axa");
+$insensitive_grep = Hyperscan::Grep("(?i)axaa$");
+$multi_match = Hyperscan::MultiMatch(@@a.*
+.*a.*
+.*a
+.*axa.*@@);
+
+$capture = Hyperscan::Capture(".*a{2}.*");
+$capture_many = Hyperscan::Capture(".*x(a+).*");
+$replace = Hyperscan::Replace("xa");
+
+SELECT
+ $match($value) AS match, -- false
+ $grep($value) AS grep, -- true
+ $insensitive_grep($value) AS insensitive_grep, -- true
+ $multi_match($value) AS multi_match, -- (false, true, true, true)
+ $multi_match($value).0 AS some_multi_match, -- false
+ $capture($value) AS capture, -- "xaa"
+ $capture_many($value) AS capture_many, -- "xa"
+ $replace($value, "b") AS replace -- "babaXaa"
+;
+```
+
diff --git a/yql/essentials/docs/en/udf/list/index.md b/yql/essentials/docs/en/udf/list/index.md
new file mode 100644
index 0000000000..f89751e80b
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/index.md
@@ -0,0 +1,18 @@
+# Functions of built-in C++ libraries
+
+Many application functions that on the one hand are too specific to become part of the YQL core, and on the other hand might be useful to a wide range of users, are available through built-in C++ libraries.
+
+* [DateTime](datetime.md)
+* [Digest](digest.md)
+* [Histogram](histogram.md)
+* [Hyperscan](hyperscan.md)
+* [Ip](ip.md)
+* [Math](math.md)
+* [Pcre](pcre.md)
+* [Pire](pire.md)
+* [Re2](re2.md)
+* [String](string.md)
+* [Unicode](unicode.md)
+* [Url](url.md)
+* [Yson](yson.md)
+
diff --git a/yql/essentials/docs/en/udf/list/ip.md b/yql/essentials/docs/en/udf/list/ip.md
new file mode 100644
index 0000000000..c635d5009e
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/ip.md
@@ -0,0 +1,47 @@
+# Ip
+
+The `Ip` module supports both the IPv4 and IPv6 addresses. By default, they are represented as binary strings of 4 and 16 bytes, respectively.
+
+## List of functions
+
+* `Ip::FromString(String{Flags:AutoMap}) -> String?` - From a human-readable representation to a binary representation.
+* `Ip::SubnetFromString(String{Flags:AutoMap}) -> String?` - From a human-readable representation of subnet to a binary representation.
+* `Ip::ToString(String{Flags:AutoMap}) -> String?` - From a binary representation to a human-readable representation.
+* `Ip::SubnetToString(String{Flags:AutoMap}) -> String?` - From a binary representation of subnet to a human-readable representation.
+* `Ip::IsIPv4(String?) -> Bool`
+* `Ip::IsIPv6(String?) -> Bool`
+* `Ip::IsEmbeddedIPv4(String?) -> Bool`
+* `Ip::ConvertToIPv6(String{Flags:AutoMap}) -> String`: IPv6 remains unchanged, and IPv4 becomes embedded in IPv6
+* `Ip::GetSubnet(String{Flags:AutoMap}, [Uint8?]) -> String`: The second argument is the subnet size, by default it's 24 for IPv4 and 64 for IPv6
+* `Ip::GetSubnetByMask(String{Flags:AutoMap}, String{Flags:AutoMap}) -> String`: The first argument is the base address, the second argument is the bit mask of a desired subnet.
+* `Ip::SubnetMatch(String{Flags:AutoMap}, String{Flags:AutoMap}) -> Bool`: The first argument is a subnet, the second argument is a subnet or an address.
+
+
+## Examples
+
+```yql
+SELECT Ip::IsEmbeddedIPv4(
+ Ip::FromString("::ffff:77.75.155.3")
+); -- true
+
+SELECT
+ Ip::ToString(
+ Ip::GetSubnet(
+ Ip::FromString("213.180.193.3")
+ )
+ ); -- "213.180.193.0"
+
+SELECT
+ Ip::SubnetMatch(
+ Ip::SubnetFromString("192.168.0.1/16"),
+ Ip::FromString("192.168.1.14"),
+ ); -- true
+
+SELECT
+ Ip::ToString(
+ Ip::GetSubnetByMask(
+ Ip::FromString("192.168.0.1"),
+ Ip::FromString("255.255.0.0")
+ )
+ ); -- "192.168.0.0"
+```
diff --git a/yql/essentials/docs/en/udf/list/math.md b/yql/essentials/docs/en/udf/list/math.md
new file mode 100644
index 0000000000..dd129399d8
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/math.md
@@ -0,0 +1,140 @@
+# Math
+
+A set of wrappers around the functions from the libm library and the Yandex utilities.
+
+## Constants {#constants}
+
+### List of functions
+
+* `Math::Pi() -> Double`
+* `Math::E() -> Double`
+* `Math::Eps() -> Double`
+
+### Examples
+
+```yql
+SELECT Math::Pi(); -- 3.141592654
+SELECT Math::E(); -- 2.718281828
+SELECT Math::Eps(); -- 2.220446049250313e-16
+```
+
+## (Double) -> Bool {#double-bool}
+
+### List of functions
+
+* `Math::IsInf(Double{Flags:AutoMap}) -> Bool`
+* `Math::IsNaN(Double{Flags:AutoMap}) -> Bool`
+* `Math::IsFinite(Double{Flags:AutoMap}) -> Bool`
+
+### Examples
+
+```yql
+SELECT Math::IsNaN(0.0/0.0); -- true
+SELECT Math::IsFinite(1.0/0.0); -- false
+```
+
+## (Double) -> Double {#double-double}
+
+### List of functions
+
+* `Math::Abs(Double{Flags:AutoMap}) -> Double`
+* `Math::Acos(Double{Flags:AutoMap}) -> Double`
+* `Math::Asin(Double{Flags:AutoMap}) -> Double`
+* `Math::Asinh(Double{Flags:AutoMap}) -> Double`
+* `Math::Atan(Double{Flags:AutoMap}) -> Double`
+* `Math::Cbrt(Double{Flags:AutoMap}) -> Double`
+* `Math::Ceil(Double{Flags:AutoMap}) -> Double`
+* `Math::Cos(Double{Flags:AutoMap}) -> Double`
+* `Math::Cosh(Double{Flags:AutoMap}) -> Double`
+* `Math::Erf(Double{Flags:AutoMap}) -> Double`
+* `Math::ErfInv(Double{Flags:AutoMap}) -> Double`
+* `Math::ErfcInv(Double{Flags:AutoMap}) -> Double`
+* `Math::Exp(Double{Flags:AutoMap}) -> Double`
+* `Math::Exp2(Double{Flags:AutoMap}) -> Double`
+* `Math::Fabs(Double{Flags:AutoMap}) -> Double`
+* `Math::Floor(Double{Flags:AutoMap}) -> Double`
+* `Math::Lgamma(Double{Flags:AutoMap}) -> Double`
+* `Math::Rint(Double{Flags:AutoMap}) -> Double`
+* `Math::Sigmoid(Double{Flags:AutoMap}) -> Double`
+* `Math::Sin(Double{Flags:AutoMap}) -> Double`
+* `Math::Sinh(Double{Flags:AutoMap}) -> Double`
+* `Math::Sqrt(Double{Flags:AutoMap}) -> Double`
+* `Math::Tan(Double{Flags:AutoMap}) -> Double`
+* `Math::Tanh(Double{Flags:AutoMap}) -> Double`
+* `Math::Tgamma(Double{Flags:AutoMap}) -> Double`
+* `Math::Trunc(Double{Flags:AutoMap}) -> Double`
+* `Math::Log(Double{Flags:AutoMap}) -> Double`
+* `Math::Log2(Double{Flags:AutoMap}) -> Double`
+* `Math::Log10(Double{Flags:AutoMap}) -> Double`
+
+### Examples
+
+```yql
+SELECT Math::Sqrt(256); -- 16
+SELECT Math::Trunc(1.2345); -- 1
+```
+
+## (Double, Double) -> Double {#doubledouble-double}
+
+### List of functions
+
+* `Math::Atan2(Double{Flags:AutoMap}, Double{Flags:AutoMap}) -> Double`
+* `Math::Fmod(Double{Flags:AutoMap}, Double{Flags:AutoMap}) -> Double`
+* `Math::Hypot(Double{Flags:AutoMap}, Double{Flags:AutoMap}) -> Double`
+* `Math::Pow(Double{Flags:AutoMap}, Double{Flags:AutoMap}) -> Double`
+* `Math::Remainder(Double{Flags:AutoMap}, Double{Flags:AutoMap}) -> Double`
+
+### Examples
+
+```yql
+SELECT Math::Atan2(1, 0); -- 1.570796327
+SELECT Math::Remainder(2.1, 2); -- 0.1
+```
+
+## (Double, Int32) -> Double {#doubleint32-double}
+
+### List of functions
+
+* `Math::Ldexp(Double{Flags:AutoMap}, Int32{Flags:AutoMap}) -> Double`
+* `Math::Round(Double{Flags:AutoMap}, [Int32?]) -> Double`: The second argument indicates the power of 10 to which we round (it's negative for decimal digits and positive for rounding to tens, thousands, or millions); the default value is 0
+
+### Examples
+
+```yql
+SELECT Math::Pow(2, 10); -- 1024
+SELECT Math::Round(1.2345, -2); -- 1.23
+```
+
+## (Double, Double, \[Double?\]) -> Bool {#doubledouble-bool}
+
+### List of functions
+
+* `Math::FuzzyEquals(Double{Flags:AutoMap}, Double{Flags:AutoMap}, [Double?]) -> Bool`: Compares two Doubles for being inside the neighborhood specified by the third argument; the default value is 1.0e-13
+
+### Examples
+
+```yql
+SELECT Math::FuzzyEquals(1.01, 1.0, 0.05); -- true
+```
+
+## Functions for computing remainders
+
+### List of functions
+
+* `Math::Mod(Int64{Flags:AutoMap}, Int64) -> Int64?`
+* `Math::Rem(Int64{Flags:AutoMap}, Int64) -> Int64?`
+
+These functions behave similarly to the built-in % operator in the case of non-negative arguments. The differences are noticeable in the case of negative arguments:
+
+* `Math::Mod` preserves the sign of the second argument (the denominator).
+* `Math::Rem` preserves the sign of the first argument (the numerator).
+
+Functions return null if the divisor is zero.
+
+### Examples
+
+```yql
+SELECT Math::Mod(-1, 7); -- 6
+SELECT Math::Rem(-1, 7); -- -1
+```
+
diff --git a/yql/essentials/docs/en/udf/list/pcre.md b/yql/essentials/docs/en/udf/list/pcre.md
new file mode 100644
index 0000000000..9cd2332cef
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/pcre.md
@@ -0,0 +1,22 @@
+# Pcre
+
+The Pcre library is currently an alias to [Hyperscan](hyperscan.md).
+
+If you depend on some features of a certain regular expression engine, it's better to internally implement UDF with a given library inside. Use Pcre as the current most-recommended option for simple matching (that can be potentially changed to something else).
+
+Currently available engines:
+
+* [Hyperscan](hyperscan.md) <span style="color: gray;">(Intel)</span>
+* [Pire](pire.md) <span style="color: gray;">(Yandex)</span>
+* [Re2](re2.md) <span style="color: gray;">(Google)</span>
+
+All three modules provide approximately the same set of functions with an identical interface. This lets you switch between them with minimal changes to a query.
+
+Inside Hyperscan, there are several implementations that use different sets of processor instructions, with the relevant instruction automatically selected based on the current processor. In HyperScan, some functions support backtracking (referencing the previously found part of the string). Those functions are implemented through hybrid use of the two libraries: Hyperscan and libpcre.
+
+[Pire](https://github.com/yandex/pire) (Perl Incompatible Regular Expressions) is a very fast library of regular expressions developed by Yandex. At the lower level, it scans the input string once, without any lookaheads or rollbacks, spending 5 machine instructions per character (on x86 and x86_64). However, since the library almost hasn't been developed since 2011-2013 and its name says "Perl incompatible", you may need to adapt your regular expressions a bit.
+
+Hyperscan and Pire are best-suited for Grep and Match.
+
+The Re2 module uses [google::RE2](https://github.com/google/re2) that offers a wide range of features ([see the official documentation](https://github.com/google/re2/wiki/Syntax)). The main benefit of the Re2 is its advanced Capture and Replace functionality. Use this library, if you need those functions.
+
diff --git a/yql/essentials/docs/en/udf/list/pire.md b/yql/essentials/docs/en/udf/list/pire.md
new file mode 100644
index 0000000000..3776e74c04
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/pire.md
@@ -0,0 +1,115 @@
+# Pire
+
+## List of functions
+
+* `Pire::Grep(pattern:String) -> (string:String?) -> Bool`
+* `Pire::Match(pattern:String) -> (string:String?) -> Bool`
+* `Pire::MultiGrep(pattern:String) -> (string:String?) -> Tuple<Bool, Bool, ...>`
+* `Pire::MultiMatch(pattern:String) -> (string:String?) -> Tuple<Bool, Bool, ...>`
+* `Pire::Capture(pattern:String) -> (string:String?) -> String?`
+* `Pire::Replace(pattern:String) -> (string:String?, replacement:String) -> String?`
+
+One of the options to match regular expressions in YQL is to use [Pire](https://github.com/yandex/pire) (Perl Incompatible Regular Expressions). This is a very fast library of regular expressions developed at Yandex: at the lower level, it looks up the input string once, without any lookaheads or rollbacks, spending 5 machine instructions per character (on x86 and x86_64).
+
+The speed is achieved by using the reasonable restrictions:
+
+* Pire is primarily focused at checking whether a string matches a regular expression.
+* The matching substring can also be returned (by Capture), but with restrictions (a match with only one group is returned).
+
+By default, all functions work in the single-byte mode. However, if the regular expression is a valid UTF-8 string but is not a valid ASCII string, the UTF-8 mode is enabled automatically.
+
+To enable the Unicode mode, you can put one character that's beyond ASCII with the `?` operator, for example: `\\w+я?`.
+
+## Call syntax {#call-syntax}
+
+To avoid compiling a regular expression at each table row, wrap the function call by [a named expression](../../syntax/expressions.md#named-nodes):
+
+```yql
+$re = Pire::Grep("\\d+"); -- create a callable value to match a specific regular expression
+SELECT * FROM table WHERE $re(key); -- use it to filter the table
+```
+
+{% note alert %}
+
+When escaping special characters in a regular expression, be sure to use the second slash, since all the standard string literals in SQL can accept C-escaped strings, and the `\d` sequence is not a valid sequence (even if it were, it wouldn't search for numbers as intended).
+
+{% endnote %}
+
+You can enable the case-insensitive mode by specifying, at the beginning of the regular expression, the flag `(?i)`.
+
+### Examples
+
+```yql
+$value = "xaaxaaxaa";
+$match = Pire::Match("a.*");
+$grep = Pire::Grep("axa");
+$insensitive_grep = Pire::Grep("(?i)axa");
+$multi_match = Pire::MultiMatch(@@a.*
+.*a.*
+.*a
+.*axa.*@@);
+$capture = Pire::Capture(".*x(a).*");
+$capture_many = Pire::Capture(".*x(a+).*");
+$replace = Pire::Replace(".*x(a).*");
+
+SELECT
+ $match($value) AS match, -- false
+ $grep($value) AS grep, -- true
+ $insensitive_grep($value) AS insensitive_grep, -- true
+ $multi_match($value) AS multi_match, -- (false, true, true, true)
+ $multi_match($value).0 AS some_multi_match, -- false
+ $capture($value) AS capture, -- "a"
+ $capture_many($value) AS capture_many, -- "aa"
+ $replace($value, "b") AS replace; -- "xaaxaaxba"
+```
+
+## Grep {#grep}
+
+Matches the regular expression with a **part of the string** (arbitrary substring).
+
+## Match {#match}
+
+Matches **the whole string** against the regular expression.
+To get a result similar to `Grep` (where substring matching is included), enclose the regular expression in `.*`. For example, use `.*foo.*` instead of `foo`.
+
+## MultiGrep/MultiMatch {#multigrep}
+
+Pire lets you match against multiple regular expressions in a single pass through the text and get a separate response for each match.
+Use the MultiGrep/MultiMatch functions to optimize the query execution speed. Be sure to do it carefully, since the size of the state machine used for matching grows exponentially with the number of regular expressions:
+
+* If you want to match a string against any of the listed expressions (the results are joined with "or"), it would be much more efficient to combine the query parts in a single regular expression with `|` and match it using regular Grep or Match.
+* Pire has a limit on the size of the state machine (YQL uses the default value set in the library). If you exceed the limit, the error is raised at the start of the query: `Failed to glue up regexes, probably the finite state machine appeared to be too large`.
+
+When you call MultiGrep/MultiMatch, regular expressions are passed one per line using [multiline string literals](../../syntax/expressions.md#multiline-string-literals):
+
+### Examples
+
+```yql
+$multi_match = Pire::MultiMatch(@@a.*
+.*x.*
+.*axa.*@@);
+
+SELECT
+ $multi_match("a") AS a, -- (true, false, false)
+ $multi_match("axa") AS axa; -- (true, true, true)
+```
+
+## Capture {#capture}
+
+If a string matches the specified regular expression, it returns a substring that matches the group enclosed in parentheses in the regular expression.
+Capture is non-greedy: the shortest possible substring is returned.
+
+{% note alert %}
+
+The expression must contain only **one** group in parentheses. `NULL` (empty Optional) is returned in case of no match.
+
+{% endnote %}
+
+If the above limitations and features are unacceptable for some reason, we recommend that you consider [Re2::Capture](re2.md#capture).
+
+## REPLACE {#replace}
+
+Pire doesn't support replace based on a regular expression. `Pire::Replace` implemented in YQL is a simplified emulation using `Capture`. It may run correctly, if the substring occurs more than once in the source string.
+
+As a rule, it's better to use [Re2::Replace](re2.md#replace) instead.
+
diff --git a/yql/essentials/docs/en/udf/list/re2.md b/yql/essentials/docs/en/udf/list/re2.md
new file mode 100644
index 0000000000..ab527b012a
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/re2.md
@@ -0,0 +1,122 @@
+# Re2
+
+## List of functions
+
+```yql
+Re2::Grep(pattern:String, options:Struct<...>?) -> (string:String?) -> Bool
+Re2::Match(pattern:String, options:Struct<...>?) -> (string:String?) -> Bool
+Re2::Capture(pattern:String, options:Struct<...>?) -> (string:String?) -> Struct<_1:String?,foo:String?,...>
+Re2::FindAndConsume(pattern:String, options:Struct<...>?) -> (string:String?) -> List<String>
+Re2::Replace(pattern:String, options:Struct<...>?) -> (string:String?, replacement:String) -> String?
+Re2::Count(pattern:String, options:Struct<...>?) -> (string:String?) -> Uint32
+Re2::Options([CaseSensitive:Bool?,DotNl:Bool?,Literal:Bool?,LogErrors:Bool?,LongestMatch:Bool?,MaxMem:Uint64?,NeverCapture:Bool?,NeverNl:Bool?,OneLine:Bool?,PerlClasses:Bool?,PosixSyntax:Bool?,Utf8:Bool?,WordBoundary:Bool?]) -> Struct<CaseSensitive:Bool,DotNl:Bool,Literal:Bool,LogErrors:Bool,LongestMatch:Bool,MaxMem:Uint64,NeverCapture:Bool,NeverNl:Bool,OneLine:Bool,PerlClasses:Bool,PosixSyntax:Bool,Utf8:Bool,WordBoundary:Bool>
+```
+
+The Re2 module supports regular expressions based on [google::RE2](https://github.com/google/re2) with a wide range of features provided ([see the official documentation](https://github.com/google/re2/wiki/Syntax)).
+
+By default, the UTF-8 mode is enabled automatically if the regular expression is a valid UTF-8-encoded string, but is not a valid ASCII string. You can manually control the settings of the re2 library, if you pass the result of the `Re2::Options` function as the second argument to other module functions, next to the regular expression.
+
+{% note warning %}
+
+Make sure to double all the backslashes in your regular expressions (if they are within a quoted string): standard string literals are treated as C-escaped strings in SQL. You can also format regular expressions as raw strings `@@regexp@@`: double slashes are not needed in this case.
+
+{% endnote %}
+
+## Examples
+
+```yql
+$value = "xaaxaaxaa";
+$options = Re2::Options(false AS CaseSensitive);
+$match = Re2::Match("[ax]+\\d");
+$grep = Re2::Grep("a.*");
+$capture = Re2::Capture(".*(?P<foo>xa?)(a{2,}).*");
+$replace = Re2::Replace("x(a+)x");
+$count = Re2::Count("a", $options);
+
+SELECT
+ $match($value) AS match, -- false
+ $grep($value) AS grep, -- true
+ $capture($value) AS capture, -- (_0: 'xaaxaaxaa', _1: 'aa', foo: 'x')
+ $capture($value)._1 AS capture_member, -- "aa"
+ $replace($value, "b\\1z") AS replace, -- "baazaaxaa"
+ $count($value) AS count; -- 6
+```
+
+## Re2::Grep / Re2::Match {#match}
+
+If you leave out the details of implementation and syntax of regular expressions, those functions are totally similar [to the same-name functions](pire.md#match) from the Pire module. With other things equal and no specific preferences, we recommend that you use `Pire::Grep or Pire::Match`.
+
+You can call the `Re2::Grep` function by using a `REGEXP` expression (see the [basic expression syntax](../../syntax/expressions.md#regexp)).
+
+For example, the following two queries are equivalent (also in terms of computing efficiency):
+
+* `$grep = Re2::Grep("b+"); SELECT $grep("aaabccc");`
+* `SELECT "aaabccc" REGEXP "b+";`
+
+## Re2::Capture {#capture}
+
+Unlike [Pire::Capture](pire.md#capture), `Re2::Capture` supports multiple and named capturing groups.
+Result type: a structure with the fields of the type `String?`.
+
+* Each field corresponds to a capturing group with the applicable name.
+* For unnamed groups, the following names are generated: `_1`, `_2`, etc.
+* The result always includes the `_0` field containing the entire substring matching the regular expression.
+
+For more information about working with structures in YQL, see the [section on containers](../../types/containers.md).
+
+## Re2::FindAndConsume {#findandconsume}
+
+Searches for all occurrences of the regular expression in the passed text and returns a list of values corresponding to the parenthesized part of the regular expression for each occurrence.
+
+## Re2::Replace {#replace}
+
+Works as follows:
+
+* In the input string (first argument), all the non-overlapping substrings matching the regular expression are replaced by the specified string (second argument).
+* In the replacement string, you can use the contents of capturing groups from the regular expression using back-references in the format: `\\1`, `\\2` etc. The `\\0` back-reference stands for the whole substring that matches the regular expression.
+
+## Re2::Count {#count}
+
+Returns the number of non-overlapping substrings of the input string that have matched the regular expression.
+
+## Re2::Options {#options}
+
+Notes on Re2::Options from the official [repository](https://github.com/google/re2/blob/main/re2/re2.h#L595-L617)
+
+| Parameter | Default | Comments |
+| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | ------------------------------------------------------------------------------------- |
+| CaseSensitive:Bool? | true | match is case-sensitive (regexp can override with (?i) unless in posix_syntax mode) |
+| DotNl:Bool? | false | let `.` match `\n` (default ) |
+| Literal:Bool? | false | interpret string as literal, not regexp |
+| LogErrors:Bool? | true | log syntax and execution errors to ERROR |
+| LongestMatch:Bool? | false | search for longest match, not first match |
+| MaxMem:Uint64? | - | (see below) approx. max memory footprint of RE2 |
+| NeverCapture:Bool? | false | parse all parents as non-capturing |
+| NeverNl:Bool? | false | never match \n, even if it is in regexp |
+| PosixSyntax:Bool? | false | restrict regexps to POSIX egrep syntax |
+| Utf8:Bool? | true | text and pattern are UTF-8; otherwise Latin-1 |
+| The following options are only consulted when PosixSyntax == true. <bt>When PosixSyntax == false, these features are always enabled and cannot be turned off; to perform multi-line matching in that case, begin the regexp with (?m). |
+| PerlClasses:Bool? | false | allow Perl's \d \s \w \D \S \W |
+| WordBoundary:Bool? | false | allow Perl's \b \B (word boundary and not) |
+| OneLine:Bool? | false | ^ and $ only match beginning and end of text |
+
+It is not recommended to use Re2::Options in the code. Most parameters can be replaced with regular expression flags.
+
+### Flag usage examples
+
+```yql
+$value = "Foo bar FOO"u;
+-- enable case-insensitive mode
+$capture = Re2::Capture(@@(?i)(foo)@@);
+
+SELECT
+ $capture($value) AS capture; -- ("_0": "Foo", "_1": "Foo")
+
+$capture = Re2::Capture(@@(?i)(?P<foo>FOO).*(?P<bar>bar)@@);
+
+SELECT
+ $capture($value) AS capture; -- ("_0": "Foo bar", "bar": "bar", "foo": "Foo")
+```
+
+In both cases, the word FOO will be found. Using the raw string @@regexp@@ lets you avoid double slashes.
+
diff --git a/yql/essentials/docs/en/udf/list/string.md b/yql/essentials/docs/en/udf/list/string.md
new file mode 100644
index 0000000000..73281c2514
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/string.md
@@ -0,0 +1,148 @@
+# String
+
+Functions for ASCII strings:
+
+## List of functions
+
+* `String::Base64Encode(String{Flags:AutoMap}) -> String`
+
+* `String::Base64Decode(String) -> String?`
+
+* `String::Base64StrictDecode(String) -> String?`
+
+* `String::EscapeC(String{Flags:AutoMap}) -> String`
+
+* `String::UnescapeC(String{Flags:AutoMap}) -> String`
+
+* `String::HexEncode(String{Flags:AutoMap}) -> String`
+
+* `String::HexDecode(String) -> String?`
+
+* `String::EncodeHtml(String{Flags:AutoMap}) -> String`
+
+* `String::DecodeHtml(String{Flags:AutoMap}) -> String`
+
+* `String::CgiEscape(String{Flags:AutoMap}) -> String`
+
+* `String::CgiUnescape(String{Flags:AutoMap}) -> String`
+
+* `String::Strip(String{Flags:AutoMap}) -> String`
+
+* `String::Collapse(String{Flags:AutoMap}) -> String`
+
+* `String::CollapseText(String{Flags:AutoMap}, Uint64) -> String`
+
+* `String::Contains(String?, String) -> Bool`
+
+* `String::Find(String{Flags:AutoMap}, String, [Uint64?]) -> Int64`: Returns the first position found or -1. The optional argument is the offset from the beginning of the string.
+
+* `String::ReverseFind(String{Flags:AutoMap}, String, [Uint64?]) -> Int64`: Returns the last position found or -1. The optional argument is the offset from the beginning of the string.
+
+* `String::HasPrefix(String?, String) -> Bool`
+
+* `String::HasPrefixIgnoreCase(String?, String) -> Bool`
+
+* `String::StartsWith(String?, String) -> Bool`
+
+* `String::StartsWithIgnoreCase(String?, String) -> Bool`
+
+* `String::HasSuffix(String?, String) -> Bool`
+
+* `String::HasSuffixIgnoreCase(String?, String) -> Bool`
+
+* `String::EndsWith(String?, String) -> Bool`
+
+* `String::EndsWithIgnoreCase(String?, String) -> Bool`
+
+* `String::Substring(String{Flags:AutoMap}, [Uint64?, Uint64?]) -> String`
+
+* `String::AsciiToLower(String{Flags:AutoMap}) -> String`: Changes only Latin characters. For working with other alphabets, see Unicode::ToLower
+
+* `String::AsciiToUpper(String{Flags:AutoMap}) -> String`: Changes only Latin characters. For working with other alphabets, see Unicode::ToUpper
+
+* `String::AsciiToTitle(String{Flags:AutoMap}) -> String`: Changes only Latin characters. For working with other alphabets, see Unicode::ToTitle
+
+* `String::SplitToList( String?, String, [ DelimeterString:Bool?, SkipEmpty:Bool?, Limit:Uint64? ]) -> List<String>`
+
+ The first argument is the source string
+ The second argument is a delimiter
+ The third argument includes the following parameters:
+
+ - DelimeterString:Bool? — treating a delimiter as a string (true, by default) or a set of characters "any of" (false)
+ - SkipEmpty:Bool? — whether to skip empty strings in the result, is false by default
+ - Limit:Uint64? — Limits the number of fetched components (unlimited by default); if the limit is exceeded, the raw suffix of the source string is returned in the last item
+
+* `String::JoinFromList(List<String>{Flags:AutoMap}, String) -> String`
+
+* `String::ToByteList(List<String>{Flags:AutoMap}) -> List<Byte>`
+
+* `String::FromByteList(List<Uint8>) -> String`
+
+* `String::ReplaceAll(String{Flags:AutoMap}, String, String) -> String`: Arguments: input, find, replacement
+
+* `String::ReplaceFirst(String{Flags:AutoMap}, String, String) -> String`: Arguments: input, find, replacement
+
+* `String::ReplaceLast(String{Flags:AutoMap}, String, String) -> String`: Arguments: input, find, replacement
+
+* `String::RemoveAll(String{Flags:AutoMap}, String) -> String`: The second argument is interpreted as an unordered set of characters to delete
+
+* `String::RemoveFirst(String{Flags:AutoMap}, String) -> String`: An unordered set of characters in the second argument, only the first encountered character from set is deleted
+
+* `String::RemoveLast(String{Flags:AutoMap}, String) -> String`: An unordered set of characters in the second argument, only the last encountered character from the set is deleted
+
+* `String::IsAscii(String{Flags:AutoMap}) -> Bool`
+
+* `String::IsAsciiSpace(String{Flags:AutoMap}) -> Bool`
+
+* `String::IsAsciiUpper(String{Flags:AutoMap}) -> Bool`
+
+* `String::IsAsciiLower(String{Flags:AutoMap}) -> Bool`
+
+* `String::IsAsciiAlpha(String{Flags:AutoMap}) -> Bool`
+
+* `String::IsAsciiAlnum(String{Flags:AutoMap}) -> Bool`
+
+* `String::IsAsciiHex(String{Flags:AutoMap}) -> Bool`
+
+* `String::LevensteinDistance(String{Flags:AutoMap}, String{Flags:AutoMap}) -> Uint64`
+
+* `String::LeftPad(String{Flags:AutoMap}, Uint64, [String?]) -> String`
+
+* `String::RightPad(String{Flags:AutoMap}, Uint64) -> String`
+
+* `String::Hex(Uint64{Flags:AutoMap}) -> String`
+
+* `String::SHex(Int64{Flags:AutoMap}) -> String`
+
+* `String::Bin(Uint64{Flags:AutoMap}) -> String`
+
+* `String::SBin(Int64{Flags:AutoMap}) -> String`
+
+* `String::HexText(String{Flags:AutoMap}) -> String`
+
+* `String::BinText(String{Flags:AutoMap}) -> String`
+
+* `String::HumanReadableDuration(Uint64{Flags:AutoMap}) -> String`
+
+* `String::HumanReadableQuantity(Uint64{Flags:AutoMap}) -> String`
+
+* `String::HumanReadableBytes(Uint64{Flags:AutoMap}) -> String`
+
+* `String::Prec(Double{Flags:AutoMap}, Uint64) -> String`
+
+* `String::Reverse(String?) -> String?`
+
+{% note alert %}
+
+The functions from the String library don't support Cyrillic and can only work with ASCII characters. To work with UTF-8 encoded strings, use functions from [Unicode](unicode.md).
+
+{% endnote %}
+
+## Examples
+
+```yql
+SELECT String::Base64Encode("YQL"); -- "WVFM"
+SELECT String::Strip("YQL "); -- "YQL"
+SELECT String::SplitToList("1,2,3,4,5,6,7", ",", 3 as Limit); -- ["1", "2", "3", "4,5,6,7"]
+```
+
diff --git a/yql/essentials/docs/en/udf/list/toc_base.yaml b/yql/essentials/docs/en/udf/list/toc_base.yaml
new file mode 100644
index 0000000000..8dbeb3fb82
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/toc_base.yaml
@@ -0,0 +1,16 @@
+items:
+- name: Overview
+ href: index.md
+- { name: DateTime, href: datetime.md }
+- { name: Digest, href: digest.md }
+- { name: Histogram, href: histogram.md }
+- { name: Hyperscan, href: hyperscan.md }
+- { name: Ip, href: ip.md }
+- { name: Math, href: math.md }
+- { name: Pcre, href: pcre.md }
+- { name: Pire, href: pire.md }
+- { name: Re2, href: re2.md }
+- { name: String, href: string.md }
+- { name: Unicode, href: unicode.md }
+- { name: Url, href: url.md }
+- { name: Yson, href: yson.md }
diff --git a/yql/essentials/docs/en/udf/list/toc_i.yaml b/yql/essentials/docs/en/udf/list/toc_i.yaml
new file mode 100644
index 0000000000..28325999d2
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/toc_i.yaml
@@ -0,0 +1,2 @@
+items:
+- include: { mode: link, path: toc_base.yaml } \ No newline at end of file
diff --git a/yql/essentials/docs/en/udf/list/unicode.md b/yql/essentials/docs/en/udf/list/unicode.md
new file mode 100644
index 0000000000..7509daa23c
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/unicode.md
@@ -0,0 +1,159 @@
+# Unicode
+
+Functions for Unicode strings.
+
+## List of functions
+
+* `Unicode::IsUtf(String) -> Bool`
+
+ Checks whether a string is a valid UTF-8 sequence. For example, the string `"\xF0"` isn't a valid UTF-8 sequence, but the string `"\xF0\x9F\x90\xB1"` correctly describes a UTF-8 cat emoji.
+
+* `Unicode::GetLength(Utf8{Flags:AutoMap}) -> Uint64`
+
+ Returns the length of a utf-8 string in unicode code points. Surrogate pairs are counted as one character.
+
+ ```yql
+ SELECT Unicode::GetLength("жніўня"); -- 6
+ ```
+
+* `Unicode::Find(string:Utf8{Flags:AutoMap}, subString:Utf8, [pos:Uint64?]) -> Uint64?`
+
+* `Unicode::RFind(string:Utf8{Flags:AutoMap}, subString:Utf8, [pos:Uint64?]) -> Uint64?`
+
+ Finding the first (`RFind` - the last) occurrence of a substring in a string starting from the `pos` position. Returns the position of the first character from the found substring. In case of failure, returns Null.
+
+ ```yql
+ SELECT Unicode::Find("aaa", "bb"); -- Null
+ ```
+
+* `Unicode::Substring(string:Utf8{Flags:AutoMap}, from:Uint64?, len:Uint64?) -> Utf8`
+
+ Returns a `string` substring starting with `from` that is `len` characters long. If the `len` argument is omitted, the substring is taken to the end of the source string.
+
+ If `from` exceeds the length of the original string, an empty string `""` is returned.
+
+ ```yql
+ SELECT Unicode::Substring("0123456789abcdefghij", 10); -- "abcdefghij"
+ ```
+
+* The `Unicode::Normalize...` functions convert the passed UTF-8 string to a [normalization form](https://unicode.org/reports/tr15/#Norm_Forms):
+
+ * `Unicode::Normalize(Utf8{Flags:AutoMap}) -> Utf8` -- NFC
+ * `Unicode::NormalizeNFD(Utf8{Flags:AutoMap}) -> Utf8`
+ * `Unicode::NormalizeNFC(Utf8{Flags:AutoMap}) -> Utf8`
+ * `Unicode::NormalizeNFKD(Utf8{Flags:AutoMap}) -> Utf8`
+ * `Unicode::NormalizeNFKC(Utf8{Flags:AutoMap}) -> Utf8`
+
+* `Unicode::Translit(string:Utf8{Flags:AutoMap}, [lang:String?]) -> Utf8`
+
+ Transliterates with Latin letters the words from the passed string, consisting entirely of characters of the alphabet of the language passed by the second argument. If no language is specified, the words are transliterated from Russian. Available languages: "kaz", "rus", "tur", and "ukr".
+
+ ```yql
+ SELECT Unicode::Translit("Тот уголок земли, где я провел"); -- "Tot ugolok zemli, gde ya provel"
+ ```
+
+* `Unicode::LevensteinDistance(stringA:Utf8{Flags:AutoMap}, stringB:Utf8{Flags:AutoMap}) -> Uint64`
+
+ Calculates the Levenshtein distance for the passed strings.
+
+* `Unicode::Fold(Utf8{Flags:AutoMap}, [ Language:String?, DoLowerCase:Bool?, DoRenyxa:Bool?, DoSimpleCyr:Bool?, FillOffset:Bool? ]) -> Utf8`
+
+ Performs [case folding](https://www.w3.org/TR/charmod-norm/#definitionCaseFolding) on the passed string.
+
+ Parameters:
+
+ - `Language` is set according to the same rules as in `Unicode::Translit()`.
+ - `DoLowerCase` converts a string to lowercase letters, defaults to `true`.
+ - `DoRenyxa` converts diacritical characters to similar Latin characters, defaults to `true`.
+ - `DoSimpleCyr` converts diacritical Cyrillic characters to similar Latin characters, defaults to `true`.
+ - `FillOffset` parameter is not used.
+
+ ```yql
+ SELECT Unicode::Fold("Kongreßstraße", false AS DoSimpleCyr, false AS DoRenyxa); -- "kongressstrasse"
+ SELECT Unicode::Fold("ҫурт"); -- "сурт"
+ SELECT Unicode::Fold("Eylül", "Turkish" AS Language); -- "eylul"
+ ```
+
+* `Unicode::ReplaceAll(input:Utf8{Flags:AutoMap}, find:Utf8, replacement:Utf8) -> Utf8`
+
+* `Unicode::ReplaceFirst(input:Utf8{Flags:AutoMap}, find:Utf8, replacement:Utf8) -> Utf8`
+
+* `Unicode::ReplaceLast(input:Utf8{Flags:AutoMap}, find:Utf8, replacement:Utf8) -> Utf8`
+
+ Replaces all/first/last occurrences of the `find` string in the `input` with `replacement`.
+
+* `Unicode::RemoveAll(input:Utf8{Flags:AutoMap}, symbols:Utf8) -> Utf8`
+
+* `Unicode::RemoveFirst(input:Utf8{Flags:AutoMap}, symbols:Utf8) -> Utf8`
+
+* `Unicode::RemoveLast(input:Utf8{Flags:AutoMap}, symbols:Utf8) -> Utf8`
+
+ Deletes all/first/last occurrences of characters in the `symbols` set from the `input`. The second argument is interpreted as an unordered set of characters to be removed.
+
+ ```yql
+ SELECT Unicode::ReplaceLast("absence", "enc", ""); -- "abse"
+ SELECT Unicode::RemoveAll("abandon", "an"); -- "bdo"
+ ```
+
+* `Unicode::ToCodePointList(Utf8{Flags:AutoMap}) -> List<Uint32>`
+
+ Splits a string into a Unicode sequence of codepoints.
+
+* `Unicode::FromCodePointList(List<Uint32>{Flags:AutoMap}) -> Utf8`
+
+ Generates a Unicode string from codepoints.
+
+ ```yql
+ SELECT Unicode::ToCodePointList("Щавель"); -- [1065, 1072, 1074, 1077, 1083, 1100]
+ SELECT Unicode::FromCodePointList(AsList(99,111,100,101,32,112,111,105,110,116,115,32,99,111,110,118,101,114,116,101,114)); -- "code points converter"
+ ```
+
+* `Unicode::Reverse(Utf8{Flags:AutoMap}) -> Utf8`
+
+ Reverses a string.
+
+* `Unicode::ToLower(Utf8{Flags:AutoMap}) -> Utf8`
+
+* `Unicode::ToUpper(Utf8{Flags:AutoMap}) -> Utf8`
+
+* `Unicode::ToTitle(Utf8{Flags:AutoMap}) -> Utf8`
+
+ Converts a string to UPPER, lower, or Title case.
+
+* `Unicode::SplitToList( string:Utf8?, separator:Utf8, [ DelimeterString:Bool?, SkipEmpty:Bool?, Limit:Uint64? ]) -> List<Utf8>`
+
+ Splits a string into substrings by separator.
+`string` -- Source string. `separator` -- Separator. Parameters:
+
+ - DelimeterString:Bool? — treating a delimiter as a string (true, by default) or a set of characters "any of" (false)
+ - SkipEmpty:Bool? - whether to skip empty strings in the result, is false by default
+ - Limit:Uint64? - Limits the number of fetched components (unlimited by default); if the limit is exceeded, the raw suffix of the source string is returned in the last item
+
+* `Unicode::JoinFromList(List<Utf8>{Flags:AutoMap}, separator:Utf8) -> Utf8`
+
+ Concatenates a list of strings via a `separator` into a single string.
+
+ ```yql
+ SELECT Unicode::SplitToList("One, two, three, four, five", ", ", 2 AS Limit); -- ["One", "two", "three, four, five"]
+ SELECT Unicode::JoinFromList(["One", "two", "three", "four", "five"], ";"); -- "One;two;three;four;five"
+ ```
+
+* `Unicode::ToUint64(string:Utf8{Flags:AutoMap}, [prefix:Uint16?]) -> Uint64`
+
+ Converts a string to a number.
+
+ The second optional argument sets the number system. By default, 0 (automatic detection by prefix).
+ Supported prefixes: `0x(0X)` - base-16, `0` - base-8. Defaults to base-10.
+ The `-` sign before a number is interpreted as in C unsigned arithmetic. For example, `-0x1` -> UI64_MAX.
+ If there are incorrect characters in a string or a number goes beyond ui64, the function terminates with an error.
+
+* `Unicode::TryToUint64(string:Utf8{Flags:AutoMap}, [prefix:Uint16?]) -> Uint64?`
+
+ Similar to the `Unicode::ToUint64()` function, except that it returns `NULL` instead of an error.
+
+ ```yql
+ SELECT Unicode::ToUint64("77741"); -- 77741
+ SELECT Unicode::ToUint64("-77741"); -- 18446744073709473875
+ SELECT Unicode::TryToUint64("asdh831"); -- Null
+ ```
+
diff --git a/yql/essentials/docs/en/udf/list/url.md b/yql/essentials/docs/en/udf/list/url.md
new file mode 100644
index 0000000000..0dbe3d5b48
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/url.md
@@ -0,0 +1,203 @@
+# Url
+
+## Normalize {#normalize}
+
+* `Url::Normalize(String) -> String?`
+
+Normalizes the URL in a robot-friendly way: converts the hostname into lowercase, strips out certain fragments, and so on.
+The normalization result only depends on the URL itself. The normalization **DOES NOT** include operations depending on the external data: transformation based on duplicates, mirrors, etc.
+
+Returned value:
+
+* Normalized URL.
+* `NULL`, if the passed string argument can't be parsed as a URL.
+
+### Examples
+
+```yql
+SELECT Url::Normalize("hTTp://wWw.yDb.TECH/"); -- "http://www.ydb.tech/"
+SELECT Url::Normalize("http://ydb.tech#foo"); -- "http://ydb.tech/"
+```
+
+## NormalizeWithDefaultHttpScheme {#normalizewithdefaulthttpscheme}
+
+* `Url::NormalizeWithDefaultHttpScheme(String?) -> String?`
+
+Normalizes similarly to `Url::Normalize`, but inserts the `http://` schema in case there is no schema.
+
+Returned value:
+
+* Normalized URL.
+* Source URL, if the normalization has failed.
+
+### Examples
+
+```yql
+SELECT Url::NormalizeWithDefaultHttpScheme("wWw.yDb.TECH"); -- "http://www.ydb.tech/"
+SELECT Url::NormalizeWithDefaultHttpScheme("http://ydb.tech#foo"); -- "http://ydb.tech/"
+```
+
+## Encode / Decode {#encode}
+
+Encode a UTF-8 string to the urlencoded format (`Url::Encode`) and back (`Url::Decode`).
+
+### List of functions
+
+* `Url::Encode(String?) -> String?`
+* `Url::Decode(String?) -> String?`
+
+### Examples
+
+```yql
+SELECT Url::Decode("http://ydb.tech/%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0");
+ -- "http://ydb.tech/page"
+SELECT Url::Encode("http://ydb.tech/page");
+ -- "http://ydb.tech/%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0"
+```
+
+## Parse {#parse}
+
+Parses the URL into parts.
+
+```yql
+Url::Parse(Parse{Flags:AutoMap}) -> Struct< Frag: String?, Host: String?, ParseError: String?, Pass: String?, Path: String?, Port: String?, Query: String?, Scheme: String?, User: String? >
+```
+
+### Examples
+
+```yql
+SELECT Url::Parse(
+ "https://en.wikipedia.org/wiki/Isambard_Kingdom_Brunel?s=24&g=h-24#Great_Western_Railway");
+/*
+(
+ "Frag": "Great_Western_Railway",
+ "Host": "en.wikipedia.org",
+ "ParseError": null,
+ "Pass": null,
+ "Path": "/wiki/Isambard_Kingdom_Brunel",
+ "Port": null,
+ "Query": "s=24&g=h-24",
+ "Scheme": "https",
+ "User": null
+)
+*/
+```
+
+## Get... {#get}
+
+Get a component of the URL.
+
+### List of functions
+
+* `Url::GetScheme(String{Flags:AutoMap}) -> String`
+* `Url::GetHost(String?) -> String?`
+* `Url::GetHostPort(String?) -> String?`
+* `Url::GetSchemeHost(String?) -> String?`
+* `Url::GetSchemeHostPort(String?) -> String?`
+* `Url::GetPort(String?) -> String?`
+* `Url::GetTail(String?) -> String?` -- everything following the host: path + query + fragment
+* `Url::GetPath(String?) -> String?`
+* `Url::GetFragment(String?) -> String?`
+* `Url::GetCGIParam(String?, String) -> String?` -- The second parameter is the name of the intended CGI parameter.
+* `Url::GetDomain(String?, Uint8) -> String?` -- The second parameter is the required domain level.
+* `Url::GetTLD(String{Flags:AutoMap}) -> String`
+* `Url::IsKnownTLD(String{Flags:AutoMap}) -> Bool` -- Registered on [iana.org](http://www.iana.org/).
+* `Url::IsWellKnownTLD(String{Flags:AutoMap}) -> Bool` -- Belongs to a small whitelist of com, net, org, ru, and so on.
+* `Url::GetDomainLevel(String{Flags:AutoMap}) -> Uint64`
+* `Url::GetSignificantDomain(String{Flags:AutoMap}, [List<String>?]) -> String`
+
+ Returns a second-level domain in most cases and a third-level domain for the hostnames like: `***.XXX.YY`, where `XXX` is com, net, org, co, gov, or edu. You can redefine this list using an optional second argument
+
+* `Url::GetOwner(String{Flags:AutoMap}) -> String`
+
+ Returns the domain that's most likely owned by an individual or organization. Unlike `Url::GetSignificantDomain`, it uses a special whitelist. Besides the `***.co.uk` domains, it can return a third-level domain used by free hosting sites and blogs (for example: something.livejournal.com)
+
+### Examples
+
+```yql
+SELECT Url::GetScheme("https://ydb.tech"); -- "https://"
+SELECT Url::GetDomain("http://www.ydb.tech", 2); -- "ydb.tech"
+```
+
+## Cut... {#cut}
+
+* `Url::CutScheme(String?) -> String?`
+
+ Returns the passed URL without the schema (`http://`, `https://`, etc.).
+
+* `Url::CutWWW(String?) -> String?`
+
+ Returns the passed domain without the "www." prefix (if any).
+
+* `Url::CutWWW2(String?) -> String?`
+
+ Returns the passed domain without the prefixes like "www.", "www2.", "wwww777." (if any).
+
+* `Url::CutQueryStringA­ndFragment(String{Flags:AutoMap}) -> String`
+
+ Returns a copy of the passed URL, stripping out all the CGI parameters and fragments ("?foo=bar" and/or "#baz").
+
+### Examples
+
+```yql
+SELECT Url::CutScheme("http://www.ydb.tech"); -- "www.ydb.tech"
+SELECT Url::CutWWW("www.ydb.tech"); -- "ydb.tech"
+```
+
+## ...Punycode... {#punycode}
+
+[Punycode](https://en.wikipedia.org/wiki/Punycode) transformations.
+
+### List of functions
+
+* `Url::HostNameToPunycode(String{Flag:AutoMap}) -> String?`
+* `Url::ForceHostNameToPunycode(String{Flag:AutoMap}) -> String`
+* `Url::PunycodeToHostName(String{Flag:AutoMap}) -> String?`
+* `Url::ForcePunycodeToHostName(String{Flag:AutoMap}) -> String`
+* `Url::CanBePunycodeHostName(String{Flag:AutoMap}) -> Bool`
+
+### Examples
+
+```yql
+SELECT Url::PunycodeToHostName("xn--80aniges7g.xn--j1aef"); -- "example.com"
+```
+
+## ...Query... {#query}
+
+[Query](https://docs.python.org/3/library/urllib.parse.html) transformations.
+
+### List of functions
+
+```yql
+Url::QueryStringToList(String{Flag:AutoMap}, [
+ KeepBlankValues:Bool?, -- Empty values in percent-encoded queries are interpreted as empty strings, defaults to false.
+ Strict:Bool?, -- If false, parsing errors are ignored and incorrect fields are skipped, defaults to true.
+ MaxFields:Uint32?, -- The maximum number of fields. If exceeded, an exception is thrown. Defaults to Max<Uint32>.
+ Separator:String? -- A key-value pair separator, defaults to '&'.
+]) -> List<Tuple<String, String>>
+Url::QueryStringToDict(String{Flag:AutoMap}, [
+ KeepBlankValues:Bool?, -- Empty values in percent-encoded queries are interpreted as empty strings, defaults to false.
+ Strict:Bool?, -- If false, parsing errors are ignored and incorrect fields are skipped, defaults to true.
+ MaxFields:Uint32?, -- The maximum number of fields. If exceeded, an exception is thrown. Defaults to Max<Uint32>.
+ Separator:String? -- A key-value pair separator, defaults to '&'.
+]) -> Dict<String, List<String>>
+Url::BuildQueryString(Dict<String, List<String?>>{Flag:AutoMap}, [
+ Separator:String? -- A key-value pair separator, defaults to '&'.
+]) -> String
+Url::BuildQueryString(Dict<String, String?>{Flag:AutoMap}, [
+ Separator:String? -- A key-value pair separator, defaults to '&'.
+]) -> String
+Url::BuildQueryString(List<Tuple<String, String?>>{Flag:AutoMap}, [
+ Separator:String? -- A key-value pair separator, defaults to '&'.
+]) -> String
+```
+
+### Examples
+
+```yql
+SELECT Url::QueryStringToList("a=1&b=2&a=3"); -- [("a", "1"), ("b", "2"), ("a", "3")]
+SELECT Url::QueryStringToDict("a=1&b=2&a=3"); -- {"b" : ["2"], "a" : ["1", "3"]}
+SELECT Url::BuildQueryString([("a", "1"), ("a", "3"), ("b", "2")]); -- "a=1&a=3&b=2"
+SELECT Url::BuildQueryString({"a" : "1", "b" : "2"}); -- "b=2&a=1"
+SELECT Url::BuildQueryString({"a" : ["1", "3"], "b" : ["2", "4"]}); -- "b=2&b=4&a=1&a=3"
+```
diff --git a/yql/essentials/docs/en/udf/list/yson.md b/yql/essentials/docs/en/udf/list/yson.md
new file mode 100644
index 0000000000..5a398dda9f
--- /dev/null
+++ b/yql/essentials/docs/en/udf/list/yson.md
@@ -0,0 +1,308 @@
+# Yson
+
+<!-- markdownlint-disable no-trailing-punctuation -->
+
+YSON is a JSON-like data format developed at Yandex.
+
+* Similarities with JSON:
+
+ * Does not have a strict scheme.
+ * Besides simple data types, it supports dictionaries and lists in arbitrary combinations.
+
+* Some differences from JSON:
+
+ * It also has a binary representation in addition to the text representation.
+ * The text representation uses semicolons instead of commas and equal signs instead of colons.
+
+* The concept of "attributes" is supported, that is, named properties that can be assigned to a node in the tree.
+
+Implementation specifics and functionality of the module:
+
+* Along with YSON, this module also supports standard JSON to expand the application scope in a way.
+* It works with a DOM representation of YSON in memory that in YQL terms is passed between functions as a "resource" (see the [description of special data types](../../types/special.md)). Most of the module's functions have the semantics of a query to perform a specified operation with a resource and return an empty [optional](../../types/optional.md) type if the operation failed because the actual data type mismatched the expected one.
+* Provides several main classes of functions (find below a complete list and detailed description of functions):
+
+ * `Yson::Parse***`: Getting a resource with a DOM object from serialized data, with all further operations performed on the obtained resource.
+ * `Yson::From`: Getting a resource with a DOM object from simple YQL data types or containers (lists or dictionaries).
+ * `Yson::ConvertTo***`: Converting a resource to [primitive data types](../../types/primitive.md) or [containers](../../types/containers.md).
+ * `Yson::Lookup***`: Getting a single list item or a dictionary with optional conversion to the relevant data type.
+ * `Yson::YPath***`: Getting one element from the document tree based on the relative path specified, optionally converting it to the relevant data type.
+ * `Yson::Serialize***`: Getting a copy of data from the resource and serializing the data in one of the formats.
+
+* For convenience, when serialized Yson and Json are passed to functions expecting a resource with a DOM object, implicit conversion using `Yson::Parse` or `Yson::ParseJson` is done automatically. In SQL syntax, the dot or square brackets operator automatically adds a `Yson::Lookup` call. To serialize a resource, you still need to call `Yson::ConvertTo***` or `Yson::Serialize***`. It means that, for example, to get the "foo" element as a string from the Yson column named mycolumn and serialized as a dictionary, you can write: `SELECT Yson::ConvertToString(mycolumn["foo"]) FROM mytable;` or `SELECT Yson::ConvertToString(mycolumn.foo) FROM mytable;`. In the variant with a dot, special characters can be escaped by [general rules for IDs](../../syntax/expressions.md#escape).
+
+The module's functions must be considered as "building blocks" from which you can assemble different structures, for example:
+
+* `Yson::Parse*** -> Yson::Serialize***`: Converting from one format to other.
+* `Yson::Parse*** -> Yson::Lookup -> Yson::Serialize***`: Extracting the value of the specified subtree in the source YSON tree.
+* `Yson::Parse*** -> Yson::ConvertToList -> ListMap -> Yson::Lookup***`: Extracting items by a key from the YSON list.
+
+
+
+## Examples
+
+```yql
+$node = Json(@@
+ {"abc": {"def": 123, "ghi": "hello"}}
+@@);
+SELECT Yson::SerializeText($node.abc) AS `yson`;
+-- {"def"=123;"ghi"="\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82"}
+```
+
+```yql
+$node = Yson(@@
+ <a=z;x=y>[
+ {abc=123; def=456};
+ {abc=234; xyz=789};
+ ]
+@@);
+$attrs = Yson::YPath($node, "/@");
+
+SELECT
+ ListMap(Yson::ConvertToList($node), ($x) -> { return Yson::LookupInt64($x, "abc") }) AS abcs,
+ Yson::ConvertToStringDict($attrs) AS attrs,
+ Yson::SerializePretty(Yson::Lookup($node, "7", Yson::Options(false AS Strict))) AS miss;
+
+/*
+- abcs: `[123; 234]`
+- attrs: `{"a"="z";"x"="y"}`
+- miss: `NULL`
+*/
+```
+
+## Yson::Parse... {#ysonparse}
+
+```yql
+Yson::Parse(Yson{Flags:AutoMap}) -> Resource<'Yson2.Node'>
+Yson::ParseJson(Json{Flags:AutoMap}) -> Resource<'Yson2.Node'>
+Yson::ParseJsonDecodeUtf8(Json{Flags:AutoMap}) -> Resource<'Yson2.Node'>
+
+Yson::Parse(String{Flags:AutoMap}) -> Resource<'Yson2.Node'>? -- accepts YSON in any format
+Yson::ParseJson(String{Flags:AutoMap}) -> Resource<'Yson2.Node'>?
+Yson::ParseJsonDecodeUtf8(String{Flags:AutoMap}) -> Resource<'Yson2.Node'>?
+```
+
+The result of all three functions is non-serializable: it can only be passed as the input to other function from the Yson library. However, you can't save it to a table or return to the client as a result of the operation: such an attempt results in a typing error. You also can't return it outside [subqueries](../../syntax/select/index.md): if you need to do this, call [Yson::Serialize](#ysonserialize), and the optimizer will remove unnecessary serialization and deserialization if materialization isn't needed in the end.
+
+{% note info %}
+
+The `Yson::ParseJsonDecodeUtf8` expects that characters outside the ASCII range must be additionally escaped.
+
+{% endnote %}
+
+## Yson::From {#ysonfrom}
+
+```yql
+Yson::From(T) -> Resource<'Yson2.Node'>
+```
+
+`Yson::From` is a polymorphic function that converts most primitive data types and containers (lists, dictionaries, tuples, structures, and so on) into a Yson resource. The source object type must be Yson-compatible. For example, in dictionary keys, you can only use the `String` or `Utf8` data types, but not `String?` or `Utf8?` .
+
+### Example
+
+```yql
+SELECT Yson::Serialize(Yson::From(TableRow())) FROM table1;
+```
+
+## Yson::WithAttributes
+
+```yql
+Yson::WithAttributes(Resource<'Yson2.Node'>{Flags:AutoMap}, Resource<'Yson2.Node'>{Flags:AutoMap}) -> Resource<'Yson2.Node'>?
+```
+
+Adds attributes (the second argument) to the Yson node (the first argument). The attributes must constitute a map node.
+
+## Yson::Equals
+
+```yql
+Yson::Equals(Resource<'Yson2.Node'>{Flags:AutoMap}, Resource<'Yson2.Node'>{Flags:AutoMap}) -> Bool
+```
+
+Checking trees in memory for equality. The operation is tolerant to the source serialization format and the order of keys in dictionaries.
+
+## Yson::GetHash
+
+```yql
+Yson::GetHash(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Uint64
+```
+
+Calculating a 64-bit hash from an object tree.
+
+## Yson::Is...
+
+```yql
+Yson::IsEntity(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsString(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsDouble(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsUint64(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsInt64(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsBool(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsList(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsDict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+```
+
+Checking that the current node has the appropriate type. The Entity is `#`.
+
+## Yson::GetLength
+
+```yql
+Yson::GetLength(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Uint64?
+```
+
+Getting the number of elements in a list or dictionary.
+
+## Yson::ConvertTo... {#ysonconvertto}
+
+```yql
+Yson::ConvertTo(Resource<'Yson2.Node'>{Flags:AutoMap}, Type<T>) -> T
+Yson::ConvertToBool(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Bool?
+Yson::ConvertToInt64(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Int64?
+Yson::ConvertToUint64(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Uint64?
+Yson::ConvertToDouble(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Double?
+Yson::ConvertToString(Resource<'Yson2.Node'>{Flags:AutoMap}) -> String?
+Yson::ConvertToList(Resource<'Yson2.Node'>{Flags:AutoMap}) -> List<Resource<'Yson2.Node'>>
+Yson::ConvertToBoolList(Resource<'Yson2.Node'>{Flags:AutoMap}) -> List<Bool>
+Yson::ConvertToInt64List(Resource<'Yson2.Node'>{Flags:AutoMap}) -> List<Int64>
+Yson::ConvertToUint64List(Resource<'Yson2.Node'>{Flags:AutoMap}) -> List<Uint64>
+Yson::ConvertToDoubleList(Resource<'Yson2.Node'>{Flags:AutoMap}) -> List<Double>
+Yson::ConvertToStringList(Resource<'Yson2.Node'>{Flags:AutoMap}) -> List<String>
+Yson::ConvertToDict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,Resource<'Yson2.Node'>>
+Yson::ConvertToBoolDict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,Bool>
+Yson::ConvertToInt64Dict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,Int64>
+Yson::ConvertToUint64Dict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,Uint64>
+Yson::ConvertToDoubleDict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,Double>
+Yson::ConvertToStringDict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,String>
+```
+
+{% note warning %}
+
+These functions do not do implicit type casting by default, that is, the value in the argument must exactly match the function called.
+
+{% endnote %}
+
+`Yson::ConvertTo` is a polymorphic function that converts the data type that is specified in the second argument and supports containers (lists, dictionaries, tuples, structures, and so on) into a Yson resource.
+
+### Example
+
+```yql
+$data = Yson(@@{
+ "name" = "Anya";
+ "age" = 15u;
+ "params" = {
+ "ip" = "95.106.17.32";
+ "last_time_on_site" = 0.5;
+ "region" = 213;
+ "user_agent" = "Mozilla/5.0"
+ }
+}@@);
+SELECT Yson::ConvertTo($data,
+ Struct<
+ name: String,
+ age: Uint32,
+ params: Dict<String,Yson>
+ >
+);
+```
+
+## Yson::Contains {#ysoncontains}
+
+```yql
+Yson::Contains(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Bool?
+```
+
+Checks for a key in the dictionary. If the object type is a map, then it searches among the keys.
+If the object type is a list, then the key must be a decimal number, i.e., an index in the list.
+
+## Yson::Lookup... {#ysonlookup}
+
+```yql
+Yson::Lookup(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Resource<'Yson2.Node'>?
+Yson::LookupBool(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Bool?
+Yson::LookupInt64(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Int64?
+Yson::LookupUint64(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Uint64?
+Yson::LookupDouble(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Double?
+Yson::LookupString(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> String?
+Yson::LookupDict(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Dict<String,Resource<'Yson2.Node'>>?
+Yson::LookupList(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> List<Resource<'Yson2.Node'>>?
+```
+
+The above functions are short notations for a typical use case: `Yson::YPath`: go to a level in the dictionary and then extract the value — `Yson::ConvertTo***`. For all the listed functions, the second argument is a key name from the dictionary (unlike YPath, it has no `/`prefix) or an index from the list (for example, `7`). They simplify the query and produce a small gain in speed.
+
+## Yson::YPath {#ysonypath}
+
+```yql
+Yson::YPath(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Resource<'Yson2.Node'>?
+Yson::YPathBool(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Bool?
+Yson::YPathInt64(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Int64?
+Yson::YPathUint64(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Uint64?
+Yson::YPathDouble(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Double?
+Yson::YPathString(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> String?
+Yson::YPathDict(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Dict<String,Resource<'Yson2.Node'>>?
+Yson::YPathList(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> List<Resource<'Yson2.Node'>>?
+```
+
+Lets you get a part of the resource based on the source resource and the part's path in YPath format.
+
+
+
+## Yson::Attributes {#ysonattributes}
+
+```yql
+Yson::Attributes(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,Resource<'Yson2.Node'>>
+```
+
+Getting all node attributes as a dictionary.
+
+## Yson::Serialize... {#ysonserialize}
+
+```yql
+Yson::Serialize(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Yson -- A binary representation
+Yson::SerializeText(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Yson
+Yson::SerializePretty(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Yson -- To get a text result, wrap it in ToBytes(...)
+```
+
+## Yson::SerializeJson {#ysonserializejson}
+
+```yql
+Yson::SerializeJson(Resource<'Yson2.Node'>{Flags:AutoMap}, [Resource<'Yson2.Options'>?, SkipMapEntity:Bool?, EncodeUtf8:Bool?, WriteNanAsString:Bool?]) -> Json?
+```
+
+* `SkipMapEntity` serializes `#` values in dictionaries. The value of attributes is not affected by the flag. By default, `false`.
+* `EncodeUtf8` responsible for escaping non-ASCII characters. By default, `false`.
+* `WriteNanAsString` allows serializing `NaN` and `Inf` values as strings. By default, `false`.
+
+The `Yson` and `Json` data types returned by serialization functions are special cases of a string that is known to contain data in the given format (Yson/Json).
+
+## Yson::Options {#ysonoptions}
+
+```yql
+Yson::Options([AutoConvert:Bool?, Strict:Bool?]) -> Resource<'Yson2.Options'>
+```
+
+It's passed in the last optional argument (omitted for brevity) to the methods `Parse...`, `ConvertTo...`, `Contains`, `Lookup...`, and `YPath...` that accept the result of the `Yson::Options` call. By default, all the `Yson::Options` fields are false and when enabled (true), they modify the behavior as follows:
+
+* **AutoConvert**: If the value passed to Yson doesn't match the result data type exactly, the value is converted where possible. For example, `Yson::ConvertToInt64` in this mode will convert even Double numbers to Int64.
+* **Strict**: By default, all functions from the Yson library return an error in case of issues during query execution (for example, an attempt to parse a string that is not Yson/Json, or an attempt to search by a key in a scalar type, or when a conversion to an incompatible data type has been requested, and so on). If you disable the strict mode, `NULL` is returned instead of an error in most cases. When converting to a dictionary or list (`ConvertTo<Type>Dict` or `ConvertTo<Type>List`), improper items are excluded from the resulting collection.
+
+### Example
+
+```yql
+$yson = @@{y = true; x = 5.5}@@y;
+SELECT Yson::LookupBool($yson, "z"); --- null
+SELECT Yson::LookupBool($yson, "y"); --- true
+
+SELECT Yson::LookupInt64($yson, "x"); --- Error
+SELECT Yson::LookupInt64($yson, "x", Yson::Options(false as Strict)); --- null
+SELECT Yson::LookupInt64($yson, "x", Yson::Options(true as AutoConvert)); --- 5
+
+SELECT Yson::ConvertToBoolDict($yson); --- Error
+SELECT Yson::ConvertToBoolDict($yson, Yson::Options(false as Strict)); --- { "y": true }
+SELECT Yson::ConvertToDoubleDict($yson, Yson::Options(false as Strict)); --- { "x": 5.5 }
+```
+
+If you need to use the same Yson library settings throughout the query, it's more convenient to use [PRAGMA yson.AutoConvert;](../../syntax/pragma.md#yson.autoconvert) and/or [PRAGMA yson.Strict;](../../syntax/pragma.md#yson.strict). Only with these `PRAGMA` you can affect implicit calls to the Yson library occurring when you work with Yson/Json data types.
+
+## See also
+
+* [{#T}](../../recipes/accessing-json.md)
+* [{#T}](../../recipes/modifying-json.md)
diff --git a/yql/essentials/docs/presets.yaml b/yql/essentials/docs/presets.yaml
new file mode 100644
index 0000000000..e9427569bb
--- /dev/null
+++ b/yql/essentials/docs/presets.yaml
@@ -0,0 +1,49 @@
+default:
+ oss: true
+ ya_make: true
+
+rtmr:
+ backend_name: RTMR
+ backend_name_lower: rtmr
+ rtmr: true
+ example_cluster: rtmr_yql_alpha
+ feature_not_null: true
+ feature_column_container_type: true
+ feature_mapreduce: true
+ process_command: PROCESS STREAM
+ select_command: SELECT STREAM
+ feature_temp_table: true
+
+ydb:
+ backend_name: YDB
+ backend_name_lower: ydb
+ ydb: true
+ example_cluster: ydbtest
+ feature_secondary_index: true
+ feature_changefeed: true
+ feature_replace: true
+ feature_upsert: true
+ feature_join: true
+ feature_map_tables: true
+ feature_group_by_rollup_cube: true
+ feature_window_functions: true
+ feature_bulk_tables: false
+
+yt:
+ backend_name: YT
+ backend_name_lower: yt
+ yt: true
+ example_cluster: hahn
+ feature_mapreduce: true
+ feature_column_container_type: true
+ feature_subquery: true
+ feature_upsert: true
+ feature_join: true
+ feature_insert_with_truncate: true
+ feature_bulk_tables: true # CONCAT, RANGE, TablePath(), INSERT INTO details...
+ feature_group_by_rollup_cube: true
+ feature_window_functions: true
+ feature_codegen: true
+ feature_functional_tables: true
+ feature_udf_noncpp: true
+ feature_temp_table: true
diff --git a/yql/essentials/docs/ru/_includes/cast_examples.md b/yql/essentials/docs/ru/_includes/cast_examples.md
new file mode 100644
index 0000000000..24eb207204
--- /dev/null
+++ b/yql/essentials/docs/ru/_includes/cast_examples.md
@@ -0,0 +1,16 @@
+
+```yql
+SELECT
+ CAST("12345" AS Double), -- 12345.0
+ CAST(1.2345 AS Uint8), -- 1
+ CAST(12345 AS String), -- "12345"
+ CAST("1.2345" AS Decimal(5, 2)), -- 1.23
+ CAST("xyz" AS Uint64) IS NULL, -- true, так как не удалось
+ CAST(-1 AS Uint16) IS NULL, -- true, отрицательное в беззнаковое
+ CAST([-1, 0, 1] AS List<Uint8?>), -- [null, 0, 1]
+ --Тип элемента опциональный: неудачный элемент в null.
+ CAST(["3.14", "bad", "42"] AS List<Float>), -- [3.14, 42]
+ --Тип элемента не опциональный: неудачный элемент удалён.
+ CAST(255 AS Uint8), -- 255
+ CAST(256 AS Uint8) IS NULL -- true, выходит за диапазон
+```
diff --git a/yql/essentials/docs/ru/_includes/decimal_args.md b/yql/essentials/docs/ru/_includes/decimal_args.md
new file mode 100644
index 0000000000..1b56d44e70
--- /dev/null
+++ b/yql/essentials/docs/ru/_includes/decimal_args.md
@@ -0,0 +1,4 @@
+Для параметрического типа данных Decimal дополнительно указывается два аргумента:
+
+* общее число десятичных знаков (до 35, включительно);
+* число десятичных знаков после запятой (из общего числа, то есть строго не больше предыдущего аргумента).
diff --git a/yql/essentials/docs/ru/_includes/frompg.md b/yql/essentials/docs/ru/_includes/frompg.md
new file mode 100644
index 0000000000..2c0413b7b6
--- /dev/null
+++ b/yql/essentials/docs/ru/_includes/frompg.md
@@ -0,0 +1,15 @@
+| PostgreSQL | YQL |
+|---|---|
+| `bool` | `bool` |
+| `int2` | `Int16` |
+| `int4` | `Int32` |
+| `int8` | `Int64` |
+| `float4` | `Float` |
+| `float8` | `Double` |
+| `bytea` | `String` |
+| `varchar` | `Utf8` |
+| `text` | `Utf8` |
+| `cstring` | `Utf8` |
+| `uuid` | `Uuid` |
+| `date` | `Date32` |
+| `timestamp` | `Timestamp64` |
diff --git a/yql/essentials/docs/ru/_includes/topg.md b/yql/essentials/docs/ru/_includes/topg.md
new file mode 100644
index 0000000000..0d316752d0
--- /dev/null
+++ b/yql/essentials/docs/ru/_includes/topg.md
@@ -0,0 +1,35 @@
+| YQL | PostgreSQL | Название PostgreSQL-типа в YQL |
+|---|---|---|
+| `Bool` | `bool` |`pgbool` |
+| `Int8` | `int2` |`pgint2` |
+| `Uint8` | `int2` |`pgint2` |
+| `Int16` | `int2` |`pgint2` |
+| `Uint16` | `int4` |`pgint4` |
+| `Int32` | `int4` |`pgint4` |
+| `Uint32` | `int8` |`pgint8` |
+| `Int64` | `int8` |`pgint8` |
+| `Uint64` | `numeric` |`pgnumeric` |
+| `Float` | `float4` |`pgfloat4` |
+| `Double` | `float8` |`pgfloat8` |
+| `String` | `bytea` |`pgbytea` |
+| `Utf8` | `text` |`pgtext` |
+| `Yson` | `bytea` |`pgbytea` |
+| `Json` | `json` |`pgjson` |
+| `Uuid` | `uuid` |`pguuid` |
+| `JsonDocument` | `jsonb` |`pgjsonb` |
+| `Date` | `date` |`pgdate` |
+| `Datetime` | `timestamp` |`pgtimestamp` |
+| `Timestamp` | `timestamp` |`pgtimestamp` |
+| `Interval` | `interval` | `pginterval` |
+| `TzDate` | `text` |`pgtext` |
+| `TzDatetime` | `text` |`pgtext` |
+| `TzTimestamp` | `text` |`pgtext` |
+| `Date32` | `date` | `pgdate`|
+| `Datetime64` | `timestamp` |`pgtimestamp` |
+| `Timestamp64` | `timestamp` |`pgtimestamp` |
+| `Interval64`| `interval` |`pginterval` |
+| `TzDate32` | `text` | |`pgtext` |
+| `TzDatetime64` | `text` | |`pgtext` |
+| `TzTimestamp64` | `text` | |`pgtext` |
+| `Decimal` | `numeric` |`pgnumeric` |
+| `DyNumber` | `numeric` |`pgnumeric` |
diff --git a/yql/essentials/docs/ru/builtins/aggregation.md b/yql/essentials/docs/ru/builtins/aggregation.md
new file mode 100644
index 0000000000..0a7a333bc3
--- /dev/null
+++ b/yql/essentials/docs/ru/builtins/aggregation.md
@@ -0,0 +1,802 @@
+# Агрегатные функции
+
+## COUNT {#count}
+
+### Сигнатура
+
+```yql
+COUNT(*)->Uint64
+COUNT(T)->Uint64
+COUNT(T?)->Uint64
+```
+
+Подсчет количества строк в строковой или колоночной таблице (если в качестве аргумента указана `*` или константа) или непустых значений в столбце таблицы (если в качестве аргумента указано имя столбца).
+
+Как и другие агрегатные функции, может использоваться в сочетании с [GROUP BY](../syntax/group_by.md) для получения статистики по частям таблицы, соответствующим значениям в столбцах, по которым идет группировка. А модификатор [DISTINCT](../syntax/group_by.md#distinct) позволяет посчитать число уникальных значений.
+
+### Примеры
+
+```yql
+SELECT COUNT(*) FROM my_table;
+```
+
+```yql
+SELECT key, COUNT(value) FROM my_table GROUP BY key;
+```
+
+```yql
+SELECT COUNT(DISTINCT value) FROM my_table;
+```
+
+## MIN и MAX {#min-max}
+
+### Сигнатура
+
+```yql
+MIN(T?)->T?
+MIN(T)->T?
+MAX(T?)->T?
+MAX(T)->T?
+```
+
+Минимальное или максимальное значение.
+
+В качестве аргумента допустимо произвольное вычислимое выражение с результатом, допускающим сравнение значений.
+
+### Примеры
+
+```yql
+SELECT MIN(value), MAX(value) FROM my_table;
+```
+
+## SUM {#sum}
+
+### Сигнатура
+
+```yql
+SUM(Unsigned?)->Uint64?
+SUM(Signed?)->Int64?
+SUM(Interval?)->Interval?
+SUM(Decimal(N, M)?)->Decimal(35, M)?
+```
+
+Сумма чисел.
+
+В качестве аргумента допустимо произвольное вычислимое выражение с числовым результатом или типом `Interval`.
+
+Целые числа автоматически расширяются до 64 бит, чтобы уменьшить риск переполнения.
+
+```yql
+SELECT SUM(value) FROM my_table;
+```
+
+## AVG {#avg}
+
+### Сигнатура
+
+```yql
+AVG(Double?)->Double?
+AVG(Interval?)->Interval?
+AVG(Decimal(N, M)?)->Decimal(N, M)?
+```
+
+Арифметическое среднее.
+
+В качестве аргумента допустимо произвольное вычислимое выражение с числовым результатом или типом `Interval`.
+
+Целочисленные значения и интервалы времени автоматически приводятся к Double.
+
+### Примеры
+
+```yql
+SELECT AVG(value) FROM my_table;
+```
+
+## COUNT_IF {#count-if}
+
+### Сигнатура
+
+```yql
+COUNT_IF(Bool?)->Uint64?
+```
+
+Количество строк, для которых указанное в качестве аргумента выражение истинно (результат вычисления выражения — true).
+
+Значение `NULL` приравнивается к `false` (в случае, если тип аргумента `Bool?`).
+
+Функция *не* выполняет неявного приведения типов к булевым для строк и чисел.
+
+### Примеры
+
+```yql
+SELECT
+ COUNT_IF(value % 2 == 1) AS odd_count
+```
+
+{% note info %}
+
+Если нужно посчитать число уникальных значений на строках, где выполняется условие, то в отличие от остальных агрегатных функций модификатор [DISTINCT](../syntax/group_by.md#distinct) тут не поможет, так как в аргументах нет никаких значений. Для получения данного результата, стоит воспользоваться в подзапросе встроенной функцией [IF](../builtins/basic.md#if) с двумя аргументами (чтобы в else получился `NULL`), а снаружи сделать [COUNT(DISTINCT ...)](#count) по её результату.
+
+{% endnote %}
+
+## SUM_IF и AVG_IF {#sum-if}
+
+### Сигнатура
+
+```yql
+SUM_IF(Unsigned?, Bool?)->Uint64?
+SUM_IF(Signed?, Bool?)->Int64?
+SUM_IF(Interval?, Bool?)->Interval?
+
+AVG_IF(Double?, Bool?)->Double?
+```
+
+Сумма или арифметическое среднее, но только для строк, удовлетворяющих условию, переданному вторым аргументом.
+
+Таким образом, `SUM_IF(value, condition)` является чуть более короткой записью для `SUM(IF(condition, value))`, аналогично для `AVG`. Расширение типа данных аргумента работает так же аналогично одноименным функциям без суффикса.
+
+### Примеры
+
+```yql
+SELECT
+ SUM_IF(value, value % 2 == 1) AS odd_sum,
+ AVG_IF(value, value % 2 == 1) AS odd_avg,
+FROM my_table;
+```
+
+При использовании [фабрики агрегационной функции](basic.md#aggregationfactory) в качестве первого аргумента [AGGREGATE_BY](#aggregate-by) передается `Tuple` из значения и предиката.
+
+```yql
+$sum_if_factory = AggregationFactory("SUM_IF");
+$avg_if_factory = AggregationFactory("AVG_IF");
+
+SELECT
+ AGGREGATE_BY(AsTuple(value, value % 2 == 1), $sum_if_factory) AS odd_sum,
+ AGGREGATE_BY(AsTuple(value, value % 2 == 1), $avg_if_factory) AS odd_avg
+FROM my_table;
+```
+
+## SOME {#some}
+
+### Сигнатура
+
+```yql
+SOME(T?)->T?
+SOME(T)->T?
+```
+
+Получить значение указанного в качестве аргумента выражения для одной из строк таблицы. Не дает никаких гарантий о том, какая именно строка будет использована.
+
+Из-за отсутствия гарантий `SOME` вычислительно дешевле, чем часто использующиеся в подобных ситуациях [MIN и MAX](#min-max).
+
+### Примеры
+
+```yql
+SELECT
+ SOME(value)
+FROM my_table;
+```
+
+{% note alert %}
+
+При вызове агрегатной функции `SOME` несколько раз **не** гарантируется, что все значения результатов будут взяты с одной строки исходной таблицы. Для получения данной гарантии, нужно запаковать значения в какой-либо из контейнеров и передавать в `SOME` уже его. Например, для структуры это можно сделать с помощью [AsStruct](basic.md#asstruct)
+
+{% endnote %}
+
+## CountDistinctEstimate, HyperLogLog и HLL {#countdistinctestimate}
+
+### Сигнатура
+
+```yql
+CountDistinctEstimate(T)->Uint64?
+HyperLogLog(T)->Uint64?
+HLL(T)->Uint64?
+```
+
+Примерная оценка числа уникальных значений по алгоритму [HyperLogLog](https://en.wikipedia.org/wiki/HyperLogLog). Логически делает то же самое, что и [COUNT(DISTINCT ...)](#count), но работает значительно быстрее ценой некоторой погрешности.
+
+Аргументы:
+
+1. Значение для оценки;
+2. Точность (от 4 до 18 включительно, по умолчанию 14).
+
+Выбор точности позволяет разменивать дополнительное потребление вычислительных ресурсов и оперативной памяти на уменьшение погрешности.
+
+На данный момент все три функции являются алиасами, но в будущем `CountDistinctEstimate` может начать использовать другой алгоритм.
+
+### Примеры
+
+```yql
+SELECT
+ CountDistinctEstimate(my_column)
+FROM my_table;
+```
+
+```yql
+SELECT
+ HyperLogLog(my_column, 4)
+FROM my_table;
+```
+
+
+
+## AGGREGATE_LIST {#agg-list}
+
+### Сигнатура
+
+```yql
+AGGREGATE_LIST(T? [, limit:Uint64])->List<T>
+AGGREGATE_LIST(T [, limit:Uint64])->List<T>
+AGGREGATE_LIST_DISTINCT(T? [, limit:Uint64])->List<T>
+AGGREGATE_LIST_DISTINCT(T [, limit:Uint64])->List<T>
+```
+
+Получить все значения столбца в виде списка. В сочетании с `DISTINCT` возвращает только уникальные значения. Опциональный второй параметр задает максимальное количество получаемых значений. Значение 0 равносильно отсутствию лимита.
+
+Если заранее известно, что уникальных значений не много, то лучше воспользоваться агрегатной функцией `AGGREGATE_LIST_DISTINCT`, которая строит тот же результат в памяти (которой при большом числе уникальных значений может не хватить).
+
+Порядок элементов в результирующем списке зависит от реализации и снаружи не задается. Чтобы получить упорядоченный список, необходимо отсортировать результат, например с помощью [ListSort](list.md#listsort).
+
+Чтобы получить список нескольких значений с одной строки, важно *НЕ* использовать функцию `AGGREGATE_LIST` несколько раз, а сложить все нужные значения в контейнер, например через [AsList](basic.md#aslist) или [AsTuple](basic.md#astuple) и передать этот контейнер в один вызов `AGGREGATE_LIST`.
+
+Например, можно использовать в сочетании с `DISTINCT` и функцией [String::JoinFromList](../udf/list/string.md) (аналог `','.join(list)` из Python) для распечатки в строку всех значений, которые встретились в столбце после применения [GROUP BY](../syntax/group_by.md).
+
+### Примеры
+
+```yql
+SELECT
+ AGGREGATE_LIST( region ),
+ AGGREGATE_LIST( region, 5 ),
+ AGGREGATE_LIST( DISTINCT region ),
+ AGGREGATE_LIST_DISTINCT( region ),
+ AGGREGATE_LIST_DISTINCT( region, 5 )
+FROM users
+```
+
+```yql
+-- Аналог GROUP_CONCAT из MySQL
+SELECT
+ String::JoinFromList(CAST(AGGREGATE_LIST(region, 2) AS List<String>), ",")
+FROM users
+```
+
+Существует также короткая форма записи этих функций - `AGG_LIST` и `AGG_LIST_DISTINCT`.
+
+{% note alert %}
+
+Выполняется **НЕ** ленивым образом, поэтому при использовании нужно быть уверенным, что список получится разумных размеров, примерно в пределах тысячи элементов. Чтобы подстраховаться, можно воспользоваться вторым опциональным числовым аргументом, который включает ограничение на число элементов в списке.
+
+{% endnote %}
+
+
+## MAX_BY и MIN_BY {#max-min-by}
+
+### Сигнатура
+
+```yql
+MAX_BY(T1?, T2)->T1?
+MAX_BY(T1, T2)->T1?
+MAX_BY(T1, T2, limit:Uint64)->List<T1>?
+
+MIN_BY(T1?, T2)->T1?
+MIN_BY(T1, T2)->T1?
+MIN_BY(T1, T2, limit:Uint64)->List<T1>?
+```
+
+Вернуть значение первого аргумента для строки таблицы, в которой второй аргумент оказался минимальным/максимальным.
+
+Опционально можно указать третий аргумент N, который влияет на поведение в случае, если в таблице есть несколько строк с одинаковым минимальным или максимальным значением:
+
+* Если N не указано — будет возвращено значение одной из строк, а остальные отбрасываются.
+* Если N указано — будет возвращен список со всеми значениями, но не более N, все значения после достижения указанного числа отбрасываются.
+
+При выборе значения N рекомендуется не превышать порядка сотен или тысяч, чтобы не возникало проблем с лимтами памяти.
+
+Если для задачи обязательно нужны все значения, и их количество может измеряться десятками тысяч и больше, то вместо данных агрегационных функций следует использовать `JOIN` исходной таблицы с подзапросом, где по ней же сделан `GROUP BY + MIN/MAX` на интересующих вас колонках.
+
+{% note warning %}
+
+Если второй аргумент всегда `NULL`, то результатом агрегации будет `NULL`.
+
+{% endnote %}
+
+При использовании [фабрики агрегационной функции](basic.md#aggregationfactory) в качестве первого аргумента [AGGREGATE_BY](#aggregate-by) передается `Tuple` из значения и ключа.
+
+### Примеры
+
+```yql
+SELECT
+ MIN_BY(value, LENGTH(value)),
+ MAX_BY(value, key, 100)
+FROM my_table;
+```
+
+```yql
+$min_by_factory = AggregationFactory("MIN_BY");
+$max_by_factory = AggregationFactory("MAX_BY", 100);
+
+SELECT
+ AGGREGATE_BY(AsTuple(value, LENGTH(value)), $min_by_factory),
+ AGGREGATE_BY(AsTuple(value, key), $max_by_factory)
+FROM my_table;
+```
+
+
+## TOP и BOTTOM {#top-bottom}
+
+### Сигнатура
+
+```yql
+TOP(T?, limit:Uint32)->List<T>
+TOP(T, limit:Uint32)->List<T>
+BOTTOM(T?, limit:Uint32)->List<T>
+BOTTOM(T, limit:Uint32)->List<T>
+```
+
+Вернуть список максимальных/минимальных значений выражения. Первый аргумент - выражение, второй - ограничение на количество элементов.
+
+### Примеры
+
+```yql
+SELECT
+ TOP(key, 3),
+ BOTTOM(value, 3)
+FROM my_table;
+```
+
+```yql
+$top_factory = AggregationFactory("TOP", 3);
+$bottom_factory = AggregationFactory("BOTTOM", 3);
+
+SELECT
+ AGGREGATE_BY(key, $top_factory),
+ AGGREGATE_BY(value, $bottom_factory)
+FROM my_table;
+```
+
+## TOP_BY и BOTTOM_BY {#top-bottom-by}
+
+### Сигнатура
+
+```yql
+TOP_BY(T1, T2, limit:Uint32)->List<T1>
+BOTTOM_BY(T1, T2, limit:Uint32)->List<T1>
+```
+
+Вернуть список значений первого аргумента для строк с максимальными/минимальными значениями второго аргумента. Третий аргумент - ограничение на количество элементов в списке.
+
+При использовании [фабрики агрегационной функции](basic.md#aggregationfactory) в качестве первого аргумента [AGGREGATE_BY](#aggregate-by) передается `Tuple` из значения и ключа. Ограничение на количество элементов в этом случае передаётся вторым аргументом при создании фабрики.
+
+### Примеры
+
+```yql
+SELECT
+ TOP_BY(value, LENGTH(value), 3),
+ BOTTOM_BY(value, key, 3)
+FROM my_table;
+```
+
+```yql
+$top_by_factory = AggregationFactory("TOP_BY", 3);
+$bottom_by_factory = AggregationFactory("BOTTOM_BY", 3);
+
+SELECT
+ AGGREGATE_BY(AsTuple(value, LENGTH(value)), $top_by_factory),
+ AGGREGATE_BY(AsTuple(value, key), $bottom_by_factory)
+FROM my_table;
+```
+
+
+## TOPFREQ и MODE {#topfreq-mode}
+
+### Сигнатура
+
+```yql
+TOPFREQ(T [, num:Uint32 [, bufSize:Uint32]])->List<Struct<Frequency:Uint64, Value:T>>
+MODE(T [, num:Uint32 [, bufSize:Uint32]])->List<Struct<Frequency:Uint64, Value:T>>
+```
+
+Получение **приближенного** списка самых часто встречающихся значений колонки с оценкой их числа. Возвращают список структур с двумя полями:
+
+* `Value`— найденное часто встречающееся значение;
+* `Frequency` — оценка числа упоминаний в таблице.
+
+Обязательный аргумент: само значение.
+
+Опциональные аргументы:
+
+1. Для `TOPFREQ` — желаемое число элементов в результате. `MODE` является алиасом к `TOPFREQ` с 1 в этом аргументе. У `TOPFREQ` по умолчанию тоже 1.
+2. Число элементов в используемом буфере, что позволяет разменивать потребление памяти на точность. По умолчанию 100.
+
+### Примеры
+
+```yql
+SELECT
+ MODE(my_column),
+ TOPFREQ(my_column, 5, 1000)
+FROM my_table;
+```
+
+
+## STDDEV и VARIANCE {#stddev-variance}
+
+### Сигнатура
+
+```yql
+STDDEV(Double?)->Double?
+STDDEV_POPULATION(Double?)->Double?
+POPULATION_STDDEV(Double?)->Double?
+STDDEV_SAMPLE(Double?)->Double?
+STDDEVSAMP(Double?)->Double?
+
+VARIANCE(Double?)->Double?
+VARIANCE_POPULATION(Double?)->Double?
+POPULATION_VARIANCE(Double?)->Double?
+VARPOP(Double?)->Double?
+VARIANCE_SAMPLE(Double?)->Double?
+```
+
+Стандартное отклонение и дисперсия по колонке. Используется [однопроходной параллельный алгоритм](https://en.wikipedia.org/wiki/Algorithms_for_calculating_variance#Parallel_algorithm), результат которого может отличаться от полученного более распространенными методами, требующими двух проходов по данным.
+
+По умолчанию вычисляются выборочная дисперсия и стандартное отклонение. Доступны несколько способов записи:
+
+* с суффиксом/префиксом `POPULATION`, например: `VARIANCE_POPULATION`, `POPULATION_VARIANCE` — вычисляет дисперсию/стандартное отклонение для генеральной совокупности;
+* с суффиксом `SAMPLE` или без суффикса, например `VARIANCE_SAMPLE`, `SAMPLE_VARIANCE`, `VARIANCE` — вычисляет выборочную дисперсию и стандартное отклонение.
+
+Также определено несколько сокращенных алиасов, например `VARPOP` или `STDDEVSAMP`.
+
+Если все переданные значения — `NULL`, возвращает `NULL`.
+
+### Примеры
+
+```yql
+SELECT
+ STDDEV(numeric_column),
+ VARIANCE(numeric_column)
+FROM my_table;
+```
+
+
+## CORRELATION и COVARIANCE {#correlation-covariance}
+
+### Сигнатура
+
+```yql
+CORRELATION(Double?, Double?)->Double?
+COVARIANCE(Double?, Double?)->Double?
+COVARIANCE_SAMPLE(Double?, Double?)->Double?
+COVARIANCE_POPULATION(Double?, Double?)->Double?
+```
+
+Корреляция и ковариация двух колонок.
+
+Также доступны сокращенные версии `CORR` или `COVAR`, а для ковариации - версии с суффиксом `SAMPLE` / `POPULATION` по аналогии с описанной выше [VARIANCE](#stddev-variance).
+
+В отличие от большинства других агрегатных функций не пропускают `NULL`, а считают его за 0.
+
+При использовании [фабрики агрегационной функции](basic.md#aggregationfactory) в качестве первого аргумента [AGGREGATE_BY](#aggregate-by) передается `Tuple` из двух значений.
+
+### Примеры
+
+```yql
+SELECT
+ CORRELATION(numeric_column, another_numeric_column),
+ COVARIANCE(numeric_column, another_numeric_column)
+FROM my_table;
+```
+
+```yql
+$corr_factory = AggregationFactory("CORRELATION");
+
+SELECT
+ AGGREGATE_BY(AsTuple(numeric_column, another_numeric_column), $corr_factory)
+FROM my_table;
+```
+
+## PERCENTILE и MEDIAN {#percentile-median}
+
+### Сигнатура
+
+```yql
+PERCENTILE(T, Double)->T
+PERCENTILE(T, Tuple<Double, ...>)->Tuple<T, ...>
+PERCENTILE(T, Struct<name1:Double, ...>)->Struct<name1:T, ...>
+PERCENTILE(T, List<Double>)->List<T>
+
+MEDIAN(T, [ Double ])->T
+MEDIAN(T, [ Tuple<Double, ...> ])->Tuple<T, ...>
+MEDIAN(T, [ Struct<name1:Double, ...> ])->Struct<name1:T, ...>
+MEDIAN(T, [ List<Double> ])->List<T>
+```
+
+Подсчет процентилей по амортизированной версии алгоритма [TDigest](https://github.com/tdunning/t-digest). `MEDIAN(x)` без второго аргумента — алиас для `PERCENTILE(x, 0.5)`.
+`MEDIAN` с двумя аргументами полностью эквивалентен `PERCENTILE`.
+
+В качестве первого аргумента `PERCENTILE`/`MEDIAN` принимает выражение типа `T`. В качестве типа `T` на данный момент поддерживаются типы `Interval` и `Double` (а также типы которые допускают неявное приведение к ним - например целочисленные типы).
+
+В качестве второго аргумента можно использовать либо один `Double` (значение перцентиля), либо сразу несколько значений перцентиля в виде `Tuple`/`Struct`/`List`.
+
+Значения прецентиля должны лежать в диапазоне от 0.0 до 1.0 включительно.
+
+### Примеры
+
+```yql
+SELECT
+ MEDIAN(numeric_column),
+ PERCENTILE(numeric_column, 0.99),
+ PERCENTILE(CAST(string_column as Double), (0.01, 0.5, 0.99)), -- подсчет сразу трех перцентилей
+ PERCENTILE(numeric_column, AsStruct(0.01 as p01, 0.5 as median, 0.99 as p99)), -- используя структуру, значениям перцентиля можно дать удобные имена
+ PERCENTILE(numeric_column, ListFromRange(0.00, 1.05, 0.05)), -- подсчет множества перцентилей (от 0.0 до 1.0 включительно с шагом 0.05)
+FROM my_table;
+```
+
+
+
+## HISTOGRAM {#histogram}
+
+### Сигнатура
+
+```yql
+HISTOGRAM(Double?)->HistogramStruct?
+HISTOGRAM(Double?, weight:Double)->HistogramStruct?
+HISTOGRAM(Double?, intervals:Uint32)->HistogramStruct?
+HISTOGRAM(Double?, weight:Double, intervals:Uint32)->HistogramStruct?
+```
+
+В описании сигнатур под HistogramStruct подразумевается результат работы агрегатной функции, который является структурой определенного вида.
+
+Построение примерной гистограммы по числовому выражению с автоматическим выбором корзин.
+
+[Вспомогательные функции](../udf/list/histogram.md)
+
+### Базовые настройки
+
+Ограничение на число корзин можно задать с помощью опционального аргумента, значение по умолчанию — 100. Следует иметь в виду, что дополнительная точность стоит дополнительных вычислительных ресурсов и может негативно сказываться на времени выполнения запроса, а в экстремальных случаях — и на его успешности.
+
+### Поддержка весов
+
+Имеется возможность указать «вес» для каждого значения, участвующего в построении гистограммы. Для этого вторым аргументом в агрегатную функцию нужно передать выражение для вычисления веса. По умолчанию всегда используется вес `1.0`. Если используются нестандартные веса, ограничение на число корзин можно задать третьим аргументом.
+
+В случае, если передано два аргумента, смысл второго аргумента определяется по его типу (целочисленный литерал — ограничение на число корзин, в противном случае — вес).
+
+### Алгоритмы
+
+* [Оригинальный whitepaper](http://jmlr.org/papers/volume11/ben-haim10a/ben-haim10a.pdf);
+
+Доступны разные модификации алгоритма:
+
+```yql
+AdaptiveDistanceHistogram
+AdaptiveWeightHistogram
+AdaptiveWardHistogram
+BlockWeightHistogram
+BlockWardHistogram
+```
+
+По умолчанию `HISTOGRAM` является синонимом к `AdaptiveWardHistogram`. Обе функции эквивалентны и взаимозаменимы во всех контекстах.
+
+Алгоритмы Distance, Weight и Ward отличаются формулами объединения двух точек в одну:
+
+```c++
+TWeightedValue CalcDistanceQuality(const TWeightedValue& left, const TWeightedValue& right) {
+ return TWeightedValue(right.first - left.first, left.first);
+}
+
+TWeightedValue CalcWeightQuality(const TWeightedValue& left, const TWeightedValue& right) {
+ return TWeightedValue(right.second + left.second, left.first);
+}
+
+TWeightedValue CalcWardQuality(const TWeightedValue& left, const TWeightedValue& right) {
+ const double N1 = left.second;
+ const double N2 = right.second;
+ const double mu1 = left.first;
+ const double mu2 = right.first;
+ return TWeightedValue(N1 * N2 / (N1 + N2) * (mu1 - mu2) * (mu1 - mu2), left.first);
+}
+```
+
+Чем отличается Adaptive и Block:
+
+{% block info %}
+
+Contrary to adaptive histogram, block histogram doesn't rebuild bins after the addition of each point. Instead, it accumulates points and in case the amount of points overflows specified limits, it shrinks all the points at once to produce histogram. Indeed, there exist two limits and two shrinkage operations:
+
+1. FastGreedyShrink is fast but coarse. It is used to shrink from upper limit to intermediate limit (override FastGreedyShrink to set specific behaviour).
+2. SlowShrink is slow, but produces finer histogram. It shrinks from the intermediate limit to the actual number of bins in a manner similar to that in adaptive histogram (set CalcQuality in constuctor)
+
+While FastGreedyShrink is used most of the time, SlowShrink is mostly used for histogram finalization
+
+{% endblock %}
+
+### Если нужна точная гистограмма
+
+1. Можно воспользоваться описанными ниже агрегатными функциями с фиксированными сетками корзин: [LinearHistogram](#linearhistogram) или [LogarithmicHistogram](#linearhistogram).
+2. Можно самостоятельно вычислить номер корзины для каждой строки и сделать по нему [GROUP BY](../syntax/group_by.md).
+
+При использовании [фабрики агрегационной функции](basic.md#aggregationfactory) в качестве первого аргумента [AGGREGATE_BY](#aggregate-by) передается `Tuple` из значения и веса.
+
+### Примеры
+
+```yql
+SELECT
+ HISTOGRAM(numeric_column)
+FROM my_table;
+```
+
+```yql
+SELECT
+ Histogram::Print(
+ HISTOGRAM(numeric_column, 10),
+ 50
+ )
+FROM my_table;
+```
+
+```yql
+$hist_factory = AggregationFactory("HISTOGRAM");
+
+SELECT
+ AGGREGATE_BY(AsTuple(numeric_column, 1.0), $hist_factory)
+FROM my_table;
+```
+
+## LinearHistogram, LogarithmicHistogram и LogHistogram {#linearhistogram}
+
+Построение гистограммы по явно указанной фиксированной шкале корзин.
+
+### Сигнатура
+
+```yql
+LinearHistogram(Double?)->HistogramStruct?
+LinearHistogram(Double? [, binSize:Double [, min:Double [, max:Double]]])->HistogramStruct?
+
+LogarithmicHistogram(Double?)->HistogramStruct?
+LogarithmicHistogram(Double? [, logBase:Double [, min:Double [, max:Double]]])->HistogramStruct?
+LogHistogram(Double?)->HistogramStruct?
+LogHistogram(Double? [, logBase:Double [, min:Double [, max:Double]]])->HistogramStruct?
+```
+
+Аргументы:
+
+1. Выражение, по значению которого строится гистограмма. Все последующие — опциональны.
+2. Расстояние между корзинами для `LinearHistogram` или основание логарифма для `LogarithmicHistogram` / `LogHistogram` (это алиасы). В обоих случаях значение по умолчанию — 10.
+3. Минимальное значение. По умолчанию минус бесконечность.
+4. Максимальное значение. По умолчанию плюс бесконечность.
+
+Формат результата полностью аналогичен [адаптивным гистограммам](#histogram), что позволяет использовать тот же [набор вспомогательных функций](../udf/list/histogram.md).
+
+Если разброс входных значений неконтролируемо велик, рекомендуется указывать минимальное и максимальное значение для предотвращения потенциальных падений из-за высокого потребления памяти.
+
+### Примеры
+
+```yql
+SELECT
+ LogarithmicHistogram(numeric_column, 2)
+FROM my_table;
+```
+
+## CDF (cumulative distribution function) {#histogramcdf}
+
+К каждому виду функции Histogram можно приписать суффикс CDF для построения кумулятивной функции распределения. Конструкции
+
+```yql
+SELECT
+ Histogram::ToCumulativeDistributionFunction(Histogram::Normalize(<вид_функции>Histogram(numeric_column)))
+FROM my_table;
+```
+
+
+```yql
+SELECT
+ <вид_функции>HistogramCDF(numeric_column)
+FROM my_table;
+```
+
+полностью эквивалентны.
+
+## BOOL_AND, BOOL_OR и BOOL_XOR {#bool-and-or-xor}
+
+### Сигнатура
+
+```yql
+BOOL_AND(Bool?)->Bool?
+BOOL_OR(Bool?)->Bool?
+BOOL_XOR(Bool?)->Bool?
+```
+
+Применение соответствующей логической операции (`AND`/`OR`/`XOR`) ко всем значениям булевой колонки или выражения.
+
+В отличие от большинства агрегатных функций, эти функции **не пропускают** `NULL` значение при агрегации и действуют по правилу:
+
+- `true AND null == null`
+- `false OR null == null`
+
+Для `BOOL_AND`:
+
+- Для любого количества значений `true` и хотя бы одного `NULL` значения, результатом будет `NULL`.
+- В случае хотя бы одного `false` значения, результатом будет `false`, независимо от наличия `NULL`.
+
+Для `BOOL_OR`:
+
+- Для любого количества значений `false` и хотя бы одного `NULL` значения, результатом будет `NULL`.
+- В случае хотя бы одного `true` значения, результатом будет `true`, независимо от наличия `NULL`.
+
+Для `BOOL_XOR`:
+
+- В случае хотя бы одного `NULL` значения, результатом будет `NULL`.
+
+Примеры описанного поведения приведены ниже.
+
+Для агрегации с пропуском `NULL`-ов можно использовать функции `MIN`/`MAX` или `BIT_AND`/`BIT_OR`/`BIT_XOR`.
+
+### Примеры
+
+```yql
+$data = [
+ <|nonNull: true, nonFalse: true, nonTrue: NULL, anyVal: true|>,
+ <|nonNull: false, nonFalse: NULL, nonTrue: NULL, anyVal: NULL|>,
+ <|nonNull: false, nonFalse: NULL, nonTrue: false, anyVal: false|>,
+];
+
+SELECT
+ BOOL_AND(nonNull) as nonNullAnd, -- false
+ BOOL_AND(nonFalse) as nonFalseAnd, -- NULL
+ BOOL_AND(nonTrue) as nonTrueAnd, -- false
+ BOOL_AND(anyVal) as anyAnd, -- false
+ BOOL_OR(nonNull) as nonNullOr, -- true
+ BOOL_OR(nonFalse) as nonFalseOr, -- true
+ BOOL_OR(nonTrue) as nonTrueOr, -- NULL
+ BOOL_OR(anyVal) as anyOr, -- true
+ BOOL_XOR(nonNull) as nonNullXor, -- true
+ BOOL_XOR(nonFalse) as nonFalseXor, -- NULL
+ BOOL_XOR(nonTrue) as nonTrueXor, -- NULL
+ BOOL_XOR(anyVal) as anyXor, -- NULL
+FROM AS_TABLE($data);
+```
+
+## BIT_AND, BIT_OR и BIT_XOR {#bit-and-or-xor}
+
+Применение соответствующей битовой операции ко всем значениям числовой колонки или выражения.
+
+### Примеры
+
+```yql
+SELECT
+ BIT_XOR(unsigned_numeric_value)
+FROM my_table;
+```
+
+## SessionStart {#session-start}
+
+Без аргументов. Допускается только при наличии [SessionWindow](../syntax/group_by.md#session-window) в
+[GROUP BY](../syntax/group_by.md) / [PARTITION BY](../syntax/window.md#partition).
+Возвращает значение ключевой колонки `SessionWindow`. В случае `SessionWindow` с двумя аргументами – минимальное значение первого аргумента внутри группы/раздела.
+В случае раширенного варианта `SessionWindoow` – значение второго элемента кортежа, возвращаемого `<calculate_lambda>`, при котором первый элемент кортежа равен `True`.
+
+
+## AGGREGATE_BY и MULTI_AGGREGATE_BY {#aggregate-by}
+
+Применение [фабрики агрегационной функции](basic.md#aggregationfactory) ко всем значениям колонки или выражения. Функция `MULTI_AGGREGATE_BY` требует, чтобы в значении колонки или выражения была структура, кортеж или список, и применяет фабрику поэлементно, размещая результат в контейнере той же формы. Если в разных значениях колонки или выражения содержатся списки разной длины, результирующий список будет иметь наименьшую из длин этих списков.
+
+1. Колонка, `DISTINCT` колонка или выражение;
+2. Фабрика.
+
+### Примеры
+
+```yql
+$count_factory = AggregationFactory("COUNT");
+
+SELECT
+ AGGREGATE_BY(DISTINCT column, $count_factory) as uniq_count
+FROM my_table;
+
+SELECT
+ MULTI_AGGREGATE_BY(nums, AggregationFactory("count")) as count,
+ MULTI_AGGREGATE_BY(nums, AggregationFactory("min")) as min,
+ MULTI_AGGREGATE_BY(nums, AggregationFactory("max")) as max,
+ MULTI_AGGREGATE_BY(nums, AggregationFactory("avg")) as avg,
+ MULTI_AGGREGATE_BY(nums, AggregationFactory("percentile", 0.9)) as p90
+FROM my_table;
+```
+
diff --git a/yql/essentials/docs/ru/builtins/basic.md b/yql/essentials/docs/ru/builtins/basic.md
new file mode 100644
index 0000000000..da9f1503b3
--- /dev/null
+++ b/yql/essentials/docs/ru/builtins/basic.md
@@ -0,0 +1,1564 @@
+
+# Базовые встроенные функции
+
+Ниже описаны функции общего назначения, а для специализированных функций есть отдельные статьи: [агрегатные](aggregation.md), [оконные](window.md), а также для работы со [списками](list.md), [словарями](dict.md), [структурами](struct.md), [типами данных](types.md) и [генерацией кода](codegen.md).
+
+
+## COALESCE {#coalesce}
+
+Перебирает аргументы слева направо и возвращает первый найденный непустой аргумент. Чтобы результат получился гарантированно непустым (не [optional типа](../types/optional.md)), самый правый аргумент должен быть такого типа (зачастую используют литерал). При одном аргументе возвращает его без изменений.
+
+### Сигнатура
+
+```yql
+COALESCE(T?, ..., T)->T
+COALESCE(T?, ..., T?)->T?
+```
+
+Позволяет передавать потенциально пустые значения в функции, которые не умеют обрабатывать их самостоятельно.
+
+Доступен краткий формат записи в виде оператора `??`. Можно использовать алиас `NVL`.
+
+### Примеры
+
+```yql
+SELECT COALESCE(
+ maybe_empty_column,
+ "it's empty!"
+) FROM my_table;
+```
+
+```yql
+SELECT
+ maybe_empty_column ?? "it's empty!"
+FROM my_table;
+```
+
+```yql
+SELECT NVL(
+ maybe_empty_column,
+ "it's empty!"
+) FROM my_table;
+```
+
+Все три примера выше эквивалентны.
+
+
+## LENGTH {#length}
+
+Возвращает длину строки в байтах. Также эта функция доступна под именем `LEN`.
+
+### Сигнатура
+
+```yql
+LENGTH(T)->Uint32
+LENGTH(T?)->Uint32?
+```
+
+### Примеры
+
+```yql
+SELECT LENGTH("foo");
+```
+
+```yql
+SELECT LEN("bar");
+```
+
+{% note info %}
+
+Для вычисления длины строки в unicode символах можно воспользоваться функцией [Unicode::GetLength](../udf/list/unicode.md).<br/><br/>Для получения числа элементов в списке нужно использовать функцию [ListLength](list.md#listlength).
+
+{% endnote %}
+
+
+## SUBSTRING {#substring}
+
+Возвращает подстроку.
+
+### Сигнатура
+
+```yql
+Substring(String[, Uint32? [, Uint32?]])->String
+Substring(String?[, Uint32? [, Uint32?]])->String?
+```
+
+Обязательные аргументы:
+
+* Исходная строка;
+* Позиция — отступ от начала строки в байтах (целое число) или `NULL`, означающий «от начала».
+
+Опциональные аргументы:
+
+* Длина подстроки — количество байт, начиная с указанной позиции (целое число, или `NULL` по умолчанию, означающий «до конца исходной строки»).
+
+Индексация с нуля. Если указанные позиция и длина выходят за пределы строки, возвращает пустую строку.
+Если входная строка является опциональной, то таким же является и результат.
+
+### Примеры
+
+```yql
+SELECT SUBSTRING("abcdefg", 3, 1); -- d
+```
+
+```yql
+SELECT SUBSTRING("abcdefg", 3); -- defg
+```
+
+```yql
+SELECT SUBSTRING("abcdefg", NULL, 3); -- abc
+```
+
+
+## FIND {#find}
+
+Поиск позиции подстроки в строке.
+
+### Сигнатура
+
+```yql
+Find(String, String[, Uint32?])->Uint32?
+Find(String?, String[, Uint32?])->Uint32?
+Find(Utf8, Utf8[, Uint32?])->Uint32?
+Find(Utf8?, Utf8[, Uint32?])->Uint32?
+```
+
+Обязательные аргументы:
+
+* Исходная строка;
+* Искомая подстрока.
+
+Опциональные аргументы:
+
+* Позиция — в байтах, с которой начинать поиск (целое число, или `NULL` по умолчанию, означающий «от начала исходной строки»).
+
+Возвращает первую найденную позицию подстроки или `NULL`, означающий что искомая подстрока с указанной позиции не найдена.
+
+### Примеры
+
+```yql
+SELECT FIND("abcdefg_abcdefg", "abc"); -- 0
+```
+
+```yql
+SELECT FIND("abcdefg_abcdefg", "abc", 1); -- 8
+```
+
+```yql
+SELECT FIND("abcdefg_abcdefg", "abc", 9); -- null
+```
+
+## RFIND {#rfind}
+
+Обратный поиск позиции подстроки в строке, от конца к началу.
+
+### Сигнатура
+
+```yql
+RFind(String, String[, Uint32?])->Uint32?
+RFind(String?, String[, Uint32?])->Uint32?
+RFind(Utf8, Utf8[, Uint32?])->Uint32?
+RFind(Utf8?, Utf8[, Uint32?])->Uint32?
+```
+
+Обязательные аргументы:
+
+* Исходная строка;
+* Искомая подстрока.
+
+Опциональные аргументы:
+
+* Позиция — в байтах, с которой начинать поиск (целое число, или `NULL` по умолчанию, означающий «от конца исходной строки»).
+
+Возвращает первую найденную позицию подстроки или `NULL`, означающий, что искомая подстрока с указанной позиции не найдена.
+
+### Примеры
+
+```yql
+SELECT RFIND("abcdefg_abcdefg", "bcd"); -- 9
+```
+
+```yql
+SELECT RFIND("abcdefg_abcdefg", "bcd", 8); -- 1
+```
+
+```yql
+SELECT RFIND("abcdefg_abcdefg", "bcd", 0); -- null
+```
+
+
+## StartsWith, EndsWith {#starts_ends_with}
+
+Проверка наличия префикса или суффикса в строке.
+
+### Сигнатуры
+
+```yql
+StartsWith(T str, U prefix)->Bool[?]
+
+EndsWith(T str, U suffix)->Bool[?]
+```
+
+Обязательные аргументы:
+
+* Исходная строка;
+* Искомая подстрока.
+
+Аргументы должны иметь тип `String`/`Utf8` (или опциональный `String`/`Utf8`) либо строковый PostgreSQL тип (`PgText`/`PgBytea`/`PgVarchar`).
+Результатом функции является опциональный Bool, за исключением случая, когда оба аргумента неопциональные – в этом случае возвращается Bool.
+
+### Примеры
+
+```yql
+SELECT StartsWith("abc_efg", "abc") AND EndsWith("abc_efg", "efg"); -- true
+```
+
+```yql
+SELECT StartsWith("abc_efg", "efg") OR EndsWith("abc_efg", "abc"); -- false
+```
+
+```yql
+SELECT StartsWith("abcd", NULL); -- null
+```
+
+```yql
+SELECT EndsWith(NULL, Utf8("")); -- null
+```
+
+```yql
+SELECT StartsWith("abc_efg"u, "abc"p) AND EndsWith("abc_efg", "efg"pv); -- true
+```
+
+
+## IF {#if}
+
+Проверяет условие `IF(condition_expression, then_expression, else_expression)`.
+
+Является упрощенной альтернативой для [CASE WHEN ... THEN ... ELSE ... END](../syntax/expressions.md#case).
+
+### Сигнатура
+
+```yql
+IF(Bool, T, T)->T
+IF(Bool, T)->T?
+```
+
+Аргумент `else_expression` можно не указывать. В этом случае, если условие ложно (`condition_expression` вернул `false`), будет возвращено пустое значение с типом, соответствующим `then_expression` и допускающим значение `NULL`. Таким образом, у результата получится [optional тип данных](../types/optional.md).
+
+### Примеры
+
+```yql
+SELECT
+ IF(foo > 0, bar, baz) AS bar_or_baz,
+ IF(foo > 0, foo) AS only_positive_foo
+FROM my_table;
+```
+
+
+## NANVL {#nanvl}
+
+Заменяет значения `NaN` (not a number) в выражениях типа `Float`, `Double` или [Optional](../types/optional.md).
+
+### Сигнатура
+
+```yql
+NANVL(Float, Float)->Float
+NANVL(Double, Double)->Double
+```
+
+Аргументы:
+
+1. Выражение, в котором нужно произвести замену.
+2. Значение, на которое нужно заменить `NaN`.
+
+Если один из агрументов `Double`, то в выдаче `Double`, иначе `Float`. Если один из агрументов `Optional`, то и в выдаче `Optional`.
+
+### Примеры
+
+```yql
+SELECT
+ NANVL(double_column, 0.0)
+FROM my_table;
+```
+
+
+## Random... {#random}
+
+Генерирует псевдослучайное число:
+
+* `Random()` — число с плавающей точкой (Double) от 0 до 1;
+* `RandomNumber()` — целое число из всего диапазона Uint64;
+* `RandomUuid()` — [Uuid version 4](https://tools.ietf.org/html/rfc4122#section-4.4).
+
+### Сигнатуры
+
+```yql
+Random(T1[, T2, ...])->Double
+RandomNumber(T1[, T2, ...])->Uint64
+RandomUuid(T1[, T2, ...])->Uuid
+```
+
+При генерации случайных чисел аргументы не используются и нужны исключительно для управления моментом вызова. В каждый момент вызова возвращается новое случайное число. Поэтому:
+
+* Повторный вызов Random в рамках **одного запроса** при идентичном наборе аргументов возвращает тот же самый набор случайных чисел. Важно понимать, что речь именно про сами аргументы (текст между круглыми скобками), а не их значения.
+
+* Вызовы Random с одним и тем же набором аргументов в **разных запросах** вернут разные наборы случайных чисел.
+
+{% note warning %}
+
+Если Random используется в [именованных выражениях](../syntax/expressions.md#named-nodes), то его однократное вычисление не гарантируется. В зависимости от оптимизаторов и среды исполнения он может посчитаться как один раз, так и многократно. Для гарантированного однократного подсчета необходимо в этом случае материализовать именованное выражение в таблицу.
+
+{% endnote %}
+
+Сценарии использования:
+
+* `SELECT RANDOM(1);` — получить одно случайное значение на весь запрос и несколько раз его использовать (чтобы получить несколько, можно передать разные константы любого типа);
+* `SELECT RANDOM(1) FROM table;` — одно и то же случайное число на каждую строку таблицы;
+* `SELECT RANDOM(1), RANDOM(2) FROM table;` — по два случайных числа на каждую строку таблицы, все числа в каждой из колонок одинаковые;
+* `SELECT RANDOM(some_column) FROM table;` — разные случайные числа на каждую строку таблицы;
+* `SELECT RANDOM(some_column), RANDOM(some_column) FROM table;` — разные случайные числа на каждую строку таблицы, но в рамках одной строки — два одинаковых числа;
+* `SELECT RANDOM(some_column), RANDOM(some_column + 1) FROM table;` или `SELECT RANDOM(some_column), RANDOM(other_column) FROM table;` — две колонки, и все с разными числами.
+
+### Примеры
+
+```yql
+SELECT
+ Random(key) -- [0, 1)
+FROM my_table;
+```
+
+```yql
+SELECT
+ RandomNumber(key) -- [0, Max<Uint64>)
+FROM my_table;
+```
+
+```yql
+SELECT
+ RandomUuid(key) -- Uuid version 4
+FROM my_table;
+```
+
+```yql
+SELECT
+ RANDOM(column) AS rand1,
+ RANDOM(column) AS rand2, -- same as rand1
+ RANDOM(column, 1) AS randAnd1, -- different from rand1/2
+ RANDOM(column, 2) AS randAnd2 -- different from randAnd1
+FROM my_table;
+```
+
+
+## Udf {#udf}
+
+Строит `Callable` по заданному названию функции и опциональным `external user types`, `RunConfig` и `TypeConfig`.
+
+* `Udf(Foo::Bar)` — Функция `Foo::Bar` без дополнительных параметров.
+* `Udf(Foo::Bar)(1, 2, 'abc')` — Вызов udf `Foo::Bar`.
+* `Udf(Foo::Bar, Int32, @@{"device":"AHCI"}@@ as TypeConfig")(1, 2, 'abc')` — Вызов udf `Foo::Bar` с дополнительным типом `Int32` и указанным `TypeConfig`.
+* `Udf(Foo::Bar, "1e9+7" as RunConfig")(1, 'extended' As Precision)` — Вызов udf `Foo::Bar` с указанным `RunConfig` и именоваными параметрами.
+
+### Сигнатуры
+
+```yql
+Udf(Callable[, T1, T2, ..., T_N][, V1 as TypeConfig][,V2 as RunConfig]])->Callable
+```
+
+Где `T1`, `T2`, и т. д. -- дополнительные (`external`) пользовательские типы.
+
+### Примеры
+
+```yql
+$IsoParser = Udf(DateTime2::ParseIso8601);
+SELECT $IsoParser("2022-01-01");
+```
+
+```yql
+SELECT Udf(Unicode::IsUtf)("2022-01-01")
+```
+
+```yql
+$config = @@{
+ "name":"MessageFoo",
+ "meta": "..."
+}@@;
+SELECT Udf(Protobuf::TryParse, $config As TypeConfig)("")
+```
+
+
+## CurrentUtc... {#current-utc}
+
+`CurrentUtcDate()`, `CurrentUtcDatetime()` и `CurrentUtcTimestamp()` - получение текущей даты и/или времени в UTC. Тип данных результата указан в конце названия функции.
+
+### Сигнатуры
+
+```yql
+CurrentUtcDate(...)->Date
+CurrentUtcDatetime(...)->Datetime
+CurrentUtcTimestamp(...)->Timestamp
+```
+
+Аргументы опциональны и работают по тому же принципу, что и у [RANDOM](#random).
+
+### Примеры
+
+```yql
+SELECT CurrentUtcDate();
+```
+
+```yql
+SELECT CurrentUtcTimestamp(TableRow()) FROM my_table;
+```
+
+
+## CurrentTz... {#current-tz}
+
+`CurrentTzDate()`, `CurrentTzDatetime()` и `CurrentTzTimestamp()` - получение текущей даты и/или времени в указанной в первом аргументе [IANA временной зоне](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones). Тип данных результата указан в конце названия функции.
+
+### Сигнатуры
+
+```yql
+CurrentTzDate(String, ...)->TzDate
+CurrentTzDatetime(String, ...)->TzDatetime
+CurrentTzTimestamp(String, ...)->TzTimestamp
+```
+
+Последующие аргументы опциональны и работают по тому же принципу, что и у [RANDOM](#random).
+
+### Примеры
+
+```yql
+SELECT CurrentTzDate("Europe/Moscow");
+```
+
+```yql
+SELECT CurrentTzTimestamp("Europe/Moscow", TableRow()) FROM my_table;
+```
+
+## AddTimezone
+
+Добавление информации о временной зоне к дате/времени, заданных в UTC. При выводе в результате `SELECT` или после `CAST` в `String` будут применены правила временной зоны по вычислению смещения времени.
+
+### Сигнатура
+
+```yql
+AddTimezone(Date, String)->TzDate
+AddTimezone(Date?, String)->TzDate?
+AddTimezone(Datetime, String)->TzDatetime
+AddTimezone(Datetime?, String)->TzDatetime?
+AddTimezone(Timestamp, String)->TzTimestamp
+AddTimezone(Timestamp?, String)->TzTimestamp?
+```
+
+Аргументы:
+
+1. Дата - тип `Date`/`Datetime`/`Timestamp`;
+2. [IANA имя временной зоны](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones).
+
+Тип результата - `TzDate`/`TzDatetime`/`TzTimestamp`, в зависимости от типа данных входа.
+
+### Примеры
+
+```yql
+SELECT AddTimezone(Datetime("2018-02-01T12:00:00Z"), "Europe/Moscow");
+```
+
+## RemoveTimezone
+
+Удаление информации о временной зоне и перевод в дату/время, заданные в UTC.
+
+### Сигнатура
+
+```yql
+RemoveTimezone(TzDate)->Date
+RemoveTimezone(TzDate?)->Date?
+RemoveTimezone(TzDatetime)->Datetime
+RemoveTimezone(TzDatetime?)->Datetime?
+RemoveTimezone(TzTimestamp)->Timestamp
+RemoveTimezone(TzTimestamp?)->Timestamp?
+```
+
+Аргументы:
+
+1. Дата - тип `TzDate`/`TzDatetime`/`TzTimestamp`.
+
+Тип результата - `Date`/`Datetime`/`Timestamp`, в зависимости от типа данных входа.
+
+### Примеры
+
+```yql
+SELECT RemoveTimezone(TzDatetime("2018-02-01T12:00:00,Europe/Moscow"));
+```
+
+
+## Version {#version}
+
+`Version()` возвращает строку, описывающую текущую версию узла, обрабатывающего запрос. В некоторых случаях, например, во время постепенного обновлений кластера, она может возвращать разные строки в зависимости от того, какой узел обрабатывает запрос. Функция не принимает никаких аргументов.
+
+### Примеры
+
+```yql
+SELECT Version();
+```
+
+
+## MAX_OF, MIN_OF, GREATEST и LEAST {#max-min}
+
+Возвращает минимальный или максимальный среди N аргументов. Эти функции позволяют не использовать стандартную для SQL конструкцию `CASE WHEN a < b THEN a ELSE b END`, которая была бы особенно громоздкой для N больше двух.
+
+### Сигнатуры
+
+```yql
+MIN_OF(T[,T,...})->T
+MAX_OF(T[,T,...})->T
+```
+
+Типы аргументов должны быть приводимы друг к другу и могут допускать значение `NULL`.
+
+`GREATEST` является синонимом к `MAX_OF`, а `LEAST` — к `MIN_OF`.
+
+### Примеры
+
+```yql
+SELECT MIN_OF(1, 2, 3);
+```
+
+
+## AsTuple, AsStruct, AsList, AsDict, AsSet, AsListStrict, AsDictStrict и AsSetStrict {#as-container}
+
+Создает контейнеры соответствующих типов. Также доступна [операторная запись](#containerliteral) литералов контейнеров.
+
+Особенности:
+
+* Элементы контейнеров передаются через аргументы, таким образом число элементов результирующего контейнера равно числу переданных аргументов, кроме случая, когда повторяются ключи словаря.
+* В `AsTuple` и `AsStruct` могут быть вызваны без аргументов, а также аргументы могут иметь разные типы.
+* Имена полей в `AsStruct` задаются через `AsStruct(field_value AS field_name)`.
+* Для создания списка требуется хотя бы один аргумент, если нужно вывести типы элементов. Для создания пустого списка с заданным типом элементов используется функция [ListCreate](list.md#listcreate). Можно создать пустой список как вызов `AsList()` без аргументов, в этом случае это выражение будет иметь тип `EmptyList`.
+* Для создания словаря требуется хотя бы один аргумент, если нужно вывести типы элементов. Для создания пустого словаря с заданным типом элементов используется функция [DictCreate](dict.md#dictcreate). Можно создать пустой словарь как вызов `AsDict()` без аргументов, в этом случае это выражение будет иметь тип `EmptyDict`.
+* Для создания множества требуется хотя бы один аргумент, если нужно вывести типы элементов. Для создания пустого множества с заданным типом элементов используется функция [SetCreate](dict.md#setcreate). Можно создать пустое множество как вызов `AsSet()` без аргументов, в этом случае это выражение будет иметь тип `EmptyDict`.
+* `AsList` выводит общий тип элементов списка. При несовместимых типах генерируется ошибка типизации.
+* `AsDict` выводит раздельно общие типы ключей и значений. При несовместимых типах генерируется ошибка типизации.
+* `AsSet` выводит общие типы ключей. При несовместимых типах генерируется ошибка типизации.
+* `AsListStrict`, `AsDictStrict`, `AsSetStrict` требуют одинакового типа для аргументов.
+* В `AsDict` и `AsDictStrict` в качестве аргументов ожидаются `Tuple` из двух элементов: ключ и значение, соответственно. Если ключи повторяются, в словаре останется только значение для первого ключа.
+* В `AsSet` и `AsSetStrict` в качестве аргументов ожидаются ключи.
+
+### Примеры
+
+```yql
+SELECT
+ AsTuple(1, 2, "3") AS `tuple`,
+ AsStruct(
+ 1 AS a,
+ 2 AS b,
+ "3" AS c
+ ) AS `struct`,
+ AsList(1, 2, 3) AS `list`,
+ AsDict(
+ AsTuple("a", 1),
+ AsTuple("b", 2),
+ AsTuple("c", 3)
+ ) AS `dict`,
+ AsSet(1, 2, 3) AS `set`
+```
+
+
+## Литералы контейнеров {#containerliteral}
+
+Для некоторых контейнеров возможна операторная форма записи их литеральных значений:
+
+* Кортеж — `(value1, value2...)`;
+* Структура — `<|name1: value1, name2: value2...|>`;
+* Список — `[value1, value2,...]`;
+* Словарь — `{key1: value1, key2: value2...}`;
+* Множество — `{key1, key2...}`.
+
+Во всех случаях допускается незначащая хвостовая запятая. Для кортежа с одним элементом эта запятая является обязательной - `(value1,)`.
+Для имен полей в литерале структуры допускается использовать выражение, которое можно посчитать в evaluation time, например, строковые литералы, а также идентификаторы (в том числе в backticks).
+
+Для списка внутри используется функция [AsList](#as-container), словаря - [AsDict](#as-container), множества - [AsSet](#as-container), кортежа - [AsTuple](#as-container), структуры - [AsStruct](#as-container).
+
+### Примеры
+
+```yql
+$name = "computed " || "member name";
+SELECT
+ (1, 2, "3") AS `tuple`,
+ <|
+ `complex member name`: 2.3,
+ b: 2,
+ $name: "3",
+ "inline " || "computed member name": false
+ |> AS `struct`,
+ [1, 2, 3] AS `list`,
+ {
+ "a": 1,
+ "b": 2,
+ "c": 3,
+ } AS `dict`,
+ {1, 2, 3} AS `set`
+```
+
+
+## Variant {#variant}
+
+`Variant()` создает значение варианта над кортежем или структурой.
+
+### Сигнатура
+
+```yql
+Variant(T, String, Type<Variant<...>>)->Variant<...>
+```
+
+Аргументы:
+
+* Значение
+* Строка с именем поля или индексом кортежа
+* Тип варианта
+
+### Пример
+
+```yql
+$var_type = Variant<foo: Int32, bar: Bool>;
+
+SELECT
+ Variant(6, "foo", $var_type) as Variant1Value,
+ Variant(false, "bar", $var_type) as Variant2Value;
+```
+
+## AsVariant {#asvariant}
+
+`AsVariant()` создает значение [варианта над структурой](../types/containers.md) с одним полем. Это значение может быть неявно преобразовано к любому варианту над структурой, в которой совпадает для этого имени поля тип данных и могут быть дополнительные поля с другими именами.
+
+### Сигнатура
+
+```yql
+AsVariant(T, String)->Variant
+```
+
+Аргументы:
+
+* Значение
+* Строка с именем поля
+
+### Пример
+
+```yql
+SELECT
+ AsVariant(6, "foo") as VariantValue
+```
+
+## Visit, VisitOrDefault {#visit}
+
+Обрабатывает возможные значения варианта, представленного структурой или кортежем, с использованием предоставленных функций-обработчиков для каждого из его полей/элементов.
+
+### Сигнатура
+
+```yql
+Visit(Variant<key1: K1, key2: K2, ...>, K1->R AS key1, K2->R AS key2, ...)->R
+Visit(Variant<K1, K2, ...>, K1->R, K2->R, ...)->R
+
+VisitOrDefault(Variant<K1, K2, ...>{Flags:AutoMap}, R, [K1->R, [K2->R, ...]])->R
+VisitOrDefault(Variant<key1: K1, key2: K2, ...>{Flags:AutoMap}, R, [K1->R AS key1, [K2->R AS key2, ...]])->R
+```
+
+### Аргументы
+
+* Для варианта над структурой функция принимает сам вариант в качестве позиционного аргумента и по одному именованному аргументу-обработчику для каждого поля этой структуры.
+* Для варианта над кортежем функция принимает сам вариант и по одному обработчику на каждый элемент кортежа в качестве позиционных аргументов.
+* Модификация `VisitOrDefault` принимает дополнительный позиционный аргумент (на втором месте), представляющий значение по умолчанию, и позволяет не указывать некоторые обработчики.
+
+### Пример
+
+```yql
+$vartype = Variant<num: Int32, flag: Bool, str: String>;
+$handle_num = ($x) -> { return 2 * $x; };
+$handle_flag = ($x) -> { return If($x, 200, 10); };
+$handle_str = ($x) -> { return Unwrap(CAST(LENGTH($x) AS Int32)); };
+
+$visitor = ($var) -> { return Visit($var, $handle_num AS num, $handle_flag AS flag, $handle_str AS str); };
+SELECT
+ $visitor(Variant(5, "num", $vartype)), -- 10
+ $visitor(Just(Variant(True, "flag", $vartype))), -- Just(200)
+ $visitor(Just(Variant("somestr", "str", $vartype))), -- Just(7)
+ $visitor(Nothing(OptionalType($vartype))), -- Nothing(Optional<Int32>)
+ $visitor(NULL) -- NULL
+;
+```
+
+## VariantItem {#variantitem}
+
+Возвращает значение гомогенного варианта (т.е. содержащего поля/элементы одного типа).
+
+### Сигнатура
+
+```yql
+VariantItem(Variant<key1: K, key2: K, ...>{Flags:AutoMap})->K
+VariantItem(Variant<K, K, ...>{Flags:AutoMap})->K
+```
+
+### Пример
+
+```yql
+$vartype1 = Variant<num1: Int32, num2: Int32, num3: Int32>;
+SELECT
+ VariantItem(Variant(7, "num2", $vartype1)), -- 7
+ VariantItem(Just(Variant(5, "num1", $vartype1))), -- Just(5)
+ VariantItem(Nothing(OptionalType($vartype1))), -- Nothing(Optional<Int32>)
+ VariantItem(NULL) -- NULL
+;
+```
+
+## Way {#way}
+
+Возвращает активное поле (активный индекс) варианта поверх структуры (кортежа).
+
+### Сигнатура
+
+```yql
+Way(Variant<key1: K1, key2: K2, ...>{Flags:AutoMap})->Utf8
+Way(Variant<K1, K2, ...>{Flags:AutoMap})->Uint32
+```
+
+### Пример
+
+```yql
+$vr = Variant(1, "0", Variant<Int32, String>);
+$vrs = Variant(1, "a", Variant<a:Int32, b:String>);
+
+
+SELECT Way($vr); -- 0
+SELECT Way($vrs); -- "a"
+
+```
+
+## Enum {#enum}
+
+`Enum()` cоздает значение перечисления.
+
+### Сигнатура
+
+```yql
+Enum(String, Type<Enum<...>>)->Enum<...>
+```
+
+Аргументы:
+
+* Строка с именем поля
+* Тип перечисления
+
+### Пример
+
+```yql
+$enum_type = Enum<Foo, Bar>;
+SELECT
+ Enum("Foo", $enum_type) as Enum1Value,
+ Enum("Bar", $enum_type) as Enum2Value;
+```
+
+## AsEnum {#asenum}
+
+`AsEnum()` создает значение [перечисления](../types/containers.md) с одним элементом. Это значение может быть неявно преобразовано к любому перечислению, содержащему такое имя.
+
+### Сигнатура
+
+```yql
+AsEnum(String)->Enum<'tag'>
+```
+
+Аргументы:
+
+* Строка с именем элемента перечисления
+
+### Пример
+
+```yql
+SELECT
+ AsEnum("Foo");
+```
+
+
+## AsTagged, Untag {#as-tagged}
+
+Оборачивает значение в [Tagged тип данных](../types/special.md) с указанной меткой с сохранением физического типа данных. `Untag` — обратная операция.
+
+### Сигнатура
+
+```yql
+AsTagged(T, tagName:String)->Tagged<T,tagName>
+AsTagged(T?, tagName:String)->Tagged<T,tagName>?
+
+Untag(Tagged<T, tagName>)->T
+Untag(Tagged<T, tagName>?)->T?
+```
+
+Обязательные аргументы:
+
+1. Значение произвольного типа;
+2. Имя метки.
+
+Возвращает копию значения из первого аргумента с указанной меткой в типе данных.
+
+Примеры сценариев использования:
+
+* Возвращение на клиент для отображения в веб-интерфейсе медиа-файлов из base64-encoded строк.
+* Защита на границах вызова UDF от передачи некорректных значений;
+* Дополнительные уточнения на уровне типов возвращаемых колонок.
+
+## TablePath {#tablepath}
+
+Доступ к текущему имени таблицы, что бывает востребовано при использовании [CONCAT](../syntax/select/concat.md#concat) и других подобных механизмов.
+
+### Сигнатура
+
+```yql
+TablePath()->String
+```
+
+Аргументов нет. Возвращает строку с полным путём, либо пустую строку и warning при использовании в неподдерживаемом контексте (например, при работе с подзапросом или диапазоном из 1000+ таблиц).
+
+{% note info %}
+
+Функции [TablePath](#tablepath), [TableName](#tablename) и [TableRecordIndex](#tablerecordindex) не работают для временных и анонимных таблиц (возвращают пустую строку или 0 для [TableRecordIndex](#tablerecordindex)).
+Данные функции вычисляются в момент [выполнения](../syntax/select/index.md#selectexec) проекции в `SELECT`, и к этому моменту текущая таблица уже может быть временной.
+Чтобы избежать такой ситуации, следует поместить вычисление этих функций в подзапрос, как это сделано во втором примере ниже.
+
+{% endnote %}
+
+### Примеры
+
+```yql
+SELECT TablePath() FROM CONCAT(table_a, table_b);
+```
+
+```yql
+SELECT key, tpath_ AS path FROM (SELECT a.*, TablePath() AS tpath_ FROM RANGE(`my_folder`) AS a)
+WHERE key IN $subquery;
+```
+
+## TableName {#tablename}
+
+Получить имя таблицы из пути к таблице. Путь можно получить через функцию [TablePath](#tablepath).
+
+### Сигнатура
+
+```yql
+TableName()->String
+TableName(String)->String
+TableName(String, String)->String
+```
+
+Необязательные аргументы:
+
+* путь к таблице, по умолчанию используется `TablePath()` (также см. его ограничения);
+* указание системы ("yt"), по правилам которой выделяется имя таблицы. Указание системы нужно только в том случае, если с помощью [USE](../syntax/use.md) не указан текущий кластер.
+
+### Примеры
+
+```yql
+USE hahn;
+SELECT TableName() FROM CONCAT(table_a, table_b);
+```
+
+## TableRecordIndex {#tablerecordindex}
+
+Доступ к текущему порядковому номеру строки в исходной физической таблице, **начиная с 1** (зависит от реализации хранения).
+
+### Сигнатура
+
+```yql
+TableRecordIndex()->Uint64
+```
+
+Аргументов нет. При использовании в сочетании с [CONCAT](../syntax/select/concat.md#concat) и другими подобными механизмами нумерация начинается заново для каждой таблицы на входе. В случае использования в некорректном контексте возвращает 0.
+
+### Пример
+
+```yql
+SELECT TableRecordIndex() FROM my_table;
+```
+
+
+## TableRow, JoinTableRow {#tablerow}
+
+Получение всей строки таблицы целиком в виде структуры. Аргументов нет. `JoinTableRow` в случае `JOIN`-ов всегда возвращает структуру с префиксами таблиц.
+
+### Сигнатура
+
+```yql
+TableRow()->Struct
+```
+
+### Пример
+
+```yql
+SELECT TableRow() FROM my_table;
+```
+
+## FileContent и FilePath {#file-content-path}
+
+### Сигнатуры
+
+```yql
+FilePath(String)->String
+FileContent(String)->String
+```
+
+Аргумент `FileContent` и `FilePath` — строка с алиасом.
+
+### Примеры
+
+```yql
+SELECT "Content of "
+ || FilePath("my_file.txt")
+ || ":\n"
+ || FileContent("my_file.txt");
+```
+## FolderPath {#folderpath}
+
+Получение пути до корня директории с несколькими «приложенными» файлами с указанным общим префиксом.
+
+### Сигнатура
+
+```yql
+FolderPath(String)->String
+```
+
+Аргумент — строка с префиксом среди алиасов.
+
+Также см. [PRAGMA File](../syntax/pragma.md#file) и [PRAGMA Folder](../syntax/pragma.md#folder).
+
+### Примеры
+
+```yql
+PRAGMA File("foo/1.txt", "http://url/to/somewhere");
+PRAGMA File("foo/2.txt", "http://url/to/somewhere/else");
+PRAGMA File("bar/3.txt", "http://url/to/some/other/place");
+
+SELECT FolderPath("foo"); -- в директории по возвращённому пути будут
+ -- находиться файлы 1.txt и 2.txt, скачанные по указанным выше ссылкам
+```
+
+## ParseFile
+
+Получить из приложенного текстового файла список значений. Может использоваться в сочетании с [IN](../syntax/expressions.md#in) и прикладыванием файла по URL.
+
+Поддерживается только один формат файла — по одному значению на строку.
+
+### Сигнатура
+
+```yql
+ParseFile(String, String)->List<T>
+```
+
+Два обязательных аргумента:
+
+1. Тип ячейки списка: поддерживаются только строки и числовые типы;
+2. Имя приложенного файла.
+
+{% note info %}
+
+Возвращаемое значение - ленивый список. Для многократного использования его нужно обернуть в функцию [ListCollect](list.md#listcollect)
+
+{% endnote %}
+
+### Примеры
+
+```yql
+SELECT ListLength(ParseFile("String", "my_file.txt"));
+```
+
+```yql
+SELECT * FROM my_table
+WHERE int_column IN ParseFile("Int64", "my_file.txt");
+```
+
+## Ensure... {#ensure}
+
+Проверка пользовательских условий:
+
+* `Ensure()` — проверка верности предиката во время выполнения запроса.
+* `EnsureType()` — проверка точного соответствия типа выражения указанному.
+* `EnsureConvertibleTo()` — мягкая проверка соответствия типа выражения, работающая по тем же правилам, что и неявное приведение типов.
+
+Если проверка не прошла успешно, то весь запрос завершается с ошибкой.
+
+### Сигнатуры
+
+```yql
+Ensure(T, Bool, String)->T
+EnsureType(T, Type<T>, String)->T
+EnsureConvertibleTo(T, Type<T>, String)->T
+```
+
+Аргументы:
+
+1. Выражение, которое станет результатом вызова функции в случае успеха проверки. Оно же подвергается проверке на тип данных в соответствующих функциях.
+2. В Ensure — булевый предикат, который проверяется на `true`. В остальных функциях — тип данных, который может быть получен через [предназначенные для этого функции](types.md), либо строковый литерал с [текстовым описанием типа](../types/type_string.md).
+3. Опциональная строка с комментарием к ошибке, которая попадет в общее сообщение об ошибке при завершении запроса. Для проверок типов не может использовать сами данные, так как они выполняются на этапе валидации запроса, а для Ensure — может быть произвольным выражением.
+
+Для проверки условий по финальному результату вычисления Ensure удобно использовать в сочетании с [DISCARD SELECT](../syntax/discard.md).
+
+
+### Примеры
+
+```yql
+SELECT Ensure(
+ value,
+ value < 100,
+ "value out or range"
+) AS value FROM my_table;
+```
+
+```yql
+SELECT EnsureType(
+ value,
+ TypeOf(other_value),
+ "expected value and other_value to be of same type"
+) AS value FROM my_table;
+```
+
+```yql
+SELECT EnsureConvertibleTo(
+ value,
+ Double?,
+ "expected value to be numeric"
+) AS value FROM my_table;
+```
+
+
+## AssumeStrict {#assumestrict}
+
+### Сигнатура
+
+```yql
+AssumeStrict(T)->T
+```
+
+Функция `AssumeStrict` возвращает свой аргумент. Использование этой функции – способ сказать оптимизатору YQL, что выражение в аргументе является *строгим*, т.е. свободным от ошибок времени выполнения.
+Большинство встроенных функций и операторов YQL являются строгими, но есть исключения – например [Unwrap](#optional-ops) и [Ensure](#ensure).
+Кроме того, нестрогим выражением считается вызов UDF.
+
+Если есть уверенность, что при вычислении выражения ошибок времени выполнения на самом деле не возникает, то имеет смысл использовать `AssumeStrict`.
+
+### Пример
+
+```yql
+SELECT * FROM T1 AS a JOIN T2 AS b USING(key)
+WHERE AssumeStrict(Unwrap(CAST(a.key AS Int32))) == 1;
+```
+
+В данном примере мы считаем что все значения текстовой колонки `a.key` в таблице `T1` являются валидными числами, поэтому Unwrap не приводит к ошибке.
+При налиичии `AssumeStrict` оптимизатор сможет выполнить сначала фильтрацию, а потом JOIN.
+Без `AssumeStrict` такая оптимизация не выполняется – оптимизатор обязан учитывать ситуацию, при которой в колонке `a.key` есть нечисловые значения, которые отфильтровываются `JOIN`ом.
+
+
+## Likely {#likely}
+
+### Сигнатура
+
+```yql
+Likely(Bool)->Bool
+Likely(Bool?)->Bool?
+```
+
+Функция `Likely` возвращает свой аргумент. Функция является подсказкой оптимизатору и говорит о том, что в большинстве случаев ее аргумент будет иметь значение `True`.
+Например, наличие такой функции в `WHERE` означает что фильтр является слабоселективным.
+
+### Пример
+
+```yql
+SELECT * FROM T1 AS a JOIN T2 AS b USING(key)
+WHERE Likely(a.amount > 0) -- почти всегда верно
+```
+
+При наличии `Likely` оптимизатор не будет стараться выполнить фильтрацию перед `JOIN`.
+
+## EvaluateExpr, EvaluateAtom {#evaluate_expr_atom}
+
+Возможность выполнить выражение до начала основного расчета и подставить его результат в запрос как литерал (константу). Во многих контекстах, где в стандартном SQL ожидалась бы только константа (например, в именах таблиц, количестве строк в [LIMIT](../syntax/select/limit_offset.md) и т.п.) этот функционал активируется неявным образом автоматически.
+
+EvaluateExpr может использоваться в тех местах, где грамматикой уже ожидается выражение. Например, с его помощью можно:
+
+* округлить текущее время до дней, недель или месяцев и подставить в запрос, что затем позволит корректно работать [кешированию запросов](../syntax/pragma.md#yt.querycachemode), хотя обычно использование [функций для получения текущего времени](#current-utc) его полностью отключает;
+* сделать тяжелое вычисление с небольшим результатом один раз на запрос вместо одного раза на каждую джобу.
+
+EvaluateAtom позволяет динамически создать [атом](../types/special.md), но т.к. ими в основном оперирует более низкий уровень [s-expressions](/docs/s_expressions/functions), то использовать эту функцию напрямую как правило не рекомендуется.
+
+Единственный аргумент у обоих функций — само выражение для вычисления и подстановки.
+
+Ограничения:
+
+* выражение не должно приводить к запуску MapReduce операций;
+* данный функционал полностью заблокирован в YQL over YDB.
+
+### Примеры
+
+```yql
+$now = CurrentUtcDate();
+SELECT EvaluateExpr(
+ DateTime::MakeDate(DateTime::StartOfWeek($now)
+ )
+);
+```
+
+## Литералы простых типов {#data-type-literals}
+
+Для простых типов могут быть созданы литералы на основании строковых литералов.
+
+### Синтаксис
+
+`<Простой тип>( <строка>[, <дополнительные атрибуты>] )`
+
+В отличие от `CAST("myString" AS MyType)`:
+
+* Проверка на приводимость литерала к требуемому типу происходит на этапе валидации;
+* Результат не является optional.
+
+Для типов данных `Date`, `Datetime`, `Timestamp` и `Interval` поддерживаются литералы только в формате, соответствующем [ISO 8601](https://ru.wikipedia.org/wiki/ISO_8601). У `Interval` есть следующие отличия от стандарта:
+
+* поддерживается отрицательный знак для сдвигов в прошлое;
+* микросекунды могут быть записаны как дробная часть секунд;
+* единицы измерения больше недель не доступны;
+* не поддерживаются варианты с началом/концом интервала, а также повторами.
+
+Для типов данных `TzDate`, `TzDatetime`, `TzTimestamp` литералы также задаются в формате, соответствующем [ISO 8601](https://ru.wikipedia.org/wiki/ISO_8601), но вместо опционального суффикса Z через запятую указывается [IANA имя временной зоны](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones), например, GMT или Europe/Moscow.
+
+{% include [decimal args](../_includes/decimal_args.md) %}
+
+### Примеры
+
+```yql
+SELECT
+ Bool("true"),
+ Uint8("0"),
+ Int32("-1"),
+ Uint32("2"),
+ Int64("-3"),
+ Uint64("4"),
+ Float("-5"),
+ Double("6"),
+ Decimal("1.23", 5, 2), -- до 5 десятичных знаков, из которых 2 после запятой
+ String("foo"),
+ Utf8("привет"),
+ Yson("<a=1>[3;%false]"),
+ Json(@@{"a":1,"b":null}@@),
+ Date("2017-11-27"),
+ Datetime("2017-11-27T13:24:00Z"),
+ Timestamp("2017-11-27T13:24:00.123456Z"),
+ Interval("P1DT2H3M4.567890S"),
+ TzDate("2017-11-27,Europe/Moscow"),
+ TzDatetime("2017-11-27T13:24:00,America/Los_Angeles"),
+ TzTimestamp("2017-11-27T13:24:00.123456,GMT"),
+ Uuid("f9d5cc3f-f1dc-4d9c-b97e-766e57ca4ccb");
+```
+
+## ToBytes и FromBytes {#to-from-bytes}
+
+Конвертация [простых типов данных](../types/primitive.md) в строку со своим бинарным представлением и обратно. Числа представляются в [little endian](https://en.wikipedia.org/wiki/Endianness#Little-endian).
+
+### Сигнатуры
+
+```yql
+ToBytes(T)->String
+ToBytes(T?)->String?
+
+FromBytes(String, Type<T>)->T?
+FromBytes(String?, Type<T>)->T?
+```
+
+### Примеры
+
+```yql
+SELECT
+ ToBytes(123), -- "\u0001\u0000\u0000\u0000"
+ FromBytes(
+ "\xd2\x02\x96\x49\x00\x00\x00\x00",
+ Uint64
+ ); -- 1234567890ul
+```
+
+
+## ByteAt {#byteat}
+
+Получение значение байта в строке по индексу от её начала. В случае некорректного индекса возвращается `NULL`.
+
+### Сигнатура
+
+```yql
+ByteAt(String, Uint32)->Uint8
+ByteAt(String?, Uint32)->Uint8?
+
+ByteAt(Utf8, Uint32)->Uint8
+ByteAt(Utf8?, Uint32)->Uint8?
+```
+
+Аргументы:
+
+1. Строка: `String` или `Utf8`;
+2. Индекс: `Uint32`.
+
+### Примеры
+
+```yql
+SELECT
+ ByteAt("foo", 0), -- 102
+ ByteAt("foo", 1), -- 111
+ ByteAt("foo", 9); -- NULL
+```
+
+
+## ...Bit {#bitops}
+
+`TestBit()`, `ClearBit()`, `SetBit()` и `FlipBit()` - проверить, сбросить, установить или инвертировать бит в беззнаковом числе по указанному порядковому номеру бита.
+
+### Сигнатуры
+
+```yql
+TestBit(T, Uint8)->Bool
+TestBit(T?, Uint8)->Bool?
+
+ClearBit(T, Uint8)->T
+ClearBit(T?, Uint8)->T?
+
+SetBit(T, Uint8)->T
+SetBit(T?, Uint8)->T?
+
+FlipBit(T, Uint8)->T
+FlipBit(T?, Uint8)->T?
+```
+
+Аргументы:
+
+1. Беззнаковое число, над которым выполнять требуемую операцию. TestBit также реализован и для строк.
+2. Номер бита.
+
+TestBit возвращает `true/false`. Остальные функции возвращают копию своего первого аргумента с проведенным соответствующим преобразованием.
+
+### Примеры
+
+```yql
+SELECT
+ TestBit(1u, 0), -- true
+ SetBit(8u, 0); -- 9
+```
+
+
+## Abs {#abs}
+
+Абсолютное значение числа.
+
+### Сигнатура
+
+```yql
+Abs(T)->T
+Abs(T?)->T?
+```
+
+### Примеры
+
+```yql
+SELECT Abs(-123); -- 123
+```
+
+
+## Just {#optional-ops}
+
+`Just()` - Изменить тип данных значения на [optional](../types/optional.md) от текущего типа данных (то есть `T` превращается в `T?`).
+
+### Сигнатура
+
+```yql
+Just(T)->T?
+```
+
+### Примеры
+
+```yql
+SELECT
+ Just("my_string"); -- String?
+```
+
+## Unwrap {#unwrap}
+
+`Unwrap()` - Преобразование значения [optional](../types/optional.md) типа данных в соответствующий не-optional тип с ошибкой времени выполнений, если в данных оказался `NULL`. Таким образом, `T?` превращается в `T`.
+
+Если значение не является [optional](../types/optional.md), то функция возвращает свой первый аргумент без изменений.
+
+### Сигнатура
+
+```yql
+Unwrap(T?)->T
+Unwrap(T?, Utf8)->T
+Unwrap(T?, String)->T
+```
+
+Аргументы:
+
+1. Значение для преобразования;
+2. Опциональная строка с комментарием для текста ошибки.
+
+Обратная операция — [Just](#optional-ops).
+
+### Примеры
+
+```yql
+$value = Just("value");
+
+SELECT Unwrap($value, "Unexpected NULL for $value");
+```
+
+## Nothing {#nothing}
+
+`Nothing()` - Создать пустое значение указанного [Optional](../types/optional.md) типа данных.
+
+### Сигнатура
+
+```yql
+Nothing(Type<T?>)->T?
+```
+
+### Примеры
+
+```yql
+SELECT
+ Nothing(String?); -- пустое значение (NULL) с типом String?
+```
+
+[Подробнее о ParseType и других функциях для работы с типами данных](types.md).
+
+
+## Callable {#callable}
+
+Создать вызываемое значение с заданной сигнатурой из лямбда-функции. Обычно используется для того, чтобы размещать вызываемые значения в контейнерах.
+
+### Сигнатура
+
+```yql
+Callable(Type<Callable<(...)->T>>, lambda)->Callable<(...)->T>
+```
+
+Аргументы:
+
+1. Тип;
+2. Лямбда-функция.
+
+### Примеры
+
+```yql
+$lambda = ($x) -> {
+ RETURN CAST($x as String)
+};
+
+$callables = AsTuple(
+ Callable(Callable<(Int32)->String>, $lambda),
+ Callable(Callable<(Bool)->String>, $lambda),
+);
+
+SELECT $callables.0(10), $callables.1(true);
+```
+
+
+## Pickle, Unpickle {#pickle}
+
+`Pickle()` и `StablePickle()` сериализуют произвольный объект в последовательность байт, если это возможно. Типовыми несериализуемыми объектами являются Callable и Resource. Формат сериализации не версионируется, допускается использовать в пределах одного запроса. Для типа Dict функция StablePickle предварительно сортирует ключи, а для Pickle порядок элементов словаря в сериализованном представлении не определен.
+
+`Unpickle()` — обратная операция (десериализация), где первым аргументом передается тип данных результата, а вторым — строка с результатом `Pickle()` или `StablePickle()`.
+
+### Сигнатуры
+
+```yql
+Pickle(T)->String
+StablePickle(T)->String
+Unpickle(Type<T>, String)->T
+```
+
+### Примеры
+
+```yql
+SELECT *
+FROM my_table
+WHERE Digest::MurMurHash32(
+ Pickle(TableRow())
+ ) % 10 == 0; -- в реальности лучше использовать TABLESAMPLE
+
+$buf = Pickle(123);
+SELECT Unpickle(Int32, $buf);
+```
+
+
+## StaticMap
+
+Преобразует структуру или кортеж, применяя лямбду к каждому элементу.
+
+### Сигнатура
+
+```yql
+StaticMap(Struct<...>, lambda)->Struct<...>
+StaticMap(Tuple<...>, lambda)->Tuple<...>
+```
+
+Аргументы:
+
+* Структура или кортеж;
+* Лямбда для обработки элементов.
+
+Результат: структура или кортеж с аналогичным первому аргументу количеством и именованием элементов, а типы данных элементов определяются результатами лямбды.
+
+### Примеры
+
+```yql
+SELECT *
+FROM (
+ SELECT
+ StaticMap(TableRow(), ($item) -> {
+ return CAST($item AS String);
+ })
+ FROM my_table
+) FLATTEN COLUMNS; -- преобразование всех колонок в строки
+```
+
+
+
+## StaticZip
+
+Поэлементно "склеивает" структуры или кортежи. Все аргументы (один и более) должны быть либо структурами с одинаковым набором полей, либо кортежами одинаковой длины.
+Результататом будет соответственно структура или кортеж.
+Каждый элемент результата – кортеж с соответствующими элементами из аргументов.
+
+### Сигнатура
+
+```yql
+StaticZip(Struct, Struct)->Struct
+StaticZip(Tuple, Tuple)->Tuple
+```
+
+### Примеры
+
+```yql
+$one = <|k1:1, k2:2.0|>;
+$two = <|k1:3.0, k2:4|>;
+
+-- поэлементное сложение двух структур
+SELECT StaticMap(StaticZip($one, $two), ($tuple)->($tuple.0 + $tuple.1)) AS sum;
+```
+
+
+## StaticFold, StaticFold1 {#staticfold}
+
+```yql
+StaticFold(obj:Struct/Tuple, initVal, updateLambda)
+StaticFold1(obj:Struct/Tuple, initLambda, updateLambda)
+```
+
+Статическая левоассоциативная свертка структуры или кортежа.
+Для кортежей свертка производится в порядке от меньшего индекса к большему, для структур порядок не гарантируется.
+
+- `obj` - объект, элементы которого нужно свернуть
+- `initVal` - *(для StaticFold)* исходное состояние свертки
+- `initLambda` - *(для StaticFold1)* функция для получения исходного состояния по первому элементу
+- `updateLambda` - функция обновления состояния (принимает в аргументах следующий элемент объекта и предыдущее состояние)
+
+`StaticFold(<|key_1:$el_1, key_2:$el_2, ..., key_n:$el_n|>, $init, $f)` преобразуется в свертку:
+
+```yql
+$f($el_n, ...$f($el_2, $f($init, el_1))...)
+```
+
+`StaticFold1(<|key_1:$el_1, key_2:$el_2, ..., key_n:$el_n|>, $f0, $f)`:
+
+```yql
+$f($el_n, ...$f($el_2, $f($f0($init), el_1))...)
+```
+
+`StaticFold1(<||>, $f0, $f)` вернет `NULL`.
+
+Аналогично работает и с кортежами.
+
+
+## AggregationFactory {#aggregationfactory}
+
+Создать фабрику для [агрегационных функций](aggregation.md) для того чтобы разделить процесс описания того, как агрегировать данные, и то, к каким данным это применять.
+
+Аргументы:
+
+1. Строка в кавычках, являющаяся именем агрегационной функции, например ["MIN"](aggregation.md#min).
+2. Опциональные параметры агрегационной функции, которые не зависят от данных. Например, значение percentile в [PERCENTILE](aggregation.md#percentile).
+
+Полученную фабрику можно использовать как второй параметр функции [AGGREGATE_BY](aggregation.md#aggregateby).
+Если агрегационная функция работает на двух колонках вместо одной, как например, [MIN_BY](aggregation.md#minby), то в [AGGREGATE_BY](aggregation.md#aggregateby) первым аргументом передается `Tuple` из двух значений. Подробнее это указано при описании такой агрегационной функции.
+
+### Примеры
+
+```yql
+$factory = AggregationFactory("MIN");
+SELECT
+ AGGREGATE_BY(value, $factory) AS min_value -- применить MIN агрегацию к колонке value
+FROM my_table;
+```
+
+## AggregateTransformInput {#aggregatetransform}
+
+`AggregateTransformInput()` преобразует фабрику для [агрегационных функций](aggregation.md), например, полученную через функцию [AggregationFactory](#aggregationfactory) в другую фабрику, в которой перед началом выполнения агрегации производится указанное преобразование входных элементов.
+
+Аргументы:
+
+1. Фабрика для агрегационных функций;
+2. Лямбда функция с одним аргументом, преобразующая входной элемент.
+
+### Примеры
+
+```yql
+$f = AggregationFactory("sum");
+$g = AggregateTransformInput($f, ($x) -> (cast($x as Int32)));
+$h = AggregateTransformInput($f, ($x) -> ($x * 2));
+SELECT ListAggregate([1,2,3], $f); -- 6
+SELECT ListAggregate(["1","2","3"], $g); -- 6
+SELECT ListAggregate([1,2,3], $h); -- 12
+```
+
+## AggregateTransformOutput {#aggregatetransformoutput}
+
+`AggregateTransformOutput()` преобразует фабрику для [агрегационных функций](aggregation.md), например, полученную через функцию [AggregationFactory](#aggregationfactory) в другую фабрику, в которой после окончания выполнения агрегации производится указанное преобразование результата.
+
+Аргументы:
+
+1. Фабрика для агрегационных функций;
+2. Лямбда функция с одним аргументом, преобразующая результат.
+
+### Примеры
+
+```yql
+$f = AggregationFactory("sum");
+$g = AggregateTransformOutput($f, ($x) -> ($x * 2));
+SELECT ListAggregate([1,2,3], $f); -- 6
+SELECT ListAggregate([1,2,3], $g); -- 12
+```
+
+## AggregateFlatten {#aggregateflatten}
+
+Адаптирует фабрику для [агрегационных функций](aggregation.md), например, полученную через функцию [AggregationFactory](#aggregationfactory) так, чтобы выполнять агрегацию над входными элементами - списками. Эта операция похожа на [FLATTEN LIST BY](../syntax/flatten.md) - производится агрегация каждого элемента списка.
+
+Аргументы:
+
+1. Фабрика для агрегационных функций.
+
+### Примеры
+
+```yql
+$i = AggregationFactory("AGGREGATE_LIST_DISTINCT");
+$j = AggregateFlatten($i);
+SELECT AggregateBy(x, $j) from (
+ SELECT [1,2] as x
+ union all
+ SELECT [2,3] as x
+); -- [1, 2, 3]
+
+```
+
+## YQL::, s-expressions {#s-expressions}
+
+Полный список внутренних функций YQL находится в [документации к s-expressions](/docs/s_expressions/functions), альтернативному низкоуровневому синтаксису YQL. Любую из перечисленных там функций можно вызвать и из SQL синтаксиса, добавив к её имени префикс `YQL::`, но это не рекомендуется делать, т.к. данный механизм предназначен в первую очередь для временного обхода возможных проблем, а также для нужд внутреннего тестирования.
+
+Если функция доступна в SQL синтаксисе без префикса `YQL::`, то её поведение имеет право отличаться от одноименной функции из документации по s-expressions, если таковая существует.
+
diff --git a/yql/essentials/docs/ru/builtins/codegen.md b/yql/essentials/docs/ru/builtins/codegen.md
new file mode 100644
index 0000000000..1d6cd2373e
--- /dev/null
+++ b/yql/essentials/docs/ru/builtins/codegen.md
@@ -0,0 +1,182 @@
+
+# Функции для работы с генерацией кода
+
+Во время выполнения вычислений можно сгенерировать код, состоящий из узлов [S-expressions](/docs/s_expressions). Для этого используется механизм представления кода, упакованного в [ресурс](../types/special.md). После конструирования кода можно подставить его в основную програму с помощью функции [EvaluateCode](#evaluatecode). Для отладки сконвертировать код в строку можно с помощью функции [FormatCode](#formatcode).
+
+Возможные типы узлов в S-expressions, которые можно использовать для генерации кода:
+
+* Атом - нетипизированная строка из нуля и более символов.
+* Список - последовательность из нуля и более узлов. Соответствует типу `кортеж` в SQL.
+* Вызов встроенной функции - состоит из имени, выраженного атомом, и последовательности из нуля и более узлов, которые являются аргументами этой функции.
+* Объявление лямбда функции - состоит из объявления имен аргументов и узла, который является корнем тела этой лямбда функции.
+* Аргумент лямбды функции - узел, который может использоваться только внутри тела лямбда-функции.
+* Мир - специальный узел, маркирующий операции ввода/вывода.
+
+Узлы S-expressions образуют ориентированный граф. При этом атомы - всегда листовые узлы, так как не могут содержать дочерних узлов.
+
+В текстовой записи S-expressions записываются следующим образом:
+
+* Атом - `'"foo"`. Символ апострофа (') является признаком цитирования последующей строки, обычно заключенной в кавычки.
+* Список - `'("foo" "bar")`. Символ апострофа (') является признаком того, что в скобках не будет вызова функции.
+* Вызов встроенной функции - `(foo "bar")`. Первый элемент внутри скобок - обязательное имя функции, а далее указываются ее аргументы.
+* Объявление лямбда функции - `(lambda '(x y) (+ x y))`. После ключевого слова `lambda` стоит список из имен аргументов, за которым следует тело лямбда функции.
+* Аргумент лямбда функции - `x`. В отличие от атома, строка без символа апострофа (') является ссылкой на имя в текущей области видимости. При объявлении лямбда функции в область видимости тела добавляются имена аргументов, причем при необходимости скрывается имя из объемлющей области видимости.
+* Мир - `world`.
+
+## FormatCode
+
+Сериализация кода в виде [S-expressions](/docs/s_expressions). Код не должен содержать свободных аргументов функций, т.е. для сериализации кода лямбда функции нужно передавать ее целиком, а не выражения, потенциально содержащие аргументы лямбда функции.
+
+### Примеры
+
+```yql
+SELECT FormatCode(AtomCode("foo"));
+-- (
+-- (return '"foo")
+-- )
+```
+
+## WorldCode
+
+Построить узел кода с типом `мир`.
+
+### Примеры
+
+```yql
+SELECT FormatCode(WorldCode());
+-- (
+-- (return world)
+-- )
+```
+
+## AtomCode
+
+Построить узел кода с типом `атом` из строки, переданной в аргумент.
+
+### Примеры
+
+```yql
+SELECT FormatCode(AtomCode("foo"));
+-- (
+-- (return '"foo")
+-- )
+```
+
+## ListCode
+
+Построить узел кода с типом `список` из набора узлов или списков узлов кода, переданных в аргументы. При этом списки из аргументов встраиваются как отдельно перечисленные узлы кода.
+
+### Примеры
+
+```yql
+SELECT FormatCode(ListCode(
+ AtomCode("foo"),
+ AtomCode("bar")));
+-- (
+-- (return '('"foo" '"bar"))
+-- );
+
+SELECT FormatCode(ListCode(AsList(
+ AtomCode("foo"),
+ AtomCode("bar"))));
+-- (
+-- (return '('"foo" '"bar"))
+-- )
+```
+
+## FuncCode
+
+Построить узел кода с типом `вызов встроенной функции` из строки с именем функции и набора узлов или списков узлов кода, переданных в аргументы. При этом списки из аргументов встраиваются как отдельно перечисленные узлы кода.
+
+### Примеры
+
+```yql
+SELECT FormatCode(FuncCode(
+ "Baz",
+ AtomCode("foo"),
+ AtomCode("bar")));
+-- (
+-- (return (Baz '"foo" '"bar"))
+-- )
+
+SELECT FormatCode(FuncCode(
+ "Baz",
+ AsList(
+ AtomCode("foo"),
+ AtomCode("bar"))));
+-- (
+-- (return (Baz '"foo" '"bar"))
+-- )
+```
+
+## LambdaCode
+
+Построить узел кода с типом `объявление лямбда функции` можно из:
+
+* [Лямбда функции](../syntax/expressions.md#lambda), если заранее известно количество аргументов. В этом случае в качестве аргументов этой лямбда функции будут переданы узлы типа `аргумент`.
+* Количества аргументов и [лямбда функции](../syntax/expressions.md#lambda) с одним аргументом. В этом случае в качестве аргумента этой лямбды функции будет передан список узлов типа `аргумент`.
+
+### Примеры
+
+```yql
+SELECT FormatCode(LambdaCode(($x, $y) -> {
+ RETURN FuncCode("+", $x, $y);
+}));
+-- (
+-- (return (lambda '($1 $2) (+ $1 $2)))
+-- )
+
+SELECT FormatCode(LambdaCode(2, ($args) -> {
+ RETURN FuncCode("*", Unwrap($args[0]), Unwrap($args[1]));
+}));
+-- (
+-- (return (lambda '($1 $2) (* $1 $2)))
+-- )
+```
+
+## EvaluateCode
+
+Подстановка в основную программу узла кода, переданного в аргумент.
+
+### Примеры
+
+```yql
+SELECT EvaluateCode(FuncCode("Int32", AtomCode("1"))); -- 1
+
+$lambda = EvaluateCode(LambdaCode(($x, $y) -> {
+ RETURN FuncCode("+", $x, $y);
+}));
+SELECT $lambda(1, 2); -- 3
+```
+
+## ReprCode
+
+Подстановка в основную программу узла кода, который является представлением результата вычисления выражения, переданного в аргумент.
+
+### Примеры
+
+```yql
+$add3 = EvaluateCode(LambdaCode(($x) -> {
+ RETURN FuncCode("+", $x, ReprCode(1 + 2));
+}));
+SELECT $add3(1); -- 4
+```
+
+## QuoteCode
+
+Подстановка в основную программу узла кода, который является представлением выражения или [лямбда функции](../syntax/expressions.md#lambda), переданной в аргумент. Если во время подстановки были найдены свободные аргументы лямбда функций, то они вычисляются и подставляются в код как в функции [ReprCode](#reprcode).
+
+### Примеры
+
+```yql
+$lambda = ($x, $y) -> { RETURN $x + $y };
+$makeClosure = ($y) -> {
+ RETURN EvaluateCode(LambdaCode(($x) -> {
+ RETURN FuncCode("Apply", QuoteCode($lambda), $x, ReprCode($y))
+ }))
+};
+
+$closure = $makeClosure(2);
+SELECT $closure(1); -- 3
+```
+
diff --git a/yql/essentials/docs/ru/builtins/dict.md b/yql/essentials/docs/ru/builtins/dict.md
new file mode 100644
index 0000000000..e79b9a83bd
--- /dev/null
+++ b/yql/essentials/docs/ru/builtins/dict.md
@@ -0,0 +1,445 @@
+
+# Функции для работы со словарями
+
+## DictCreate {#dictcreate}
+
+### Сигнатура
+
+```yql
+DictCreate(K,V)->Dict<K,V>
+```
+
+Сконструировать пустой словарь. Передается два аргумента — для ключа и значения, в каждом из которых указывается строка с описанием типа данных, либо сам тип, полученный с помощью [предназначенных для этого функций](types.md). Словарей с неизвестным типом ключа или значения в YQL не бывает.
+
+В качестве типа ключа могут быть заданы:
+
+* [примитивный тип данных](../types/primitive.md) (кроме `Yson` и `Json`),
+* примитивный тип данных (кроме `Yson` и `Json`) с признаком опциональности,
+* кортеж длины не менее два из типов, перечисленных выше.
+
+[Документация по формату описания типа](../types/type_string.md).
+
+### Примеры
+
+```yql
+SELECT DictCreate(String, Tuple<String,Double?>);
+```
+
+```yql
+SELECT DictCreate(Tuple<Int32?,String>, OptionalType(DataType("String")));
+```
+
+```yql
+SELECT DictCreate(ParseType("Tuple<Int32?,String>"), ParseType("Tuple<String,Double?>"));
+```
+
+## SetCreate {#setcreate}
+
+### Сигнатура
+
+```yql
+SetCreate(T)->Set<T>
+```
+
+Сконструировать пустое множество. Передается аргумент - тип ключа, возможно, полученный с помощью [предназначенных для этого функций](types.md). Множеств с неизвестным типом ключа в YQL не бывает. Ограничения на тип ключа такие же как и на тип ключа для словаря. Следует иметь ввиду, что множество это словарь с типом значения `Void` и множество также можно создать и с помощью функции `DictCreate`. Отсюда также следует, что все функции, которые принимают на вход `Dict<K,V>` могут также принимать `Set<K>`.
+
+[Документация по формату описания типа](../types/type_string.md).
+
+### Примеры
+
+```yql
+SELECT SetCreate(String);
+```
+
+```yql
+SELECT SetCreate(Tuple<Int32?,String>);
+```
+
+## DictLength {#dictlength}
+
+### Сигнатура
+
+```yql
+DictLength(Dict<K,V>)->Uint64
+DictLength(Dict<K,V>?)->Uint64?
+```
+
+Количество элементов в словаре.
+
+### Примеры
+
+```yql
+SELECT DictLength(AsDict(AsTuple(1, AsList("foo", "bar"))));
+```
+
+```yql
+SELECT DictLength(dict_column) FROM my_table;
+```
+
+## DictHasItems {#dicthasitems}
+
+### Сигнатура
+
+```yql
+DictHasItems(Dict<K,V>)->Bool
+DictHasItems(Dict<K,V>?)->Bool?
+```
+
+Проверка того, что словарь содержит хотя бы один элемент.
+
+### Примеры
+
+```yql
+SELECT DictHasItems(AsDict(AsTuple(1, AsList("foo", "bar")))) FROM my_table;
+```
+
+```yql
+SELECT DictHasItems(dict_column) FROM my_table;
+```
+
+## DictItems {#dictitems}
+
+### Сигнатура
+
+```yql
+DictItems(Dict<K,V>)->List<Tuple<K,V>>
+DictItems(Dict<K,V>?)->List<Tuple<K,V>>?
+```
+
+Получение содержимого словаря в виде списка кортежей с парами ключ-значение (`List<Tuple<key_type,value_type>>`).
+
+### Примеры
+
+```yql
+SELECT DictItems(AsDict(AsTuple(1, AsList("foo", "bar"))));
+-- [ ( 1, [ "foo", "bar" ] ) ]
+```
+
+```yql
+SELECT DictItems(dict_column)
+FROM my_table;
+```
+
+## DictKeys {#dictkeys}
+
+### Сигнатура
+
+```yql
+DictKeys(Dict<K,V>)->List<K>
+DictKeys(Dict<K,V>?)->List<K>?
+```
+
+Получение списка ключей словаря.
+
+### Примеры
+
+```yql
+SELECT DictKeys(AsDict(AsTuple(1, AsList("foo", "bar"))));
+-- [ 1 ]
+```
+
+```yql
+SELECT DictKeys(dict_column)
+FROM my_table;
+```
+
+## DictPayloads {#dictpayloads}
+
+### Сигнатура
+
+```yql
+DictPayloads(Dict<K,V>)->List<V>
+DictPayloads(Dict<K,V>?)->List<V>?
+```
+
+Получение списка значений словаря.
+
+### Примеры
+
+```yql
+SELECT DictPayloads(AsDict(AsTuple(1, AsList("foo", "bar"))));
+-- [ [ "foo", "bar" ] ]
+```
+
+```yql
+SELECT DictPayloads(dict_column)
+FROM my_table;
+```
+
+## DictLookup {#dictlookup}
+
+### Сигнатура
+
+```yql
+DictLookup(Dict<K,V>, K)->V?
+DictLookup(Dict<K,V>?, K)->V?
+DictLookup(Dict<K,V>, K?)->V?
+DictLookup(Dict<K,V>?, K?)->V?
+```
+
+Получение элемента словаря по ключу.
+
+### Примеры
+
+```yql
+SELECT DictLookup(AsDict(
+ AsTuple(1, AsList("foo", "bar")),
+ AsTuple(2, AsList("bar", "baz"))
+), 1);
+-- [ "foo", "bar" ]
+```
+
+```yql
+SELECT DictLookup(dict_column, "foo")
+FROM my_table;
+```
+
+## DictContains {#dictcontains}
+
+### Сигнатура
+
+```yql
+DictContains(Dict<K,V>, K)->Bool
+DictContains(Dict<K,V>?, K)->Bool
+DictContains(Dict<K,V>, K?)->Bool
+DictContains(Dict<K,V>?, K?)->Bool
+```
+
+Проверка наличия элемента в словаре по ключу. Возвращает true или false.
+
+### Примеры
+
+```yql
+SELECT DictContains(AsDict(
+ AsTuple(1, AsList("foo", "bar")),
+ AsTuple(2, AsList("bar", "baz"))
+), 42);
+-- false
+```
+
+```yql
+SELECT DictContains(dict_column, "foo")
+FROM my_table;
+```
+
+## DictAggregate {#dictaggregate}
+
+### Сигнатура
+
+```yql
+DictAggregate(Dict<K,List<V>>, List<V>->T)->Dict<K,T>
+DictAggregate(Dict<K,List<V>>?, List<V>->T)->Dict<K,T>?
+```
+
+Применить [фабрику агрегационных функций](basic.md#aggregationfactory) для переданного словаря, в котором каждое значение является списком. Фабрика применяется отдельно внутри каждого ключа.
+Если список является пустым, то результат агрегации будет такой же, как для пустой таблицы: 0 для функции `COUNT` и `NULL` для других функций.
+Если в переданном словаре список по некоторому ключу является пустым, то такой ключ удаляется из результата.
+Если переданный словарь является опциональным и содержит значение `NULL`, то в результате также будет `NULL`.
+
+Аргументы:
+
+1. Словарь;
+2. [Фабрика агрегационных функций](basic.md#aggregationfactory).
+
+
+### Примеры
+
+```yql
+SELECT DictAggregate(AsDict(
+ AsTuple(1, AsList("foo", "bar")),
+ AsTuple(2, AsList("baz", "qwe"))),
+ AggregationFactory("Max"));
+-- {1 : "foo", 2 : "qwe" }
+```
+
+## SetIsDisjoint {#setisjoint}
+
+### Сигнатура
+
+```yql
+SetIsDisjoint(Dict<K,V1>, Dict<K,V2>)->Bool
+SetIsDisjoint(Dict<K,V1>?, Dict<K,V2>)->Bool?
+SetIsDisjoint(Dict<K,V1>, Dict<K,V2>?)->Bool?
+SetIsDisjoint(Dict<K,V1>?, Dict<K,V2>?)->Bool?
+
+SetIsDisjoint(Dict<K,V1>, List<K>)->Bool
+SetIsDisjoint(Dict<K,V1>?, List<K>)->Bool?
+SetIsDisjoint(Dict<K,V1>, List<K>?)->Bool?
+SetIsDisjoint(Dict<K,V1>?, List<K>?)->Bool?
+```
+
+Проверка того, что словарь и список или другой словарь не пересекаются по ключам.
+
+Таким образом есть два варианта вызова:
+
+* С аргументами `Dict<K,V1>` и `List<K>`;
+* С аргументами `Dict<K,V1>` и `Dict<K,V2>`.
+
+### Примеры
+
+```yql
+SELECT SetIsDisjoint(ToSet(AsList(1, 2, 3)), AsList(7, 4)); -- true
+SELECT SetIsDisjoint(ToSet(AsList(1, 2, 3)), ToSet(AsList(3, 4))); -- false
+```
+
+## SetIntersection {#setintersection}
+
+### Сигнатура
+
+```yql
+SetIntersection(Dict<K,V1>, Dict<K,V2>)->Set<K>
+SetIntersection(Dict<K,V1>?, Dict<K,V2>)->Set<K>?
+SetIntersection(Dict<K,V1>, Dict<K,V2>?)->Set<K>?
+SetIntersection(Dict<K,V1>?, Dict<K,V2>?)->Set<K>?
+
+SetIntersection(Dict<K,V1>, Dict<K,V2>, (K,V1,V2)->U)->Dict<K,U>
+SetIntersection(Dict<K,V1>?, Dict<K,V2>, (K,V1,V2)->U)->Dict<K,U>?
+SetIntersection(Dict<K,V1>, Dict<K,V2>?, (K,V1,V2)->U)->Dict<K,U>?
+SetIntersection(Dict<K,V1>?, Dict<K,V2>?, (K,V1,V2)->U)->Dict<K,U>?
+```
+
+Строит пересечение двух словарей по ключам.
+
+Аргументы:
+
+* Два словаря: `Dict<K,V1>` и `Dict<K,V2>`.
+* Необязательная функция, которая объединяет значения из исходных словарей для построения значений выходного словаря. Если тип такой функции `(K,V1,V2) -> U`, то типом результата будет `Dict<K,U>`. Если функция не задана, типом результата будет `Dict<K,Void>`, а значения из исходных словарей игнорируются.
+
+### Примеры
+
+```yql
+SELECT SetIntersection(ToSet(AsList(1, 2, 3)), ToSet(AsList(3, 4))); -- { 3 }
+SELECT SetIntersection(
+ AsDict(AsTuple(1, "foo"), AsTuple(3, "bar")),
+ AsDict(AsTuple(1, "baz"), AsTuple(2, "qwe")),
+ ($k, $a, $b) -> { RETURN AsTuple($a, $b) });
+-- { 1 : ("foo", "baz") }
+```
+
+{% note info %}
+
+В примере использовалась [лямбда функция](../syntax/expressions.md#lambda).
+
+{% endnote %}
+
+## SetIncludes {#setincludes}
+
+### Сигнатура
+
+```yql
+SetIncludes(Dict<K,V1>, List<K>)->Bool
+SetIncludes(Dict<K,V1>?, List<K>)->Bool?
+SetIncludes(Dict<K,V1>, List<K>?)->Bool?
+SetIncludes(Dict<K,V1>?, List<K>?)->Bool?
+
+SetIncludes(Dict<K,V1>, Dict<K,V2>)->Bool
+SetIncludes(Dict<K,V1>?, Dict<K,V2>)->Bool?
+SetIncludes(Dict<K,V1>, Dict<K,V2>?)->Bool?
+SetIncludes(Dict<K,V1>?, Dict<K,V2>?)->Bool?
+```
+
+Проверка того, что в ключи заданного словаря входят все элементы списка или ключи второго словаря.
+
+Таким образом есть два варианта вызова:
+
+* С аргументами `Dict<K,V1>` и `List<K>`;
+* С аргументами `Dict<K,V1>` и `Dict<K,V2>`.
+
+### Примеры
+
+```yql
+SELECT SetIncludes(ToSet(AsList(1, 2, 3)), AsList(3, 4)); -- false
+SELECT SetIncludes(ToSet(AsList(1, 2, 3)), ToSet(AsList(2, 3))); -- true
+```
+
+## SetUnion {#setunion}
+
+### Сигнатура
+
+```yql
+SetUnion(Dict<K,V1>, Dict<K,V2>)->Set<K>
+SetUnion(Dict<K,V1>?, Dict<K,V2>)->Set<K>?
+SetUnion(Dict<K,V1>, Dict<K,V2>?)->Set<K>?
+SetUnion(Dict<K,V1>?, Dict<K,V2>?)->Set<K>?
+
+SetUnion(Dict<K,V1>, Dict<K,V2>,(K,V1?,V2?)->U)->Dict<K,U>
+SetUnion(Dict<K,V1>?, Dict<K,V2>,(K,V1?,V2?)->U)->Dict<K,U>?
+SetUnion(Dict<K,V1>, Dict<K,V2>?,(K,V1?,V2?)->U)->Dict<K,U>?
+SetUnion(Dict<K,V1>?, Dict<K,V2>?,(K,V1?,V2?)->U)->Dict<K,U>?
+```
+
+Строит объединение двух словарей по ключам.
+
+Аргументы:
+
+* Два словаря: `Dict<K,V1>` и `Dict<K,V2>`.
+* Необязательная функция, которая объединяет значения из исходных словарей для построения значений выходного словаря. Если тип такой функции `(K,V1?,V2?) -> U`, то типом результата будет `Dict<K,U>`. Если функция не задана, типом результата будет `Dict<K,Void>`, а значения из исходных словарей игнорируются.
+
+### Примеры
+
+```yql
+SELECT SetUnion(ToSet(AsList(1, 2, 3)), ToSet(AsList(3, 4))); -- { 1, 2, 3, 4 }
+SELECT SetUnion(
+ AsDict(AsTuple(1, "foo"), AsTuple(3, "bar")),
+ AsDict(AsTuple(1, "baz"), AsTuple(2, "qwe")),
+ ($k, $a, $b) -> { RETURN AsTuple($a, $b) });
+-- { 1 : ("foo", "baz"), 2 : (null, "qwe"), 3 : ("bar", null) }
+```
+
+## SetDifference {#setdifference}
+
+### Сигнатура
+
+```yql
+SetDifference(Dict<K,V1>, Dict<K,V2>)->Dict<K,V1>
+SetDifference(Dict<K,V1>?, Dict<K,V2>)->Dict<K,V1>?
+SetDifference(Dict<K,V1>, Dict<K,V2>?)->Dict<K,V1>?
+SetDifference(Dict<K,V1>?, Dict<K,V2>?)->Dict<K,V1>?
+```
+
+Строит словарь, в котором есть все ключи с соответствующими значениями первого словаря, для которых нет ключа во втором словаре.
+
+### Примеры
+
+```yql
+SELECT SetDifference(ToSet(AsList(1, 2, 3)), ToSet(AsList(3, 4))); -- { 1, 2 }
+SELECT SetDifference(
+ AsDict(AsTuple(1, "foo"), AsTuple(2, "bar")),
+ ToSet(AsList(2, 3)));
+-- { 1 : "foo" }
+```
+
+## SetSymmetricDifference {#setsymmetricdifference}
+
+### Сигнатура
+
+```yql
+SetSymmetricDifference(Dict<K,V1>, Dict<K,V2>)->Set<K>
+SetSymmetricDifference(Dict<K,V1>?, Dict<K,V2>)->Set<K>?
+SetSymmetricDifference(Dict<K,V1>, Dict<K,V2>?)->Set<K>?
+SetSymmetricDifference(Dict<K,V1>?, Dict<K,V2>?)->Set<K>?
+
+SetSymmetricDifference(Dict<K,V1>, Dict<K,V2>,(K,V1?,V2?)->U)->Dict<K,U>
+SetSymmetricDifference(Dict<K,V1>?, Dict<K,V2>,(K,V1?,V2?)->U)->Dict<K,U>?
+SetSymmetricDifference(Dict<K,V1>, Dict<K,V2>?,(K,V1?,V2?)->U)->Dict<K,U>?
+SetSymmetricDifference(Dict<K,V1>?, Dict<K,V2>?,(K,V1?,V2?)->U)->Dict<K,U>?
+```
+
+Строит симметрическую разность двух словарей по ключам.
+
+Аргументы:
+
+* Два словаря: `Dict<K,V1>` и `Dict<K,V2>`.
+* Необязательная функция, которая объединяет значения из исходных словарей для построения значений выходного словаря. Если тип такой функции `(K,V1?,V2?) -> U`, то типом результата будет `Dict<K,U>`. Если функция не задана, типом результата будет `Dict<K,Void>`, а значения из исходных словарей игнорируются.
+
+### Примеры
+
+```yql
+SELECT SetSymmetricDifference(ToSet(AsList(1, 2, 3)), ToSet(AsList(3, 4))); -- { 1, 2, 4 }
+SELECT SetSymmetricDifference(
+ AsDict(AsTuple(1, "foo"), AsTuple(3, "bar")),
+ AsDict(AsTuple(1, "baz"), AsTuple(2, "qwe")),
+ ($k, $a, $b) -> { RETURN AsTuple($a, $b) });
+-- { 2 : (null, "qwe"), 3 : ("bar", null) }
+```
+
diff --git a/yql/essentials/docs/ru/builtins/index.md b/yql/essentials/docs/ru/builtins/index.md
new file mode 100644
index 0000000000..85deb9975e
--- /dev/null
+++ b/yql/essentials/docs/ru/builtins/index.md
@@ -0,0 +1,13 @@
+
+# Встроенные функции YQL
+
+- [Базовые](basic.md)
+- [Агрегатные](aggregation.md)
+- [Оконные](window.md)
+- [Для работы со списками](list.md)
+- [Для работы со словарями](dict.md)
+- [Для работы со структурами](struct.md)
+- [Для работы с типами](types.md)
+- [Для работы с генерацией кода](codegen.md)
+- [Для работы с JSON](json.md)
+- [Библиотеки C++](../udf/list/index.md)
diff --git a/yql/essentials/docs/ru/builtins/json.md b/yql/essentials/docs/ru/builtins/json.md
new file mode 100644
index 0000000000..0415a46849
--- /dev/null
+++ b/yql/essentials/docs/ru/builtins/json.md
@@ -0,0 +1,1199 @@
+
+# Функции для работы с JSON
+
+<!-- markdownlint-disable no-trailing-punctuation -->
+
+**JSON** - слабо схематизированный [формат данных](https://www.json.org), представленный в YQL типом `Json`. В отличии от реляционных таблиц, JSON может хранить данные, для которых схема не определена. Вот пример валидного JSON:
+
+```json
+[
+ {
+ "name": "Jim Holden",
+ "age": 30
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": "twenty years old"
+ }
+]
+```
+
+Несмотря на то, что в первом объекте поле `age` имеет тип `Number` (`"age": 21`), а во втором `String` (`"age": "twenty years old"`), это полностью валидный JSON.
+
+Для работы с JSON, YQL реализует подмножество стандарта [SQL support for JavaScript Object Notation (JSON)](https://www.iso.org/standard/67367.html), являющегося частью общепринятого стандарта ANSI SQL.
+
+## Cookbook
+
+```yql
+$json = CAST(@@{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30
+ }
+ ]
+}@@ AS Json);
+
+SELECT
+ JSON_EXISTS($json, "$.friends[*].name"), -- True,
+ JSON_VALUE($json, "$.friends[0].age"), -- "35" (тип Utf8?)
+ JSON_QUERY($json, "$.friends[0]"); -- {"name": "James Holden", "age": 35}
+
+```
+
+### Обращение к полю в базе данных
+
+В таблицах данные могут хранить в JSON или в строковом представлении. Функции `JSON_*` для работы ожидают на вход JSON. Для преобразования `String->JSON` нужно воспользоваться функцией `CAST`, например `CAST (my_string AS JSON)`.
+
+## JsonPath
+
+Для обращения к значениям внутри JSON используется язык запросов JsonPath. Все функции для работы с JSON принимают JsonPath запрос в качестве аргумента.
+
+Сразу разберем пример. Пусть у нас есть JSON:
+
+```json
+{
+ "comments": [
+ {
+ "id": 123,
+ "text": "A whisper will do, if it's all that you can manage."
+ },
+ {
+ "id": 456,
+ "text": "My life has become a single, ongoing revelation that I haven’t been cynical enough."
+ }
+ ]
+}
+```
+
+Тогда чтобы получить текст второго комментария можно написать JsonPath запрос:
+
+```yql
+$.comments[1].text
+```
+
+В этом запросе:
+
+1. `$` - это способ обратиться ко всему JSON
+2. `$.comments` - обращение к ключу `comments` объекта JSON
+3. `$.comments[1]` - обращение ко второму элементу массива JSON (нумерация с элементов начинается с 0)
+4. `$.comments[1].text` - обращение к ключу `text` объекта JSON
+5. Результат выполнения: `"My life has become a single, ongoing revelation that I haven’t been cynical enough."`
+
+### Quick reference
+
+| Операция | Пример |
+|-----------------------------------------|-------------------------------------------------|
+| Извлечь ключ JSON объекта | `$.key` |
+| Извлечь все ключи JSON объекта | `$.*` |
+| Обращение к элементу массива | `$[25]` |
+| Извлечение подотрезка массива | `$[2 to 5]` |
+| Обращение к последнему элементу массива | `$[last]` |
+| Обращение ко всем элементам массива | `$[*]` |
+| Унарные операции | `- 1` |
+| Бинарные операции | `(12 * 3) % 4 + 8` |
+| Обращение к переменной | `$variable` |
+| Логические операции | `(1 > 2) &#124;&#124; (3 <= 4) && ("string" == "another")&#124; |
+| Соответствие регулярному выражению | `$.name like_regex "^[A-Za-z]+$"` |
+| Проверка префикса строки | `$.name starts with "Bobbie"` |
+| Проверка существования пути | `exists ($.profile.name)` |
+| Проверка булевского выражения на null | `($.age > 20) is unknown` |
+| Фильтрация значений | `$.friends ? (@.age >= 18 && @.gender == "male")` |
+| Получение типа значения | `$.name.type()` |
+| Получение размера массива | `$.friends.size()` |
+| Преобразование строки в число | `$.number.double()` |
+| Округление числа вверх | `$.number.ceiling()` |
+| Округление числа вниз | `$.number.floor()` |
+| Абсолютное значение числа | `$.number.abs()` |
+| Получение пар ключ-значения из объекта | `$.profile.keyvalue()` |
+
+### Модель данных
+
+Результат выполнения всех JsonPath выражений - это последовательность JSON значений. Например:
+
+- Результат выражения `"Bobbie"` - это последовательность длины 1 с единственным элементом `"Bobbie"`.
+- Результат выражения `$` (взятие всего JSON объекта) на JSON `[1, 2, 3]` - это `[1, 2, 3]`. Последовательность из 1 элемента, массива `[1, 2, 3]`
+- Результат выражения `$[*]` (извлечение всех элементов массива) на JSON `[1, 2, 3]` - это `1, 2, 3`. Последовательность из трех элементов `1`, `2` и `3`
+
+Если входная последовательность состоит из нескольких значений, некоторые операции исполнятся для каждого элемента (например, доступ к ключу JSON объекта). При этом другие операции требуют последовательности из одного элемента на вход (например, бинарные арифметические операции).
+
+Поведение конкретной операции описано в соответствующей секции документации.
+
+### Режим выполнения
+
+JsonPath поддерживает два режима выполнения - `lax` и `strict`. Указание режима не обязательно, по умолчанию используется `lax`. Режим указывается в начале запроса, например: `strict $.key`.
+
+Поведение при каждом режиме описано в разделе соответствующих JsonPath операций.
+
+#### Автоматическая распаковка массива
+
+При обращении к ключу JSON объекта в `lax` режиме массивы автоматически распаковываются.
+
+##### Пример
+
+```json
+[
+ {
+ "key": 123
+ },
+ {
+ "key": 456
+ }
+]
+```
+
+Запрос `lax $.key` успешно выполнится с результатом `123, 456`. Поскольку `$` является массивом, он автоматически распакуется, и обращение к ключу JSON объекта `$.key` будет выполнено для каждого элемента массива.
+
+При этом запрос `strict $.key` завершится с ошибкой. В `strict` режиме нет автоматической распаковки массивов. `$` является массивом, а не объектом, поэтому обращение к ключу объекта `$.key` не может быть выполнено. Это можно исправить, написав `strict $[*].key`.
+
+Распаковка происходит только на 1 уровень вглубь. В случае вложенных массивов распаковывается только самый внешний из них.
+
+#### Обертка в массив
+
+При обращении к элементу массива в `lax` режиме JSON значения автоматически оборачиваются в массив.
+
+##### Пример
+
+```json
+{
+ "name": "Avasarala"
+}
+```
+
+Запрос `lax $[0].name` выполнится успешно с результатом `"Avasarala"`. Поскольку `$` не является массивом, он будет автоматически обернут в массив длины один. Обращение к первому элементу `$[0]` вернет исходный JSON объект, в котором будет взят ключ `name`.
+
+При этом запрос `strict $[0].name` завершится с ошибкой. В `strict` режиме нет автоматической обертки в массив. `$` является объектом, а не массивом, поэтому обращение к элементу `$[0]` не может быть выполнено. Это можно исправить, написав `strict $.name`.
+
+#### Обработка ошибок
+
+Некоторые ошибки конвертируются в пустой результат при выполнении в `lax` режиме.
+
+### Литералы
+
+Значения некоторых типов можно указать в JsonPath запросе используя литералы:
+
+| Тип | Пример |
+| ------------------ | ---------------- |
+| Числа | `42`, `-1.23e-5` |
+| Булевские значения | `false`, `true` |
+| Null | `null` |
+| Строки | `"Belt"` |
+
+### Обращение к ключу JSON объекта
+
+JsonPath поддерживает обращение к ключам JSON объектов: `$.session.user.name`.
+
+{% note info %}
+
+Обращение без кавычек можно использовать только для ключей, которые начинаются с буквы английского алфавита или подчеркивания, и содержат в себе только буквы английского алфавита, подчеркивания, цифры и знак доллара. Для всех остальных ключей необходимо использовать кавычки. Например: `$.profile."this string has spaces"`, `$.user."42 is the answer"`
+
+{% endnote %}
+
+Для каждого значения из входной последовательности:
+
+1. Если значение является массивом, в `lax` режиме происходит автоматическая распаковка массива
+2. Если значение не является JSON объектом или указанный ключ в этом JSON объекте отсутствует, в `strict` режиме запрос завершается ошибкой. В `lax` режиме для этого значения возвращается пустой результат
+
+Результат выражения - конкатенация результатов для каждого значения из входной последовательности.
+
+#### Пример
+
+```json
+{
+ "name": "Amos",
+ "friends": [
+ {
+ "name": "Jim"
+ },
+ {
+ "name": "Alex"
+ }
+ ]
+}
+```
+
+| | `lax` | `strict` |
+|------------------|------------------|----------|
+| `$.name` | `"Amos"` | `"Amos"` |
+| `$.surname` | Пустой результат | Ошибка |
+| `$.friends.name` | `"Jim", "Alex"` | Ошибка |
+
+### Обращение ко всем ключам JSON объекта
+
+JsonPath поддерживает обращение ко всем ключам JSON объектов сразу: `$.*`.
+
+Для каждого значения из входной последовательности:
+
+1. Если значение является массивом, в `lax` режиме происходит автоматическая распаковка массива
+2. Если значение не является JSON объектом, в `strict` режиме запрос завершается ошибкой. В `lax` режиме для этого значения возвращается пустой результат
+
+Результат выражения - конкатенация результатов для каждого значения из входной последовательности.
+
+#### Пример
+
+```json
+{
+ "profile": {
+ "id": 123,
+ "name": "Amos"
+ },
+ "friends": [
+ {
+ "name": "Jim"
+ },
+ {
+ "name": "Alex"
+ }
+ ]
+}
+```
+
+| | `lax` | `strict` |
+| ------------- | --------------- | ------------- |
+| `$.profile.*` | `123, "Amos"` | `123, "Amos"` |
+| `$.friends.*` | `"Jim", "Alex"` | Ошибка |
+
+### Обращение к элементу массива
+
+JsonPath поддерживает обращение к элементам массивов: `$.friends[1, 3 to last - 1]`.
+
+Для каждого значения из входной последовательности:
+
+1. Если значение не является массивом, то в `strict` режиме запрос завершается ошибкой. В `lax` режиме происходит автоматическая обертка в массив
+2. Ключевое слово `last` заменяется на последний индекс массива. Использование `last` вне обращения к массиву - это ошибка в обоих режимах
+3. Вычисляются указанные индексы. Каждый из них должен быть единственным числом, иначе запрос завершается ошибкой в обоих режимах
+4. Если индекс является дробным числом, он округляется вниз
+5. Если индекс выходит за границы массива, то в `strict` режиме запрос завершается ошибкой. В `lax` режиме такой индекс игнорируется
+6. Если указан отрезок и его стартовый индекс больше конечного индекса (например `$[20 to 1]`), то в `strict` режиме запрос завершается ошибкой. В `lax` режиме такой отрезок игнорируется.
+7. К результату добавляются все элементы по указанным индексам. Отрезки включают в себя **оба конца**
+
+#### Примеры
+
+```json
+[
+ {
+ "name": "Camina",
+ "surname": "Drummer"
+ },
+ {
+ "name": "Josephus",
+ "surname": "Miller"
+ },
+ {
+ "name": "Bobbie",
+ "surname": "Draper"
+ },
+ {
+ "name": "Julie",
+ "surname": "Mao"
+ }
+]
+```
+
+| | `lax` | `strict` |
+| ----------------------------- | ------------------------------- | ------------------------------- |
+| `$[0].name` | `"Camina"` | `"Camina"` |
+| `$[1, 2 to 3].name` | `"Josephus", "Bobbie", "Julie"` | `"Josephus", "Bobbie", "Julie"` |
+| `$[last - 2].name` | `"Josephus"` | `"Josephus"` |
+| `$[2, last + 200 to 50].name` | `"Bobbie"` | Ошибка |
+| `$[50].name` | Пустой результат | Ошибка |
+
+### Обращение ко всем элементам массива
+
+JsonPath поддерживает обращение ко всем элементам массива сразу: `$[*]`.
+
+Для каждого значения из входной последовательности:
+
+1. Если значение не является массивом, то в `strict` режиме запрос завершается ошибкой. В `lax` режиме происходит автоматическая обертка в массив
+2. К результату добавляются все элементы текущего массива
+
+#### Примеры
+
+```json
+[
+ {
+ "class": "Station",
+ "title": "Medina"
+ },
+ {
+ "class": "Corvette",
+ "title": "Rocinante"
+ }
+]
+```
+
+| | `lax` | `strict` |
+| ------------------- | ------------------------- | ----------------------- |
+| `$[*].title` | `"Medina", "Rocinante"` | `"Medina", "Rocinante"` |
+| `lax $[0][*].class` | `"Station"` | Ошибка |
+
+Разберем последний пример по шагам:
+
+1. `$[0]` возвращает первый элемент массива, то есть `{"class": "Station", "title": "Medina"}`
+2. `$[0][*]` ожидает массив на вход, но был дан объект. Происходит автоматическая обертка в массив, получается `[ {"class": "Station", "title": "Medina"} ]`
+3. Теперь `$[0][*]` может выполниться и возвращает все элементы массива, то есть `{"class": "Station", "title": "Medina"}`
+4. `$[0][*].class` возвращает поле `class`, то есть `"Station"`.
+
+### Арифметические операции
+
+{% note info %}
+
+Все арифметические операции работают с числами как с Double. Возможна [потеря точности](https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html) при вычислениях.
+
+{% endnote %}
+
+#### Унарные операции
+
+JsonPath поддерживает унарный `+` и `-`.
+
+Унарная операция применяется ко всем значениям из входной последовательности. Если унарной операции подать на вход не число, запрос завершится ошибкой в обоих режимах.
+
+##### Пример
+
+```json
+[1, 2, 3, 4]
+```
+
+Запрос `strict -$[*]` завершится успешно с результатом `-1, -2, -3, -4`.
+
+Запрос `lax -$` завершится с ошибкой, потому что `$` является массивом, а не числом.
+
+#### Бинарные операции
+
+JsonPath поддерживает бинарные арифметические операции (в порядке убывания приоритета):
+
+1. Умножение `*`, деление чисел с плавающей точкой `/`, взятие остатка `%` (работает как функция `MOD` в `SQL`)
+2. Сложение `+`, вычитание `-`
+
+Порядок выполнения операций можно поменять используя скобочки.
+
+В случае если каждый аргумент бинарной операции не является единственным числом или происходит деление на ноль, запрос завершается ошибкой в обоих режимах.
+
+##### Примеры
+
+- `(1 + 2) * 3` даст `9`
+- `1 / 2` даст `0.5`
+- `5 % 2` даст `1`
+- `1 / 0` завершится ошибкой
+- При JSON `[-32.4, 5.2]` запрос `$[0] % $[1]` даст `-1.2`
+- При JSON `[1, 2, 3, 4]` запрос `lax $[*] + $[*]` завершится ошибкой, так как результат выражения `$[*]` - это `1, 2, 3, 4`, несколько чисел. Бинарная операция требует только одно число для каждого своего аргумента.
+
+### Булевские значения
+
+В отличии от некоторых языков программирования, в JsonPath булевскими значениями считаются не только `true` (истина) и `false` (ложь), но и `null` (неопределенность).
+
+JsonPath считает все значения, полученные из JSON документа, не булевскими. Например, запрос `! $.is_valid_user` (логическое отрицание, примененное к полю `is_valid_user`), является синтаксически неверным поскольку поле `is_valid_user` не является булевским значением (даже если по факту в нем хранится `true` или `false`). Правильный способ написать такой запрос - это явно использовать сравнение с булевским значением, например `$.is_valid_user == false`.
+
+### Логические операции
+
+JsonPath поддерживает некоторые логические операции для работы с булевскими значениями.
+
+Аргументы всех логических операций должны являться единственным булевским значением.
+Все логические операции возвращают булевское значение.
+
+#### Логическое отрицание !
+
+Таблица истинности:
+
+| `x` | `!x` |
+| ------- | ------- |
+| `true` | `false` |
+| `false` | `true` |
+| `null` | `null` |
+
+#### Логическое И &&
+
+Таблица истинности, первый столбец это левый аргумент, первая строка это правый аргумент, каждая клетка это результат применения логического И с левым и правым аргументами:
+
+| `&&` | `true` | `false` | `null` |
+| ------- | ------- | ------- | ------- |
+| `true` | `true` | `false` | `null` |
+| `false` | `false` | `false` | `false` |
+| `null` | `null` | `false` | `null` |
+
+#### Логическое ИЛИ ||
+
+Таблица истинности, первый столбец это левый аргумент, первая строка это правый аргумент, каждая клетка это результат применения логического ИЛИ с левым и правым аргументами:
+
+| `\|\|` | `true` | `false` | `null` |
+| ------- | ------- | ------- | ------- |
+| `true` | `true` | `true` | `true` |
+| `false` | `true` | `false` | `null` |
+| `null` | `true` | `null` | `null` |
+
+##### Примеры
+
+- `! (true == true)`, результат `false`
+- `(true == true) && (true == false)`, результат `false`
+- `(true == true) || (true == false)`, результат `true`
+
+### Операторы сравнения
+
+JsonPath реализует операторы сравнения для значений:
+
+- Равенство, `==`
+- Неравенство, `!=` и `<>`
+- Меньше и меньше либо равно, `<` и `<=`
+- Больше и больше либо равно, `>` и `>=`
+
+Все операторы сравнения возвращают булевское значение. Оба аргумента оператора поддерживают наличие нескольких значений.
+
+Если при вычислении аргументов оператора возникла ошибка, оператор возвращает `null`. При этом выполнение JsonPath запроса продолжается.
+
+Для каждого из аргументов производится автоматическая распаковка массивов. После этого для каждой пары, где первый элемент берется из последовательности левого аргумента, а второй элемент из последовательности правого аргумента:
+
+1. Выполняется сравнение элементов пары
+2. Если при сравнении возникла ошибка, устанавливается флаг `ERROR`
+3. Если результат сравнения это истина, устанавливается флаг `FOUND`
+4. Если один из флагов `ERROR` или `FOUND` установлен и запрос исполняется в `lax` режиме, больше никакие пары не рассматриваются
+
+Если после рассмотрения пар:
+
+1. Установлен флаг `ERROR`, оператор возвращает `null`
+2. Установлен флаг `FOUND`, оператор возвращает `true`
+3. Иначе оператор возвращает `false`
+
+Можно сказать что данный алгоритм рассматривает все пары из декартового произведения левого и правого аргумента, пытаясь найти ту, сравнение которой вернет истину.
+
+Сравнение элементов в паре производится по следующим правилам:
+
+1. Если левый или правый аргумент являются массивом или объектом, сравнение завершается с ошибкой
+2. `null == null` возвращает истину
+3. Во всех остальных случаях если один из аргументов `null`, возвращается ложь
+4. Если левый и правый аргумент разных типов, сравнение завершается с ошибкой
+5. Строки сравниваются побайтово
+6. `true` считается больше `false`
+7. Числа сравниваются с точностью `1e-20`
+
+#### Пример
+
+Для примера рассмотрим JSON документ
+
+```json
+{
+ "left": [1, 2],
+ "right": [4, "Inaros"]
+}
+```
+
+и разберем по шагам выполнение запроса `lax $.left < $.right`:
+
+1. Автоматическая распаковка массивов в левом и правом аргументе. В качестве левого аргумента получаем последовательность `1, 2`, в качестве правого `4, "Iranos"`
+2. Рассматриваем пару `(1, 4)`. Сравнение проходит успешно, `1 < 4` это истина. Устанавливаем флаг `FOUND`
+3. Поскольку выполнение происходит в `lax` режиме и установлен флаг `FOUND`, больше никакие пары мы не рассматриваем
+4. Поскольку установлен флаг `FOUND`, оператор возвращает истину
+
+Разберем тот же запрос, но в другом режиме выполнения: `strict $.left < $.right`:
+
+1. Автоматическая распаковка массивов в левом и правом аргументе. В качестве левого аргумента получаем последовательность `1, 2`, в качестве правого `4, "Iranos"`
+2. Рассматриваем пару `(1, 4)`. Сравнение проходит успешно, `1 < 4` это истина. Устанавливаем флаг `FOUND`
+3. Рассматриваем пару `(2, 4)`. Сравнение проходит успешно, `2 < 4` это истина. Устанавливаем флаг `FOUND`
+4. Рассматриваем пару `(1, "Iranos")`. Сравнение завершается ошибкой (число нельзя сравнить со строкой). Устанавливаем флаг `ERROR`
+5. Рассматриваем пару `(2, "Iranos")`. Сравнение завершается ошибкой (число нельзя сравнить со строкой). Устанавливаем флаг `ERROR`
+6. Поскольку установлен флаг `ERROR`, оператор возвращает `null`
+
+### Предикаты
+
+JsonPath поддерживает предикаты - выражения, возвращающие булевское значение, и проверяющие некоторое условие. Их можно использовать, например, в фильтрах.
+
+#### `like_regex`
+
+Предикат `like_regex` позволяет проверить строку на соответствие регулярному выражению. Синтаксис регулярных выражений такой же как в [Hyperscan UDF](../udf/list/hyperscan.md) и [REGEXP](../syntax/expressions.md#regexp).
+
+##### Синтаксис
+
+```yql
+<expression> like_regex <regexp string> [flag <flag string>]
+```
+
+Где:
+
+1. `<expression>` - это JsonPath выражение, содержащее строки, которые следует проверить на соответствие регулярному выражению
+2. `<regexp string>` - это строка, содержащая регулярное выражение
+3. `flag <flag string>` - это опциональная секция, в которой `<flag string>` является строкой с флагами для исполнения регулярного выражения
+
+Поддерживаемые флаги:
+
+- `i` - отключение чувствительности к регистру
+
+##### Исполнение
+
+Перед проверкой производится автоматическая распаковка массивов во входной последовательности.
+
+После этого для каждого элемента входной последовательности:
+
+1. Выполняется проверка на соответствие элемента регулярному выражению
+2. Если элемент не является строкой, устанавливается флаг `ERROR`
+3. Если результат проверки это истина, устанавливается флаг `FOUND`
+4. Если один из флагов `ERROR` или `FOUND` установлен и запрос исполняется в `lax` режиме, больше никакие пары не рассматриваются
+
+Если после рассмотрения пар:
+
+1. Установлен флаг `ERROR`, предикат возвращает `null`
+2. Установлен флаг `FOUND`, предикат возвращает `true`
+3. Иначе предикат возвращает `false`
+
+#### Примеры
+
+1. `"123456" like_regex "^[0-9]+$"` возвращает `true`
+2. `"123abcd456" like_regex "^[0-9]+$"` возвращает `false`
+3. `"Naomi Nagata" like_regex "nag"` возвращает `false`
+4. `"Naomi Nagata" like_regex "nag" flag "i"` возвращает `true`
+
+#### `starts with`
+
+Предикат `starts with` позволяет проверить является ли одна строка префиксом другой.
+
+##### Синтаксис
+
+```yql
+<string expression> starts with <prefix expression>
+```
+
+Где:
+
+1. `<string expression>` - это JsonPath выражение, содержащее строку, которую нужно проверить
+2. `<prefix expression>` - это JsonPath выражение, содержащее строку-префикс
+
+То есть предикат будет проверять что `<string expression>` начинается со строки `<prefix expression>`.
+
+##### Исполнение
+
+Первый аргумент предиката должен быть единственной строкой.
+
+Второй аргумент предиката должен быть последовательностью (возможно, из нескольких) строк.
+
+Для каждого элемента из последовательности строк-префиксов:
+
+1. Выполняется проверка "является ли элемент префиксом входной строки"
+2. Если элемент не является строкой, устанавливается флаг `ERROR`
+3. Если результат проверки это истина, устанавливается флаг `FOUND`
+4. Если один из флагов `ERROR` или `FOUND` установлен и запрос исполняется в `lax` режиме, больше никакие пары не рассматриваются
+
+Если после рассмотрения пар:
+
+1. Установлен флаг `ERROR`, предикат возвращает `null`
+2. Установлен флаг `FOUND`, предикат возвращает `true`
+3. Иначе предикат возвращает `false`
+
+##### Примеры
+
+1. `"James Holden" starts with "James"` возвращает `true`
+2. `"James Holden" starts with "Amos"` возвращает `false`
+
+#### `exists`
+
+Предикат `exists` позволяет проверить, возвращает ли JsonPath выражение хотя бы один элемент.
+
+##### Синтаксис
+
+```yql
+exists (<expression>)
+```
+
+Где `<expression>` - это JsonPath выражение, которое нужно проверить. Скобки вокруг выражения обязательны.
+
+##### Исполнение
+
+1. Исполняется переданное JsonPath выражение
+2. Если в результате исполнения возникла ошибка, предикат возвращает `null`
+3. Если в результате исполнения была получена пустая последовательность, предикат возвращает `false`
+4. Иначе предикат возвращает `true`
+
+##### Примеры
+
+Рассмотрим JSON документ:
+
+```json
+{
+ "profile": {
+ "name": "Josephus",
+ "surname": "Miller"
+ }
+}
+```
+
+1. `exists ($.profile.name)` возвращает `true`
+2. `exists ($.friends.profile.name)` возвращает `false`
+3. `strict exists ($.friends.profile.name)` возвращает `null`, потому что в `strict` режиме обращение к несуществующим ключам объекта это ошибка
+
+#### `is unknown`
+
+Предикат `is unknown` позволяет проверить, является ли булевское значение `null`.
+
+##### Синтаксис
+
+```yql
+(<expression>) is unknown
+```
+
+Где `<expression>` - это JsonPath выражение, которое нужно проверить. Допускаются только выражения, возвращающие булевское значение. Скобки вокруг выражения обязательны.
+
+##### Исполнение
+
+1. Если переданное выражение возвращает `null`, предикат возвращает `true`
+2. Иначе предикат возвращает `false`
+
+##### Примеры
+
+1. `(1 == 2) is unknown` возвращает `false`. Выражение `1 == 2` вернуло `false`, что не является `null`
+2. `(1 == "string") is unknown` возвращает `true`. Выражение `1 == "string"` вернуло `null`, поскольку в JsonPath строки и числа не сравнимы
+
+### Фильтры
+
+JsonPath позволяет фильтровать значения, полученные в ходе выполнения запроса.
+
+Выражение в фильтре должно возвращать булевское значение.
+Перед фильтрацией производится автоматическая распаковка массивов во входной последовательности.
+
+Для каждого элемента входной последовательности:
+
+1. Значение текущего фильтруемого объекта `@` становится равным текущему элементу входной последовательности
+2. Исполняется выражение в фильтре
+3. Если в ходе выполнения выражения возникла ошибка, текущий элемент входной последовательности пропускается
+4. Если результат исполнения выражения это единственное значение `true`, текущий элемент добавляется в результат фильтра
+
+#### Пример
+
+Пусть у нас есть JSON документ, описывающий друзей пользователя
+
+```json
+{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35,
+ "money": 500
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30,
+ "money": 345
+ }
+ ]
+}
+```
+
+и мы хотим получить с помощью JsonPath запроса друзей которые старше 32 лет. Для этого можно написать следующий запрос:
+
+```yql
+$.friends ? (@.age > 32)
+```
+
+Разберем запрос по частям:
+
+- `$.friends` - обращение к массиву `friends` в JSON документе
+- `? ( ... )` - синтаксис фильтра. Выражение внутри скобок называется предикатом
+- `@` - обращение к текущему фильтруемому объекту. В нашем примере это объект, описывающий друга пользователя
+- `@.age` - обращение к полю `age` текущего фильтруемого объекта
+- `@.age > 32` - сравнение поля `age` со значением 32. В результате выполнения запроса останутся только те значения, для которых данный предикат вернул истину
+
+В результате выполнения этого запроса будет получен только первый друг из массива друзей пользователя.
+
+Как и многие другие операторы языка JsonPath, фильтры можно выстраивать в цепочки. Разберем более сложный запрос, который отбирает имена друзей которые старше 20 лет и которые имеют меньше чем 400 единиц валюты:
+
+```yql
+$.friends ? (@.age > 20) ? (@.money < 400) . name
+```
+
+Разберем запрос по частям:
+
+- `$.friends` - обращение к массиву `friends` в JSON документе
+- `? (@.age > 20)` - первый фильтр. Поскольку все друзья старше 20, он просто вернет все элементы массива `friends`
+- `? (@.money < 400)` - второй фильтр. Вернет только второй элемент массива `friends`, поскольку только у него поле `money` имеет значение меньше 400
+- `.name` - обращение к полю `name` у отфильтрованных объектов
+
+В результате выполнения этого запроса будет получена последовательность из одного элемента - `"Naomi Nagata"`.
+
+На практике рекомендуется объединять несколько фильтров в один если есть такая возможность. Рассмотренный запрос эквивалентен `$.friends ? (@.age > 20 && @.money < 400) . name`.
+
+### Методы
+
+JsonPath поддерживает методы - функции, которые преобразуют одни последовательности значений в другие. Синтаксис вызова метода похож на обращение к ключу объекта:
+
+```yql
+$.friends.size()
+```
+
+Также как и обращение к ключам объекта, вызовы методов можно выстраивать в цепочки:
+
+```yql
+$.numbers.double().floor()
+```
+
+#### `type`
+
+Метод `type` возвращает строчку с названием типа переданного значения.
+
+Для каждого элемента входной последовательности метод добавляет строчку в выходную последовательность в соответствии с табличкой:
+
+| Тип значения | Строка с названием типа |
+| ------------------ | ------------------------ |
+| Null | `"null"` |
+| Булевское значение | `"boolean"` |
+| Число | `"number"` |
+| Строка | `"string"` |
+| Массив | `"array"` |
+| Объект | `"object"` |
+
+##### Примеры
+
+1. `"Naomi".type()` возвращает `"string"`
+2. `false.type()` возвращает `"boolean"`
+
+#### `size`
+
+Метод `size` возвращает размер массива.
+
+Для каждого элемента входной последовательности метод добавляет в выходную последовательность:
+
+1. Размер массива, если тип элемента это массив
+2. Для всех остальных типов (включая объекты) `1`
+
+#### Примеры
+
+Рассмотрим JSON документ:
+
+```json
+{
+ "array": [1, 2, 3],
+ "object": {
+ "a": 1,
+ "b": 2
+ },
+ "scalar": "string"
+}
+```
+
+И запросы к нему:
+
+1. `$.array.size()` возвращает `3`
+2. `$.object.size()` возвращает `1`
+3. `$.scalar.size()` возвращает `1`
+
+#### `double`
+
+Метод `double` конвертирует строки в числа.
+
+Перед выполнением производится автоматическая распаковка массивов во входной последовательности.
+
+Все элементы во входной последовательности должны быть строками, которые содержат числа в десятичной записи. Допускается указание дробной части и экспоненты.
+
+##### Примеры
+
+1. `"125".double()` возвращает `125`
+2. `"125.456".double()` возвращает `125.456`
+3. `"125.456e-3".double()` возвращает `0.125456`
+
+#### `ceiling`
+
+Метод `ceiling` округляет числа вверх.
+
+Перед выполнением производится автоматическая распаковка массивов во входной последовательности.
+
+Все элементы во входной последовательности должны быть числами.
+
+##### Примеры
+
+1. `(1.3).ceiling()` возвращает `2`
+2. `(1.8).ceiling()` возвращает `2`
+3. `(1.5).ceiling()` возвращает `2`
+4. `(1.0).ceiling()` возвращает `1`
+
+#### `floor`
+
+Метод `floor` округляет числа вниз.
+
+Перед выполнением производится автоматическая распаковка массивов во входной последовательности.
+
+Все элементы во входной последовательности должны быть числами.
+
+##### Примеры
+
+1. `(1.3).floor()` возвращает `1`
+2. `(1.8).floor()` возвращает `1`
+3. `(1.5).floor()` возвращает `1`
+4. `(1.0).floor()` возвращает `1`
+
+#### `abs`
+
+Метод `abs` вычисляет абсолютное значение числа (убирает знак).
+
+Перед выполнением производится автоматическая распаковка массивов во входной последовательности.
+
+Все элементы во входной последовательности должны быть числами.
+
+##### Примеры
+
+1. `(0.0).abs()` возвращает `0`
+2. `(1.0).abs()` возвращает `1`
+3. `(-1.0).abs()` возвращает `1`
+
+#### `keyvalue`
+
+Метод `keyvalue` конвертирует объект в последовательность пар ключ-значение.
+
+Перед выполнением производится автоматическая распаковка массивов во входной последовательности.
+
+Все элементы во входной последовательности должны быть объектами.
+
+Для каждого элемента входной последовательности:
+
+1. Рассматривается каждая пара ключ-значение в элементе
+2. Для каждой такой пары формируется объект с ключами `name` и `value`
+3. `name` хранит строку с названием ключа из пары
+4. `value` хранит значение из пары
+5. Все объекты для этого элемента добавляются в выходную последовательность
+
+##### Примеры
+
+Рассмотрим JSON документ:
+
+```json
+{
+ "name": "Chrisjen",
+ "surname": "Avasarala",
+ "age": 70
+}
+```
+
+Для него запрос `$.keyvalue()` вернет последовательность:
+
+```json
+{
+ "name": "age",
+ "value": 70
+},
+{
+ "name": "name",
+ "value": "Chrisjen"
+},
+{
+ "name": "surname",
+ "value": "Avasarala"
+}
+```
+
+### Переменные
+
+Функции использующие JsonPath могут передавать значения внутрь запроса, они называются переменными. Чтобы обратиться к переменной, нужно написать символ `$` и название переменной: `$variable`.
+
+#### Пример
+
+Пусть переменная `planet` равна
+
+```json
+{
+ "name": "Mars",
+ "gravity": 0.376
+}
+```
+
+Тогда запрос `strict $planet.name` даст `"Mars"`.
+
+В отличии от многих языков программирования, JsonPath не поддерживает создание новых переменных или изменение существующих.
+
+## Общие аргументы
+
+Все функции для работы с JSON принимают:
+
+1. JSON значение (может быть произвольным выражением типа `Json` или `Json?`)
+2. JsonPath запрос (должен быть явно указан строковым литералом)
+3. **(Опционально)** `PASSING` секция
+
+### PASSING секция
+
+Позволяет передавать значения в JsonPath запрос в качестве переменных.
+
+#### Синтаксис
+
+```yql
+PASSING
+ <expression 1> AS <variable name 1>,
+ <expression 2> AS <variable name 2>,
+ ...
+```
+
+`<expression>` может быть следующих типов:
+
+- Числа, `Date`, `DateTime` и `Timestamp` (будет произведен `CAST` в тип `Double` перед передачей в JsonPath)
+- `Utf8`, `Bool` и `Json`
+
+Имя переменной `<variable name>` можно указать несколькими способами:
+
+- Как SQL имя, например `variable`
+- В кавычках, например `"variable"`
+
+#### Пример
+
+```yql
+JSON_VALUE(
+ $json,
+ "$.timestamp - $Now + $Hour"
+ PASSING
+ 24 * 60 as Hour,
+ CurrentUtcTimestamp() as "Now"
+)
+```
+
+## JSON_EXISTS {#json_exists}
+
+Функция `JSON_EXISTS` позволяет проверить, удовлетворяет ли JSON значение указанному JsonPath.
+
+### Синтаксис
+
+```yql
+JSON_EXISTS(
+ <JSON expression>,
+ <JsonPath query>,
+ [<PASSING clause>]
+ [{TRUE | FALSE | UNKNOWN | ERROR} ON ERROR]
+)
+```
+
+Возвращаемое значение: `Bool?`
+
+Значения по умолчанию: если `ON ERROR` секция не указана, используется `FALSE ON ERROR`
+
+Поведение:
+
+1. Если `<JSON expression>` это `NULL` или пустой `Json?`, то возвращается пустой `Bool?`
+2. Если при выполнении JsonPath возникла ошибка, то возвращаемое значение зависит от `ON ERROR` секции:
+
+ - `TRUE` - вернуть `True`
+ - `FALSE` - вернуть `False`
+ - `UNKNOWN` - вернуть пустой `Bool?`
+ - `ERROR` - завершить весь запрос с ошибкой
+
+3. Если результат выполнения JsonPath - это одно или несколько значений, возвращается `True`
+4. Иначе возвращается `False`
+
+#### Примеры
+
+```yql
+$json = CAST(@@{
+ "title": "Rocinante",
+ "crew": [
+ "James Holden",
+ "Naomi Nagata",
+ "Alex Kamai",
+ "Amos Burton"
+ ]
+}@@ as Json);
+
+SELECT
+ JSON_EXISTS($json, "$.title"), -- True
+ JSON_EXISTS($json, "$.crew[*]"), -- True
+ JSON_EXISTS($json, "$.nonexistent"); -- False, так как JsonPath вернет пустой результат
+
+SELECT
+ -- Ошибка JsonPath, вернет False, так как по умолчанию используется FALSE ON ERROR
+ JSON_EXISTS($json, "strict $.nonexistent");
+
+SELECT
+ -- Ошибка JsonPath, весь YQL запрос завершится ошибкой
+ JSON_EXISTS($json, "strict $.nonexistent" ERROR ON ERROR);
+```
+
+## JSON_VALUE {#json_value}
+
+Функция `JSON_VALUE` позволяет извлечь из JSON скалярное значение (все что не массив и не объект).
+
+### Синтаксис
+
+```yql
+JSON_VALUE(
+ <JSON expression>,
+ <JsonPath query>,
+ [<PASSING clause>]
+ [RETURNING <type>]
+ [{ERROR | NULL | DEFAULT <expr>} ON EMPTY]
+ [{ERROR | NULL | DEFAULT <expr>} ON ERROR]
+)
+```
+
+Возвращаемое значение: `<type>?`
+
+Значения по умолчанию:
+
+1. Если `ON EMPTY` секция не указана, используется `NULL ON EMPTY`
+2. Если `ON ERROR` секция не указана, используется `NULL ON ERROR`
+3. Если `RETURNING` секция не указана, в качестве `<type>` используется `Utf8`
+
+Поведение:
+
+1. Если `<JSON expression>` это `NULL` или пустой `Json?`, то возвращается пустой `<type>?`
+2. Если возникла ошибка, то возвращаемое значение зависит от `ON ERROR` секции:
+
+ - `NULL` - вернуть пустой `<type>?`
+ - `ERROR` - завершить весь запрос с ошибкой
+ - `DEFAULT <expr>` - вернуть `<expr>`, предварительно сделав `CAST` в тип `<type>?`. Если `CAST` не удастся, весь запрос завершится с ошибкой
+
+3. Если в результате выполнения JsonPath получился пустой результат, то возвращаемое значение зависит от `ON EMPTY` секции:
+
+ - `NULL` - вернуть пустой `<type>?`
+ - `ERROR` - завершить весь запрос с ошибкой
+ - `DEFAULT <expr>` - вернуть `<expr>`, предварительно сделав `CAST` в тип `<type>?`. Если `CAST` не удастся, то поведение соответствует `ON ERROR` секции
+
+4. Если результат выполнения JsonPath - это одно значение, то:
+
+ - Если `RETURNING` секция не была указана, значение конвертируется в `Utf8`
+ - Иначе производится `CAST` значения в `<type>`. Если `CAST` не удастся, то поведение соответствует `ON ERROR` секции. При этом значение из JSON должно "соответствовать" типу `<type>`.
+
+5. Вернуть полученный результат
+
+Определим соответствие JSON типов YQL типам:
+
+- JSON Number - числовые типы, `Date`, `DateTime` и `Timestamp`
+- JSON Bool - `Bool`
+- JSON String - `Utf8` и `String`
+
+Ошибками при выполнении `JSON_VALUE` считаются:
+
+- Ошибки во время вычисления JsonPath
+- Результат выполнения JsonPath - это несколько значений или не скалярное значение
+- Тип полученного из JSON значения не совпадает с ожидаемым
+
+`RETURNING` секция поддерживает типы чисел, `Date`, `DateTime`, `Timestamp`, `Utf8`, `String` и `Bool`.
+
+#### Примеры
+
+```yql
+$json = CAST(@@{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30
+ }
+ ]
+}@@ as Json);
+
+SELECT
+ JSON_VALUE($json, "$.friends[0].age"), -- "35" (тип Utf8?)
+ JSON_VALUE($json, "$.friends[0].age" RETURNING Uint64), -- 35 (тип Uint64?)
+ JSON_VALUE($json, "$.friends[0].age" RETURNING Utf8); -- пустой Utf8?, так как произошла ошибка. Тип JSON значения Number не соответствует строковому типу Utf8
+
+SELECT
+ -- "empty" (тип String?)
+ JSON_VALUE(
+ $json,
+ "$.friends[50].name"
+ RETURNING String
+ DEFAULT "empty" ON EMPTY
+ );
+
+SELECT
+ -- 20 (тип Uint64?). Результат выполнения JsonPath пустой, но значение
+ -- по умолчанию из секции ON EMPTY не может быть приведено к Uint64.
+ -- Поэтому используется значение из ON ERROR
+ JSON_VALUE(
+ $json,
+ "$.friends[50].age"
+ RETURNING Uint64
+ DEFAULT -1 ON EMPTY
+ DEFAULT 20 ON ERROR
+ );
+
+```
+
+## JSON_QUERY {#json_query}
+
+Функция `JSON_QUERY` позволяет извлекать из JSON массивы и объекты.
+
+### Синтаксис
+
+```yql
+JSON_QUERY(
+ <JSON expression>,
+ <JsonPath query>,
+ [<PASSING clause>]
+ [WITHOUT [ARRAY] | WITH [CONDITIONAL | UNCONDITIONAL] [ARRAY] WRAPPER]
+ [{ERROR | NULL | EMPTY ARRAY | EMPTY OBJECT} ON EMPTY]
+ [{ERROR | NULL | EMPTY ARRAY | EMPTY OBJECT} ON ERROR]
+)
+```
+
+Возвращаемое значение `Json?`
+
+Значения по умолчанию
+
+1. Если `ON EMPTY` секция не указана, используется `NULL ON EMPTY`
+2. Если `ON ERROR` секция не указана, используется `NULL ON ERROR`
+3. Если `WRAPPER` секция не указана, используется `WITHOUT WRAPPER`
+4. Если указана секция `WITH WRAPPER`, но не указано `CONDITIONAL` или `UNCONDITIONAL`, используется `UNCONDITIONAL`
+
+Поведение:
+
+{% note info %}
+
+Указывать секции `WITH ... WRAPPER` и `ON EMPTY` одновременно нельзя
+
+{% endnote %}
+
+1. Если `<JSON expression>` это `NULL` или пустой `Json?`, то возвращается пустой `Json?`
+2. Если указана `WRAPPER` секция, то:
+
+ - `WITHOUT WRAPPER` или `WITHOUT ARRAY WRAPPER` - никак не преобразовывать результат выполнения JsonPath
+ - `WITH UNCONDITIONAL WRAPPER` или `WITH UNCONDITIONAL ARRAY WRAPPER` - обернуть результат выполнения JsonPath в массив
+ - `WITH CONDITIONAL WRAPPER` или `WITH CONDITIONAL ARRAY WRAPPER` - обернуть результат выполнения JsonPath в массив если он не является единственным массивом или объектом
+
+3. Если в результате выполнения JsonPath получился пустой результат, то возвращаемое значение зависит от `ON EMPTY` секции:
+
+ - `NULL` - вернуть пустой `Json?`
+ - `ERROR` - завершить весь запрос с ошибкой
+ - `EMPTY ARRAY` - вернуть пустой JSON массив, `[]`
+ - `EMPTY OBJECT` - вернуть пустой JSON объект, `{}`
+
+4. Если возникла ошибка, то возвращаемое значение зависит от `ON ERROR` секции:
+
+ - `NULL` - вернуть пустой `Json?`
+ - `ERROR` - завершить весь запрос с ошибкой
+ - `EMPTY ARRAY` - вернуть пустой JSON массив, `[]`
+ - `EMPTY OBJECT` - вернуть пустой JSON объект, `{}`
+
+5. Вернуть полученный результат
+
+Ошибками при выполнении `JSON_QUERY` считаются:
+
+- Ошибки во время вычисления JsonPath
+- Результат выполнения JsonPath - это несколько значений (даже после применения секции `WRAPPER`) или скалярное значение
+
+### Примеры
+
+```yql
+$json = CAST(@@{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30
+ }
+ ]
+}@@ as Json);
+
+SELECT
+ JSON_QUERY($json, "$.friends[0]"); -- {"name": "James Holden", "age": 35}
+
+SELECT
+ JSON_QUERY($json, "$.friends.name" WITH UNCONDITIONAL WRAPPER); -- ["James Holden", "Naomi Nagata"]
+
+SELECT
+ JSON_QUERY($json, "$.friends[0]" WITH CONDITIONAL WRAPPER), -- {"name": "James Holden", "age": 35}
+ JSON_QUERY($json, "$.friends.name" WITH CONDITIONAL WRAPPER); -- ["James Holden", "Naomi Nagata"]
+```
+
+## Смотрите также
+
+* [{#T}](../recipes/accessing-json.md)
+* [{#T}](../recipes/modifying-json.md)
diff --git a/yql/essentials/docs/ru/builtins/list.md b/yql/essentials/docs/ru/builtins/list.md
new file mode 100644
index 0000000000..3c6ec6d41e
--- /dev/null
+++ b/yql/essentials/docs/ru/builtins/list.md
@@ -0,0 +1,991 @@
+# Функции для работы со списками
+
+## ListCreate {#list-create}
+
+Сконструировать пустой список. В единственном аргументе указывается строка с описанием типа данных ячейки списка, либо сам тип, полученный с помощью [предназначенных для этого функций](types.md). Списков с неизвестным типом ячейки в YQL не бывает.
+
+[Документация по формату описания типа](../types/type_string.md).
+
+### Примеры
+
+```yql
+SELECT ListCreate(Tuple<String,Double?>);
+```
+
+```yql
+SELECT ListCreate(OptionalType(DataType("String")));
+```
+
+### Сигнатура
+
+```yql
+ListCreate(T)->List<T>
+```
+
+## AsList и AsListStrict {#aslist}
+
+Сконструировать список из одного или более аргументов. Типы аргументов должны быть совместимы в случае `AsList` и строго совпадать в случае `AsListStrict`.
+
+### Примеры
+
+```yql
+SELECT AsList(1, 2, 3, 4, 5);
+```
+
+### Сигнатура
+
+```yql
+AsList(T..)->List<T>
+```
+
+## ListLength {#listlength}
+
+Количество элементов в списке.
+
+### Примеры
+
+```yql
+SELECT ListLength(list_column) FROM my_table;
+```
+
+### Сигнатура
+
+```yql
+ListLength(List<T>)->Uint64
+ListLength(List<T>?)->Uint64?
+```
+
+## ListHasItems
+
+Проверка того, что список содержит хотя бы один элемент.
+
+### Примеры
+
+```yql
+SELECT ListHasItems(list_column) FROM my_table;
+```
+
+### Сигнатура
+
+```yql
+ListHasItems(List<T>)->Bool
+ListHasItems(List<T>?)->Bool?
+```
+
+## ListCollect {#listcollect}
+
+Преобразовать ленивый список (строится, например, функциями [ListFilter](#listmap), [ListMap](#listmap), [ListFlatMap](#listmap)) в энергичный. В отличие от ленивого списка, в котором каждый повторный проход заново вычисляет его содержимое, в энергичном списке содержимое списка строится сразу ценой большего потребления памяти.
+
+### Примеры
+
+```yql
+SELECT ListCollect(list_column) FROM my_table;
+```
+
+### Сигнатура
+
+```yql
+ListCollect(LazyList<T>)->List<T>
+ListCollect(LazyList<T>?)->List<T>?
+```
+
+## ListSort, ListSortAsc и ListSortDesc {#listsort}
+
+Отсортировать список. По умолчанию выполняется сортировка по возрастанию (`ListSort` — алиас к `ListSortAsc`).
+
+Аргументы:
+
+1. Список;
+2. Опциональное выражение для получения ключа сортировки из элемента списка (по умолчанию сам элемент).
+
+### Примеры
+
+```yql
+SELECT ListSortDesc(list_column) FROM my_table;
+```
+
+```yql
+$list = AsList(
+ AsTuple("x", 3),
+ AsTuple("xx", 1),
+ AsTuple("a", 2)
+);
+
+SELECT ListSort($list, ($x) -> {
+ RETURN $x.1;
+});
+```
+
+{% note info %}
+
+В примере использовалась [лямбда функция](../syntax/expressions.md#lambda).
+
+{% endnote %}
+
+### Сигнатура
+
+```yql
+ListSort(List<T>)->List<T>
+ListSort(List<T>?)->List<T>?
+
+ListSort(List<T>, (T)->U)->List<T>
+ListSort(List<T>?, (T)->U)->List<T>?
+```
+
+## ListExtend и ListExtendStrict {#listextend}
+
+Последовательно соединить списки (конкатенация списков). В качестве аргументов могут быть списки, опциональные списки и `NULL`.
+Типы элементов списков должны быть совместимы в случае `ListExtend` и строго совпадать в случае `ListExtendStrict`.
+Если хотя бы один из списков является опциональным, то таким же является и результат.
+Если хотя бы один аргумент является `NULL`, то тип результата - `NULL`.
+
+### Примеры
+
+```yql
+SELECT ListExtend(
+ list_column_1,
+ list_column_2,
+ list_column_3
+) FROM my_table;
+```
+
+```yql
+$l1 = AsList("a", "b");
+$l2 = AsList("b", "c");
+$l3 = AsList("d", "e");
+
+SELECT ListExtend($l1, $l2, $l3); -- ["a","b","b","c","d","e"]
+```
+
+### Сигнатура
+
+```yql
+ListExtend(List<T>..)->List<T>
+ListExtend(List<T>?..)->List<T>?
+```
+
+## ListUnionAll {#listunionall}
+
+Последовательно соединить списки структур (конкатенация списков). В выходном списке структур будет присутствовать поле, если оно есть хотя бы в одном исходном списке, при этом в случае отсутствия такого поля в каком-либо списке оно дополняется как NULL. В случае, когда поле присутствует в двух и более списках, поле в результате приводит в общий тип.
+
+Если хотя бы один из списков является опциональным, то таким же является и результат.
+
+### Примеры
+
+```yql
+SELECT ListUnionAll(
+ list_column_1,
+ list_column_2,
+ list_column_3
+) FROM my_table;
+```
+
+```yql
+$l1 = AsList(
+ <|value:1|>,
+ <|value:2|>
+);
+$l2 = AsList(
+ <|key:"a"|>,
+ <|key:"b"|>
+);
+SELECT ListUnionAll($l1, $l2); -- result: [("value":1),("value":2),("key":"a"),("key":"b")]
+ -- schema: List<Struct<key : String?, value : Int32?>>
+```
+
+### Сигнатура
+
+```yql
+ListUnionAll(List<Struct<..>>, List<Struct<..>>..)->List<Struct<..>>
+ListUnionAll(List<Struct<..>>?, List<Struct<..>>?..)->List<Struct<..>>?
+```
+
+## ListZip и ListZipAll {#listzip}
+
+По входящим спискам построить список пар, содержащих соответствующие по индексу элементы списков (`List<Tuple<first_list_element_type,second_list_element_type>>`).
+
+Длина возвращаемого списка определяется самым коротким списком для ListZip и самым длинным — для ListZipAll.
+Когда более короткий список исчерпан, в качестве пары к элементам более длинного списка подставляется пустое значение (`NULL`) соответствующего [optional типа](../types/optional.md).
+
+### Примеры
+
+```yql
+SELECT
+ ListZip(list_column_1, list_column_2, list_column_3),
+ ListZipAll(list_column_1, list_column_2)
+FROM my_table;
+```
+
+```yql
+$l1 = AsList("a", "b");
+$l2 = AsList(1, 2, 3);
+
+SELECT ListZip($l1, $l2); -- [("a",1),("b",2)]
+SELECT ListZipAll($l1, $l2); -- [("a",1),("b",2),(null,3)]
+```
+
+### Сигнатура
+
+```yql
+ListZip(List<T1>, List<T2>)->List<Tuple<T1, T2>>
+ListZip(List<T1>?, List<T2>?)->List<Tuple<T1, T2>>?
+
+ListZipAll(List<T1>, List<T2>)->List<Tuple<T1?, T2?>>
+ListZipAll(List<T1>?, List<T2>?)->List<Tuple<T1?, T2?>>?
+```
+
+## ListEnumerate {#listenumerate}
+
+Построить список пар (Tuple), содержащих номер элемента и сам элемент (`List<Tuple<Uint64,list_element_type>>`).
+
+### Примеры
+
+```yql
+SELECT ListEnumerate(list_column) FROM my_table;
+```
+
+### Сигнатура
+
+```yql
+ListEnumerate(List<T>)->List<Tuple<Uint64, T>>
+ListEnumerate(List<T>?)->List<Tuple<Uint64, T>>?
+```
+
+## ListReverse {#listreverse}
+
+Развернуть список.
+
+### Примеры
+
+```yql
+SELECT ListReverse(list_column) FROM my_table;
+```
+
+### Сигнатура
+
+```yql
+ListReverse(List<T>)->List<T>
+ListReverse(List<T>?)->List<T>?
+```
+
+## ListSkip {#listskip}
+
+Возвращает копию списка с пропущенным указанным числом первых элементов.
+
+Первый аргумент — исходный список, второй — сколько элементов пропустить.
+
+### Примеры
+
+```yql
+SELECT
+ ListSkip(list_column, 3)
+FROM my_table;
+```
+
+```yql
+$l1 = AsList(1, 2, 3, 4, 5);
+
+SELECT ListSkip($l1, 2); -- [3,4,5]
+```
+
+### Сигнатура
+
+```yql
+ListSkip(List<T>, Uint64)->List<T>
+ListSkip(List<T>?, Uint64)->List<T>?
+```
+
+## ListTake {#listtake}
+
+Возвращает копию списка, состоящую из ограниченного числа элементов второго списка.
+
+Первый аргумент — исходный список, второй — не больше скольких элементов с начала оставить.
+
+### Примеры
+
+```yql
+SELECT ListTake(list_column, 3) FROM my_table;
+```
+
+```yql
+$l1 = AsList(1, 2, 3, 4, 5);
+
+SELECT ListTake($l1, 2); -- [1,2]
+```
+
+### Сигнатура
+
+```yql
+ListTake(List<T>, Uint64)->List<T>
+ListTake(List<T>?, Uint64)->List<T>?
+```
+
+## ListSample и ListSampleN {#listsample}
+
+Возвращает выборку без повторений из элементов списка.
+
+- `ListSample` выбирает каждый элемент независимо с заданной вероятностью.
+
+- `ListSampleN` выбирает фиксированное количество элементов (если длина списка меньше размера выборки, то вернется исходный список).
+
+Если вероятность/размер выборки является NULL, то вернется исходный список.
+
+Дополнительный аргумент используется для управления случайностью, подробнее см. [документацию к `Random`](basic.md#random).
+
+### Примеры
+
+```yql
+$list = AsList(1, 2, 3, 4, 5);
+
+SELECT ListSample($list, 0.5); -- [1, 2, 5]
+SELECT ListSampleN($list, 2); -- [4, 2]
+```
+
+### Сигнатура
+
+```yql
+ListSample(List<T>, Double?[, U])->List<T>
+ListSample(List<T>?, Double?[, U])->List<T>?
+
+ListSampleN(List<T>, Uint64?[, U])->List<T>
+ListSampleN(List<T>?, Uint64?[, U])->List<T>?
+```
+
+## ListShuffle {#listshuffle}
+
+Возвращает копию списка с элементами, перестановленными в случайном порядке. Дополнительный аргумент используется для управления случайностью, подробнее см. [документацию к `Random`](basic.md#random).
+
+### Примеры
+
+```yql
+$list = AsList(1, 2, 3, 4, 5);
+
+SELECT ListShuffle($list); -- [1, 3, 5, 2, 4]
+```
+
+### Сигнатура
+
+```yql
+ListShuffle(List<T>[, U])->List<T>
+ListShuffle(List<T>?[, U])->List<T>?
+```
+
+## ListIndexOf {#listindexof}
+
+Ищет элемент с указанным значением в списке и при первом обнаружении возвращает его индекс. Отсчет индексов начинается с 0, а в случае отсутствия элемента возвращается `NULL`.
+
+### Примеры
+
+```yql
+SELECT
+ ListIndexOf(list_column, 123)
+FROM my_table;
+```
+
+```yql
+$l1 = AsList(1, 2, 3, 4, 5);
+
+SELECT ListIndexOf($l1, 2); -- 1
+```
+
+### Сигнатура
+
+```yql
+ListIndexOf(List<T>, T)->Uint64?
+ListIndexOf(List<T>?, T)->Uint64?
+```
+
+## ListMap, ListFlatMap и ListFilter {#listmap}
+
+Применяют к каждому элементу списка указанную в качестве второго аргумента функцию. Различаются возвращаемым результатом:
+
+* `ListMap` — возвращает список с результатами;
+* `ListFlatMap` — возвращает список с результатами, объединяя и разворачивая первый уровень результатов (списков или опциональных значений) по каждому элементу;
+* `ListFilter` — оставляет только те элементы, для которых функция вернула `true`.
+
+{% note info %}
+
+В `ListFlatMap` использование опциональных значений в результатах функции является устаревшим, вместо этого следует использовать комбинацию [`ListNotNull`](#listnotnull) и `ListMap`.
+
+{% endnote %}
+
+Аргументы:
+
+1. Исходный список;
+2. Функции для обработки элементов, например:
+
+ * [Лямбда функция](../syntax/expressions.md#lambda);
+ * `Module::Function` - С++ UDF;
+
+Если исходный список является опциональным, то таким же является и выходной список.
+
+### Примеры
+
+```yql
+SELECT
+ ListMap(list_column, ($x) -> { RETURN $x > 2; }),
+ ListFlatMap(list_column, My::Udf)
+FROM my_table;
+```
+
+```yql
+$list = AsList("a", "b", "c");
+
+$filter = ($x) -> {
+ RETURN $x == "b";
+};
+
+SELECT ListFilter($list, $filter); -- ["b"]
+```
+
+```yql
+$list = AsList(1,2,3,4);
+$callable = Python::test(Callable<(Int64)->Bool>, "def test(i): return i % 2");
+SELECT ListFilter($list, $callable); -- [1,3]
+```
+
+### Сигнатура
+
+```yql
+ListMap(List<T>, (T)->U)->List<U>
+ListMap(List<T>?, (T)->U)->List<U>?
+
+ListFlatMap(List<T>, (T)->List<U>)->List<U>
+ListFlatMap(List<T>?, (T)->List<U>)->List<U>?
+ListFlatMap(List<T>, (T)->U?)->List<U>
+ListFlatMap(List<T>?, (T)->U?)->List<U>?
+
+ListFilter(List<T>, (T)->Bool)->List<T>
+ListFilter(List<T>?, (T)->Bool)->List<T>?
+```
+
+## ListNotNull {#listnotnull}
+
+Применяет трансформацию исходного списка, пропуская пустые опциональные элементы, и усиливает тип элемента до неопционального. Для списка с неопциональными элементами возвращает исходный список без изменений.
+
+Если исходный список является опциональным, то таким же является и выходной список.
+
+### Примеры
+
+```yql
+SELECT ListNotNull([1,2]), -- [1,2]
+ ListNotNull([3,null,4]); -- [3,4]
+```
+
+### Сигнатура
+
+```yql
+ListNotNull(List<T?>)->List<T>
+ListNotNull(List<T?>?)->List<T>?
+```
+
+## ListFlatten {#listflatten}
+
+Разворачивает список списков в плоский список с сохранением порядка элементов. В качестве элемента списка верхнего уровня поддерживается опциональный список, который интерпретируется как пустой в случае `NULL`.
+
+Если исходный список является опциональным, то таким же является и выходной список.
+
+### Примеры
+
+```yql
+SELECT ListFlatten([[1,2],[3,4]]), -- [1,2,3,4]
+ ListFlatten([null,[3,4],[5,6]]); -- [3,4,5,6]
+```
+
+### Сигнатура
+
+```yql
+ListFlatten(List<List<T>?>)->List<T>
+ListFlatten(List<List<T>?>?)->List<T>?
+```
+
+## ListUniq и ListUniqStable {#listuniq}
+
+Возвращает копию списка, в котором оставлен только уникальный набор элементов. В случае ListUniq порядок элементов результирующего набора не определен, в случае ListUniqStable элементы находятся в порядке вхождения в исходный список.
+
+### Примеры
+
+```yql
+SELECT ListUniq([1, 2, 3, 2, 4, 5, 1]) -- [5, 4, 2, 1, 3]
+SELECT ListUniqStable([1, 2, 3, 2, 4, 5, 1]) -- [1, 2, 3, 4, 5]
+SELECT ListUniqStable([1, 2, null, 7, 2, 8, null]) -- [1, 2, null, 7, 8]
+```
+
+### Сигнатура
+
+```yql
+ListUniq(List<T>)->List<T>
+ListUniq(List<T>?)->List<T>?
+
+ListUniqStable(List<T>)->List<T>
+ListUniqStable(List<T>?)->List<T>?
+```
+
+## ListAny и ListAll {#listany}
+
+Для списка булевых значений возвращает `true`, если:
+
+* `ListAny` — хотя бы один элемент равен `true`;
+* `ListAll` — все элементы равны `true`.
+
+В противном случае возвращает false.
+
+### Примеры
+
+```yql
+SELECT
+ ListAll(bool_column),
+ ListAny(bool_column)
+FROM my_table;
+```
+
+### Сигнатура
+
+```yql
+ListAny(List<Bool>)->Bool
+ListAny(List<Bool>?)->Bool?
+ListAll(List<Bool>)->Bool
+ListAll(List<Bool>?)->Bool?
+```
+
+## ListHas {#listhas}
+
+Содержит ли список указанный элемент. При этом `NULL` значения считаются равными друг другу, а при `NULL` входном списке результат всегда `false`.
+
+### Примеры
+
+```yql
+SELECT
+ ListHas(list_column, "my_needle")
+FROM my_table;
+```
+
+```yql
+$l1 = AsList(1, 2, 3, 4, 5);
+
+SELECT ListHas($l1, 2); -- true
+SELECT ListHas($l1, 6); -- false
+```
+
+### Сигнатура
+
+```yql
+ListHas(List<T>, U)->Bool
+ListHas(List<T>?, U)->Bool
+```
+
+## ListHead, ListLast {#listheadlast}
+
+Возвращают первый и последний элемент списка.
+
+### Примеры
+
+```yql
+SELECT
+ ListHead(numeric_list_column) AS head,
+ ListLast(numeric_list_column) AS last
+FROM my_table;
+```
+
+### Сигнатура
+
+```yql
+ListHead(List<T>)->T?
+ListHead(List<T>?)->T?
+ListLast(List<T>)->T?
+ListLast(List<T>?)->T?
+```
+
+## ListMin, ListMax, ListSum и ListAvg {#listminy}
+
+Применяет соответствующую агрегатную функцию ко всем элементам списка числовых значений.
+
+### Примеры
+
+```yql
+SELECT
+ ListMax(numeric_list_column) AS max,
+ ListMin(numeric_list_column) AS min,
+ ListSum(numeric_list_column) AS sum,
+ ListAvg(numeric_list_column) AS avg
+FROM my_table;
+```
+
+### Сигнатура
+
+```yql
+ListMin(List<T>)->T?
+ListMin(List<T>?)->T?
+```
+
+## ListFold, ListFold1 {#listfold}
+
+Свёртка списка.
+
+Аргументы:
+
+1. Список
+2. Начальное состояние U для ListFold, initLambda(item:T)->U для ListFold1
+3. updateLambda(item:T, state:U)->U
+
+Возвращаемый тип:
+U для ListFold, опциональный U для ListFold1.
+
+### Примеры
+
+```yql
+$l = [1, 4, 7, 2];
+$y = ($x, $y) -> { RETURN $x + $y; };
+$z = ($x) -> { RETURN 4 * $x; };
+
+SELECT
+ ListFold($l, 6, $y) AS fold, -- 20
+ ListFold([], 3, $y) AS fold_empty, -- 3
+ ListFold1($l, $z, $y) AS fold1, -- 17
+ ListFold1([], $z, $y) AS fold1_empty; -- Null
+```
+
+### Сигнатура
+
+```yql
+ListFold(List<T>, U, (T, U)->U)->U
+ListFold(List<T>?, U, (T, U)->U)->U?
+
+ListFold1(List<T>, (T)->U, (T, U)->U)->U?
+ListFold1(List<T>?, (T)->U, (T, U)->U)->U?
+```
+
+## ListFoldMap, ListFold1Map {#listfoldmap}
+
+Преобразует каждый элемент i в списке путём вызова handler(i, state).
+
+Аргументы:
+
+1. Список
+2. Начальное состояние S для ListFoldMap, initLambda(item:T)->кортеж (U S) для ListFold1Map
+3. handler(item:T, state:S)->кортеж (U S)
+
+Возвращаемый тип:
+Список элементов U.
+
+### Примеры
+
+```yql
+$l = [1, 4, 7, 2];
+$x = ($i, $s) -> { RETURN ($i * $s, $i + $s); };
+$t = ($i) -> { RETURN ($i + 1, $i + 2); };
+
+SELECT
+ ListFoldMap([], 1, $x), -- []
+ ListFoldMap($l, 1, $x), -- [1, 8, 42, 26]
+ ListFold1Map([], $t, $x), -- []
+ ListFold1Map($l, $t, $x); -- [2, 12, 49, 28]
+```
+
+### Сигнатура
+
+```yql
+ListFoldMap(List<T>, S, (T, S)->Tuple<U,S>)->List<U>
+ListFoldMap(List<T>?, S, (T, S)->Tuple<U,S>)->List<U>?
+
+ListFold1Map(List<T>, (T)->Tuple<U,S>, (T, S)->Tuple<U,S>)->List<U>
+ListFold1Map(List<T>?, (T)->Tuple<U,S>, (T, S)->Tuple<U,S>)->List<U>?
+```
+
+## ListFromRange {#listfromrange}
+
+Генерация последовательности чисел или дат с указанным шагом. Аналог `xrange` в Python 2, но дополнительно с поддержкой дат и чисел с плавающей точкой.
+
+Аргументы:
+
+1. Начало
+2. Конец
+3. Шаг. Опционально, по умолчанию 1 для числовых последовательностей, 1 день для `Date`/`TzDate`, 1 секунда для `Datetime`/`TzDatetime` и 1 микросекунда для `Timestamp`/`TzTimestamp`/`Interval`
+
+Особенности:
+
+* Конец не включительный, т.е. `ListFromRange(1,3) == AsList(1,2)`.
+* Тип элементов результатов выбирается как наиболее широкий из типов аргументов, например результатом `ListFromRange(1, 2, 0.5)` получится список `Double`.
+* Если начало и конец имеют один из типов дат, то шаг должен иметь тип `Interval`.
+* Список является «ленивым», но при неправильном использовании всё равно может привести к потреблению большого объема оперативной памяти.
+* Если шаг положительный и конец меньше или равен началу, то список будет пустой.
+* Если шаг отрицательный и конец больше или равен началу, то список будет пустой.
+* Если шаг не положительный и не отрицательный (0 или NaN), то список будет пустой.
+* Если один из параметров опциональный, то результат будет опциональный список.
+* Если один из параметров равен `NULL`, то результат будет `NULL`.
+
+### Примеры
+
+```yql
+SELECT
+ ListFromRange(-2, 2), -- [-2, -1, 0, 1]
+ ListFromRange(2, 1, -0.5); -- [2.0, 1.5]
+```
+
+```yql
+SELECT ListFromRange(Datetime("2022-05-23T15:30:00Z"), Datetime("2022-05-30T15:30:00Z"), DateTime::IntervalFromDays(1));
+```
+
+### Сигнатура
+
+```yql
+ListFromRange(T{Flags:AutoMap}, T{Flags:AutoMap}, T?)->LazyList<T> -- T — числовой тип
+ListFromRange(T{Flags:AutoMap}, T{Flags:AutoMap}, I?)->LazyList<T> -- T — тип, представляющий дату/время, I — интервал
+```
+
+## ListReplicate {#listreplicate}
+
+Создает список из нескольких копий указанного значения.
+
+Обязательные аргументы:
+
+1. Значение;
+2. Число копий.
+
+### Примеры
+
+```yql
+SELECT ListReplicate(true, 3); -- [true, true, true]
+```
+
+### Сигнатура
+
+```yql
+ListReplicate(T, Uint64)->List<T>
+```
+
+## ListConcat {#listconcat}
+
+Объединяет список строк в одну строку.
+Вторым параметром можно задать разделитель.
+
+### Примеры
+
+```yql
+SELECT
+ ListConcat(string_list_column),
+ ListConcat(string_list_column, "; ")
+FROM my_table;
+```
+
+```yql
+$l1 = AsList("h", "e", "l", "l", "o");
+
+SELECT ListConcat($l1); -- "hello"
+SELECT ListConcat($l1, " "); -- "h e l l o"
+```
+
+### Сигнатура
+
+```yql
+ListConcat(List<String>)->String?
+ListConcat(List<String>?)->String?
+
+ListConcat(List<String>, String)->String?
+ListConcat(List<String>?, String)->String?
+```
+
+## ListExtract {#listextract}
+
+По списку структур возвращает список содержащихся в них полей с указанным именем.
+
+### Примеры
+
+```yql
+SELECT
+ ListExtract(struct_list_column, "MyMember")
+FROM my_table;
+```
+
+```yql
+$l = AsList(
+ <|key:"a", value:1|>,
+ <|key:"b", value:2|>
+);
+SELECT ListExtract($l, "key"); -- ["a", "b"]
+```
+
+### Сигнатура
+
+```yql
+ListExtract(List<Struct<..>>, String)->List<T>
+ListExtract(List<Struct<..>>?, String)->List<T>?
+```
+
+## ListTakeWhile, ListSkipWhile {#listtakewhile}
+
+`ListTakeWhile` выдает список от начала, пока предикат истинный, далее список заканчивается.
+
+`ListSkipWhile` пропускает отрезок списка от начала, пока предикат истинный, далее выдает остаток список не обращая внимания на предикат.
+`ListTakeWhileInclusive` выдает список от начала, пока предикат истинный, далее список заканчивается, но также включает элемент, на котором сработал останавливающий предикат.
+`ListSkipWhileInclusive` пропускает отрезок списка от начала, пока предикат истинный, далее выдает остаток список не обращая внимания на предикат, но не включая элемент, на котором сработал предикат, а начинает со следующего за ним.
+
+Обязательные аргументы:
+
+1. Список;
+2. Предикат.
+
+Если входной список является опциональным, то таким же является и результат.
+
+### Примеры
+
+```yql
+$data = AsList(1, 2, 5, 1, 2, 7);
+
+SELECT
+ ListTakeWhile($data, ($x) -> {return $x <= 3}), -- [1, 2]
+ ListSkipWhile($data, ($x) -> {return $x <= 3}), -- [5, 1, 2, 7]
+ ListTakeWhileInclusive($data, ($x) -> {return $x <= 3}), -- [1, 2, 5]
+ ListSkipWhileInclusive($data, ($x) -> {return $x <= 3}); -- [1, 2, 7]
+```
+
+### Сигнатура
+
+```yql
+ListTakeWhile(List<T>, (T)->Bool)->List<T>
+ListTakeWhile(List<T>?, (T)->Bool)->List<T>?
+```
+
+## ListAggregate {#listaggregate}
+
+Применить [фабрику агрегационных функций](basic.md#aggregationfactory) для переданного списка.
+Если переданный список является пустым, то результат агрегации будет такой же, как для пустой таблицы: 0 для функции `COUNT` и `NULL` для других функций.
+Если переданный список является опциональным и равен `NULL`, то в результате также будет `NULL`.
+
+Аргументы:
+
+1. Список;
+2. [Фабрика агрегационных функций](basic.md#aggregationfactory).
+
+### Примеры
+
+```yql
+SELECT ListAggregate(AsList(1, 2, 3), AggregationFactory("Sum")); -- 6
+```
+
+### Сигнатура
+
+```yql
+ListAggregate(List<T>, AggregationFactory)->T
+ListAggregate(List<T>?, AggregationFactory)->T?
+```
+
+## ToDict и ToMultiDict {#todict}
+
+Преобразуют список из кортежей с парами ключ-значение в словарь. В случае конфликтов по ключам во входном списке `ToDict` оставляет первое значение, а `ToMultiDict` — собирает из всех значений список.
+
+Таким образом:
+
+* `ToDict` из `List<Tuple<K, V>>` делает `Dict<K, V>`
+* `ToMultiDict` из `List<Tuple<K, V>>` делает `Dict<K, List<V>>`
+
+Также поддерживаются опциональные списки, что приводит к опциональному словарю в результате.
+
+### Примеры
+
+```yql
+SELECT
+ ToDict(tuple_list_column)
+FROM my_table;
+```
+
+```yql
+$l = AsList(("a",1), ("b", 2), ("a", 3));
+SELECT ToDict($l); -- {"a": 1,"b": 2}
+```
+
+### Сигнатура
+
+```yql
+ToDict(List<Tuple<K,V>>)->Dict<K,V>
+ToDict(List<Tuple<K,V>>?)->Dict<K,V>?
+```
+
+## ToSet {#toset}
+
+Преобразует список в словарь, в котором ключи являются уникальными элементами этого списка, а значения отсутствуют и имеют тип `Void`. Для списка `List<T>` тип результата будет `Dict<T, Void>`.
+Также поддерживается опциональный список, что приводит к опциональному словарю в результате.
+
+Обратная функция - получить список ключей словаря [DictKeys](dict.md#dictkeys).
+
+### Примеры
+
+```yql
+SELECT
+ ToSet(list_column)
+FROM my_table;
+```
+
+```yql
+$l = AsList(1,1,2,2,3);
+SELECT ToSet($l); -- {1,2,3}
+```
+
+### Сигнатура
+
+```yql
+ToSet(List<T>)->Set<T>
+ToSet(List<T>?)->Set<T>?
+```
+
+## ListFromTuple
+
+Строит список из кортежа, в котором типы элементов совместимы друг с другом. Для опционального кортежа на выходе получается опциональный список. Для NULL аргумента - NULL. Для пустого кортежа - EmptyList.
+
+### Примеры
+
+```yql
+$t = (1,2,3);
+SELECT ListFromTuple($t); -- [1,2,3]
+```
+
+### Сигнатура
+
+```yql
+ListFromTuple(Null)->Null
+ListFromTuple(Tuple<>)->EmptyList
+ListFromTuple(Tuple<T1,T2,...>)->List<T>
+ListFromTuple(Tuple<T1,T2,...>?)->List<T>?
+```
+
+## ListToTuple
+
+Строит кортеж из списка и явно указанной ширины кортежа. Все элементы кортежа будут иметь тот же тип, что и тип элемента списка. Если длина списка не соотвествует указанной ширине кортежа, будет возвращена ошибка. Для опционального списка на выходе получается опциональный кортеж. Для NULL аргумента - NULL.
+
+### Примеры
+
+```yql
+$l = [1,2,3];
+SELECT ListToTuple($l, 3); -- (1,2,3)
+```
+
+### Сигнатура
+
+```yql
+ListToTuple(Null,N)->Null
+ListToTuple(EmptyList,N)->()) -- N должен быть 0
+ListToTuple(List<T>, N)->Tuple<T,T,...T> -- ширина кортежа N
+ListToTuple(List<T>?, N)->Tuple<T,T,...T>? -- ширина кортежа N
+```
+
+## ListTop, ListTopAsc, ListTopDesc, ListTopSort, ListTopSortAsc и ListTopSortDesc {#listtop}
+
+Выбрать топ значениий из списка. `ListTopSort*` — дополнительно отсортировать список возвращенных значений. По умолчанию выбираются наименьшие значения (функции без суффикса — алиас к функциям `*Asc`; `*Desc` — выбор наибольших значений).
+
+`ListTopSort` эффективнее, чем последовательные `ListTop` и `ListSort`, так как `ListTop` может уже частично отсортировать список для поиска нужных значений. Однако, `ListTop` эффективнее `ListTopSort`, если сортировка не нужна.
+
+Аргументы:
+
+1. Список;
+2. Размер выборки;
+3. Опциональное выражение для получения ключа сортировки из элемента списка (по умолчанию сам элемент).
+
+### Сигнатура
+
+```yql
+ListTop(List<T>{Flags:AutoMap}, N)->List<T>
+ListTop(List<T>{Flags:AutoMap}, N, (T)->U)->List<T>
+```
+
+Сигнатуры остальных функций совпадают с `ListTop`.
+
diff --git a/yql/essentials/docs/ru/builtins/struct.md b/yql/essentials/docs/ru/builtins/struct.md
new file mode 100644
index 0000000000..6fdfd3475b
--- /dev/null
+++ b/yql/essentials/docs/ru/builtins/struct.md
@@ -0,0 +1,470 @@
+
+# Функции для работы со структурами
+
+## TryMember {#trymember}
+
+Попытка получить значение поля из структуры, а в случае его отсутствия среди полей или null в значении структуры использовать значение по умолчанию.
+Тип `default_value` должен совпадать с типом поля `key` из структуры.
+
+### Сигнатура
+
+```yql
+TryMember(struct:Struct<...>, key:String, default_value:T) -> T
+TryMember(struct:Struct<...>?, key:String, default_value:T) -> T?
+```
+
+Аргументы:
+
+1. struct - исходная структура;
+2. key - имя поля;
+3. default_value - значение по умолчанию если поле отсутствует
+
+{% note info %}
+
+Имя поля (key) не может зависеть от данных или от аргументов лямбды. В этом случае функция TryMember не может быть протипизирована.
+
+{% endnote %}
+
+### Примеры
+
+```yql
+$struct = <|a:1|>;
+SELECT
+ TryMember(
+ $struct,
+ "a",
+ 123
+ ) AS a, -- 1
+ TryMember(
+ $struct,
+ "b",
+ 123
+ ) AS b; -- 123
+```
+
+## ExpandStruct {#expandstruct}
+
+Добавление одного или нескольких новых полей в структуру. Возвращается новая раширенная структура. В случае возникновения дублей в наборе полей будет возвращена ошибка.
+
+### Сигнатура
+
+```yql
+ExpandStruct(struct:Struct<...>, value_1:T1 AS key_1:K, value_2:T2 AS key_2:K, ....) -> Struct<...>
+```
+
+Аргументы:
+
+* В первый аргумент передается исходная структура для расширения.
+* Все остальные аргументы должны быть именованными, каждый аргумент добавляет новое поле и имя аргумента используется в роли имени поля (по аналогии с [AsStruct](basic.md#asstruct)).
+
+### Примеры
+
+```yql
+$struct = <|a:1|>;
+SELECT
+ ExpandStruct(
+ $struct,
+ 2 AS b,
+ "3" AS c
+ ) AS abc; -- ("a": 1, "b": 2, "c": "3")
+```
+
+## AddMember {#addmember}
+
+Добавление одного нового поля в структуру. Если необходимо добавление нескольких полей, предпочтительнее использовать [ExpandStruct](#expandstruct).
+
+В случае возникновения дублей в наборе полей будет возвращена ошибка.
+
+### Сигнатура
+
+```yql
+AddMember(struct:Struct<...>, new_key:String, new_value:T) -> Struct<...>
+```
+
+Аргументы:
+
+1. struct - исходная структура;
+2. new_key - имя нового поля;
+3. new_value - значение нового поля.
+
+### Примеры
+
+```yql
+$struct = <|a:1|>;
+SELECT
+ AddMember(
+ $struct,
+ "b",
+ 2
+ ) AS ab; -- ("a": 1, "b": 2)
+```
+
+## RemoveMember {#removemember}
+
+Удаление поля из структуры. Если указанного поля не существовало, будет возвращена ошибка.
+
+### Сигнатура
+
+```yql
+RemoveMember(struct:Struct<...>, key_to_delete:String) -> Struct<...>
+```
+
+Аргументы:
+
+1. Исходная структура;
+2. Имя поля для удаления
+
+### Примеры
+
+```yql
+$struct = <|a:1, b:2|>;
+SELECT
+ RemoveMember(
+ $struct,
+ "b"
+ ) AS a; -- ("a": 1)
+```
+
+## ForceRemoveMember {#forceremovemember}
+
+Удаление поля из структуры.
+
+Если указанного поля не существовало, в отличии от [RemoveMember](#removemember) ошибка возвращена не будет.
+
+### Сигнатура
+
+```yql
+ForceRemoveMember(struct:Struct<...>, key_to_delete:String) -> Struct<...>
+```
+
+Аргументы:
+
+1. Исходная структура;
+2. Имя поля для удаления.
+
+### Примеры
+
+```yql
+$struct = <|a:1, b:2|>;
+SELECT
+ ForceRemoveMember(
+ $struct,
+ "c"
+ ) AS ab; -- ("a": 1, "b": 2)
+```
+
+## ChooseMembers {#choosemembers}
+
+Выделение из структуры полей с заданными именами. Возвращается новая структура только из заданных полей.
+
+Если какого-либо из полей не существовало, будет возвращена ошибка.
+
+### Сигнатура
+
+```yql
+ChooseMembers(struct:Struct<...>, list_of_keys:List<String>) -> Struct<...>
+```
+
+Аргументы:
+
+1. Исходная структура;
+2. Список имен полей.
+
+### Примеры
+
+```yql
+$struct = <|a:1, b:2, c:3|>;
+SELECT
+ ChooseMembers(
+ $struct,
+ ["a", "b"]
+ ) AS ab; -- ("a": 1, "b": 2)
+```
+
+## RemoveMembers {#removemembers}
+
+Исключение из структуры полей с заданными именами.
+
+Если какого-либо из полей не существовало, будет возвращена ошибка.
+
+### Сигнатура
+
+```yql
+RemoveMembers(struct:Struct<...>, list_of_delete_keys:List<String>) -> Struct<...>
+```
+
+Аргументы:
+
+1. Исходная структура;
+2. Список имен полей.
+
+### Примеры
+
+```yql
+$struct = <|a:1, b:2, c:3|>;
+SELECT
+ RemoveMembers(
+ $struct,
+ ["a", "b"]
+ ) AS c; -- ("c": 3)
+```
+
+## ForceRemoveMembers {#forceremovemembers}
+
+Исключение из структуры полей с заданными именами.
+
+Если какого-либо из полей не существовало, то оно игнорируется.
+
+### Сигнатура
+
+```yql
+ForceRemoveMembers(struct:Struct<...>, list_of_delete_keys:List<String>) -> Struct<...>
+```
+
+Аргументы:
+
+1. Исходная структура;
+2. Список имен полей.
+
+### Примеры
+
+```yql
+$struct = <|a:1, b:2, c:3|>;
+SELECT
+ ForceRemoveMembers(
+ $struct,
+ ["a", "b", "z"]
+ ) AS c; -- ("c": 3)
+```
+
+## CombineMembers {#combinemembers}
+
+Объединение полей нескольких структур в новую структуру.
+
+В случае возникновения дублей в результирующем наборе полей будет возвращена ошибка.
+
+### Сигнатура
+
+```yql
+CombineMembers(struct1:Struct<...>, struct2:Struct<...>, .....) -> Struct<...>
+CombineMembers(struct1:Struct<...>?, struct2:Struct<...>?, .....) -> Struct<...>
+```
+
+Аргументы: две и более структуры.
+
+### Примеры
+
+```yql
+$struct1 = <|a:1, b:2|>;
+$struct2 = <|c:3|>;
+SELECT
+ CombineMembers(
+ $struct1,
+ $struct2
+ ) AS abc; -- ("a": 1, "b": 2, "c": 3)
+```
+
+## FlattenMembers {#flattenmembers}
+
+Объединение полей нескольких новых структур в новую структуру с поддержкой префиксов.
+
+В случае возникновения дублей в результирующем наборе полей будет возвращена ошибка.
+
+### Сигнатура
+
+```yql
+FlattenMembers(prefix_struct1:Tuple<String, Struct<...>>, prefix_struct2:Tuple<String, Struct<...>>, ...) -> Struct<...>
+```
+
+Аргументы: два и более кортежа из двух элементов: префикс и структура.
+
+### Примеры
+
+```yql
+$struct1 = <|a:1, b:2|>;
+$struct2 = <|c:3|>;
+SELECT
+ FlattenMembers(
+ AsTuple("foo", $struct1), -- fooa, foob
+ AsTuple("bar", $struct2) -- barc
+ ) AS abc; -- ("barc": 3, "fooa": 1, "foob": 2)
+```
+
+## StructMembers {#structmembers}
+
+Возвращает неупорядоченный список имен полей (возможно, сняв один уровень опциональности) для единственного аргумента - структуры. Для `NULL` аргумента возвращается пустой список строк.
+
+### Сигнатура
+
+```yql
+StructMembers(struct:Struct<...>) -> List<String>
+StructMembers(struct:Struct<...>?) -> List<String>
+StructMembers(NULL) -> []
+```
+
+Аргумент: структура
+
+### Примеры
+
+```yql
+$struct = <|a:1, b:2|>;
+SELECT
+ StructMembers($struct) AS a, -- ['a', 'b']
+ StructMembers(NULL) AS b; -- []
+```
+
+## RenameMembers {#renamemembers}
+
+Переименовывает поля в переданной структуре. При этом исходное поле можно переименовать в несколько новых. Все поля, не упомянутые в переименовании как исходные, переносятся в результирующую структуру. Если нет какого-то исходного поля в списке для переименования, выдается ошибка. Для опциональной структуры либо `NULL` таким же является и результат.
+
+### Сигнатура
+
+```yql
+RenameMembers(struct:Struct<...>, rename_rules:List<Tuple<String, String>>) -> Struct<...>
+```
+
+Аргументы:
+
+1. Исходная структура;
+2. Список имен полей в форме списка таплов: исходное имя, новое имя.
+
+### Примеры
+
+```yql
+$struct = <|a:1, b:2|>;
+SELECT
+ RenameMembers($struct, [('a', 'c'), ('a', 'e')]); -- (b:2, c:1, e:1)
+```
+
+## ForceRenameMembers {#forecerenamemembers}
+
+Переименовывает поля в переданной структуре. При этом исходное поле можно переименовать в несколько новых. Все поля, не упомянутые в переименовании как исходные, переносятся в результирующую структуру. Если нет какого-то исходного поля в списке для переименования, оно игнорируется. Для опциональной структуры либо `NULL` таким же является и результат.
+
+### Сигнатура
+
+```yql
+ForceRenameMembers(struct:Struct<...>, rename_rules:List<Tuple<String, String>>) -> Struct<...>
+```
+
+Аргументы:
+
+1. Исходная структура;
+2. Список имен полей в форме списка таплов: исходное имя, новое имя.
+
+### Примеры
+
+```yql
+$struct = <|a:1, b:2|>;
+SELECT
+ ForceRenameMembers($struct, [('a', 'c'), ('d', 'e')]); -- (b:2, c:1)
+```
+
+## GatherMembers {#gathermembers}
+
+Возвращает неупорядоченный список таплов из имени поля и значения. Для `NULL` аргумента возвращается `EmptyList`. Можно использовать только в тех случаях, когда типы элементов в структуре одинаковы или совместимы. Для опциональной структуры возвращает опциональный список.
+
+### Сигнатура
+
+```yql
+GatherMembers(struct:Struct<...>) -> List<Tuple<String,V>>
+GatherMembers(struct:Struct<...>?) -> List<Tuple<String,V>>?
+GatherMembers(NULL) -> []
+```
+
+Аргумент: структура
+
+### Примеры
+
+```yql
+$struct = <|a:1, b:2|>;
+SELECT
+ GatherMembers($struct), -- [('a', 1), ('b', 2)]
+ GatherMembers(null); -- []
+```
+
+## SpreadMembers {#spreadmembers}
+
+Создает структуру с заданным списком полей и применяет к ней заданный список исправлений в формате (имя поля, значение). Все типы полей результирующей структуры совпадают, и равны типу значений в списке исправлений с добавленной опциональностью (если еще не были таковыми). Если поле не было упомянуто среди списка редактируемых полей, оно возвращается как `NULL`. Среди всех исправлений по одному полю сохраняется последнее. Если в списке исправлений встречается поле, которого нет в списке ожидаемых полей, выдается ошибка.
+
+### Сигнатура
+
+```yql
+SpreadMembers(list_of_tuples:List<Tuple<String, T>>, result_keys:List<String>) -> Struct<...>
+```
+
+Аргументы:
+
+1. Список таплов: имя поля, значение поля;
+2. Список всех возможных имен полей в структуре.
+
+### Примеры
+
+```yql
+SELECT
+ SpreadMembers([('a',1),('a',2)],['a','b']); -- (a: 2, b: null)
+```
+
+## ForceSpreadMembers {#forcespreadmembers}
+
+Создает структуру с заданным списком полей и применяет к ней заданный список исправлений в формате (имя поля, значение). Все типы полей результирующей структуры совпадают, и равны типу значений в списке исправлений с добавленной опциональностью (если еще не были таковыми). Если поле не было упомянуто среди списка редактируемых полей, оно возвращается как `NULL`. Среди всех исправлений по одному полю сохраняется последнее. Если в списке исправлений встречается поле, которого нет в списке ожидаемых полей, то это исправление игнорируется.
+
+### Сигнатура
+
+```yql
+ForceSpreadMembers(list_of_tuples:List<Tuple<String, T>>, result_keys:List<String>) -> Struct<...>
+```
+
+Аргументы:
+
+1. Список таплов: имя поля, значение поля;
+2. Список всех возможных имен полей в структуре.
+
+### Примеры
+
+```yql
+SELECT
+ ForceSpreadMembers([('a',1),('a',2),('c',100)],['a','b']); -- (a: 2, b: null)
+```
+
+## StructUnion, StructIntersection, StructDifference, StructSymmetricDifference
+
+Комбинируют две структуры одним из четырех способов, используя предоставленную функцию для слияния полей с одинаковыми именами:
+
+* `StructUnion` добавляет в результат все поля обеих структур;
+* `StructIntersection` — поля, которые есть в обеих структурах;
+* `StructDifference` — поля которые есть в left, но которых нет в right;
+* `StructSymmetricDifference` — все поля, которые есть только в одной из структур.
+
+### Сигнатуры
+
+```yql
+StructUnion(left:Struct<...>, right:Struct<...>[, mergeLambda:(name:String, l:T1?, r:T2?)->T])->Struct<...>
+StructIntersection(left:Struct<...>, right:Struct<...>[, mergeLambda:(name:String, l:T1?, r:T2?)->T])->Struct<...>
+StructDifference(left:Struct<...>, right:Struct<...>)->Struct<...>
+StructSymmetricDifference(left:Struct<...>, right:Struct<...>)->Struct<...>
+```
+
+Аргументы:
+
+1. `left` - первая структура;
+2. `right` - вторая структура;
+3. `mergeLambda` - _(опционально)_ позволяет задать функцию для объединения полей (аргументы: имя поля, `Optional` значение поля в первой структуре, `Optional` значение поля во второй структуре - аргументы принимают значение `Nothing<T?>` в случае отсутствия соответствующего поля); по умолчанию выбирается значение поля из первой структуры, а если в первой отсутствует — из второй.
+
+### Примеры
+
+```yql
+$merge = ($name, $l, $r) -> {
+ return ($l ?? 0) + ($r ?? 0);
+};
+$left = <|a: 1, b: 2, c: 3|>;
+$right = <|c: 1, d: 2, e: 3|>;
+
+SELECT
+ StructUnion($left, $right), -- <|a: 1, b: 2, c: 3, d: 2, e: 3|>
+ StructUnion($left, $right, $merge), -- <|a: 1, b: 2, c: 4, d: 2, e: 3|>
+ StructIntersection($left, $right, $merge), -- <|c: 4|>
+ StructDifference($left, $right), -- <|a: 1, b: 1|>
+ StructSymmetricDifference($left, $right) -- <|a: 1, b: 2, d: 2, e: 3|>
+;
+```
+
diff --git a/yql/essentials/docs/ru/builtins/toc_i.yaml b/yql/essentials/docs/ru/builtins/toc_i.yaml
new file mode 100644
index 0000000000..15d55542d5
--- /dev/null
+++ b/yql/essentials/docs/ru/builtins/toc_i.yaml
@@ -0,0 +1,13 @@
+items:
+- { name: Обзор, href: index.md }
+- { name: Базовые, href: basic.md }
+- { name: Агрегатные, href: aggregation.md }
+- { name: Оконные, href: window.md }
+- { name: Для работы со списками, href: list.md }
+- { name: Для работы со словарями, href: dict.md }
+- { name: Для работы со структурами, href: struct.md }
+- { name: Для работы с типами, href: types.md }
+- { name: Для работы с генерацией кода, href: codegen.md }
+- { name: Для работы с JSON, href: json.md }
+- name: Библиотеки C++
+ include: { mode: link, path: ../udf/list/toc_i.yaml }
diff --git a/yql/essentials/docs/ru/builtins/types.md b/yql/essentials/docs/ru/builtins/types.md
new file mode 100644
index 0000000000..ec05c53b53
--- /dev/null
+++ b/yql/essentials/docs/ru/builtins/types.md
@@ -0,0 +1,986 @@
+
+# Функции для работы с типами данных
+
+Помимо обычных функций, которые работают с конкретными значениями (типа FIND, COALESCE), YQL поддерживает функции для работами с [типами](../types/index.md).
+Функции позволяют узнать тип произвольного выражения, проанализировать контейнерный тип и создавть новый контейнерный тип на основе имеющегося.
+
+## Примеры
+
+```yql
+$itemType = TypeOf($item);
+SELECT CAST($foo AS ListType($itemType)); -- каст $foo к типу List<$itemType>
+```
+
+## FormatType {#formattype}
+
+### Сигнатура
+
+```yql
+FormatType(Type)->String
+FormatType(TypeHandle)->String
+```
+
+Сериализация типа или хендла типа в человекочитаемую строку. Это полезно для отладки, а также будет использоваться в последующих примерах данного раздела. [Документация по формату](../types/type_string.md).
+
+## FormatTypeDiff и FormatTypeDiffPretty {#formattypediff}
+
+### Сигнатура
+
+```yql
+FormatTypeDiff(Type, Type)->String
+FormatTypeDiff(TypeHandle, TypeHandle)->String
+
+FormatTypeDiffPretty(Type, Type)->String
+FormatTypeDiffPretty(TypeHandle, TypeHandle)->String
+```
+
+Получение строкового представления разницы двух типов или двух хендлов типов. Pretty-версия делает результирующую строку более читаемой путем добавления переводов строк и пробелов.
+
+## ParseType {#parsetype}
+
+### Сигнатура
+
+```yql
+ParseType(String)->Type
+```
+
+Построение типа по строке с его описанием. [Документация по её формату](../types/type_string.md).
+
+### Примеры
+
+```yql
+SELECT FormatType(ParseType("List<Int32>")); -- List<int32>
+```
+
+## TypeOf {#typeof}
+
+### Сигнатура
+
+```yql
+TypeOf(<any expression>)->Type
+```
+
+Получение типа значения, переданного в аргумент.
+
+### Примеры
+
+```yql
+SELECT FormatType(TypeOf("foo")); -- String
+```
+
+```yql
+SELECT FormatType(TypeOf(AsTuple(1, 1u))); -- Tuple<Int32,Uint32>
+```
+
+## InstanceOf {#instanceof}
+
+### Сигнатура
+
+```yql
+InstanceOf(Type)->объект типа Type
+```
+
+Возвращает экземпляр объекта указанного типа. Полученный объект не имеет какого-то определенного значения.
+InstanceOf можно использовать только в том случае, если результат выражения в котором InstanceOf используется зависит от типа InstanceOf, но не от значения.
+В противном случае операция будет завершена с ошибкой.
+
+### Примеры
+
+```yql
+SELECT InstanceOf(ParseType("Int32")) + 1.0; -- ошибка (Can't execute InstanceOf): результат зависит от (неопределенного) значения InstanceOf
+SELECT FormatType(TypeOf(
+ InstanceOf(ParseType("Int32")) +
+ InstanceOf(ParseType("Double"))
+)); -- вернет Double, так как сложение Int32 и Double возвращает Double (InstanceOf используется в контексте, где важен только его тип, но не значение)
+```
+
+## DataType {#datatype}
+
+### Сигнатура
+
+```yql
+DataType(String, [String, ...])->Type
+```
+
+Возвращает тип для [примитивных типов данных](../types/primitive.md) по его имени.
+Для некоторых типов (например Decimal) необходимо передавать параметры типа в качестве дополнительных аргументов.
+
+### Примеры
+
+```yql
+SELECT FormatType(DataType("Bool")); -- Bool
+SELECT FormatType(DataType("Decimal","5","1")); -- Decimal(5,1)
+```
+
+## OptionalType {#optionaltype}
+
+### Сигнатура
+
+```yql
+OptionalType(Type)->опциональный Type
+```
+
+Добавляет в переданный тип возможность содержать `NULL`.
+
+### Примеры
+
+```yql
+SELECT FormatType(OptionalType(DataType("Bool"))); -- Bool?
+SELECT FormatType(OptionalType(ParseType("List<String?>"))); -- List<String?>?
+```
+
+## ListType и StreamType {#listtype}
+
+### Сигнатура
+
+```yql
+ListType(Type)->тип списка с элементами типа Type
+StreamType(Type)->тип потока с элементами типа Type
+```
+
+Строит тип списка или потока по переданному типу элемента.
+
+### Примеры
+
+```yql
+SELECT FormatType(ListType(DataType("Bool"))); -- List<Bool>
+```
+
+## DictType {#dicttype}
+
+### Сигнатура
+
+```yql
+DictType(Type, Type)->тип словаря
+```
+
+Строит тип словаря по переданным типам ключа (первый аргумент) и значения (второй аргумент).
+
+### Примеры
+
+```yql
+SELECT FormatType(DictType(
+ DataType("String"),
+ DataType("Double")
+)); -- Dict<String,Double>
+```
+
+## TupleType {#tupletype}
+
+### Сигнатура
+
+```yql
+TupleType(Type, ...)->тип кортежа
+```
+
+Строит тип кортежа по переданным типам элементов.
+
+### Примеры
+
+```yql
+SELECT FormatType(TupleType(
+ DataType("String"),
+ DataType("Double"),
+ OptionalType(DataType("Bool"))
+)); -- Tuple<String,Double,Bool?>
+```
+
+## StructType {#structtype}
+
+### Сигнатура
+
+```yql
+StructType(Type AS ElementName1, Type AS ElementName2, ...)->тип структуры
+```
+
+Строит тип структуры по переданным типам элементов. Для указания имен элементов используется стандартный синтаксис именованных аргументов.
+
+### Примеры
+
+```yql
+SELECT FormatType(StructType(
+ DataType("Bool") AS MyBool,
+ ListType(DataType("String")) AS StringList
+)); -- Struct<'MyBool':Bool,'StringList':List<String>>
+```
+
+## VariantType {#varianttype}
+
+### Сигнатура
+
+```yql
+VariantType(StructType)->тип варианта над структурой
+VariantType(TupleType)->тип варианта над кортежем
+```
+
+Возвращает тип варианта по низлежащему типу (структуры или кортежа).
+
+### Примеры
+
+```yql
+SELECT FormatType(VariantType(
+ ParseType("Struct<foo:Int32,bar:Double>")
+)); -- Variant<'bar':Double,'foo':Int32>
+```
+
+## ResourceType {#resourcetype}
+
+### Сигнатура
+
+```yql
+ResourceType(String)->тип ресурса
+```
+
+Возвращает тип [ресурса](../types/special.md) по переданной строковой метке.
+
+### Примеры
+
+```yql
+SELECT FormatType(ResourceType("Foo")); -- Resource<'Foo'>
+```
+
+## CallableType {#callabletype}
+
+### Сигнатура
+
+```yql
+CallableType(Uint32, Type, [Type, ...])->тип вызываемого значения
+```
+
+Строит тип вызываемого значения по следующим аргументам:
+
+1. Число опциональных аргументов (если все обязательные — 0).
+2. Тип результата.
+3. Все последующие аргументы CallableType трактуются как типы аргументов вызываемого значения со сдвигом на два обязательных (например, третий аргумент CallableType описывает тип первого аргумента вызываемого значения).
+
+### Примеры
+
+```yql
+SELECT FormatType(CallableType(
+ 1, -- optional args count
+ DataType("Double"), -- result type
+ DataType("String"), -- arg #1 type
+ OptionalType(DataType("Int64")) -- arg #2 type
+)); -- Callable<(String,[Int64?])->Double>
+```
+
+## GenericType, UnitType и VoidType {#generictype}
+
+### Сигнатура
+
+```yql
+GenericType()->тип
+UnitType()->тип
+VoidType()->тип
+```
+
+Возвращают одноименные [специальные типы данных](../types/special.md). Аргументов нет, так как они не параметризуются.
+
+### Примеры
+
+```yql
+SELECT FormatType(VoidType()); -- Void
+```
+
+## OptionalItemType, ListItemType и StreamItemType {#optionalitemtype}
+
+### Сигнатура
+
+```yql
+OptionalItemType(OptionalType)->тип элемента опционального типа
+ListItemType(ListType)->тип элемента списочного типа
+StreamItemType(StreamType)->тип элемента потокового типа
+```
+
+Если этим функциям передается тип, то они выполняют действие, обратное [OptionalType](#optionaltype), [ListType](#listtype) и [StreamType](#listtype) — возвращают тип элемента по типу соответствующего контейнера.
+
+Если этим функциям передается хендл типа, то выполняют действие, обратное [OptionalTypeHandle](#optionaltypehandle), [ListTypeHandle](#list-stream-typehandle) и [StreamTypeHandle](#list-stream-typehandle) - возвращают хендл типа элемента по хендлу типа соответствующего контейнера.
+
+### Примеры
+
+```yql
+SELECT FormatType(ListItemType(
+ ParseType("List<Int32>")
+)); -- Int32
+```
+
+```yql
+SELECT FormatType(ListItemType(
+ ParseTypeHandle("List<Int32>")
+)); -- Int32
+```
+
+## DictKeyType и DictPayloadType {#dictkeytype}
+
+### Сигнатура
+
+```yql
+DictKetType(DictType)->тип ключа словаря
+DictPayloadType(DictType)->тип значения словаря
+```
+
+Возвращают тип ключа или значения по типу словаря.
+
+### Примеры
+
+```yql
+SELECT FormatType(DictKeyType(
+ ParseType("Dict<Int32,String>")
+)); -- Int32
+```
+
+## TupleElementType {#tupleelementtype}
+
+### Сигнатура
+
+```yql
+TupleElementType(TupleType, String)->тип элемента кортежа
+```
+
+Возвращает тип элемента кортежа по типу кортежа и индексу элемента (индекс с нуля).
+
+### Примеры
+
+```yql
+SELECT FormatType(TupleElementType(
+ ParseType("Tuple<Int32,Double>"), "1"
+)); -- Double
+```
+
+## StructMemberType {#structmembertype}
+
+### Сигнатура
+
+```yql
+StructMemberType(StructType, String)->тип элемента структуры
+```
+
+Возвращает тип элемента структуры по типу структуры и имени элемента.
+
+### Примеры
+
+```yql
+SELECT FormatType(StructMemberType(
+ ParseType("Struct<foo:Int32,bar:Double>"), "foo"
+)); -- Int32
+```
+
+## CallableResultType и CallableArgumentType {#callableresulttype}
+
+### Сигнатура
+
+```yql
+CallableResultType(CallableType)->тип результата вызываемого значения
+CallableArgumentType(CallableType, Uint32)->тип аругмента вызываемого значения
+```
+
+`CallableResultType` возвращает тип результата по типу вызываемого значения, а `CallableArgumentType` — тип аргумента по типу вызываемого значения и его индексу (индекс с нуля).
+
+### Примеры
+
+```yql
+$callable_type = ParseType("(String,Bool)->Double");
+
+SELECT FormatType(CallableResultType(
+ $callable_type
+)), -- Double
+FormatType(CallableArgumentType(
+ $callable_type, 1
+)); -- Bool
+```
+
+## VariantUnderlyingType {#variantunderlyingtype}
+
+### Сигнатура
+
+```yql
+VariantUnderlyingType(VariantType)->низлежащий тип варианта
+```
+
+Если этой функции передается тип, то она выполняет действие, обратное [VariantType](#varianttype) — возвращает низлежащий тип по типу варианта.
+
+Если этой функции передается хендл типа, то она выполняет действие, обратное [VariantTypeHandle](#varianttypehandle) — возвращает хендл низлежащего типа по хендлу типа варианта.
+
+### Примеры
+
+```yql
+SELECT FormatType(VariantUnderlyingType(
+ ParseType("Variant<foo:Int32,bar:Double>")
+)), -- Struct<'bar':Double,'foo':Int32>
+FormatType(VariantUnderlyingType(
+ ParseType("Variant<Int32,Double>")
+)); -- Tuple<Int32,Double>
+```
+
+```yql
+SELECT FormatType(VariantUnderlyingType(
+ ParseTypeHandle("Variant<foo:Int32,bar:Double>")
+)), -- Struct<'bar':Double,'foo':Int32>
+FormatType(VariantUnderlyingType(
+ ParseTypeHandle("Variant<Int32,Double>")
+)); -- Tuple<Int32,Double>
+```
+
+## Функции для работы с типами данных во время выполнения вычислений
+
+Для работы с типами данных во время выполнения вычислений используется механизм хендлов типов - [ресурс](../types/special.md), содержащий непрозрачное описание типа. После конструирования хендла типа можно вернуться к обычному типу с помощью функции [EvaluateType](#evaluatetype). Для отладки сконвертировать хендл типа в строку можно с помощью функции [FormatType](#formattype).
+
+### TypeHandle
+
+Получение хендла типа из типа, переданного в аргумент.
+
+#### Сигнатура
+
+```yql
+TypeHandle(Type)->хэндл типа
+```
+
+#### Примеры
+
+```yql
+SELECT FormatType(TypeHandle(TypeOf("foo"))); -- String
+```
+
+### EvaluateType
+
+#### Сигнатура
+
+```yql
+EvaluateType(TypeHandle)->тип
+```
+
+Получение типа из хендла типа, переданного в аргумент. Функция вычисляется до начала основного расчета, как и [EvaluateExpr](basic.md#evaluate_expr_atom).
+
+#### Примеры
+
+```yql
+SELECT FormatType(EvaluateType(TypeHandle(TypeOf("foo")))); -- String
+```
+
+### ParseTypeHandle
+
+#### Сигнатура
+
+```yql
+ParseTypeHandle(String)->хэндл типа
+```
+
+Построение хендла типа по строке с его описанием. [Документация по её формату](../types/type_string.md).
+
+#### Примеры
+
+```yql
+SELECT FormatType(ParseTypeHandle("List<Int32>")); -- List<int32>
+```
+
+### TypeKind
+
+#### Сигнатура
+
+```yql
+TypeKind(TypeHandle)->String
+```
+
+Получение названия верхнего уровня типа из хендла типа, переданного в аргумент.
+
+#### Примеры
+
+```yql
+SELECT TypeKind(TypeHandle(TypeOf("foo"))); -- Data
+SELECT TypeKind(ParseTypeHandle("List<Int32>")); -- List
+```
+
+### DataTypeComponents
+
+#### Сигнатура
+
+```yql
+DataTypeComponents(DataTypeHandle)->List<String>
+```
+
+Получение названия и параметров [примитивного типа данных](../types/primitive.md) из хендла примитивного типа, переданного в аргумент. Обратная функция - [DataTypeHandle](#datatypehandle).
+
+#### Примеры
+
+```yql
+SELECT DataTypeComponents(TypeHandle(TypeOf("foo"))); -- ["String"]
+SELECT DataTypeComponents(ParseTypeHandle("Decimal(4,1)")); -- ["Decimal", "4", "1"]
+```
+
+### DataTypeHandle
+
+#### Сигнатура
+
+```yql
+DataTypeHandle(List<String>)->хэндл примитивного типа данных
+```
+
+Построение хендла [примитивного типа данных](../types/primitive.md) из его названия и параметров, переданных списком в аргумент. Обратная функция - [DataTypeComponents](#datatypecomponents).
+
+#### Примеры
+
+```yql
+SELECT FormatType(DataTypeHandle(
+ AsList("String")
+)); -- String
+
+SELECT FormatType(DataTypeHandle(
+ AsList("Decimal", "4", "1")
+)); -- Decimal(4,1)
+```
+
+### OptionalTypeHandle
+
+#### Сигнатура
+
+```yql
+OptionalTypeHandle(TypeHandle)->хэндл опционального типа
+```
+
+Добавляет в переданный хендл типа возможность содержать `NULL`.
+
+#### Примеры
+
+```yql
+SELECT FormatType(OptionalTypeHandle(
+ TypeHandle(DataType("Bool"))
+)); -- Bool?
+```
+
+### PgTypeName
+
+#### Сигнатура
+
+```yql
+PgTypeName(PgTypeHandle)->String
+```
+
+Получение имени PostgreSQL типа из хендла типа, переданного в аргумент. Обратная функция - [PgTypeHandle](#pgtypehandle).
+
+#### Примеры
+
+```yql
+SELECT PgTypeName(ParseTypeHandle("pgint4")); -- int4
+```
+
+### PgTypeHandle
+
+#### Сигнатура
+
+```yql
+PgTypeHandle(String)->хендл типа
+```
+
+Построение хендла типа по имени PostgreSQL типа, переданного в аргумент. Обратная функция - [PgTypeName](#pgtypename).
+
+#### Примеры
+
+```yql
+SELECT FormatType(PgTypeHandle("int4")); -- pgint4
+```
+
+### ListTypeHandle и StreamTypeHandle {#list-stream-typehandle}
+
+#### Сигнатура
+
+```yql
+ListTypeHandle(TypeHandle)->хэндл списочного типа
+StreamTypeHandle(TypeHandle)->хэндл потокового типа
+```
+
+Строит хендл типа списка или потока по переданному хендлу типа элемента.
+
+#### Примеры
+
+```yql
+SELECT FormatType(ListTypeHandle(
+ TypeHandle(DataType("Bool"))
+)); -- List<Bool>
+```
+
+### EmptyListTypeHandle и EmptyDictTypeHandle
+
+#### Сигнатура
+
+```yql
+EmptyListTypeHandle()->хэндл типа пустого списка
+EmptyDictTypeHandle()->хэндл типа пустого словаря
+```
+
+Строит хендл типа пустого списка или словаря.
+
+#### Примеры
+
+```yql
+SELECT FormatType(EmptyListTypeHandle()); -- EmptyList
+```
+
+### TupleTypeComponents
+
+#### Сигнатура
+
+```yql
+TupleTypeComponents(TupleTypeHandle)->List<TypeHandle>
+```
+
+Получение списка хендлов типов элементов из хендла типа кортежа, переданного в аргумент. Обратная функция - [TupleTypeHandle](#tupletypehandle).
+
+#### Примеры
+
+```yql
+SELECT ListMap(
+ TupleTypeComponents(
+ ParseTypeHandle("Tuple<Int32, String>")
+ ),
+ ($x)->{
+ return FormatType($x)
+ }
+); -- ["Int32", "String"]
+```
+
+### TupleTypeHandle
+
+#### Сигнатура
+
+```yql
+TupleTypeHandle(List<TypeHandle>)->хэндл типа кортежа
+```
+
+Построение хендла типа кортежа из хендлов типов элементов, переданных списком в аргумент. Обратная функция - [TupleTypeComponents](#tupletypecomponents).
+
+#### Примеры
+
+```yql
+SELECT FormatType(
+ TupleTypeHandle(
+ AsList(
+ ParseTypeHandle("Int32"),
+ ParseTypeHandle("String")
+ )
+ )
+); -- Tuple<Int32,String>
+```
+
+### StructTypeComponents
+
+#### Сигнатура
+
+```yql
+StructTypeComponents(StructTypeHandle)->List<Struct<Name:String, Type:TypeHandle>>
+```
+
+Получение списка хендлов типов элементов и их имен из хендла типа структуры, переданного в аргумент. Обратная функция - [StructTypeHandle](#structtypehandle).
+
+#### Примеры
+
+```yql
+SELECT ListMap(
+ StructTypeComponents(
+ ParseTypeHandle("Struct<a:Int32, b:String>")
+ ),
+ ($x) -> {
+ return AsTuple(
+ FormatType($x.Type),
+ $x.Name
+ )
+ }
+); -- [("Int32","a"), ("String","b")]
+```
+
+### StructTypeHandle
+
+#### Сигнатура
+
+```yql
+StructTypeHandle(List<Struct<Name:String, Type:TypeHandle>>)->хэндл типа структуры
+```
+
+Построение хендла типа структуры из хендлов типов элементов и имен, переданных списком в аргумент. Обратная функция - [StructTypeComponents](#structtypecomponents).
+
+#### Примеры
+
+```yql
+SELECT FormatType(
+ StructTypeHandle(
+ AsList(
+ AsStruct(ParseTypeHandle("Int32") as Type,"a" as Name),
+ AsStruct(ParseTypeHandle("String") as Type, "b" as Name)
+ )
+ )
+); -- Struct<'a':Int32,'b':String>
+```
+
+### DictTypeComponents
+
+#### Сигнатура
+
+```yql
+DictTypeComponents(DictTypeHandle)->Struct<Key:TypeHandle, Payload:TypeHandle>
+```
+
+Получение хендла типа-ключа и хендла типа-значения - из хендла типа словаря, переданного в аргумент. Обратная функция - [DictTypeHandle](#dicttypehandle).
+
+#### Примеры
+
+```yql
+$d = DictTypeComponents(ParseTypeHandle("Dict<Int32,String>"));
+
+SELECT
+ FormatType($d.Key), -- Int32
+ FormatType($d.Payload); -- String
+```
+
+### DictTypeHandle
+
+#### Сигнатура
+
+```yql
+DictTypeHandle(TypeHandle, TypeHandle)->хэндл типа словаря
+```
+
+Построение хендла типа словаря из хендла типа-ключа и хендла типа-значения, переданных в аргументы. Обратная функция - [DictTypeComponents](#dicttypecomponents).
+
+#### Примеры
+
+```yql
+SELECT FormatType(
+ DictTypeHandle(
+ ParseTypeHandle("Int32"),
+ ParseTypeHandle("String")
+ )
+); -- Dict<Int32, String>
+```
+
+### ResourceTypeTag
+
+#### Сигнатура
+
+```yql
+ResourceTypeTag(ResourceTypeHandle)->String
+```
+
+Получение тега из хендла типа ресурса, переданного в аргумент. Обратная функция - [ResourceTypeHandle](#resourcetypehandle).
+
+#### Примеры
+
+```yql
+SELECT ResourceTypeTag(ParseTypeHandle("Resource<foo>")); -- foo
+```
+
+### ResourceTypeHandle
+
+#### Сигнатура
+
+```yql
+ResourceTypeHandle(String)->хэндл типа ресурса
+```
+
+Построение хендла типа ресурса по значению тега, переданного в аргумент. Обратная функция - [ResourceTypeTag](#resourcetypetag).
+
+#### Примеры
+
+```yql
+SELECT FormatType(ResourceTypeHandle("foo")); -- Resource<'foo'>
+```
+
+### TaggedTypeComponents
+
+#### Сигнатура
+
+```yql
+TaggedTypeComponents(TaggedTypeHandle)->Struct<Base:TypeHandle, Tag:String>
+```
+
+Получение тега и базового типа из хендла декорированного типа, переданного в аргумент. Обратная функция - [TaggedTypeHandle](#taggedtypehandle).
+
+#### Примеры
+
+```yql
+$t = TaggedTypeComponents(ParseTypeHandle("Tagged<Int32,foo>"));
+
+SELECT FormatType($t.Base), $t.Tag; -- Int32, foo
+```
+
+### TaggedTypeHandle
+
+#### Сигнатура
+
+```yql
+TaggedTypeHandle(TypeHandle, String)->хэндл декорированного типа
+```
+
+Построение хендла декорированного типа по хендлу базового типа и имени тега, переданных в аргументах. Обратная функция - [TaggedTypeComponents](#taggedtypecomponents).
+
+#### Примеры
+
+```yql
+SELECT FormatType(TaggedTypeHandle(
+ ParseTypeHandle("Int32"), "foo"
+)); -- Tagged<Int32, 'foo'>
+```
+
+### VariantTypeHandle
+
+#### Сигнатура
+
+```yql
+VariantTypeHandle(StructTypeHandle)->хэндл типа варианта над структурой
+VariantTypeHandle(TupleTypeHandle)->хэндл типа варианта над кортежем
+```
+
+Построение хендла типа варианта по хендлу низлежащего типа, переданного в аргумент. Обратная функция - [VariantUnderlyingType](#variantunderlyingtype).
+
+#### Примеры
+
+```yql
+SELECT FormatType(VariantTypeHandle(
+ ParseTypeHandle("Tuple<Int32, String>")
+)); -- Variant<Int32, String>
+```
+
+### VoidTypeHandle и NullTypeHandle
+
+#### Сигнатура
+
+```yql
+VoidTypeHandle()->хэндл типа Void
+NullTypeHandle()->хэндл типа Null
+```
+
+Построение хендла типов Void и Null соответственно.
+
+#### Примеры
+
+```yql
+SELECT FormatType(VoidTypeHandle()); -- Void
+SELECT FormatType(NullTypeHandle()); -- Null
+```
+
+### CallableTypeComponents
+
+#### Сигнатура
+
+```yql
+CallableTypeComponents(CallableTypeHandle)->
+Struct<
+ Arguments:List<Struct<
+ Flags:List<String>,
+ Name:String,
+ Type:TypeHandle>>,
+ OptionalArgumentsCount:Uint32,
+ Payload:String,
+ Result:TypeHandle
+>
+```
+
+Получение описания хендла типа вызываемого значения, переданного в аргумент. Обратная функция - [CallableTypeHandle](#callabletypehandle).
+
+#### Примеры
+
+```yql
+$formatArgument = ($x) -> {
+ return AsStruct(
+ FormatType($x.Type) as Type,
+ $x.Name as Name,
+ $x.Flags as Flags
+ )
+};
+
+$formatCallable = ($x) -> {
+ return AsStruct(
+ $x.OptionalArgumentsCount as OptionalArgumentsCount,
+ $x.Payload as Payload,
+ FormatType($x.Result) as Result,
+ ListMap($x.Arguments, $formatArgument) as Arguments
+ )
+};
+
+SELECT $formatCallable(
+ CallableTypeComponents(
+ ParseTypeHandle("(Int32,[bar:Double?{Flags:AutoMap}])->String")
+ )
+); -- (OptionalArgumentsCount: 1, Payload: "", Result: "String", Arguments: [
+ -- (Type: "Int32", Name: "", Flags: []),
+ -- (Type: "Double?", Name: "bar", Flags: ["AutoMap"]),
+ -- ])
+```
+
+### CallableArgument
+
+#### Сигнатура
+
+```yql
+CallableArgument(TypeHandle, [String, [List<String>]])->Struct<Flags:List<String>,Name:String,Type:TypeHandle>
+```
+
+Упаковка в структуру описания аргумента вызываемого значения для передачи в функцию [CallableTypeHandle](#callabletypehandle) по следующим аргументам:
+
+1. Хендл типа аргумента.
+2. Необязательное имя аргумента. Значение по умолчанию - пустая строка.
+3. Необязательные флаги аргумента в виде списка строк. Значение по умолчанию - пустой список. Поддерживаемые флаги - "AutoMap".
+
+### CallableTypeHandle
+
+#### Сигнатура
+
+```yql
+CallableTypeHandle(TypeHandle, List<Struct<Flags:List<String>,Name:String,Type:TypeHandle>>, [Uint32, [String]])->хэндл типа вызываемого значения
+```
+
+Построение хендла типа вызываемого значения по следующим аргументам:
+
+1. Хендл типа возвращаемого значения.
+2. Список описаний аргументов, полученных через функцию [CallableArgument](#callableargument).
+3. Необязательное количество необязательных аргументов в вызываемом значении. Значение по умолчанию - 0.
+4. Необязательная метка для типа вызываемого значения. Значение по умолчанию - пустая строка.
+
+Обратная функция - [CallableTypeComponents](#callabletypecomponents).
+
+#### Примеры
+
+```yql
+SELECT FormatType(
+ CallableTypeHandle(
+ ParseTypeHandle("String"),
+ AsList(
+ CallableArgument(ParseTypeHandle("Int32")),
+ CallableArgument(ParseTypeHandle("Double?"), "bar", AsList("AutoMap"))
+ ),
+ 1
+ )
+); -- Callable<(Int32,['bar':Double?{Flags:AutoMap}])->String>
+```
+
+### LambdaArgumentsCount
+
+#### Сигнатура
+
+```yql
+LambdaArgumentsCount(LambdaFunction)->Uint32
+```
+
+Получение количества аргументов в лямбда-функции.
+
+#### Примеры
+
+```yql
+SELECT LambdaArgumentsCount(($x, $y)->($x+$y))
+; -- 2
+```
+
+### LambdaOptionalArgumentsCount
+
+#### Сигнатура
+
+```yql
+LambdaOptionalArgumentsCount(LambdaFunction)->Uint32
+```
+
+Получение количества опциональных аргументов в лямбда-функции.
+
+#### Примеры
+
+```yql
+SELECT LambdaOptionalArgumentsCount(($x, $y, $z?)->(if($x,$y,$z)))
+; -- 1
+```
diff --git a/yql/essentials/docs/ru/builtins/window.md b/yql/essentials/docs/ru/builtins/window.md
new file mode 100644
index 0000000000..357400d381
--- /dev/null
+++ b/yql/essentials/docs/ru/builtins/window.md
@@ -0,0 +1,240 @@
+
+# Список оконных функций в YQL
+
+Синтаксис вызова оконных функций подробно описан в [отдельной статье](../syntax/window.md).
+
+
+## Агрегатные функции {#aggregate-functions}
+
+Все [агрегатные функции](aggregation.md) также могут использоваться в роли оконных.
+В этом случае на каждой строке оказывается результат агрегации, полученный на множестве строк из [рамки окна](../syntax/window.md#frame).
+
+### Примеры
+
+```yql
+SELECT
+ SUM(int_column) OVER w1 AS running_total,
+ SUM(int_column) OVER w2 AS total,
+FROM my_table
+WINDOW
+ w1 AS (ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW),
+ w2 AS ();
+```
+
+
+## ROW_NUMBER {#row_number}
+
+Номер строки в рамках [раздела](../syntax/window.md#partition). Без аргументов.
+
+### Сигнатура
+
+```yql
+ROW_NUMBER()->Uint64
+```
+
+### Примеры
+
+```yql
+SELECT
+ ROW_NUMBER() OVER w AS row_num
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+
+## LAG / LEAD {#lag-lead}
+
+Доступ к значению из строки [раздела](../syntax/window.md#partition), отстающей (`LAG`) или опережающей (`LEAD`) текущую на фиксированное число. В первом аргументе указывается выражение, к которому необходим доступ, а во втором — отступ в строках. Отступ можно не указывать, по умолчанию используется соседняя строка — предыдущая или следующая, соответственно, то есть подразумевается 1. В строках, для которых нет соседей с заданным расстоянием (например `LAG(expr, 3)` в первой и второй строках раздела), возвращается `NULL`.
+
+### Сигнатура
+
+```yql
+LEAD(T[,Int32])->T?
+LAG(T[,Int32])->T?
+```
+
+### Примеры
+
+```yql
+SELECT
+ int_value - LAG(int_value) OVER w AS int_value_diff
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+```yql
+SELECT item, odd, LAG(item, 1) OVER w as lag1 FROM (
+ SELECT item, item % 2 as odd FROM (
+ SELECT AsList(1, 2, 3, 4, 5, 6, 7) as item
+ )
+ FLATTEN BY item
+)
+WINDOW w As (
+ PARTITION BY odd
+ ORDER BY item
+);
+
+/* Output:
+item odd lag1
+--------------------
+2 0 NULL
+4 0 2
+6 0 4
+1 1 NULL
+3 1 1
+5 1 3
+7 1 5
+*/
+```
+
+
+## FIRST_VALUE / LAST_VALUE
+
+Доступ к значениям из первой и последней (в порядке `ORDER BY` на окне) строк [рамки окна](../syntax/window.md#frame). Единственный аргумент - выражение, к которому необходим доступ.
+
+Опционально перед `OVER` может указываться дополнительный модификатор `IGNORE NULLS`, который меняет поведение функций на первое или последнее **не пустое** (то есть не `NULL`) значение среди строк рамки окна. Антоним этого модификатора — `RESPECT NULLS` является поведением по умолчанию и может не указываться.
+
+### Сигнатура
+
+```yql
+FIRST_VALUE(T)->T?
+LAST_VALUE(T)->T?
+```
+
+### Примеры
+
+```yql
+SELECT
+ FIRST_VALUE(my_column) OVER w
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+```yql
+SELECT
+ LAST_VALUE(my_column) IGNORE NULLS OVER w
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+## NTH_VALUE
+
+Доступ к значения из заданной строки (в порядке `ORDER BY` на окне) [рамки окна](../syntax/window.md#frame). Аргументы - выражение, к которому необходим доступ и номер строки, начиная с 1.
+
+Опционально перед `OVER` может указываться дополнительный модификатор `IGNORE NULLS`, который приводит к пропуску строк с NULL в значении первого аргумента. Антоним этого модификатора — `RESPECT NULLS` является поведением по умолчанию и может не указываться.
+
+### Сигнатура
+
+```yql
+NTH_VALUE(T,N)->T?
+```
+
+### Примеры
+
+```yql
+SELECT
+ NTH_VALUE(my_column, 2) OVER w
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+```yql
+SELECT
+ NTH_VALUE(my_column, 3) IGNORE NULLS OVER w
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+
+## RANK / DENSE_RANK / PERCENT_RANK {#rank}
+
+Пронумеровать группы соседних строк [раздела](../syntax/window.md#partition) с одинаковым значением выражения в аргументе. `DENSE_RANK` нумерует группы подряд, а `RANK` — пропускает `(N - 1)` значений, где `N` — число строк в предыдущей группе. `PERCENT_RANK` выдает относительный ранг текущей строки: `(RANK - 1)/(число строк в разделе - 1)`.
+
+При отсутствии аргумента использует порядок, указанный в секции `ORDER BY` определения окна.
+Если аргумент отсутствует и `ORDER BY` не указан, то все строки считаются равными друг другу.
+
+{% note info %}
+
+Возможность передавать аргумент в `RANK`/`DENSE_RANK`/`PERCENT_RANK` является нестандартным расширением YQL.
+
+{% endnote %}
+
+### Сигнатура
+
+```yql
+RANK([T])->Uint64
+DENSE_RANK([T])->Uint64
+PERCENT_RANK([T])->Double
+```
+
+### Примеры
+
+```yql
+SELECT
+ RANK(my_column) OVER w
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+```yql
+SELECT
+ DENSE_RANK() OVER w
+FROM my_table
+WINDOW w AS (ORDER BY my_column);
+```
+
+```yql
+SELECT
+ PERCENT_RANK() OVER w
+FROM my_table
+WINDOW w AS (ORDER BY my_column);
+```
+
+
+## NTILE
+
+Распределяет строки упорядоченного [раздела](../syntax/window.md#partition) в заданное количество групп. Группы нумеруются, начиная с единицы. Для каждой строки функция NTILE возвращает номер группы,которой принадлежит строка.
+
+### Сигнатура
+
+```yql
+NTILE(Uint64)->Uint64
+```
+
+### Примеры
+
+```yql
+SELECT
+ NTILE(10) OVER w AS group_num
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+
+## CUME_DIST
+
+Возвращает относительную позицию (> 0 и <= 1) строки в рамках [раздела](../syntax/window.md#partition). Без аргументов.
+
+### Сигнатура
+
+```yql
+CUME_DIST()->Double
+```
+
+### Примеры
+
+```yql
+SELECT
+ CUME_DIST() OVER w AS dist
+FROM my_table
+WINDOW w AS (ORDER BY key);
+```
+
+
+
+## SessionState() {#session-state}
+
+Нестандартная оконная функция `SessionState()` (без аргументов) позволяет получить состояние расчета сессий из [SessionWindow](../syntax/group_by.md#session-window) для текущей строки.
+
+Допускается только при наличии `SessionWindow()` в секции `PARTITION BY` определения окна.
+
diff --git a/yql/essentials/docs/ru/index.md b/yql/essentials/docs/ru/index.md
new file mode 100644
index 0000000000..1d3314f841
--- /dev/null
+++ b/yql/essentials/docs/ru/index.md
@@ -0,0 +1,11 @@
+
+# YQL - Обзор
+
+*YQL* (Yandex Query Language) — универсальный декларативный язык запросов к системам хранения и обработки данных, диалект SQL.
+
+В данном разделе документации находится справочник по YQL, который включает разделы:
+
+- [Типы данных](types/index.md) с описанием типов данных, применяемых в YQL
+- [Синтаксис](syntax/index.md) с полным перечнем команд YQL
+- [Встроенные функции](builtins/index.md) с описанием доступных встроенных функций
+- [Рецепты](recipes/index.md) с описанием рецептов для различных задача
diff --git a/yql/essentials/docs/ru/recipes/accessing-json.md b/yql/essentials/docs/ru/recipes/accessing-json.md
new file mode 100644
index 0000000000..dec41b2636
--- /dev/null
+++ b/yql/essentials/docs/ru/recipes/accessing-json.md
@@ -0,0 +1,103 @@
+# Доступ к значениям в JSON с помощью YQL
+
+YQL предоставляет два основных способа извлечения значений из JSON:
+
+- Использование [**JSON-функций из SQL стандарта**](../builtins/json.md). Этот подход рекомендуется для простых случаев и для команд, которые знакомы с ними по другим СУБД.
+- Использование [**Yson UDF**](../udf/list/yson.md), встроенных функций для работы со [списками](../builtins/list.md) и [словарями](../builtins/dict.md), а также [лямбд](../syntax/expressions.md#lambda). Этот подход более гибкий и тесно интегрирован с системой типов данных YQL, поэтому рекомендуется для сложных случаев.
+
+Ниже приведены рецепты, которые используют один и тот же входной JSON, чтобы показать, как использовать каждый из этих вариантов для проверки существования ключа, получения конкретного значения и извлечения поддерева.
+
+## JSON-функции
+
+```yql
+$json = @@{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30
+ }
+ ]
+}@@j;
+
+SELECT
+ JSON_EXISTS($json, "$.friends[*].name"), -- True
+ CAST(JSON_VALUE($json, "$.friends[0].age") AS Int32), -- 35
+ JSON_QUERY($json, "$.friends[0]"); -- {"name": "James Holden", "age": 35}
+```
+
+Функции `JSON_*` ожидают на вход данные типа `Json`. В этом примере строковый литерал имеет суффикс `j`, обозначающий его как `Json`. В таблицах данные могут храниться либо в формате JSON, либо как строковое представление. Для преобразования данных из `String` в тип данных `JSON` используйте функцию `CAST`, например `CAST(my_string AS JSON)`.
+
+## Yson UDF
+
+Этот подход обычно сочетает в себе несколько функций и выражений, поэтому запрос может использовать различные конкретные стратегии.
+
+### Преобразование всего JSON в YQL контейнеры
+
+```yql
+$json = @@{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30
+ }
+ ]
+}@@j;
+
+$containers = Yson::ConvertTo($json, Struct<friends:List<Struct<name:String?,age:Int32?>>>);
+$has_name = ListAny(
+ ListMap($containers.friends, ($friend) -> {
+ return $friend.name IS NOT NULL;
+ })
+);
+$get_age = $containers.friends[0].age;
+$get_first_friend = Yson::SerializeJson(Yson::From($containers.friends[0]));
+
+SELECT
+ $has_name, -- True
+ $get_age, -- 35
+ $get_first_friend; -- {"name": "James Holden", "age": 35}
+```
+
+**Не** обязательно преобразовывать весь JSON объект в структурированное сочетание контейнеров. Некоторые поля могут быть опущены, если они не используются, в то время как некоторые поддеревья могут быть оставлены в неструктурированном типе данных, таком как `Json`.
+
+### Работа с представлением в памяти
+
+```yql
+$json = @@{
+ "friends": [
+ {
+ "name": "James Holden",
+ "age": 35
+ },
+ {
+ "name": "Naomi Nagata",
+ "age": 30
+ }
+ ]
+}@@j;
+
+$has_name = ListAny(
+ ListMap(Yson::ConvertToList($json.friends), ($friend) -> {
+ return Yson::Contains($friend, "name");
+ })
+);
+$get_age = Yson::ConvertToInt64($json.friends[0].age);
+$get_first_friend = Yson::SerializeJson($json.friends[0]);
+
+SELECT
+ $has_name, -- True
+ $get_age, -- 35
+ $get_first_friend; -- {"name": "James Holden", "age": 35}
+```
+
+## Смотрите также
+
+- [{#T}](modifying-json.md)
diff --git a/yql/essentials/docs/ru/recipes/index.md b/yql/essentials/docs/ru/recipes/index.md
new file mode 100644
index 0000000000..d37cd618e3
--- /dev/null
+++ b/yql/essentials/docs/ru/recipes/index.md
@@ -0,0 +1,8 @@
+# YQL рецепты
+
+Этот раздел содержит рецепты запросов для различных задач, которые можно решить с помощью YQL.
+
+Содержание:
+
+* [{#T}](accessing-json.md)
+* [{#T}](modifying-json.md)
diff --git a/yql/essentials/docs/ru/recipes/modifying-json.md b/yql/essentials/docs/ru/recipes/modifying-json.md
new file mode 100644
index 0000000000..871662c59b
--- /dev/null
+++ b/yql/essentials/docs/ru/recipes/modifying-json.md
@@ -0,0 +1,23 @@
+# Изменение JSON с помощью YQL
+
+В памяти YQL работает с неизменяемыми значениями. Таким образом, когда запросу нужно изменить что-то внутри значения JSON, следует думать об этом как о создании нового значения из частей старого.
+
+Данный пример запроса принимает входной JSON названный `$fields`, парсит его, заменяет ключ `a` на 0, удаляет ключ `d` и добавляет ключ `c` со значением 3:
+
+```yql
+$fields = '{"a": 1, "b": 2, "d": 4}'j;
+$pairs = DictItems(Yson::ConvertToInt64Dict($fields));
+$result_pairs = ListExtend(ListNotNull(ListMap($pairs, ($item) -> {
+ $item = if ($item.0 == "a", ("a", 0), $item);
+ return if ($item.0 == "d", null, $item);
+})), [("c", 3)]);
+$result_dict = ToDict($result_pairs);
+SELECT Yson::SerializeJson(Yson::From($result_dict));
+```
+
+## Смотрите также
+
+- [{#T}](../udf/list/yson.md)
+- [{#T}](../builtins/list.md)
+- [{#T}](../builtins/dict.md)
+- [{#T}](accessing-json.md)
diff --git a/yql/essentials/docs/ru/recipes/toc_i.yaml b/yql/essentials/docs/ru/recipes/toc_i.yaml
new file mode 100644
index 0000000000..be8e0a9fea
--- /dev/null
+++ b/yql/essentials/docs/ru/recipes/toc_i.yaml
@@ -0,0 +1,7 @@
+items:
+- name: Обзор
+ href: index.md
+- name: Доступ к JSON
+ href: accessing-json.md
+- name: Модификация JSON
+ href: modifying-json.md \ No newline at end of file
diff --git a/yql/essentials/docs/ru/syntax/_assets/join-YQL-06.png b/yql/essentials/docs/ru/syntax/_assets/join-YQL-06.png
new file mode 100644
index 0000000000..aae84322b7
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/_assets/join-YQL-06.png
Binary files differ
diff --git a/yql/essentials/docs/ru/syntax/action.md b/yql/essentials/docs/ru/syntax/action.md
new file mode 100644
index 0000000000..eab50e7bca
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/action.md
@@ -0,0 +1,145 @@
+# ACTION
+
+## DEFINE ACTION {#define-action}
+
+Задает именованное действие, которое представляют собой параметризуемый блок из нескольких выражений верхнего уровня.
+
+### Синтаксис
+
+1. `DEFINE ACTION` — объявление действия.
+1. [Имя действия](expressions.md#named-nodes), по которому объявляемое действие доступно далее для вызова.
+1. В круглых скобках — список имен параметров.
+1. Ключевое слово `AS`.
+1. Список выражений верхнего уровня.
+1. `END DEFINE` — маркер последнего выражения внутри действия.
+
+Один или более последних параметров могут быть помечены знаком вопроса `?` как необязательные. Если они не будут указаны при вызове, то им будет присвоено значение `NULL`.
+
+## DO {#do}
+
+Выполняет `ACTION` с указанными параметрами.
+
+### Синтаксис
+
+1. `DO` — выполнение действия.
+1. Именованное выражение, по которому объявлено действие.
+1. В круглых скобках — список значений для использования в роли параметров.
+
+`EMPTY_ACTION` — действие, которое ничего не выполняет.
+
+{% note info %}
+
+В больших запросах объявление действий можно выносить в отдельные файлы и подключать их в основной запрос с помощью [EXPORT](export_import.md#export) + [IMPORT](export_import.md#import), чтобы вместо одного длинного текста получилось несколько логических частей, в которых проще ориентироваться. Важный нюанс: директива `USE my_cluster;` в импортирующем запросе не влияет на поведение объявленных в других файлах действий.
+
+{% endnote %}
+
+### Пример
+
+```yql
+DEFINE ACTION $hello_world($name, $suffix?) AS
+ $name = $name ?? ($suffix ?? "world");
+ SELECT "Hello, " || $name || "!";
+END DEFINE;
+
+DO EMPTY_ACTION();
+DO $hello_world(NULL);
+DO $hello_world("John");
+DO $hello_world(NULL, "Earth");
+```
+
+## BEGIN .. END DO {#begin}
+
+Выполнение действия без его объявления (анонимное действие).
+
+### Синтаксис
+
+1. `BEGIN`;
+1. Список выражений верхнего уровня;
+1. `END DO`.
+
+Анонимное действие не может содержать параметров.
+
+### Пример
+
+```yql
+DO BEGIN
+ SELECT 1;
+ SELECT 2 -- здесь и в предыдущем примере ';' перед END можно не ставить
+END DO
+```
+
+## EVALUATE IF {#evaluate-if}
+
+`EVALUATE IF` — выполнение действия (action) в зависимости от выполнения условия. Далее указывается:
+
+1. Условие;
+2. [DO](#do) с именем и параметрами действия или анонимным действием;
+3. Опционально `ELSE` и следом второе `DO` для ситуации, когда условие не выполнено.
+
+## EVALUATE FOR {#evaluate-for}
+
+`EVALUATE FOR` — выполнение действия (action) для каждого элемента в списке. Далее указывается:
+
+1. [Именованное выражение](expressions.md#named-nodes), в которое будет подставляться каждый очередной элемент списка;
+2. Ключевое слово `IN`;
+3. Объявленное выше именованное выражение со списком, по которому будет выполняться действие.
+4. [DO](#do) с именем и параметрами действия или анонимным действием, в параметрах можно использовать как текущий элемент из первого пункта, так и любые объявленные выше именованные выражения, в том числе сам список.
+5. Опционально `ELSE` и следом второе `DO` для ситуации, когда список пуст.
+
+### Примеры
+
+```yql
+DEFINE ACTION $hello() AS
+ SELECT "Hello!";
+END DEFINE;
+
+DEFINE ACTION $bye() AS
+ SELECT "Bye!";
+END DEFINE;
+
+EVALUATE IF RANDOM(0) > 0.5
+ DO $hello()
+ELSE
+ DO $bye();
+
+EVALUATE IF RANDOM(0) > 0.1 DO BEGIN
+ SELECT "Hello!";
+END DO;
+
+EVALUATE FOR $i IN AsList(1, 2, 3) DO BEGIN
+ SELECT $i;
+END DO;
+```
+
+```yql
+-- скопировать таблицу $input в $count новых таблиц
+$count = 3;
+$input = "my_input";
+$inputs = ListReplicate($input, $count);
+$outputs = ListMap(
+ ListFromRange(0, $count),
+ ($i) -> {
+ RETURN "tmp/out_" || CAST($i as String)
+ }
+);
+$pairs = ListZip($inputs, $outputs);
+
+DEFINE ACTION $copy_table($pair) as
+ $input = $pair.0;
+ $output = $pair.1;
+ INSERT INTO $output WITH TRUNCATE
+ SELECT * FROM $input;
+END DEFINE;
+
+EVALUATE FOR $pair IN $pairs
+ DO $copy_table($pair)
+ELSE
+ DO EMPTY_ACTION(); -- такой ELSE можно было не указывать,
+ -- ничего не делать подразумевается по умолчанию
+```
+
+{% note info %}
+
+Стоит учитывать, что `EVALUATE` выполняется до начала работы основного запроса.
+
+{% endnote %}
diff --git a/yql/essentials/docs/ru/syntax/commit.md b/yql/essentials/docs/ru/syntax/commit.md
new file mode 100644
index 0000000000..3a6720c882
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/commit.md
@@ -0,0 +1,16 @@
+## COMMIT {#commit}
+
+По умолчанию весь YQL запрос выполняется в рамках одной транзакции и независимые его части внутри выполняются по возможности параллельно.
+С помощью ключевого слова `COMMIT;` можно добавить барьер в процесс выполнения, чтобы отложить выполнение идущих следом выражений до тех пор, пока не выполнятся все предшествующие.
+
+Чтобы коммит выполнялся аналогичным образом автоматически после каждого выражения в запросе, можно использовать `PRAGMA autocommit;`.
+
+### Примеры
+
+```yql
+INSERT INTO result1 SELECT * FROM my_table;
+INSERT INTO result2 SELECT * FROM my_table;
+COMMIT;
+-- В result2 уже будет содержимое SELECT со второй строки:
+INSERT INTO result3 SELECT * FROM result2;
+```
diff --git a/yql/essentials/docs/ru/syntax/declare.md b/yql/essentials/docs/ru/syntax/declare.md
new file mode 100644
index 0000000000..704e831a1f
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/declare.md
@@ -0,0 +1,39 @@
+
+# DECLARE
+
+Объявляет типизированное [именованное выражение](expressions.md#named-nodes), значение для которого будет передано параметром отдельно от текста запроса. Параметризация дает возможность отделить разработку аналитического решения задачи от её запуска с различными вариантами входных значений.
+
+Для транзакционной нагрузки использование параметров позволяет избежать перекомпиляции запросов при повторении однотипных вызовов, снижая потребление ресурсов сервера, и исключая время компиляции из общего времени исполнения запроса.
+
+Передача параметров поддерживается в SDK, CLI, и в графических интерфейсах.
+
+## Синтаксис
+
+```yql
+DECLARE $named-node AS data_type;
+```
+
+1. Ключевое слово `DECLARE`.
+1. `$named-node` — имя, по которому можно будет обращаться к переданному значению, должно начинаться с символа `$`.
+1. Ключевое слово `AS`.
+1. `data_type` — тип данных [в виде строки в принятом формате](../types/type_string.md).
+
+Допустимы только сериализуемые типы данных:
+
+* [Примитивные типы](../types/primitive.md).
+* [Опциональные типы](../types/optional.md).
+* [Контейнеры](../types/containers.md) за исключением `Stream<Type>`.
+* `Void` и `Null`— поддерживаемые [специальные типы](../types/special.md).
+
+## Пример
+
+```yql
+DECLARE $x AS String;
+DECLARE $y AS String?;
+DECLARE $z AS List<String>;
+
+SELECT $x, $y, $z;
+```
+
+Примеры передачи параметров для DECLARE можно найти [здесь](../types/json.md).
+
diff --git a/yql/essentials/docs/ru/syntax/discard.md b/yql/essentials/docs/ru/syntax/discard.md
new file mode 100644
index 0000000000..61cd080e36
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/discard.md
@@ -0,0 +1,28 @@
+
+# DISCARD
+
+Вычисляет [`SELECT`](select/index.md), [`REDUCE`](reduce.md) или [`PROCESS`](process.md), но не возвращает результат ни в клиент, ни в таблицу. Не может быть задано одновременно с [INTO RESULT](into_result.md).
+
+Полезно использовать в сочетании с [`Ensure`](../builtins/basic.md#ensure) для проверки выполнения пользовательских условий на финальный результат вычислений.
+
+### Примеры
+
+```yql
+DISCARD SELECT 1;
+```
+
+```yql
+INSERT INTO result_table WITH TRUNCATE
+SELECT * FROM
+my_table
+WHERE value % 2 == 0;
+
+COMMIT;
+
+DISCARD SELECT Ensure(
+ 0, -- will discard result anyway
+ COUNT(*) > 1000,
+ "Too small result table, got only " || CAST(COUNT(*) AS String) || " rows"
+) FROM result_table;
+
+```
diff --git a/yql/essentials/docs/ru/syntax/export_import.md b/yql/essentials/docs/ru/syntax/export_import.md
new file mode 100644
index 0000000000..edf2788f77
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/export_import.md
@@ -0,0 +1,61 @@
+# Вынос части запроса в отдельный файл
+
+Механизм для выноса части запроса в отдельный приложенный файл:
+
+* [PRAGMA Library](pragma.md#library) помечает приложенный файл как доступный для импорта.
+## `Export`
+* В `EXPORT $my_symbol1, $my_symbol2, ...;` перечисляется список именованных выражений в библиотеке, доступных для импорта.
+
+## `Import`
+
+* `IMPORT my_library SYMBOLS $my_symbol1, $my_symbol2, ...;` делает перечисленные именованные выражения доступными для использования ниже.
+
+{% note info %}
+
+В библиотеку могут быть вынесены [лямбды](expressions.md#lambda), [действия](action.md), [именованные подзапросы](subquery.md), константы и выражения, но __не подзапросы и не агрегатные функции__.
+
+{% endnote %}
+
+{% note warning %}
+
+Файл, на который ссылается [PRAGMA Library](pragma.md#library) должен быть приложен к запросу. __Использовать для этой цели [PRAGMA File](pragma.md#file) нельзя__.
+
+{% endnote %}
+
+
+### Примеры
+
+my_lib.sql:
+
+```yql
+$Square = ($x) -> { RETURN $x * $x; };
+$Sqrt = ($x) -> { RETURN Math::Sqrt($x); };
+
+-- Агрегационные функции, создаваемые с помощью
+-- AggregationFactory, удобно выносить в библиотеку
+$Agg_sum = AggregationFactory("SUM");
+$Agg_max = AggregationFactory("MAX");
+
+EXPORT $Square, $Sqrt, $Agg_sum, $Agg_max;
+```
+
+Запрос:
+
+```yql
+PRAGMA Library("my_lib.sql");
+IMPORT my_lib SYMBOLS $Square, $Sqrt, $Agg_sum, $Agg_max;
+SELECT
+ $Square(2), -- 4
+ $Sqrt(4); -- 2
+
+SELECT
+ AGGREGATE_BY(x, $Agg_sum), -- 5
+ AGGREGATE_BY(x, $Agg_max) -- 3
+FROM (
+ SELECT 2 AS x
+ UNION ALL
+ SELECT 3 AS x
+)
+```
+
+
diff --git a/yql/essentials/docs/ru/syntax/expressions.md b/yql/essentials/docs/ru/syntax/expressions.md
new file mode 100644
index 0000000000..4c0d3f2248
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/expressions.md
@@ -0,0 +1,560 @@
+# Выражения
+
+<!-- markdownlint-disable blanks-around-fences -->
+
+## Конкатенация строк {#concatenation}
+
+Выполняется через бинарный оператор `||`.
+
+Как и у других бинарных операторов, если в данных с одной из сторон оказался `NULL`, то и результат будет `NULL`.
+
+Не следует путать этот оператор с логическим «или», в SQL оно обозначается ключевым словом `OR`. Также не стоит пытаться делать конкатенацию через `+`.
+
+### Примеры
+
+```yql
+SELECT "fo" || "o";
+```
+
+
+## Проверка строки на соответствие шаблону {#check-match}
+
+`REGEXP` и `RLIKE` являются алиасами и представляют собой короткий способ записи для вызова [Re2::Grep](../udf/list/re2.md#match). `MATCH` — аналогично для [Re2::Match](../udf/list/re2.md#match).
+
+`LIKE` работает по следующим принципам:
+
+* В шаблонах используется два спецсимвола:
+
+ * `%` — ноль и более любых символов;
+ * `_` — ровно один любой символ.
+
+ Все остальные символы выступают как литералы, то есть обозначают сами себя.
+
+* В отличие от `REGEXP`, с шаблоном `LIKE` строка должна совпасть полностью. Например, для поиска подстроки в середине нужно добавить `%` в начале и в конце шаблона.
+* `ILIKE` является не чувствительной к регистру версией `LIKE`.
+* Если `LIKE` применяется к ключевой колонке сортированной таблицы и шаблон начинается не со спецсимвола, то фильтрация по префиксу опускается прямо до кластера, что в некоторых случаях позволяет не сканировать всю таблицу целиком. Для `ILIKE` данная оптимизация отключена.
+* Чтобы заэкранировать спецсимволы, необходимо после шаблона указать символ для экранирования с помощью ключевого слова `ESCAPE '?'`. Вместо `?` можно использовать любой символ, кроме `%`, `_` и `\`. Например, если в качестве экранирующего символа используется знак вопроса, то выражения `?%`, `?_` и `??` в шаблоне совпадут со своим вторым символом: процент, подчеркивание и знак вопроса, соответственно. По умолчанию экранирующий символ не определен.
+
+Наиболее популярный способ использования ключевых слов `LIKE` и `REGEXP` — фильтрация таблицы в выражениях с `WHERE`. Однако ограничения на использование шаблонов именно в этом контексте нет, и их можно использовать в большинстве контекстов при работе со строками, наравне, например, с конкатенацией с помощью `||`.
+
+### Примеры
+
+```yql
+SELECT * FROM my_table
+WHERE string_column REGEXP '\\d+';
+-- второй слеш нужен, так как все
+-- стандартные строковые литералы в SQL
+-- могут принимать С-escaped строки
+```
+
+```yql
+SELECT
+ string_column LIKE '___!_!_!_!!!!!!' ESCAPE '!'
+ -- ищет строку из ровно 9 символов:
+ -- 3 произвольных,
+ -- затем 3 подчеркивания
+ -- и 3 восклицательных знака
+FROM my_table;
+```
+
+```yql
+SELECT * FROM my_table
+WHERE key LIKE 'foo%bar';
+-- при наличии сортировки таблицы по key просканирует только ключи,
+-- начинающиеся на foo, и затем среди них
+-- оставит только заканчивающиеся на bar
+```
+
+
+## Операторы
+
+### Арифметические операторы {#math-operators}
+
+Операторы `+`, `-`, `*`, `/`, `%` определены для [примитивных типов данных](../types/primitive.md), являющихся разновидностями чисел.
+
+Для типа данных Decimal используется банковское округление (до ближайшего четного).
+
+#### Примеры
+
+```yql
+SELECT 2 + 2;
+```
+
+```yql
+SELECT 0.0 / 0.0;
+```
+
+### Операторы сравнения {#comparison-operators}
+
+Операторы `=`, `==`, `!=`, `<>`, `>`, `<` определены для:
+
+* Примитивных типов данных за исключением Yson и Json.
+* Кортежей и структур с одинаковым набором полей. Для структур не определен порядок, но можно проверять на (не-)равенство, а кортежи сравниваются поэлементно слева направо.
+
+#### Примеры
+
+```yql
+SELECT 2 > 1;
+```
+
+### Логические операторы {#logic-operators}
+
+С помощью операторов `AND`, `OR`, `XOR` осуществляются логические операции над булевыми значениями (`Bool`).
+
+#### Примеры
+
+```yql
+SELECT 3 > 0 AND false;
+```
+
+### Битовые операторы {#bit-operators}
+
+Битовые операции над числами:
+
+* `&`, `|`, `^` — AND, OR и XOR соответственно. Не следует путать битовые операции с аналогичными ключевыми словами. Ключевые слова `AND`, `OR` и `XOR` используются *только для булевых значений*, но не для чисел;
+* ` ~ ` — отрицание;
+* `<<`, `>>` — сдвиги влево-вправо;
+* `|<<`, `>>|` — кольцевые сдвиги влево-вправо.
+
+#### Примеры
+
+```yql
+SELECT
+ key << 10 AS key,
+ ~value AS value
+FROM my_table;
+```
+
+### Приоритет и ассоциативность операторов {#operator-priority}
+
+Приоритет оператора определяет порядок вычисления выражения содержащего разные операторы.
+Например, выражение `1 + 2 * 3` вычисляется как `1 + (2 * 3)`,
+поскольку приоритет оператора умножения больше приоритета оператора сложения.
+
+Ассоциативность определяет порядок вычисления в выражениях содержащих операторы одного типа.
+Например, выражение `1 + 2 + 3` вычисляется как `(1 + 2) + 3`, поскольку оператор сложения является лево-ассоциативным.
+С другой стороны, выражение `a ?? b ?? c` вычисляется как `a ?? (b ?? c)` из-за право-ассоциативности оператора `??`
+
+В таблице ниже указаны приоритет и ассоциативность операторов языка YQL.
+Операторы в таблице перечислены в порядке убывания приоритета.
+
+| Приоритет | Оператор | Описание | Ассоциативность |
+| --- | --- | --- | --- |
+| 1 | `a[], a.foo, a()` | Обращение к элементу контейнера, вызов функции | Левая |
+| 2 | `+a, -a, ~a, NOT a` | Унарные операторы: плюс, минус, битовое и логическое отрицание | Правая |
+| 3 | `a\|\|b` | [Конкатенация строк](#concatenation) | Левая |
+| 4 | `a*b, a/b, a%b` | Умножение,деление, остаток от деления | Левая |
+| 5 | `a+b, a-b` | Сложение / вычитание | Левая |
+| 6 | `a ?? b` | Операторная форма записи [NVL/COALESCE](../builtins/basic.md#coalesce) | Правая |
+| 7 | `a<<b, a>>b, a\|<<b, a>>\|b,` `a\|b, a^b, a&b` | Сдвиговые и логические битовые операторы | Левая |
+| 8 | `a<b, a<=b, a>=b, a>b` | Сравнение | Левая |
+| 9 | `a IN b` | Вхождение элемента в множество | Левая |
+| 9 | `a==b, a=b, a!=b, a<>b,` `a is (not) distinct from b` | Сравнение на (не)равенство | Левая |
+| 10 | `a XOR b` | Логическое XOR | Левая |
+| 11 | `a AND b` | Логическое AND | Левая |
+| 12 | `a OR b` | Логическое OR | Левая |
+
+
+## IS \[NOT\] NULL {#is-null}
+
+Проверка на пустое значение (`NULL`). Так как `NULL` является особым значением, которое [ничему не равно](../types/optional.md#null_expr), то обычные [операторы сравнения](#comparison-operators) для этой задачи не подходят.
+
+### Примеры
+
+```yql
+SELECT key FROM my_table
+WHERE value IS NOT NULL;
+```
+
+## IS \[NOT\] DISTINCT FROM {#is-distinct-from}
+
+Сравнение двух значений. В отличие от обычных [операторов сравнения](#comparison-operators), нуллы считаются равными друг другу.
+
+Сравнение осуществляется по следующим правилам:
+
+1. операторы `IS DISTINCT FROM`/`IS NOT DISTINCT FROM` определены для тех и только для тех аргументов, для которых определены операторы `!=` и `=`;
+2. результат `IS NOT DISTINCT FROM` равен логическому отрицанию результата `IS DISTINCT FROM` для данных аргументов;
+3. если результат оператора `==` не равен нуллу для некоторых аргументов, то он совпадает с результатом оператора `IS NOT DISTINCT FROM` для тех же аргументов;
+4. если оба аргумента являются незаполненными `Optional`ми или `NULL`ами, то значение `IS NOT DISTINCT FROM` равно `True`
+5. результат `IS NOT DISTINCT FROM` от незаполненного `Optional` или `NULL` и заполненного `Optional` или не-`Optional` значения равен `False`.
+
+Для значений композитных типов эти правила применяются рекурсивно.
+
+## BETWEEN {#between}
+
+Проверка на вхождение значения в диапазон. Cинтаксис: `expr [NOT] BETWEEN [ASYMMETRIC | SYMMETRIC] expr AND expr`.
+
+* `BETWEEN` и `BETWEEN ASYMMETRIC` эквивалентны, `x BETWEEN a AND b` эквивалентно `a <= x AND x <= b`.
+* `BETWEEN SYMMETRIC` автоматически переставляет аргументы местами так чтобы диапазон получился непустым,
+`x BETWEEN SYMMETRIC a AND b` эквивалентно `(x BETWEEN a AND b) OR (x BETWEEN b AND a)`.
+* `NOT` инвертирует результат проверки.
+
+### Примеры
+
+```yql
+SELECT * FROM my_table
+WHERE key BETWEEN 10 AND 20;
+```
+
+```yql
+SELECT * FROM my_table
+WHERE key NOT BETWEEN SYMMETRIC 20 AND 10;
+```
+
+
+## IN {#in}
+
+Проверка вхождения одного значения в набор значений. Логически эквивалентно цепочке сравнений на равенство через `OR`, но реализовано более эффективно.
+
+{% note warning %}
+
+В отличие от аналогичного ключевого слова в Python, в YQL `IN` **НЕ** является поиском подстроки в строке. Для поиска подстроки можно использовать функцию [String::Contains](../udf/list/string.md) или описанные выше [LIKE / REGEXP](#check-match).
+
+{% endnote %}
+
+Сразу после `IN` можно указать [хинт](lexer.md#sql-hints) `COMPACT`.
+Если `COMPACT` не указан, то `IN` с подзапросом по возможности выполняется как соответствующий `JOIN` (`LEFT SEMI` для `IN` и `LEFT ONLY` для `NOT IN`).
+Наличие `COMPACT` форсирует in-memory стратегию выполнения: из содержимого правой части `IN` в памяти сразу строится хеш-таблица, по которой затем фильтруется левая часть.
+
+Хинтом `COMPACT` следует пользоваться с осторожностью. Поскольку хеш-таблица строится в памяти, то запрос может завершиться с ошибкой, если правая часть `IN` содержит много больших и/или различных элементов.
+
+Большие списки значений стоит прикладывать к запросу через URL и использовать функцию [ParseFile](../builtins/basic.md#parsefile).
+
+### Примеры
+
+```yql
+SELECT column IN (1, 2, 3)
+FROM my_table;
+```
+
+```yql
+SELECT * FROM my_table
+WHERE string_column IN ("a", "b", "c");
+```
+
+```yql
+$foo = AsList(1, 2, 3);
+SELECT 1 IN $foo;
+```
+
+```yql
+$values = (SELECT column + 1 FROM table);
+SELECT * FROM my_table WHERE
+ -- фильтрация по in-memory хеш-таблице на основе table
+ column1 IN /*+ COMPACT() */ $values AND
+ -- с последующим LEFT ONLY JOIN с other_table
+ column2 NOT IN (SELECT other_column FROM other_table);
+```
+
+
+## AS {#as}
+
+Может использоваться в следующих сценариях:
+
+* Присвоение короткого имени (алиаса) столбцам или таблицам в рамках запроса.
+* Указание именованных аргументов при вызове функций.
+* При явном приведении типов данных для указания целевого типа, см. [CAST](#cast).
+
+### Примеры
+
+```yql
+SELECT key AS k FROM my_table;
+```
+
+```yql
+SELECT t.key FROM my_table AS t;
+```
+
+```yql
+SELECT
+ MyFunction(key, 123 AS my_optional_arg)
+FROM my_table;
+```
+
+## CAST {#cast}
+
+Пробует привести значение к указанному типу. Попытка может оказаться неуспешной и вернуть `NULL`. Для чисел может потерять точность или старшие биты.
+
+Для списков и словарей может либо удалить, либо заменить на `NULL` элементы, преобразование которых неудачно.
+Для структур и кортежей удаляет элементы, которых нет в целевом типе.
+Подробнее правила преобразований описаны [здесь](../types/cast.md).
+
+{% include [decimal_args](../_includes/decimal_args.md) %}
+
+### Примеры
+
+{% include [cast_examples](../_includes/cast_examples.md) %}
+
+
+## BITCAST {#bitcast}
+
+Выполняет побитное преобразование целочисленного значения к указанному целочисленному типу. Преобразование всегда успешно, но может потерять точность или старшие биты.
+
+### Примеры
+
+```yql
+SELECT
+ BITCAST(100000ul AS Uint32), -- 100000
+ BITCAST(100000ul AS Int16), -- -31072
+ BITCAST(100000ul AS Uint16), -- 34464
+ BITCAST(-1 AS Int16), -- -1
+ BITCAST(-1 AS Uint16); -- 65535
+```
+
+
+## CASE {#case}
+
+Условные выражения и ветвление. Аналог `if`, `switch` и тернарных операторов в императивных языках программирования.
+Если результатом выражения `WHEN` оказывается `true`, значением выражения `CASE` становится результат,
+следующий за условием, а остальная часть выражения `CASE` не вычисляется. Если же условие не выполняется,
+за ним таким же образом проверяются все последующие предложения `WHEN`. Если не выполняется
+ни одно из условий `WHEN`, значением `CASE` становится результат, записанный в предложении `ELSE`.
+Ветка `ELSE` является обязательной в выражении `CASE`. Выражения в `WHEN` проверяются последовательно, сверху вниз.
+
+Так как синтаксис достаточно громоздкий, зачастую удобнее пользоваться встроенной функцией [IF](../builtins/basic.md#if).
+
+### Примеры
+
+```yql
+SELECT
+ CASE
+ WHEN value > 0
+ THEN "positive"
+ ELSE "negative"
+ END
+FROM my_table;
+```
+
+```yql
+SELECT
+ CASE value
+ WHEN 0 THEN "zero"
+ WHEN 1 THEN "one"
+ ELSE "not zero or one"
+ END
+FROM my_table;
+```
+
+
+## Именованные выражения {#named-nodes}
+
+Сложные запросы могут выглядеть громоздко и содержать много уровней вложенности и/или повторяющихся частей. В YQL имеется возможность использовать именованные выражения – способ назначить имя произвольному выражению или подзапросу. На это именованное выражение можно ссылаться в других выражениях или подзапросах. При этом фактически происходит подстановка исходного выражения/подзапроса по месту использования.
+
+Именованное выражение определяется следующим образом:
+
+```antlr
+<named-expr> = <expression> | <subquery>;
+```
+
+Здесь `<named-expr>` состоит из символа $ и произвольного непустого идентификатора (например `$foo`).
+
+Если выражение в правой части представляет собой кортеж, то его можно автоматически распаковать, указав в левой части несколько именованных выражений через запятую:
+
+```antlr
+<named-expr1>, <named-expr2>, <named-expr3> ... = <expression-returning-tuple>;
+```
+
+В этом случае число выражений должно совпадать с размером кортежа.
+
+У каждого именованного выражения есть область видимости. Она начинается сразу после определения именованного выражения и заканчивается в конце ближайшего охватывающего scope имен (например в конце запроса либо в конце тела [лямбда-функции](#lambda), [ACTION](action.md#define-action), [SUBQUERY](subquery.md#define-subquery) или цикла [EVALUATE FOR](action.md#evaluate-for)).
+Повторное определение именованного выражения с тем же именем приводит к сокрытию предыдущего выражения из текущей области видимости.
+
+Если именованное выражение ни разу не использовалось, то генерируется предупреждение. Для того, чтобы избавиться от такого предупреждения, достаточно использовать символ подчеркивания в качестве первого символа идентификатора (например `$_foo`).
+Именованное выражение `$_` называется анонимным именованным выражением и обрабатывается специальным образом: оно работает, как если бы `$_` автоматически заменялось на `$_<some_uniq_name>`.
+Анонимными именованными выражениями удобно пользоваться в тех случаях, когда мы не интересуемся его значением. Например, для извлечения второго элемента из кортежа из трех элементов можно написать:
+
+```yql
+$_, $second, $_ = AsTuple(1, 2, 3);
+select $second;
+```
+
+Попытка сослаться на анонимное именованное выражение приводит к ошибке:
+
+```yql
+$_ = 1;
+select $_; --- ошибка: Unable to reference anonymous name $_
+export $_; --- ошибка: Can not export anonymous name $_
+```
+
+Кроме того, нельзя импортировать именованное выражение под анонимным алиасом:
+
+```yql
+import utils symbols $sqrt as $_; --- ошибка: Can not import anonymous name $_
+```
+
+Анонимные имена аргументов поддерживаются также для [лямбда-функций](#lambda), [ACTION](action.md#define-action), [SUBQUERY](subquery.md#define-subquery) и в [EVALUATE FOR](action.md#evaluate-for).
+
+{% note info %}
+
+Если в результате подстановки именованных выражений в графе выполнения запроса получились полностью одинаковые подграфы, они объединяются, чтобы такой подграф выполнялся только один раз.
+
+{% endnote %}
+
+### Примеры
+
+```yql
+$multiplier = 712;
+SELECT
+ a * $multiplier, -- $multiplier is 712
+ b * $multiplier,
+ (a + b) * $multiplier
+FROM abc_table;
+```
+
+```yql
+$intermediate = (
+ SELECT
+ value * value AS square,
+ value
+ FROM my_table
+);
+SELECT a.square * b.value
+FROM $intermediate AS a
+INNER JOIN $intermediate AS b
+ON a.value == b.square;
+```
+
+```yql
+$a, $_, $c = AsTuple(1, 5u, "test"); -- распаковка кортежа
+SELECT $a, $c;
+```
+
+```yql
+$x, $y = AsTuple($y, $x); -- swap значений выражений
+```
+
+
+## Табличные выражения {#table-contexts}
+
+Табличное выражения – это выражение, которое возвращает таблицу. Табличными выражениями в YQL являются:
+
+* подзапросы: `(SELECT key, subkey FROM T)`
+* [именованные подзапросы](#named-nodes): `$foo = SELECT * FROM T;` (использование именованного подзапроса `$foo` является табличным выражением)
+* [шаблоны подзапросов](subquery.md#define-subquery): `DEFINE SUBQUERY $foo($name) AS ... END DEFINE;` (вызов `$foo("InputTable")` является табличным выражением).
+
+
+Семантика табличного выражения зависит от контекста в котором оно используется. В YQL табличные выражения могут применяться в следующих контекстах:
+
+* табличный контекст - после [FROM](select/from.md).
+
+ Здесь табличные выражения работают как ожидается – например `$input = SELECT a, b, c FROM T; SELECT * FROM $input` вернет таблицу с тремя колонками.
+
+ Табличный контекст также возникает после [UNION ALL](select/index.md#unionall), [JOIN](join.md#join), [PROCESS](process.md#process), [REDUCE](reduce.md#reduce);
+
+* векторный контекст - после [IN](#in). В этом контексте табличное выражение обязано содержать ровно одну колонку (имя этой колонки никак не влияет на результат выражения).
+
+ Табличное выражение в векторном контексте типизируется как список (тип элемента списка при этом совпадает с типом колонки). Пример: `SELECT * FROM T WHERE key IN (SELECT k FROM T1)`;
+
+* скалярный контекст возникает *во всех остальных случаях*. Как и в векторном контексте, табличное выражение должно содержать ровно одну колонку, но значением табличного выражения будет скаляр – произвольно выбранное значение этой колонки (если получилось ноль строк, то результатом будет `NULL`). Пример: `$count = SELECT COUNT(*) FROM T; SELECT * FROM T ORDER BY key LIMIT $count / 2`.
+
+Порядок строк в табличном контексте, порядок элементов в векторном контексте и правило выбора значения в скалярном контексте (в случае если значений несколько) не определены. На этот порядок также нельзя повлиять с помощью `ORDER BY`: `ORDER BY` без `LIMIT` в табличных выражениях будет игнорироваться с выдачей предупреждения, а использование `ORDER BY` с `LIMIT` определяет множество элементов, но не порядок внутри этого множества.
+
+Из этого правила есть исключение. Именованное выражение с [PROCESS](process.md#process), будучи использованным в скалярном контексте, ведет себя как в табличном:
+
+```yql
+$input = SELECT 1 AS key, 2 AS value;
+$process = PROCESS $input;
+
+SELECT FormatType(TypeOf($process)); -- $process используется в скалярном контексте,
+ -- но результат SELECT при этом - List<Struct<'key':Int32,'value':Int32>>
+
+SELECT $process[0].key; -- вернет 1
+
+SELECT FormatType(TypeOf($input)); -- ошибка: $input в скалярном контексте должен содержать одну колонку
+```
+
+{% note warning "Внимание" %}
+
+Часто встречающейся ошибкой является использование выражения в скалярном контексте вместо табличного или векторного. Например:
+
+```yql
+$dict = SELECT key, value FROM T1;
+
+DEFINE SUBQUERY $merge_dict($table, $dict) AS
+SELECT * FROM $table LEFT JOIN $dict USING(key);
+END DEFINE;
+
+SELECT * FROM $merge_dict("Input", $dict); -- $dict здесь используется в скалярном контексте.
+ -- ошибка - в скалярном контексте ожидается ровно одна колонка
+
+```
+
+Правильное решение в данном случае выглядит так:
+
+```yql
+DEFINE SUBQUERY $dict() AS
+SELECT key, value FROM T1;
+END DEFINE;
+
+DEFINE SUBQUERY $merge_dict($table, $dict) AS
+SELECT * FROM $table LEFT JOIN $dict() USING(key); -- использование табличного выражения $dict()
+ -- (вызов шаблона подзапроса) в табличном контексте
+END DEFINE;
+
+SELECT * FROM $merge_dict("Input", $dict); -- $dict - шаблон позапроса (не табличное выражение)
+ -- передаваемый в качестве аргумента табличного выражения
+```
+
+{% endnote %}
+
+## Lambda функции {#lambda}
+
+Позволяют комбинировать несколько выражений в одно вызываемое значение.
+
+В круглых скобках перечисляются аргументы, далее после стрелки указывается тело lambda. Тело lambda состоит либо из выражения в круглых скобках, либо из фигурных скобок вокруг необязательной цепочки выражений с присвоением [именованных выражений](#named-nodes) и результата вызова после ключевого слова `RETURN` в последнем выражении.
+
+Область видимости для тела lambda — сначала локальные именованные выражения, затем аргументы, затем именованные выражения, определенные выше lambda на верхнем уровне запроса.
+
+В теле lambda можно использовать только чистые выражения — в том числе другие lambda, возможно, переданные через аргументы. Но нельзя использовать [SELECT](select/index.md), [INSERT INTO](insert_into.md) и прочие выражения верхнего уровня.
+
+Один или более последних параметров lambda могут быть помечены вопросиком как необязательные — если они не были указаны при вызове lambda, то им будет присвоено значение `NULL`.
+
+### Примеры
+
+```yql
+$f = ($y) -> {
+ $prefix = "x";
+ RETURN $prefix || $y;
+};
+
+$g = ($y) -> ("x" || $y);
+
+$h = ($x, $y?) -> ($x + ($y ?? 0));
+
+SELECT $f("y"), $g("z"), $h(1), $h(2, 3); -- "xy", "xz", 1, 5
+```
+
+```yql
+-- если результат лямбды вычисляется единственным выражением, то можно использовать более компактный вариант синтаксиса:
+$f = ($x, $_) -> ($x || "suffix"); -- второй аргумент не используется
+SELECT $f("prefix_", "whatever");
+```
+
+
+## Обращение к контейнерам {#items-access}
+
+Для адресации к значениям внутри контейнеров:
+
+* `Struct<>`, `Tuple<>` и `Variant<>` — используется **точка**. Набор ключей (для кортежа и соответствующего варианта — индексов) известен в момент компиляции запроса. Валидность ключа **проверяется** до начала выполнения запроса.
+* `List<>` и `Dict<>` — используются **квадратные скобки**. Набор ключей (для списка — индексов) известен только во время выполнения запроса. Валидность ключа **не проверяется** до начала выполнения запроса. Если значение не найдено — будет возвращено пустое значение (NULL)
+
+[Описание и список доступных контейнеров](../types/containers.md).
+
+При использовании этого синтаксиса для обращения к контейнерам в столбцах таблиц обязательно нужно указывать полное имя столбца, включая имя или алиас таблицы через точку (см. первый пример ниже).
+
+### Примеры
+
+```yql
+SELECT
+ t.struct.member,
+ t.tuple.7,
+ t.dict["key"],
+ t.list[7]
+FROM my_table AS t;
+```
+
+```yql
+SELECT
+ Sample::ReturnsStruct().member;
+```
+
diff --git a/yql/essentials/docs/ru/syntax/flatten.md b/yql/essentials/docs/ru/syntax/flatten.md
new file mode 100644
index 0000000000..7f5c2a800e
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/flatten.md
@@ -0,0 +1,138 @@
+# FLATTEN
+
+## FLATTEN BY {#flatten-by}
+
+Преобразует строки исходной таблицы с помощью вертикального разворачивания [контейнеров](../types/containers.md) переменной длины (списков или словарей).
+
+Например:
+
+* Исходная таблица:
+
+ |[a, b, c]|1|
+ | --- | --- |
+ |[d]|2|
+ |[]|3|
+
+* Таблица после вызова `FLATTEN BY` к левому столбцу:
+
+ |a|1|
+ | --- | --- |
+ |b|1|
+ |c|1|
+ |d|2|
+
+
+### Пример
+
+```yql
+$sample = AsList(
+ AsStruct(AsList('a','b','c') AS value, CAST(1 AS Uint32) AS id),
+ AsStruct(AsList('d') AS value, CAST(2 AS Uint32) AS id),
+ AsStruct(AsList() AS value, CAST(3 AS Uint32) AS id)
+);
+
+SELECT value, id FROM as_table($sample) FLATTEN BY (value);
+```
+
+Такое преобразование может быть удобным в следующих случаях:
+
+* Когда по ячейкам из столбца-контейнера необходимо вывести статистику (например, через [`GROUP BY`](group_by.md)).
+* Когда в ячейках столбца-контейнера хранятся идентификаторы из другой таблицы, которую нужно присоединить с помощью [`JOIN`](join.md).
+
+### Синтаксис
+
+* `FLATTEN BY` указывается после `FROM`, но перед `GROUP BY`, если `GROUP BY` присутствует в запросе.
+* Тип столбца-результата зависит от типа исходного столбца:
+
+| Тип контейнера | Тип результата | Комментарий |
+| --- | --- | --- |
+| `List<X>` | `X` | Тип ячейки списка |
+| `Dict<X,Y>` | `Tuple<X,Y>` | Кортеж из двух элементов с парами «ключ—значение» |
+| `Optional<X>` | `X` | Результат практически эквивалентен конструкции `WHERE foo IS NOT NULL`, но тип колонки `foo` будет изменен на `X`|
+
+* По умолчанию столбец с результатом заменяет исходный. Используйте `FLATTEN BY foo AS bar` для сохранения исходного контейнера. В результате исходный контейнер останется доступным в `foo`, а построенный — в `bar`.
+* Чтобы построить декартово произведение нескольких столбцов-контейнеров, используйте конструкцию `FLATTEN BY (a, b, c)`. Скобки обязательны, чтобы избежать конфликтов в грамматике.
+* В `FLATTEN BY` можно использовать только имена столбцов из входной таблицы. Чтобы применить `FLATTEN BY` к результату вычисления, используйте подзапрос.
+* В `FLATTEN BY` можно использовать не только столбцы, но и произвольные именованные выражения (в отличие от столбцов `AS` обязательно). Из-за грамматических неоднозначностей выражения после `FLATTEN BY` должны быть заключены в скобки: `... FLATTEN BY (ListSkip(col, 1) AS col) ...`
+* Если в исходном столбце были вложенные контейнеры, например `List<Dict<X,Y>>`, `FLATTEN BY` развернет только внешний уровень. Чтобы полностью развернуть вложенные контейнеры, используйте подзапрос.
+
+{% note info %}
+
+`FLATTEN BY` интерпретирует [опциональные типы данных](../types/optional.md) как списки длины 0 или 1. Строки таблицы с `NULL` пропускаются, и тип столбца меняется на аналогичный неопциональный.
+
+`FLATTEN BY` делает только одно преобразование за раз, поэтому на опциональных контейнерах, например, `Optional<List<String>>` следует использовать `FLATTEN LIST BY` или `FLATTEN OPTIONAL BY`.
+
+{% endnote %}
+
+### Уточнение типа контейнера {#flatten-by-specific-type}
+
+Чтобы уточнить тип контейнера, по которому необходимо произвести преобразование, можно использовать:
+
+* `FLATTEN LIST BY`
+
+ Для `Optional<List<T>>` операция `FLATTEN LIST BY` будет разворачивать список, интерпретируя `NULL`-значение как пустой список.
+* `FLATTEN DICT BY`
+
+ Для `Optional<Dict<T>>` операция `FLATTEN DICT BY` будет разворачивать словарь, интерпретируя `NULL`-значение как пустой словарь.
+* `FLATTEN OPTIONAL BY`
+
+ Чтобы фильтровать `NULL`-значения без размножения, необходимо уточнить операцию до `FLATTEN OPTIONAL BY`.
+
+#### Примеры
+
+```yql
+SELECT
+ t.item.0 AS key,
+ t.item.1 AS value,
+ t.dict_column AS original_dict,
+ t.other_column AS other
+FROM my_table AS t
+FLATTEN DICT BY dict_column AS item;
+```
+
+```yql
+SELECT * FROM (
+ SELECT
+ AsList(1, 2, 3) AS a,
+ AsList("x", "y", "z") AS b
+) FLATTEN LIST BY (a, b);
+```
+
+```yql
+SELECT * FROM (
+ SELECT
+ "1;2;3" AS a,
+ AsList("x", "y", "z") AS b
+) FLATTEN LIST BY (String::SplitToList(a, ";") as a, b);
+```
+
+### Аналоги FLATTEN BY для других СУБД {#flatten-other-dmb}
+
+* PostgreSQL: `unnest`;
+* Hive: `LATERAL VIEW`;
+* MongoDB: `unwind`;
+* Google BigQuery: `FLATTEN`;
+* ClickHouse: `ARRAY JOIN / arrayJoin`;
+
+
+
+
+## FLATTEN COLUMNS {#flatten-columns}
+
+Преобразует таблицу, в которой все столбцы должны являться структурами, в таблицу со столбцами, соответствующими каждому элементу каждой структуры из исходных столбцов.
+
+Имена исходных столбцов-структур не используются и не возвращаются в результате. Имена элементов структур не должны повторяться в исходных столбцах.
+
+### Пример
+
+```yql
+SELECT x, y, z
+FROM (
+ SELECT
+ AsStruct(
+ 1 AS x,
+ "foo" AS y),
+ AsStruct(
+ false AS z)
+) FLATTEN COLUMNS;
+```
diff --git a/yql/essentials/docs/ru/syntax/group_by.md b/yql/essentials/docs/ru/syntax/group_by.md
new file mode 100644
index 0000000000..6d0732e7e0
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/group_by.md
@@ -0,0 +1,265 @@
+## GROUP BY
+
+Группирует результаты `SELECT` по значениям указанных столбцов или выражений. Вместе с `GROUP BY` часто применяются [агрегатные функции](../builtins/aggregation.md) (`COUNT`, `MAX`, `MIN`, `SUM`, `AVG`) для выполнения вычислений в каждой группе.
+
+### Синтаксис
+
+```yql
+SELECT -- В SELECT можно использовать:
+ column1, -- ключевые колонки, заданные в GROUP BY
+ key_n, -- именованные выражения, заданные в GROUP BY
+ column1 + key_n, -- произвольные неагрегатные функции от них
+ Aggr_Func1( column2 ), -- агрегатные функции, содержащие в аргументах любые колонки,
+ Aggr_Func2( key_n + column2 ), -- включая именованные выражения, заданные в GROUP BY
+ ...
+FROM table
+GROUP BY
+ column1, column2, ...,
+ <expr> AS key_n -- При группировке по выражению ему может быть задано имя через AS,
+ -- которое может быть использовано в SELECT
+```
+
+Запрос вида `SELECT * FROM table GROUP BY k1, k2, ...` вернет все колонки, перечисленные в GROUP BY, то есть экивалентент запросу `SELECT DISTINCT k1, k2, ... FROM table`.
+
+Звездочка может также применяться в качестве аргумента агрегатной функции `COUNT`. `COUNT(*)` означает "число строк в группе".
+
+
+{% note info %}
+
+Агрегатные функции не учитывают `NULL` в своих аргументах, за исключением функции `COUNT`.
+
+{% endnote %}
+
+Также в YQL доступен механизм фабрик агрегатных функций, реализованный с помощью функций [`AGGREGATION_FACTORY`](../builtins/basic.md#aggregationfactory) и [`AGGREGATE_BY`](../builtins/aggregation.md#aggregateby).
+
+### Примеры
+
+```yql
+SELECT key, COUNT(*) FROM my_table
+GROUP BY key;
+```
+
+```yql
+SELECT double_key, COUNT(*) FROM my_table
+GROUP BY key + key AS double_key;
+```
+
+```yql
+SELECT
+ double_key, -- ОК: ключевая колонка
+ COUNT(*) AS group_size, -- OK: COUNT(*)
+ SUM(key + subkey) AS sum1, -- ОК: агрегатная функция
+ CAST(SUM(1 + 2) AS String) AS sum2, -- ОК: агрегатная функция с константным аргументом
+ SUM(SUM(1) + key) AS sum3, -- ОШИБКА: вложенные агрегации не допускаются
+ key AS k1, -- ОШИБКА: использование неключевой колонки key без агрегации
+ key * 2 AS dk1, -- ОШИБКА в YQL: использование неключевой колонки key без агрегации
+FROM my_table
+GROUP BY
+ key * 2 AS double_key,
+ subkey as sk,
+
+```
+
+
+{% note warning %}
+
+Возможность указывать имя для колонки или выражения в `GROUP BY .. AS foo` является расширением YQL. Такое имя становится видимым в `WHERE` несмотря на то, что фильтрация по `WHERE` выполняется [раньше](select/index.md#selectexec) группировки. В частности, если в таблице `T` есть две колонки `foo` и `bar`, то в запросе `SELECT foo FROM T WHERE foo > 0 GROUP BY bar AS foo` фильтрация фактически произойдет по колонке `bar` из исходной таблицы.
+
+{% endnote %}
+
+
+## GROUP BY ... SessionWindow() {#session-window}
+
+В YQL поддерживаются группировки по сессиям. К обычным выражениям в `GROUP BY` можно добавить специальную функцию `SessionWindow`:
+
+```yql
+SELECT
+ user,
+ session_start,
+ SessionStart() AS same_session_start, -- то же что и session_start
+ COUNT(*) AS session_size,
+ SUM(value) AS sum_over_session,
+FROM my_table
+GROUP BY user, SessionWindow(<time_expr>, <timeout_expr>) AS session_start
+```
+
+При этом происходит следующее:
+
+1. Входная таблица партиционируется по ключам группировки, указанным в `GROUP BY`, без учета SessionWindow (в данном случае по `user`). Если кроме SessionWindow в `GROUP BY` ничего нет, то входная таблица попадает в одну партицию
+2. Каждая партиция делится на непересекающие подмножества строк (сессии). Для этого партиция сортируется по возрастанию значения выражения `time_expr`. Границы сессий проводятся между соседними элементами партиции, разница значений `time_expr` для которых превышает `timeout_expr`
+3. Полученные таким образом сессии и являются финальными партициями, на которых вычисляются агрегатные функции.
+
+Ключевая колонка SessionWindow() (в примере `session_start`) имеет значение "минимальный `time_expr` в сессии".
+Кроме того, при наличии SessionWindow() в `GROUP BY` может использоваться специальная агрегатная функция
+[SessionStart](../builtins/aggregation.md#session-start).
+
+Поддерживается также расширенный вариант SessionWindow с четырьмя аргументами:
+
+`SessionWindow(<order_expr>, <init_lambda>, <update_lambda>, <calculate_lambda>)`
+
+Здесь:
+
+* `<order_expr>` – выражение по которому сортируется исходная партиция
+* `<init_lambda>` – лямбда-функция для инициализации состояния расчета сессий. Имеет сигнатуру `(TableRow())->State`. Вызывается один раз на первом (по порядку сортировки) элементе исходной партиции
+* `<update_lambda>` – лямбда-функция для обновления состояния расчета сессий и определения границ сессий. Имеет сигнатуру `(TableRow(), State)->Tuple<Bool, State>`. Вызывается на каждом элементе исходной партиции, кроме первого. Новое значения состояния вычисляется на основе текущей строки таблицы и предыдущего состояния. Если первый элемент возвращенного кортежа имеет значение `True`, то с _текущей_ строки начнется новая сессия. Ключ новой сессии получается путем применения `<calculate_lambda>` ко второму элементу кортежа.
+* `<calculate_lambda>` – лямбда-функция для вычисления ключа сессии ("значения" SessionWindow(), которое также доступно через SessionStart()). Функция имеет сигнатуру `(TableRow(), State)->SessionKey`. Вызывается на первом элемента партиции (после `<init_lambda>`) и на тех элементах, для которых `<update_lambda>` вернула `True` в качестве первого элемента кортежа. Стоит отметить, что для начала новой сессии необходимо, чтобы `<calculate_lambda>` вернула значение, которое отличается от предыдущего ключа сессии. При этом сессии с одинаковыми ключами не объединяются. Например, если `<calculate_lambda>` последовательно возвращает `0, 1, 0, 1`, то это будут четыре различные сессии.
+
+С помощью расширенного варианта SessionWindow можно решить, например, такую задачу: разделить партицию на сессии как в варианте SessionWindow с двумя аргументами, но с ограничением максимальной длины сессии некоторой константой:
+
+### Пример
+
+```yql
+$max_len = 1000; -- максимальная длина сессии
+$timeout = 100; -- таймаут (timeout_expr в упрощенном варианте SessionWindow)
+
+$init = ($row) -> (AsTuple($row.ts, $row.ts)); -- состояние сессии - тапл из 1) значения временной колонки ts на первой строчке сессии и 2) на текущей строчке
+$update = ($row, $state) -> {
+ $is_end_session = $row.ts - $state.0 > $max_len OR $row.ts - $state.1 > $timeout;
+ $new_state = AsTuple(IF($is_end_session, $row.ts, $state.0), $row.ts);
+ return AsTuple($is_end_session, $new_state);
+};
+$calculate = ($row, $state) -> ($row.ts);
+SELECT
+ user,
+ session_start,
+ SessionStart() AS same_session_start, -- то же что и session_start
+ COUNT(*) AS session_size,
+ SUM(value) AS sum_over_session,
+FROM my_table
+GROUP BY user, SessionWindow(ts, $init, $update, $calculate) AS session_start
+```
+
+`SessionWindow` может использоваться в `GROUP BY` только один раз.
+
+## ROLLUP, CUBE и GROUPING SETS {#rollup}
+
+Результаты вычисления агрегатной функции в виде промежуточных итогов для групп и общих итогов для отдельных столбцов или всей таблицы.
+
+### Синтаксис
+
+```yql
+SELECT
+ c1, c2, -- столбцы, по которым производится группировка
+
+AGGREGATE_FUNCTION(c3) AS outcome_c -- агрегатная функция (SUM, AVG, MIN, MAX, COUNT)
+
+FROM table_name
+
+GROUP BY
+ GROUP_BY_EXTENSION(c1, c2) -- расширение GROUP BY: ROLLUP, CUBE или GROUPING SETS
+```
+
+* `ROLLUP` — группирует значения столбцов в порядке их перечисления в аргументах (строго слева направо), формирует промежуточные итоги для каждой группы и общий итог.
+* `CUBE` — группирует значения для всех возможных комбинаций столбцов, формирует промежуточные итоги для каждой группы и общий итог.
+* `GROUPING SETS` — задает группы для промежуточных итогов.
+
+`ROLLUP`, `CUBE` и `GROUPING SETS` можно комбинировать через запятую.
+
+### GROUPING {#grouping}
+
+В промежуточном итоге значения столбцов, которые не участвуют в вычислениях, заменяются на `NULL`. В общем итоге на `NULL` заменяются значения всех столбцов. `GROUPING` — функция, которая позволяет отличить исходные значения `NULL` от `NULL`, которые были добавлены при формировании общих и промежуточных итогов.
+
+`GROUPING` возвращает битовую маску:
+
+* `0` — `NULL` для исходного пустого значения.
+* `1` — `NULL`, добавленный для промежуточного или общего итога.
+
+### Пример
+
+```yql
+SELECT
+ column1,
+ column2,
+ column3,
+
+ CASE GROUPING(
+ column1,
+ column2,
+ column3,
+ )
+ WHEN 1 THEN "Subtotal: column1 and column2"
+ WHEN 3 THEN "Subtotal: column1"
+ WHEN 4 THEN "Subtotal: column2 and column3"
+ WHEN 6 THEN "Subtotal: column3"
+ WHEN 7 THEN "Grand total"
+ ELSE "Individual group"
+ END AS subtotal,
+
+ COUNT(*) AS rows_count
+
+FROM my_table
+
+GROUP BY
+ ROLLUP(
+ column1,
+ column2,
+ column3
+ ),
+ GROUPING SETS(
+ (column2, column3),
+ (column3)
+ -- если добавить сюда ещё (column2), то в сумме
+ -- эти ROLLUP и GROUPING SETS дали бы результат,
+ -- аналогичный CUBE
+ )
+;
+```
+
+## DISTINCT {#distinct}
+
+Применение [агрегатных функций](../builtins/aggregation.md) только к уникальным значениям столбца.
+
+{% note info %}
+
+Применение `DISTINCT` к вычислимым значениям на данный момент не реализовано. С этой целью можно использовать [подзапрос](select/from.md) или выражение `GROUP BY ... AS ...`.
+
+{% endnote %}
+
+### Пример
+
+```yql
+SELECT
+ key,
+ COUNT(DISTINCT value) AS count -- топ-3 ключей по количеству уникальных значений
+FROM my_table
+GROUP BY key
+ORDER BY count DESC
+LIMIT 3;
+```
+
+Также ключевое слово `DISTINCT` может использоваться для выборки уникальных строк через [`SELECT DISTINCT`](select/distinct.md).
+
+
+## COMPACT
+
+Наличие [SQL хинта](lexer.md#sql-hints) `COMPACT` непосредственно после ключевого слова `GROUP` позволяет более эффективно выполнять агрегацию в тех случаях, когда автору запроса заранее известно, что ни по одному из ключей агрегации не встречаются большие объемы данных (больше примерно гигабайт или миллионов строк). Если это предположение на практике окажется неверным, то операция может завершиться ошибкой из-за превышения потребления оперативной памяти или работать значительно медленнее не-COMPACT версии.
+
+В отличие от обычного GROUP BY, отключается стадия Map-side combiner и дополнительные Reduce для каждого поля с [DISTINCT](#distinct) агрегацией.
+
+### Пример
+
+```yql
+SELECT
+ key,
+ COUNT(DISTINCT value) AS count -- топ-3 ключей по количеству уникальных значений
+FROM my_table
+GROUP /*+ COMPACT() */ BY key
+ORDER BY count DESC
+LIMIT 3;
+```
+
+
+## HAVING {#having}
+
+Фильтрация выборки `SELECT` по результатам вычисления [агрегатных функций](../builtins/aggregation.md). Синтаксис аналогичен конструкции [`WHERE`](select/where.md).
+
+### Пример
+
+```yql
+SELECT
+ key
+FROM my_table
+GROUP BY key
+HAVING COUNT(value) > 100;
+```
+
diff --git a/yql/essentials/docs/ru/syntax/index.md b/yql/essentials/docs/ru/syntax/index.md
new file mode 100644
index 0000000000..2fbea1dd77
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/index.md
@@ -0,0 +1,22 @@
+# Список статей по синтаксису YQL
+
+* [Лексическая структура](lexer.md)
+* [Выражения](expressions.md)
+* [ACTION](action.md)
+* [COMMIT](commit.md)
+* [DECLARE](declare.md)
+* [DISCARD](discard.md)
+* [EXPORT и IMPORT](export_import.md)
+* [FLATTEN](flatten.md)
+* [GROUP BY](group_by.md)
+* [INSERT](insert_into.md)
+* [INTO RESULT](into_result.md)
+* [JOIN](join.md)
+* [PRAGMA](pragma.md)
+* [PROCESS](process.md)
+* [REDUCE](reduce.md)
+* [SELECT](select/index.md)
+* [SUBQUERY](subquery.md)
+* [USE](use.md)
+* [VALUES](values.md)
+* [WINDOW](window.md)
diff --git a/yql/essentials/docs/ru/syntax/insert_into.md b/yql/essentials/docs/ru/syntax/insert_into.md
new file mode 100644
index 0000000000..717bc051f9
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/insert_into.md
@@ -0,0 +1,33 @@
+
+# INSERT INTO
+
+Добавляет строки в таблицу.
+
+Таблица по имени ищется в базе данных, заданной оператором [USE](use.md).
+
+`INSERT INTO` позволяет выполнять следующие операции:
+
+* Добавление константных значений с помощью [`VALUES`](values.md).
+
+ ```yql
+ INSERT INTO my_table (Key1, Key2, Value1, Value2)
+ VALUES (345987,'ydb', 'Яблочный край', 1414);
+ COMMIT;
+ ```
+
+ ```yql
+ INSERT INTO my_table (key, value)
+ VALUES ("foo", 1), ("bar", 2);
+ ```
+
+* Сохранение результата выборки `SELECT`.
+
+ ```yql
+ INSERT INTO my_table
+ SELECT Key AS Key1, "Empty" AS Key2, Value AS Value1
+ FROM my_table1;
+ ```
+
+Запись может выполняться с одним или несколькими модификаторами. Модификатор указывается после ключевого слова `WITH` после имени таблицы: `INSERT INTO ... WITH SOME_HINT`.
+Если у модификатора есть значение, то оно указывается после знака `=`: `INSERT INTO ... WITH SOME_HINT=value`.
+Если необходимо указать несколько модификаторов, то они заключаются в круглые скобки: `INSERT INTO ... WITH (SOME_HINT1=value, SOME_HINT2, SOME_HINT3=value)`.
diff --git a/yql/essentials/docs/ru/syntax/into_result.md b/yql/essentials/docs/ru/syntax/into_result.md
new file mode 100644
index 0000000000..576113fd0a
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/into_result.md
@@ -0,0 +1,19 @@
+
+# INTO RESULT
+
+Позволяет задать пользовательскую метку для [SELECT](select/index.md), [PROCESS](process.md) или [REDUCE](reduce.md). Не может быть задано одновременно с [DISCARD](discard.md).
+
+## Примеры
+
+```yql
+SELECT 1 INTO RESULT foo;
+```
+
+```yql
+SELECT * FROM
+my_table
+WHERE value % 2 == 0
+INTO RESULT `Название результата`;
+```
+
+
diff --git a/yql/essentials/docs/ru/syntax/join.md b/yql/essentials/docs/ru/syntax/join.md
new file mode 100644
index 0000000000..eada7b163b
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/join.md
@@ -0,0 +1,146 @@
+
+# JOIN
+
+Позволяет объединить несколько источников данных (подзапросов или таблиц) по равенству значений указанных столбцов или выражений (ключей `JOIN`).
+
+## Синтаксис
+
+```yql
+SELECT ... FROM table_1
+-- первый шаг объединения:
+ <Join_Type> JOIN table_2 <Join_Condition>
+ -- исходная выборка -- записи в таблице table_1
+ -- присоединяемая выборка -- записи в таблице table_2
+-- следующий шаг объединения:
+ <Join_Type> JOIN table_n <Join_Condition>
+ -- исходная выборка -- результат объединения на предыдущем шаге
+ -- присоединяемая выборка -- записи в таблице table_n
+-- могут быть следующие шаги объединения
+...
+WHERE ...
+```
+
+На каждом шаге объединения по заданным правилам определяются соответствия между строками исходной и присоединяемой выборок данных, и формируется новая выборка, в которую попадают все сочетания подошедших под условия объединения строк.
+
+{% note warning "Внимание" %}
+
+Так как колонки в YQL идентифицируются по именам, и в выборке не может быть двух колонок с одинаковыми именами, `SELECT * FROM ... JOIN ...` не может быть исполнен при наличии колонок с одинаковыми именами в объединяемых таблицах.
+
+{% endnote %}
+
+## Типы объединения (Join_Type)
+
+* `INNER` <span style="color: gray;">(по умолчанию)</span> — Строки объединяемых выборок, для которых не найдено соответствие ни с одной строкой с другой стороны, не попадут в результат.
+* `LEFT` - При отсутствии значения в присоединяемой выборке включает строку в результат со значениям колонок из исходной выборки, оставляя пустыми (`NULL`) колонки присоединяемой выборки
+* `RIGHT` - При отсутствии значения в исходной выборке включает строку в результат со значениям колонок из присоединяемой выборки, оставляя пустыми (`NULL`) колонки исходной выборки
+* `FULL` = `LEFT` + `RIGHT`
+* `LEFT/RIGHT SEMI` — одна сторона выступает как белый список (whitelist) ключей, её значения недоступны. В результат включаются столбцы только из одной таблицы, декартового произведения не возникает;
+* `LEFT/RIGHT ONLY` — вычитание множеств по ключам (blacklist). Практически эквивалентно добавлению условия `IS NULL` на ключ противоположной стороны в обычном `LEFT/RIGHT`, но, как и в `SEMI`, нет доступа к значениям;
+* `CROSS` — декартово произведение двух таблиц целиком без указания ключевых колонок, секция с `ON/USING` явно не пишется;
+* `EXCLUSION` — обе стороны минус пересечение.
+
+![JOIN](_assets/join-YQL-06.png)
+
+{% note info %}
+
+`NULL` является особым значением, которое ничему не равно. Таким образом, `NULL` с двух сторон не считаются равными друг другу. Это избавляет от неоднозначности в некоторых типах `JOIN`, а также от гигантского декартового произведения, которое часто возникает в противном случае.
+
+{% endnote %}
+
+## Условия объединения (Join_Condition)
+
+Для `CROSS JOIN` условие объединения не указывается. В результат попадет декартово произведение исходной и присоединяемой выборок, то есть сочетание всех со всеми. Количество строк в результирующей выборке будет произведением количества строк исходной и присоединяемой выборок.
+
+Для любых других типов объединения необходимо указать условие одним из двух способов:
+
+1. `USING (column_name)`. Используется при наличии в исходной и присоединяемой выборках одноименной колонки, равенство значений в которой является условием объединения.
+2. `ON (equality_conditions)`. Позволяет задать условие равенства значений колонок или выражений над колонками исходной и присоединяемой выборок, или несколько таких условий, объединенных по `and`.
+
+### Примеры
+
+```yql
+SELECT a.value as a_value, b.value as b_value
+FROM a_table AS a
+FULL JOIN b_table AS b USING (key);
+```
+
+```yql
+SELECT a.value as a_value, b.value as b_value
+FROM a_table AS a
+FULL JOIN b_table AS b ON a.key = b.key;
+```
+
+```yql
+SELECT a.value as a_value, b.value as b_value, c.column2
+FROM a_table AS a
+CROSS JOIN b_table AS b
+LEFT JOIN c_table AS c ON c.ref = a.key and c.column1 = b.value;
+```
+
+Для исключения необходимости в полном сканировании правой присоединяемой таблицы может использоваться вторичный индекс над колонками, входящими в условие соединения. Обращение ко вторичному индексу должно быть указано в явном виде, в формате `JOIN table_name VIEW index_name AS table_alias`.
+
+Например, создание индекса для использования в условии соединения:
+
+```yql
+ALTER TABLE b_table ADD INDEX b_index_ref GLOBAL ON(ref);
+```
+
+Использование созданного индекса:
+
+```yql
+SELECT a.value as a_value, b.value as b_value
+FROM a_table AS a
+INNER JOIN b_table VIEW b_index_ref AS b ON a.ref = b.ref;
+```
+
+Если в выражении помимо `JOIN` выполняется фильтрация данных, то рекомендуется обернуть те условия, про которые известно, что они вернут `true` для большинства строк, в вызов функции `LIKELY(...)`. Если предположение о преобладании положительных значений в условии окажется верно, такая подсказка может положительно сказаться на времени выполнения запроса. Также `LIKELY` может быть полезен в том случае, когда вычисление предиката ресурсоёмко и при этом сам JOIN значительно сокращает число строк.
+
+Перед любым источником данных для `JOIN` можно указать ключевое слово `ANY`, которое служит для подавления дубликатов по ключам `JOIN` с соответствующей стороны. В этом случае из множества строк с одинаковым значением ключей `JOIN` остается только одна (не уточняется какая именно – отсюда и название `ANY`).
+Данный синтаксис отличается от принятого в [ClickHouse](https://clickhouse.tech/docs/ru/sql-reference/statements/select/join/), где `ANY` пишется перед типом `JOIN` и работает только для правой стороны.
+
+Запрос
+
+```yql
+$t1 = AsList(
+ AsStruct("1" AS key, "v111" AS value),
+ AsStruct("2" AS key, "v121" AS value),
+ AsStruct("2" AS key, "v122" AS value),
+ AsStruct("3" AS key, "v131" AS value),
+ AsStruct("3" AS key, "v132" AS value));
+
+$t2 = AsList(
+ AsStruct("2" AS key, "v221" AS value),
+ AsStruct("2" AS key, "v222" AS value),
+ AsStruct("3" AS key, "v231" AS value),
+ AsStruct("3" AS key, "v232" AS value),
+ AsStruct("4" AS key, "v241" AS value));
+
+SELECT
+ a.key, a.value, b.value
+FROM ANY AS_TABLE($t1) AS a
+JOIN ANY AS_TABLE($t2) AS b
+ON a.key == b.key;
+```
+
+выдаст:
+
+|a.key|a.value|b.value|
+| --- | --- | --- |
+|"3"|"v131"|"v231"|
+|"2"|"v121"|"v221"|
+
+а без `ANY` выдал бы:
+
+|a.key|a.value|b.value|
+| --- | --- | --- |
+|"3"|"v131"|"v231"|
+|"3"|"v131"|"v232"|
+|"3"|"v132"|"v231"|
+|"3"|"v132"|"v232"|
+|"2"|"v121"|"v221"|
+|"2"|"v121"|"v222"|
+|"2"|"v122"|"v221"|
+|"2"|"v122"|"v222"|
+
+
+
diff --git a/yql/essentials/docs/ru/syntax/lexer.md b/yql/essentials/docs/ru/syntax/lexer.md
new file mode 100644
index 0000000000..e5c4d57dbb
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/lexer.md
@@ -0,0 +1,331 @@
+
+
+# Лексическая структура
+
+<!-- markdownlint-disable blanks-around-fences -->
+
+Запрос на языке YQL представляет собой валидный UTF-8 текст, который состоит из *команд* (statement) разделенных символом точка с запятой (`;`).
+Последняя точка с запятой при этом может отсутствовать.
+Каждая команда, в свою очередь, состоит из последовательности *токенов* допустимых для данной команды.
+Токеном может быть *ключевое слово*, *идентификатор*, *литерал* и другие.
+Токены разделяются пробельными символами (пробел, табуляция, перевод строки) либо *комментариями*. Комментарий не является частью команды и синтаксически эквивалентен пробельному символу.
+
+## Режимы совместимости синтаксиса {#lexer-modes}
+
+Поддерживаются два режима совместимости синтаксиса:
+
+* Расширенный C++ (по умолчанию)
+* ANSI SQL
+
+Режим ANSI SQL включается с помощью специального комментария `--!ansi_lexer`, который должен стоять в начале запроса.
+
+Особенности интерпретации лексических элементов в разных режимах совместимости описаны ниже.
+
+## Комментарии {#comments}
+
+Поддерживаются следующие виды комментариев:
+
+* Однострочные: начинается с последовательности символов `--` (два минуса *подряд*) и продолжается до конца строки
+* Многострочные: начинается с последовательности символов `/*` и заканчивается на последовательности символов `*/`
+
+```yql
+SELECT 1; -- A single-line comment
+/*
+ Some multi-line comment
+*/
+```
+
+В режиме совместимости синтаксиса C++ (по умолчанию) многострочный комментарий заканчивается на *ближайшей* последовательности символов `*/`.
+В режиме совместимости синтаксиса ANSI SQL учитывается вложенность многострочных комментариев:
+
+```yql
+--!ansi_lexer
+SELECT * FROM T; /* комментарий /* вложенный комментарий, без ansi_lexer будет ошибка */ */
+```
+
+## Ключевые слова и идентификаторы {#keywords-and-ids}
+
+**Ключевые слова** – это токены, имеющее фиксированное значение в языке YQL. Примеры ключевых слов – `SELECT`, `INSERT`, `FROM`, `ACTION` и т.д. Ключевые слова регистронезависимы, то есть `SELECT` и `SeLEcT` эквивалентны.
+Список ключевых слов не фиксирован – по мере развития языка он будет расширяться. Ключевое слово не может содержать цифры и начинаться или заканчиваться символом подчеркивания.
+
+**Идентификаторы** – это токены, которые идентифицируют имена таблиц, колонок и других объектов в YQL. Идентификаторы в YQL всегда регистрозависимы.
+Идентификатор может быть записан в теле программы без специального оформления, если он:
+
+* Не является ключевым словом
+* Начинается с латинской буквы или подчеркивания
+* Последующими символами могут быть латинская буква, подчеркивание или цифра
+
+```yql
+SELECT my_column FROM my_table; -- my_column and my_table are identifiers
+```
+
+Для записи в теле запроса произвольного идентификатора он заключается в обратные кавычки (бэктики):
+
+```yql
+SELECT `column with space` from T;
+SELECT * FROM `my_dir/my_table`
+```
+
+Идентификатор в обратных кавычках никогда не интерпретируется как ключевое слово:
+
+```yql
+SELECT `select` FROM T; -- select - имя колонки в таблице T
+```
+
+При использовании обратных кавычек применим стандартный C-эскейпинг:
+
+```yql
+SELECT 1 as `column with\n newline, \x0a newline and \` backtick `;
+```
+
+В режиме совместимости синтаксиса ANSI SQL произвольные идентификаторы также могут быть выделены заключением их в двойные кавычки. Для включения двойной кавычки в идентификатор в кавычках она должна быть удвоена:
+
+```yql
+--!ansi_lexer
+SELECT 1 as "column with "" double quoute"; -- имя колонки будет: column with " double quoute
+```
+
+## SQL хинты {#sql-hints}
+
+SQL хинты – это специальные настройки, которые позволяют пользователю влиять на план выполнения запроса
+(например, включать/выключать определенные оптимизации, форсировать стратегию JOIN-а и т.п.).
+В отличие от [PRAGMA](pragma.md), SQL хинты обладают локальным действием – они привязаны к определенной точке YQL запроса (обычно следуют после ключевого слова)
+и влияют только на соответствующий statement или даже его часть.
+SQL хинты представляют собой набор настроек "имя-список значений" и задаются внутри комментариев специального вида –
+первым символом комментария с SQL хинтами должен быть `+`:
+
+```yql
+--+ Name1(Value1 Value2 Value3) Name2(Value4) ...
+```
+
+Имя SQL хинта должно состоять из алфавтно-цифровых ASCII символов и начинаться с буквы. Регистр букв в имени хинта игнорируется.
+После имени хинта в скобках задается произвольное количество значений, разделенных пробелами. В качестве значения может выступать произвольный набор символов.
+Если в наборе символов значения имеется пробел или скобка, то необходимо использовать одинарные кавычки:
+
+```yql
+--+ foo('value with space and paren)')
+```
+
+```yql
+--+ foo('value1' value2)
+-- эквивалетно
+--+ foo(value1 value2)
+```
+
+Одинарную кавычку внутри значения необходимо эскейпить путем дублирования:
+
+```yql
+--+ foo('value with single quote '' inside')
+```
+
+Неизвестные имена SQL хинтов (либо синтаксически некорректные хинты) никогда не вызывают ошибок – они просто игнорируется:
+
+```yql
+--+ foo(value1) bar(value2 baz(value3)
+-- из-за пропущенной закрывающей скобки в bar эквивалетно
+--+ foo(value1)
+```
+
+Такое поведение связано с нежеланием ломать написанные ранее валидные YQL запросы с комментариями, которые похожи на хинты.
+При этом синтаксически корректные SQL хинты в неожиданном для YQL месте вызывают предупреждение:
+
+```yql
+-- в данный момент хинты после SELECT не поддерживаются
+SELECT /*+ foo(123) */ 1; -- предупреждение 'Hint foo will not be used'
+```
+
+Хочется заметить, что SQL хинты – это именно подсказки оптимизатору, поэтому:
+
+* хинты никогда не влияют на результат запроса
+* по мере развития оптимизаторов в YQL вполне возможна ситуация, в которой хинт становится неактуальным и начнет игнорироваться (например, полностью поменялся алгоритм, который настраивался данным хинтом, либо оптимизатор настолько улучшился, что гарантированно выбирает оптимальное решение, поэтому какие-то ручные настройки будут скорее вредить)
+
+## Строковые литералы {#string-literals}
+
+Строковый литерал (константа) записывается как последовательность символов, заключенных в одинарные кавычки. Внутри строкового литерала можно использовать правила эскейпинга в стиле C:
+
+```yql
+SELECT 'string with\n newline, \x0a newline and \' backtick ';
+```
+
+В режиме совместимости синтаксиса С++ (по-умолчанию) разрешается использовать вместо одинарных кавычек двойные:
+
+```yql
+SELECT "string with\n newline, \x0a newline and \" backtick ";
+```
+
+В режиме совместимости синтаксиса ASNI SQL двойные кавычки используются для идентификаторов, а единственный вид эскепинга который действует для строковых литералов – это дублирование символа одиночной кавычки:
+
+```yql
+--!ansi_lexer
+SELECT 'string with '' quote'; -- результат: string with ' quote
+```
+
+На основании строковых литералов могут быть получены [литералы простых типов](../builtins/basic#data-type-literals).
+
+### Многострочные строковые литералы {#multiline-string-literals}
+
+Многострочный строковой литерал записывается в виде произвольного набора символов между двойными собачками `@@`:
+
+```yql
+$text = @@some
+multiline
+text@@;
+SELECT LENGTH($text);
+```
+
+Если необходимо вставить в текст двойную собачку, ее необходимо удвоить:
+
+```yql
+$text = @@some
+multiline with double at: @@@@
+text@@;
+SELECT $text;
+```
+
+### Типизированные строковые литералы {#typed-string-literals}
+
+* Для строкового литерала, включая [многострочный](#multiline-string-literals), по умолчанию используется тип `String` (см. также [PRAGMA UnicodeLiterals](pragma.md#UnicodeLiterals)).
+* С помощью следующих суффиксов можно явно управлять типом литерала:
+
+ * `s` — `String`;
+ * `u` — `Utf8`;
+ * `y` — `Yson`;
+ * `j` — `Json`.
+
+#### Пример
+
+```yql
+SELECT "foo"u, '[1;2]'y, @@{"a":null}@@j;
+```
+
+## Числовые литералы {#literal-numbers}
+
+* Целочисленные литералы по умолчанию имеют тип `Int32`, если попадают в его диапазон, и в противном случае автоматически расширяются до `Int64`.
+* С помощью следующих суффиксов можно явно управлять типом литерала:
+
+ * `l` — `Int64`;
+ * `s` — `Int16`;
+ * `t` — `Int8`.
+
+* Добавление суффикса `u` превращает тип в соответствующий беззнаковый:
+
+ * `ul` — `Uint64`;
+ * `u` — `Uint32`;
+ * `us` — `Uint16`;
+ * `ut` — `Uint8`.
+
+* Также для целочисленных литералов доступна запись в шестнадцатеричной, восьмеричной и двоичной форме с помощью префиксов `0x`, `0o` и `0b`, соответственно. Их можно произвольным образом комбинировать с описанными выше суффиксами.
+* Литералы с плавающей точкой по умолчанию имеют тип `Double`, но с помощью суффикса `f` его можно сузить до `Float`.
+
+```yql
+SELECT
+ 123l AS `Int64`,
+ 0b01u AS `Uint32`,
+ 0xfful AS `Uint64`,
+ 0o7ut AS `Uint8`,
+ 456s AS `Int16`,
+ 1.2345f AS `Float`;
+```
+
+## Литералы PostgreSQL {#pgliterals}
+
+Строковые и числовые литералы Pg типов можно создавать с помощью специальных суффиксов (аналогично простым [строковым](#string-literals) и [числовым](#literal-numbers) литералам).
+
+### Целочисленные литералы {#intliterals}
+
+Суффикс | Тип | Комментарий
+----- | ----- | -----
+`p` | `PgInt4` | 32-битное знаковое целое (в PostgreSQL нет беззнаковых типов)
+`ps`| `PgInt2` | 16-битное знаковое целое
+`pi`| `PgInt4` |
+`pb`| `PgInt8` | 64-битное знаковое цело
+`pn`| `PgNumeric` | знаковое целое произвольной точности (до 131072 цифр)
+
+### Литералы с плавающей точкой {#floatliterals}
+
+Суффикс | Тип | Комментарий
+----- | ----- | -----
+`p` | `PgFloat8` | число с плавающей точкой (64 бит double)
+`pf4`| `PgFloat4` | число с плавающей точкой (32 бит float)
+`pf8`| `PgFloat8` |
+`pn` | `PgNumeric` | число с плавающей точкой произвольной точности (до 131072 цифр перед запятой, до 16383 цифр после запятой)
+
+### Строковые литералы {#stringliterals}
+
+Суффикс | Тип | Комментарий
+----- | ----- | -----
+`p` | `PgText` | текстовая строка
+`pt`| `PgText` |
+`pv`| `PgVarchar` | текстовая строка
+`pb`| `PgBytea` | бинарная строка
+
+{% note warning "Внимание" %}
+
+Значения строковых/числовых литералов (т.е. то что идет перед суффиксом) должны быть валидной строкой/числом с точки зрения YQL.
+В частности, должны соблюдаться правила эскейпинга YQL, а не PostgreSQL.
+
+{% endnote %}
+
+Пример:
+
+```yql
+SELECT
+ 1234p, -- pgint4
+ 0x123pb, -- pgint8
+ "тест"pt, -- pgtext
+ 123e-1000pn; -- pgnumeric
+;
+```
+
+### Литерал массива
+
+Для построения литерала массива используется функция `PgArray`:
+
+```yql
+SELECT
+ PgArray(1p, NULL ,2p) -- {1,NULL,2}, тип _int4
+;
+```
+
+### Конструктор литералов произвольного типа {#literals_constructor}
+
+Литералы всех типов (в том числе и Pg типов) могут создаваться с помощью конструктора литералов со следующей сигнатурой:
+`Имя_типа(<строковая константа>)`.
+
+Напрмер:
+
+```yql
+DECLARE $foo AS String;
+SELECT
+ PgInt4("1234"), -- то же что и 1234p
+ PgInt4(1234), -- в качестве аргумента можно использовать литеральные константы
+ PgInt4($foo), -- и declare параметры
+ PgBool(true),
+ PgInt8(1234),
+ PgDate("1932-01-07"),
+;
+```
+
+Также поддерживается встроенная функция `PgConst` со следующей сигнатурой: `PgConst(<строковое значение>, <тип>)`.
+Такой способ более удобен для кодогенерации.
+
+Например:
+
+```yql
+SELECT
+ PgConst("1234", PgInt4), -- то же что и 1234p
+ PgConst("true", PgBool)
+;
+```
+
+Для некоторых типов в функции `PgConst` можно указать дополнительные модификаторы. Возможные модификаторы для типа `pginterval` перечислены в [документации PostgreSQL](https://www.postgresql.org/docs/16/datatype-datetime.html).
+
+```yql
+SELECT
+ PgConst(90, pginterval, "day"), -- 90 days
+ PgConst(13.45, pgnumeric, 10, 1); -- 13.5
+;
+```
+
+
+
diff --git a/yql/essentials/docs/ru/syntax/not_yet_supported.md b/yql/essentials/docs/ru/syntax/not_yet_supported.md
new file mode 100644
index 0000000000..742174bd97
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/not_yet_supported.md
@@ -0,0 +1,14 @@
+# Ещё не поддерживаемые конструкции из классического SQL
+
+## \[NOT\] \[EXISTS|INTERSECT\|EXCEPT] {#not-exists}
+
+Доступный альтернативный вариант — `EXISTS` синтаксически доступен, но из-за отсутствия поддержки коррелированных подзапросов не очень полезен. Также можно переписать через `JOIN`.
+
+## NATURAL JOIN {#natural-join}
+
+Доступный альтернативный вариант — явно перечислить совпадающие с обеих сторон колонки.
+
+## NOW() / CURRENT_TIME() {#now}
+
+Доступный альтернативный вариант — воспользоваться функциями [CurrentUtcDate, CurrentUtcDatetime и CurrentUtcTimestamp](../builtins/basic.md#current-utc).
+
diff --git a/yql/essentials/docs/ru/syntax/pragma.md b/yql/essentials/docs/ru/syntax/pragma.md
new file mode 100644
index 0000000000..d104f25322
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/pragma.md
@@ -0,0 +1,464 @@
+# PRAGMA
+
+## Определение
+
+Переопределение настроек.
+
+### Синтаксис
+
+`PRAGMA x.y = "z";` или `PRAGMA x.y("z", "z2", "z3");`:
+
+* `x` — (опционально) категория настройки.
+* `y` — название настройки.
+* `z` — (опционально для флагов) значение настройки. Допустимо использование следующих суффиксов:
+
+ * `Kb`, `Mb`, `Gb` — для объема информации.
+ * `sec`, `min`, `h`, `d` — для временных значений.
+
+### Примеры
+
+```yql
+PRAGMA AutoCommit;
+```
+
+```yql
+PRAGMA TablePathPrefix = "home/yql";
+```
+
+```yql
+PRAGMA Warning("disable", "1101");
+```
+
+За некоторым исключением, значение настроек можно вернуть в состояние по умолчанию с помощью `PRAGMA my_pragma = default;`.
+
+Полный список доступных настроек [см. в таблице ниже](#pragmas).
+
+### Область действия {#pragmascope}
+
+Если не указано иное, прагма влияет на все идущие следом выражения вплоть до конца модуля, в котором она встречается.
+При необходимости и логической возможности допустимо менять значение настройки несколько раз в одном запросе, чтобы оно было разным на разных этапах выполнения.
+Существуют также специальные scoped прагмы, область действия которых определяется по тем же правилам, что и область видимости [именованных выражений](expressions.md#named-nodes).
+В отличие от scoped прагм, обычные прагмы могут использоваться только в глобальной области видимости (не внутри лямбда-функций, ACTION, SUBQUERY и т.п.).
+
+## Глобальные {#pragmas}
+
+### AutoCommit {#autocommit}
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+Автоматически выполнять [COMMIT](select/index.md#commit) после каждого выражения.
+
+### TablePathPrefix {#table-path-prefix}
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Строка | — |
+
+Добавить указанный префикс к путям таблиц внутри кластеров. Работает по принципу объединения путей в файловой системе: поддерживает ссылки на родительский каталог `..` и не требует добавления слеша справа. Например,
+
+```yql
+PRAGMA TablePathPrefix = "home/yql";
+SELECT * FROM test;
+```
+
+Префикс не добавляется, если имя таблицы указано как абсолютный путь (начинается с /).
+
+### UDF {#udf}
+
+| Тип значения | По умолчанию | Статическая /<br/>динамическая |
+| --- | --- | --- |
+| Строка | — | Статическая |
+| Строка - имя префикса, добавляемого ко всем модулям | "" | Статическая |
+
+Импорт всех UDF из указанной приложенной к запросу скомпилированной под Linux x64 разделяемой библиотеки (.so).
+При указании префикса, он добавляется перед названием всех загруженных модулей, например, CustomPrefixIp::IsIPv4 вместо Ip::IsIPv4.
+Указание префикса позволяет подгрузить одну и ту же UDF разных версий.
+
+### UseTablePrefixForEach {#use-table-prefix-for-each}
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+`EACH` использует [TablePathPrefix](#table-path-prefix) для каждого элемента списка.
+
+### Warning {#warning}
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| 1. Действие<br/>2. Код предупреждения либо символ "*"| — |
+
+Действие:
+
+* `disable` — отключить;
+* `error` — приравнять к ошибке;
+* `default` — вернуть поведение по умолчанию.
+
+Код предупреждения возвращается вместе с самим текстом (в веб-интерфейсе отображается справа).
+
+Примеры:
+
+`PRAGMA Warning("error", "*");`
+`PRAGMA Warning("disable", "1101");`
+`PRAGMA Warning("default", "4503");`
+
+В данном случае все предупреждения будут считаться ошибками, за исключением предупреждение с кодом `1101`, которое будет отключено, и `4503`, которое будет обрабатываться по умолчанию (то есть останется предупреждением). Поскольку предупреждения могут добавляться в новых релизах YQL, следует с осторожностью пользоваться конструкцией `PRAGMA Warning("error", "*");` (как минимум покрывать такие запросы автотестами).
+
+
+
+### Greetings {#greetings}
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Текст | — |
+
+Выдать указанный текст в качестве Info сообщения запроса.
+
+Пример:
+`PRAGMA Greetings("It's a good day!");`
+
+### WarningMsg {#warningmsg}
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Текст | — |
+
+Выдать указанный текст в качестве Warning сообщения запроса.
+
+Пример:
+`PRAGMA WarningMsg("Attention!");`
+
+### SimpleColumns {#simplecolumns}
+
+`SimpleColumns` / `DisableSimpleColumns`
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | true |
+
+При использовании `SELECT foo.* FROM ... AS foo` убрать префикс `foo.` у имен результирующих колонок.
+
+Работает в том числе и для [JOIN](join.md), но в этом случае имеет право упасть в случае конфликта имен (который можно разрешить с помощью [WITHOUT](select/without.md) и переименования колонок). Для JOIN в режиме SimpleColumns производится неявный Coalesce для ключевых колонок: запрос `SELECT * FROM T1 AS a JOIN T2 AS b USING(key)` в режиме SimpleColumns работает как `SELECT a.key ?? b.key AS key, ... FROM T1 AS a JOIN T2 AS b USING(key)`
+
+### CoalesceJoinKeysOnQualifiedAll
+
+`CoalesceJoinKeysOnQualifiedAll` / `DisableCoalesceJoinKeysOnQualifiedAll`
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | true |
+
+Управляет неявным Coalesce для ключевых колонок `JOIN` в режиме SimpleColumns. Если флаг установлен, то Coalesce ключевых колонок происходит при наличии хотя бы одного выражения вида `foo.*` или `*` в SELECT - например `SELECT a.* FROM T1 AS a JOIN T2 AS b USING(key)`. Если флаг сброшен, то Coalesce ключей JOIN происходит только при наличии '*' после `SELECT`
+
+### StrictJoinKeyTypes
+
+`StrictJoinKeyTypes` / `DisableStrictJoinKeyTypes`
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+Если флаг установлен, то [JOIN](join.md) будет требовать строгого совпадения типов ключей.
+По умолчанию JOIN предварительно конвертирует ключи к общему типу, что может быть нежелательно с точки зрения производительности.
+StrictJoinKeyTypes является [scoped](#pragmascope) настройкой.
+
+### AnsiInForEmptyOrNullableItemsCollections
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+Наличие этой прагмы приводит поведение оператора `IN` в соответствие со стандартом в случае наличия `NULL` в левой или правой части оператора `IN`. Также изменено поведение `IN` в случае, когда справа был Tuple с элементами разных типов. Примеры:
+
+`1 IN (2, 3, NULL) = NULL (было Just(False))`
+`NULL IN () = Just(False) (было NULL)`
+`(1, null) IN ((2, 2), (3, 3)) = Just(False) (было NULL)`
+
+Подробнее про поведение `IN` при наличии `NULL`ов в операндах можно почитать [здесь](expressions.md#in). Явным образом выбрать старое поведение можно указав прагму `DisableAnsiInForEmptyOrNullableItemsCollections`. Если никакой прагмы не задано, то выдается предупреждение и работает старый вариант.
+
+### AnsiRankForNullableKeys
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+Приводит поведение RANK/DENSE_RANK в соответствие со стандартом при наличии опциональных типов в ключах сортировки окна или в аргументе этих оконных функций. А именно:
+
+* типом результата всегда является Uint64, а не Uint64?;
+* null-ы в ключах считаются равными друг другу (текущая реализация возвращает NULL).
+
+Явным образом выбрать старое поведению можно указав прагму `DisableAnsiRankForNullableKeys`. Если никакой прагмы не задано, то выдается предупреждение и работает старый вариант.
+
+### AnsiCurrentRow
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+Приводит неявное задание рамки окна при наличии ORDER BY в соответствие со стандартом.
+Если AnsiCurrentRow не установлен, то окно `(ORDER BY key)` эквивалентно `(ORDER BY key ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)`.
+Стандарт же требует, чтобы такое окно вело себя как `(ORDER BY key RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW)`.
+Разница состоит в трактовке `CURRENT ROW`. В режиме `ROWS` `CURRENT ROW` трактуется буквально – текущая строка в партиции.
+А в режиме `RANGE` конец рамки `CURRENT ROW` означает "последняя строка в партиции с ключом сортировки, равным текущей строке".
+
+### OrderedColumns {#orderedcolumns}
+
+`OrderedColumns` / `DisableOrderedColumns`
+
+Выводить [порядок колонок](select/index.md#orderedcolumns) в SELECT/JOIN/UNION ALL и сохранять его при записи результатов. По умолчанию порядок колонок не определен.
+
+### PositionalUnionAll {#positionalunionall}
+
+Включить соответствующий стандарту поколоночный режим выполнения [UNION ALL](select/index.md#unionall). При этом автоматически включается
+[упорядоченность колонок](#orderedcolumns).
+
+### RegexUseRe2
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+Использовать Re2 UDF вместо Pcre для выполнения SQL операторов `REGEX`,`MATCH`,`RLIKE`. Re2 UDF поддерживает корректную обработку Unicode-символов в отличие от используемой по умолчанию Pcre UDF.
+
+### ClassicDivision
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | true |
+
+В классическом варианте результат целочисленного деления остаётся целочисленным (по умолчанию).
+Если отключить — результат всегда становится Double.
+ClassicDivision является [scoped](#pragmascope) настройкой.
+
+### CheckedOps
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+При включенном режиме если в результате выполнения агрегационных функций SUM/SUM_IF, бинарных операций `+`,`-`,`*`,`/`,`%` или унарной операции `-` над целыми числами происходит выход за границы целевого типа аргументов или результата, то возвращается `NULL`.
+Если отключить - переполнение не проверяется.
+Не влияет на операции с числами с плавающей точкой или `Decimal`.
+CheckedOps является [scoped](#pragmascope) настройкой.
+
+### UnicodeLiterals
+
+`UnicodeLiterals`/`DisableUnicodeLiterals`
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+При включенном режиме строковые литералы без суффиксов вида "foo"/'bar'/@@multiline@@ будут иметь тип `Utf8`, при выключенном - `String`.
+UnicodeLiterals является [scoped](#pragmascope) настройкой.
+
+### WarnUntypedStringLiterals
+
+`WarnUntypedStringLiterals`/`DisableWarnUntypedStringLiterals`
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+При включенном режиме для строковых литералов без суффиксов вида "foo"/'bar'/@@multiline@@ будет генерироваться предупреждение. Его можно подавить, если явно выбрать суффикс `s` для типа `String`, либо `u` для типа `Utf8`.
+WarnUntypedStringLiterals является [scoped](#pragmascope) настройкой.
+
+### AllowDotInAlias
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+Разрешить использовать точку в именах результирующих колонок. По умолчанию отключено, т.к. дальнейшее использование таких колонок в JOIN полностью не реализовано.
+
+### WarnUnnamedColumns
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+Генерировать предупреждение если для безымянного выражения в `SELECT` было автоматически сгенерировано имя колонки (вида `column[0-9]+`).
+
+### GroupByLimit
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Положительное число | 32 |
+
+Увеличение лимита на число группировок в [GROUP BY](group_by.md).
+
+### GroupByCubeLimit
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Положительное число | 5 |
+
+Увеличение лимита на число размерностей [GROUP BY](group_by.md#rollup-cube-group-sets).
+
+Использовать нужно аккуратно, так как вычислительная сложность запроса растет экспоненциально по отношению к числу размерностей.
+
+
+## Yson
+
+Управление поведением Yson UDF по умолчанию, подробнее см. в [документации по ней](../udf/list/yson.md) и в частности [Yson::Options](../udf/list/yson.md#ysonoptions).
+
+### `yson.AutoConvert`
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+Автоматическое конвертация значений в требуемый тип данных во всех вызовах Yson UDF, в том числе и неявных.
+
+### `yson.Strict`
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | true |
+
+Управление строгим режимом во всех вызовах Yson UDF, в том числе и неявных. Без значения или при значении `"true"` - включает строгий режим. Со значением `"false"` - отключает.
+
+### `yson.DisableStrict`
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+Инвертированная версия `yson.Strict`. Без значения или при значении `"true"` - отключает строгий режим. Со значением `"false"` - включает.
+
+## Работа с файлами
+
+### File
+
+| Тип значения | По умолчанию | Статическая /<br/>динамическая |
+| --- | --- | --- |
+| Два или три строковых аргумента — алиас, URL и опциональное имя токена | — | Статическая |
+
+Приложить файл к запросу по URL. Использовать приложенные файлы можно с помощью встроенных функций [FilePath и FileContent](../builtins/basic.md#filecontent).
+
+При указании имени токена, его значение будет использоваться для обращения к целевой системе.
+
+### FileOption
+
+| Тип значения | По умолчанию | Статическая /<br/> динамическая |
+|-------------------------------------------------|--------------|--------------------------------|
+| Три строковых аргумента — алиас, ключ, значение | — | Статическая |
+
+Установить у указанного файла опцию по заданному ключу в заданное значение. Файл с этим алиасом уже должен быть объявлен
+через [PRAGMA File](#file) или приложен к запросу.
+
+
+
+### Folder
+
+| Тип значения | По умолчанию | Статическая /<br/>динамическая |
+| --- | --- | --- |
+| Два или три строковых аргумента — префикс, URL и опциональное имя токена | — | Статическая |
+
+Приложить набор файлов к запросу по URL. Работает аналогично добавлению множества файлов через [PRAGMA File](#file) по прямым ссылкам на файлы с алиасами, полученными объединением префикса с именем файла через `/`.
+
+При указании имени токена, его значение будет использоваться для обращения к целевой системе.
+
+### Library
+
+| Тип значения | По умолчанию | Статическая /<br/>динамическая |
+| --- | --- | --- |
+| Один или два аргумента - имя файла и опциональный URL | — | Статическая |
+
+Интерпретировать указанный приложенный файл как библиотеку, из которой можно делать [IMPORT](export_import.md). Тип синтаксиса библиотеки определяется по расширению файла:
+* `.sql` для YQL диалекта SQL <span style="color: green;">(рекомендуется)</span>;
+* `.yql` для [s-expressions](/docs/s_expressions).
+
+Пример с приложенным файлом к запросу:
+
+```yql
+PRAGMA library("a.sql");
+IMPORT a SYMBOLS $x;
+SELECT $x;
+```
+
+В случае указания URL библиотека скачивается с него, а не с предварительного приложенного файла, как в следующем примере:
+
+```yql
+PRAGMA library("a.sql","http://intranet.site/5618566/text");
+IMPORT a SYMBOLS $x;
+SELECT $x;
+```
+
+При этом можно использовать подстановку текстовых параметров в URL:
+
+```yql
+DECLARE $_ver AS STRING; -- "5618566"
+PRAGMA library("a.sql","http://intranet.site/{$_ver}/text");
+IMPORT a SYMBOLS $x;
+SELECT $x;
+```
+
+### Package
+
+| Тип значения | По умолчанию | Статическая /<br/>динамическая |
+| --- | --- | --- |
+| Два или три аргумента - имя пакета, URL и опциональный токен | — | Статическая |
+
+Приложить иерархический набор файлов к запросу по URL, интерпретируя их в качестве пакета с указанным именем - взаимосвязанного набора библиотек.
+
+Имя пакета ожидается в формате ``project_name.package_name``; из библиотек пакета в дальнейшнем можно делать [IMPORT](export_import.md) с именем модуля вида ``pkg.project_name.package_name.maybe.nested.module.name``.
+
+Пример для пакета с плоской иерархией, состоящего из двух библиотек - foo.sql и bar.sql:
+
+```yql
+PRAGMA package("project.package", "http://intranet.site/path/to/package");
+IMPORT pkg.project.package.foo SYMBOLS $foo;
+IMPORT pkg.project.package.bar SYMBOLS $bar;
+SELECT $foo, $bar;
+```
+
+При этом можно использовать подстановку текстовых параметров в URL:
+
+```yql
+DECLARE $_path AS STRING; -- "path"
+PRAGMA package("project.package","http://intranet.site/{$_path}/to/package");
+IMPORT pkg.project.package.foo SYMBOLS $foo;
+IMPORT pkg.project.package.bar SYMBOLS $bar;
+SELECT $foo, $bar;
+```
+
+### OverrideLibrary
+
+| Тип значения | По умолчанию | Статическая /<br/>динамическая |
+| --- | --- | --- |
+| Один аргумент - имя файла | — | Статическая |
+
+Интерпретировать указанный приложенный файл как библиотеку и перекрыть ей одну из библиотек пакета.
+
+Имя файла ожидается в формате ``project_name/package_name/maybe/nested/module/name.EXTENSION``, поддерживаются аналогичные [PRAGMA Library](#library) расширения.
+
+Пример:
+
+```yql
+PRAGMA package("project.package", "http://intranet.site/path/to/package");
+PRAGMA override_library("project/package/maybe/nested/module/name.sql");
+
+IMPORT pkg.project.package.foo SYMBOLS $foo;
+SELECT $foo;
+```
+
+## Отладочные и служебные {#debug}
+
+### `config.flags("ValidateUdf", "Lazy")`
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Строка: None / Lazy / Greedy | None |
+
+Валидация результатов UDF на соответствие объявленной сигнатуре. Greedy режим форсирует материализацию «ленивых» контейнеров, а Lazy — нет.
+
+### `config.flags("Diagnostics")`
+
+| Тип значения | По умолчанию |
+| --- | --- |
+| Флаг | false |
+
+Получение диагностической информации от YQL в виде дополнительного результата запроса.
diff --git a/yql/essentials/docs/ru/syntax/process.md b/yql/essentials/docs/ru/syntax/process.md
new file mode 100644
index 0000000000..b8e5dc78f0
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/process.md
@@ -0,0 +1,80 @@
+# PROCESS
+
+Преобразовать входную таблицу с помощью UDF или [лямбда функции](expressions.md#lambda), которая применяется последовательно к каждой строке входа и имеет возможность для каждой строки входа создать ноль, одну или несколько строк результата (аналог Map в терминах MapReduce).
+
+Таблица по имени ищется в базе данных, заданной оператором [USE](use.md).
+
+В параметрах вызова функции после ключевого слова `USING` явно указывается, значения из каких колонок и в каком порядке передавать для каждой строки входа.
+
+Допустимы функции, которые возвращают результат одного из трех составных типов от `OutputType` (возможные варианты `OutputType` описаны ниже):
+
+* `OutputType` — на каждую строку входа всегда должна быть строка выхода, схема которой определяется типом структуры.
+* `OutputType?` — функции оставляет за собой право пропускать строки, возвращая пустые значения (`TUnboxedValue()` в C++, `None` в Python или `null` в JavaScript).
+* `Stream<OutputType>` или `List<OutputType>` — возможность вернуть несколько строк.
+
+Вне зависимости от того, какой вариант из перечисленных выше трех выбран, результат преобразовывается к плоской таблице с колонками, определяемыми типом `OutputType`.
+
+В качестве `OutputType` может выступать один из типов:
+
+* `Struct<...>` — у `PROCESS` будет ровно один выход с записями заданной структуры, представляющий собой плоскую таблицу с колонками соответствующими полям `Struct<...>`
+* `Variant<Struct<...>,...>` — у `PROCESS` число выходов будет равно числу альтернатив в `Variant`. Записи каждого выхода представлены плоской таблицей с колонками по полям из соответствующей альтернативы. Ко множеству выходов `PROCESS` в этом случае можно обратиться как к кортежу (`Tuple`) списков, который можно распаковать в отдельные [именованные выражения](expressions.md#named-nodes) и использовать независимо.
+
+В списке аргументов функции после ключевого слова `USING` можно передать одно из двух специальных именованных выражений:
+
+* `TableRow()` — текущая строка целиком в виде структуры;
+* `TableRows()` — ленивый итератор по строкам, с точки зрения типов — `Stream<Struct<...>>`. В этом случае выходным типом функции может быть только `Stream<OutputType>` или `List<OutputType>`.
+
+{% note info "Примечание" %}
+
+После выполнения `PROCESS` в рамках того же запроса по результирующей таблице (или таблицам) можно выполнить [SELECT](select/index.md), [REDUCE](reduce.md), ещё один `PROCESS` и так далее в зависимости от необходимого результата.
+
+{% endnote %}
+
+Ключевое слово `USING` и указание функции необязательны: если они не указаны, то возвращается исходная таблица. Это может быть удобно для применения [шаблона подзапроса](subquery.md).
+
+В `PROCESS` можно передать несколько входов (под входом здесь подразумевается таблица, [диапазон таблиц](select/concat.md), подзапрос, [именованное выражение](expressions.md#named-nodes)), разделенных запятой. В функцию из `USING` в этом случае можно передать только специальные именованные выражения `TableRow()` или `TableRows()`, которые будут иметь следующий тип:
+
+* `TableRow()` — альтернатива (`Variant`), где каждый элемент имеет тип структуры записи из соответствущего входа. Для каждой входной строки в альтернативе заполнен элемент, соответствущий номеру входа этой строки
+* `TableRows()` — ленивый итератор по альтернативам, с точки зрения типов — `Stream<Variant<...>>`. Альтернатива имеет такую же семантику, что и для `TableRow()`
+
+После `USING` в `PROCESS` можно опционально указать `ASSUME ORDER BY` со списком столбцов. Результат такого `PROCESS` будет считаться сортированным, но без выполнения фактической сортировки. Проверка сортированности осуществляется на этапе исполнения запроса. Поддерживается задание порядка сортировки с помощью ключевых слов `ASC` (по возрастанию) и `DESC` (по убыванию). Выражения в `ASSUME ORDER BY` не поддерживается.
+
+## Примеры
+
+```yql
+PROCESS my_table
+USING MyUdf::MyProcessor(value)
+```
+
+```yql
+$udfScript = @@
+def MyFunc(my_list):
+ return [(int(x.key) % 2, x) for x in my_list]
+@@;
+
+-- Функция возвращает итератор альтернатив
+$udf = Python3::MyFunc(Callable<(Stream<Struct<...>>) -> Stream<Variant<Struct<...>, Struct<...>>>>,
+ $udfScript
+);
+
+-- На выходе из PROCESS получаем кортеж списков
+$i, $j = (PROCESS my_table USING $udf(TableRows()));
+
+SELECT * FROM $i;
+SELECT * FROM $j;
+```
+
+```yql
+$udfScript = @@
+def MyFunc(stream):
+ for r in stream:
+ yield {"alt": r[0], "key": r[1].key}
+@@;
+
+-- Функция принимает на вход итератор альтернатив
+$udf = Python::MyFunc(Callable<(Stream<Variant<Struct<...>, Struct<...>>>) -> Stream<Struct<...>>>,
+ $udfScript
+);
+
+PROCESS my_table1, my_table2 USING $udf(TableRows());
+```
diff --git a/yql/essentials/docs/ru/syntax/reduce.md b/yql/essentials/docs/ru/syntax/reduce.md
new file mode 100644
index 0000000000..f12aabe3be
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/reduce.md
@@ -0,0 +1,110 @@
+
+# REDUCE
+
+Выполняет группировку входа по указанным ключевым столбцам, затем передает текущие ключи и ленивый итератор соответствующих им значений из остальных колонок на обработку в указанную UDF. По аналогии с `PROCESS` UDF может вернуть произвольное количество строк результата на каждый вызов, а также возвращать альтернативы (`Variant`) для создания множества выходов. В терминах MapReduce очень близок к Reduce.
+
+Указываемые следом ключевые слова:
+
+* `PRESORT` (опционально)— указание порядка внутри каждой группы, синтаксис аналогичен [ORDER BY](select/order_by.md);
+* `ON` (обязательно) — указание ключевых столбцов;
+* `USING` или `USING ALL` (обязательно) — вызов UDF, о правилах подробнее ниже.
+
+Правила передачи аргументов UDF:
+
+* Если аргументом UDF указан `TableRows()`, то UDF обязана принимать один аргумент — ленивый итератор по строкам, с точки зрения типов — `Stream<Struct<...>>`. В этом случае выходным типом функции может быть только `Stream<OutputType>` или `List<OutputType>`. Гарантируется, что данные во входном итераторе сгруппированы по ключу и, при необходимости, отсортированы согласно `PRESORT` секции. С `TableRows()` можно использовать только `USING ALL`.
+* При использовании `USING`:
+
+ * UDF обязана принимать два аргумента: в первый передается текущий ключ, а во второй — ленивый итератор с соответствующими этому ключу значениями.
+
+* При использовании `USING ALL`:
+
+ * UDF обязана принимать один аргумент — ленивый итератор кортежей (`Tuple`), где первый элемент кортежа это ключ, а второй — ленивый итератор с соответствующими этому ключу значениями.
+
+* Ключ для передачи в UDF формируется по следующему правилу. Если ключевая колонка одна, то её значение формирует ключ как есть, если несколько (список колонок указывается по аналогии с `GROUP BY` через запятую), то ключ будет формироваться как кортеж (`Tuple`) со значениями из перечисленных колонок в указанном порядке.
+* При вызове `REDUCE` в запросе в круглых скобках после имени UDF указываются только выражение, значения которого будут переданы в качестве элементов итератора (второй аргумент UDF для `USING` или второй элемент кортежа для `USING ALL`).
+
+Результат формируется аналогичным [PROCESS](process.md) образом. Также доступно ключевое слово `TableRow()` для получения строки целиком в виде структуры.
+
+В `REDUCE` можно передать несколько входов (под входом здесь подразумевается таблица, [диапазон таблиц](select/concat.md), подзапрос, [именованное выражение](expressions.md#named-nodes)), разделенных запятой. Все входы обязаны иметь указанные в `ON` ключевые колонки совпадающего типа. В функцию из `USING` в этом случае можно передать только специальное именованное выражение `TableRow()`. Второй аргумент (или второй элемент кортежа для `USING ALL`) будет содержать ленивый итератор альтернатив с заполненным элементом, соответствущим номеру входа текущей записи.
+
+После `USING` в `REDUCE` можно опционально указать `ASSUME ORDER BY` со списком столбцов. Результат такого `REDUCE` будет считаться сортированным, но без выполнения фактической сортировки. Проверка сортированности осуществляется на этапе исполнения запроса. Поддерживается задание порядка сортировки с помощью ключевых слов `ASC` (по возрастанию) и `DESC` (по убыванию). Выражения в `ASSUME ORDER BY` не поддерживается.
+
+## Примеры
+
+```yql
+REDUCE my_table
+ON key, subkey
+USING MyUdf::MyReducer(TableRow());
+```
+
+```yql
+REDUCE my_table
+ON key, subkey
+USING ALL MyUdf::MyStreamReducer(TableRow()); -- MyUdf::MyStreamReducer принимает на вход ленивый список кортежей (ключ, список записей для ключа)
+```
+
+```yql
+REDUCE my_table
+PRESORT LENGTH(subkey) DESC
+ON key
+USING MyUdf::MyReducer(
+ AsTuple(subkey, value)
+);
+```
+
+```yql
+REDUCE my_table
+ON key
+USING ALL MyUdf::MyFlatStreamReducer(TableRows()); -- MyUdf::MyFlatStreamReducer принимает на вход единый ленивый список записей
+```
+
+```yql
+-- Функция возвращает альтернативы
+$udf = Python::MyReducer(Callable<(String, Stream<Struct<...>>) -> Variant<Struct<...>, Struct<...>>>,
+ $udfScript
+);
+
+-- На выходе из REDUCE получаем кортеж списков
+$i, $j = (REDUCE my_table ON key USING $udf(TableRow()));
+
+SELECT * FROM $i;
+SELECT * FROM $j;
+```
+
+
+```yql
+$script = @@
+def MyReducer(key, values):
+ state = None, 0
+ for name, last_visit_time in values:
+ if state[1] < last_visit_time:
+ state = name, last_visit_time
+ return {
+ 'region':key,
+ 'last_visitor':state[0],
+ }
+@@;
+
+$udf = Python::MyReducer(Callable<(
+ Int64?,
+ Stream<Tuple<String?, Uint64?>>
+) -> Struct<
+ region:Int64?,
+ last_visitor:String?
+>>,
+ $script
+);
+
+REDUCE my_table
+ON region USING $udf((name, last_visit_time));
+```
+
+```yql
+-- Функция принимает на вход ключ и итератор альтернатив
+$udf = Python::MyReducer(Callable<(String, Stream<Variant<Struct<...>,Struct<...>>>) -> Struct<...>>,
+ $udfScript
+);
+
+REDUCE my_table1, my_table2 ON key USING $udf(TableRow());
+```
+
diff --git a/yql/essentials/docs/ru/syntax/select/assume_order_by.md b/yql/essentials/docs/ru/syntax/select/assume_order_by.md
new file mode 100644
index 0000000000..09cf864d4a
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/assume_order_by.md
@@ -0,0 +1,14 @@
+
+# ASSUME ORDER BY
+
+Проверка сортированности результата `SELECT` по значению в указанном столбце или нескольких столбцах. Результат такого `SELECT`-а будет считаться сортированным, но без выполнения фактической сортировки. Проверка сортированности осуществляется на этапе исполнения запроса.
+
+Как и для `ORDER BY`, поддерживается задание порядка сортировки с помощью ключевых слов `ASC` (по возрастанию) и `DESC` (по убыванию). Выражения в `ASSUME ORDER BY` не поддерживается.
+
+## Примеры
+
+```yql
+SELECT key || "suffix" as key, -CAST(subkey as Int32) as subkey
+FROM my_table
+ASSUME ORDER BY key, subkey DESC;
+```
diff --git a/yql/essentials/docs/ru/syntax/select/concat.md b/yql/essentials/docs/ru/syntax/select/concat.md
new file mode 100644
index 0000000000..c179ba9b70
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/concat.md
@@ -0,0 +1,44 @@
+# Обращение к нескольким таблицам в одном запросе
+
+В стандартном SQL для выполнения запроса по нескольким таблицам используется [UNION ALL](../select/union.md#union_all), который объединяет результаты двух и более `SELECT`. Это не совсем удобно для сценария использования, в котором требуется выполнить один и тот же запрос по нескольким таблицам (например, содержащим данные на разные даты). В YQL, чтобы было удобнее, в `SELECT` после `FROM` можно указывать не только одну таблицу или подзапрос, но и вызывать встроенные функции, позволяющие объединять данные нескольких таблиц.
+
+Для этих целей определены следующие функции:
+
+```CONCAT(`table1`, `table2`, `table3` VIEW view_name, ...)``` — объединяет все перечисленные в аргументах таблицы.
+
+```EACH($list_of_strings) или EACH($list_of_strings VIEW view_name)``` — объединяет все таблицы, имена которых перечислены в списке строк. Опционально можно передать несколько списков в отдельных аргументах по аналогии с `CONCAT`.
+
+{% note warning %}
+
+Порядок, в котором будут объединены таблицы, всеми вышеперечисленными функциями не гарантируется.
+
+Список таблиц вычисляется **до** запуска самого запроса. Поэтому созданные в процессе запроса таблицы не попадут в результаты функции.
+
+{% endnote %}
+
+По умолчанию схемы всех участвующих таблиц объединяются по правилам [UNION ALL](union.md#union-all). Если объединение схем не желательно, то можно использовать функции с суффиксом `_STRICT`, например `CONCAT_STRICT`, которые работают полностью аналогично оригинальным, но считают любое расхождение в схемах таблиц ошибкой.
+
+Для указания кластера объединяемых таблиц нужно указать его перед названием функции.
+
+Все аргументы описанных выше функций могут быть объявлены отдельно через [именованные выражения](../expressions.md#named-nodes). В этом случае в них также допустимы и простые выражения посредством неявного вызова [EvaluateExpr](../../builtins/basic.md#evaluate_expr_atom).
+
+Имя исходной таблицы, из которой изначально была получена каждая строка, можно получить при помощи функции [TablePath()](../../builtins/basic.md#tablepath).
+
+## Примеры
+
+```yql
+USE some_cluster;
+SELECT * FROM CONCAT(
+ `table1`,
+ `table2`,
+ `table3`);
+```
+
+```yql
+USE some_cluster;
+$indices = ListFromRange(1, 4);
+$tables = ListMap($indices, ($index) -> {
+ RETURN "table" || CAST($index AS String);
+});
+SELECT * FROM EACH($tables); -- идентично предыдущему примеру
+```
diff --git a/yql/essentials/docs/ru/syntax/select/distinct.md b/yql/essentials/docs/ru/syntax/select/distinct.md
new file mode 100644
index 0000000000..13ff5d78d5
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/distinct.md
@@ -0,0 +1,18 @@
+# DISTINCT
+
+Выбор уникальных строк.
+
+{% note info %}
+
+Применение `DISTINCT` к вычислимым значениям на данный момент не реализовано. С этой целью можно использовать подзапрос или выражение [`GROUP BY ... AS ...`](../group_by.md).
+
+{% endnote %}
+
+## Пример
+
+```yql
+SELECT DISTINCT value -- только уникальные значения из таблицы
+FROM my_table;
+```
+
+Также ключевое слово `DISTINCT` может использоваться для применения [агрегатных функций](../../builtins/aggregation.md) только к уникальным значениям. Подробнее см. в документации по [GROUP BY](../group_by.md).
diff --git a/yql/essentials/docs/ru/syntax/select/from.md b/yql/essentials/docs/ru/syntax/select/from.md
new file mode 100644
index 0000000000..3599ecb74a
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/from.md
@@ -0,0 +1,25 @@
+# FROM
+
+Источник данных для `SELECT`. В качестве аргумента может принимать имя таблицы, результат другого `SELECT` или [именованное выражение](../expressions.md#named-nodes). К именованным выражениям можно обращаться [как к таблицам](from_as_table.md)(`FROM AS_TABLE`).
+
+Ещё в YQL можно выполнить запрос по нескольким таблицам. Для этого в `SELECT` после `FROM` можно указывать не только одну таблицу или подзапрос, но и вызывать встроенные функции, позволяющие объединять данные [нескольких таблиц](concat.md).
+
+Между `SELECT` и `FROM` через запятую указываются имена столбцов из источника или `*` для выбора всех столбцов.
+
+Таблица по имени ищется в базе данных, заданной оператором [USE](../use.md).
+
+## Примеры
+
+```yql
+SELECT key FROM my_table;
+```
+
+```yql
+SELECT * FROM
+ (SELECT value FROM my_table);
+```
+
+```yql
+$table_name = "my_table";
+SELECT * FROM $table_name;
+```
diff --git a/yql/essentials/docs/ru/syntax/select/from_as_table.md b/yql/essentials/docs/ru/syntax/select/from_as_table.md
new file mode 100644
index 0000000000..37429d7389
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/from_as_table.md
@@ -0,0 +1,16 @@
+# FROM AS_TABLE
+
+Обращение к именованным выражениям как к таблицам с помощью функции `AS_TABLE`.
+
+`AS_TABLE($variable)` позволяет использовать значение `$variable` в качестве источника данных для запроса. При этом переменная `$variable` должна иметь тип `List<Struct<...>>`.
+
+## Пример
+
+```yql
+$data = AsList(
+ AsStruct(1u AS Key, "v1" AS Value),
+ AsStruct(2u AS Key, "v2" AS Value),
+ AsStruct(3u AS Key, "v3" AS Value));
+
+SELECT Key, Value FROM AS_TABLE($data);
+```
diff --git a/yql/essentials/docs/ru/syntax/select/from_select.md b/yql/essentials/docs/ru/syntax/select/from_select.md
new file mode 100644
index 0000000000..2e49c3f101
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/from_select.md
@@ -0,0 +1,18 @@
+<!-- markdownlint-disable no-trailing-punctuation -->
+
+# FROM ... SELECT ...
+
+Перевернутая форма записи, в которой сначала указывается источник данных, а затем — операция.
+
+## Примеры
+
+```yql
+FROM my_table SELECT key, value;
+```
+
+```yql
+FROM a_table AS a
+JOIN b_table AS b
+USING (key)
+SELECT *;
+``` \ No newline at end of file
diff --git a/yql/essentials/docs/ru/syntax/select/index.md b/yql/essentials/docs/ru/syntax/select/index.md
new file mode 100644
index 0000000000..bee4e38d49
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/index.md
@@ -0,0 +1,144 @@
+## SELECT
+
+Возвращает результат вычисления выражений, указанных после `SELECT`.
+
+Может использоваться в сочетании с другими операциями для получения иного эффекта.
+
+### Примеры
+
+```yql
+SELECT "Hello, world!";
+```
+
+```yql
+SELECT 2 + 2;
+```
+
+
+## Процедура выполнения SELECT {#selectexec}
+
+Результат запроса `SELECT` вычисляется следующим образом:
+
+* определяется набор входных таблиц – вычисляются выражения после [FROM](../select/from.md);
+* к входным таблицам применяется [SAMPLE](sample.md) / [TABLESAMPLE](sample.md)
+* выполняется [FLATTEN COLUMNS](../flatten.md#flatten-columns) или [FLATTEN BY](../flatten.md); алиасы, заданные во `FLATTEN BY`, становятся видны после этой точки;
+* выполняются все [JOIN](../join.md);
+* к полученным данным добавляются (или заменяются) колонки, заданные в [GROUP BY ... AS ...](../group_by.md);
+* выполняется [WHERE](where.md) - все данные не удовлетворяющие предикату отфильтровываются;
+* выполняется [GROUP BY](../group_by.md), вычисляются значения агрегатных функций;
+* выполняется фильтрация [HAVING](../group_by.md#having);
+* вычисляются значения [оконных функций](../window.md);
+* вычисляются выражения в `SELECT`;
+* выражениям в `SELECT` назначаются имена заданные алиасами;
+* к полученным таким образом колонкам применяется top-level [DISTINCT](distinct.md);
+* таким же образом вычисляются все подзапросы в [UNION ALL](union.md#union-all), выполняется их объединение (см. [PRAGMA AnsiOrderByLimitInUnionAll](../pragma.md#pragmas));
+* выполняется сортировка согласно [ORDER BY](order_by.md);
+* к полученному результату применяются [OFFSET и LIMIT](limit_offset.md).
+
+## Порядок колонок в YQL {#orderedcolumns}
+
+В стандартном SQL порядок колонок указанных в проекции (в `SELECT`) имеет значение. Помимо того, что порядок колонок должен сохраняться при отображении результатов запроса или при записи в новую таблицу, некоторые конструкции SQL этот порядок используют.
+Это относится в том числе к [UNION ALL](union.md#union-all) и к позиционному [ORDER BY](order_by.md) (ORDER BY ordinal).
+
+По умолчанию в YQL порядок колонок игнорируется:
+
+* порядок колонок в выходных таблицах и в результатах запроса не определен
+* схема данных результата `UNION ALL` выводится по именам колонок, а не по позициям
+
+При включении `PRAGMA OrderedColumns;` порядок колонок сохраняется в результатах запроса и выводится из порядка колонок во входных таблицах по следующим правилам:
+
+* `SELECT` с явным перечислением колонок задает соответствующий порядок;
+* `SELECT` со звездочкой (`SELECT * FROM ...`) наследует порядок из своего входа;
+* порядок колонок после [JOIN](../join.md): сначала колонки левой стороны, потом правой. Если порядок какой-либо из сторон присутствующей в выходе `JOIN` не определен, порядок колонок результата также не определен;
+* порядок `UNION ALL` зависит от режима выполнения [UNION ALL](union.md#union-all);
+* порядок колонок для [AS_TABLE](from_as_table.md) не определен;
+
+
+## Комбинация запросов {#combining-queries}
+
+Результаты нескольких SELECT (или подзапросов) могут быть объединены с помощью ключевых слов `UNION` и `UNION ALL`.
+
+```yql
+query1 UNION [ALL] query2 (UNION [ALL] query3 ...)
+```
+
+Объединение более двух запросов интерпретируется как левоассоциативная операция, то есть
+
+```yql
+query1 UNION query2 UNION ALL query3
+```
+
+интерпретируется как
+
+```yql
+(query1 UNION query2) UNION ALL query3
+```
+
+При наличии `ORDER BY/LIMIT/DISCARD/INTO RESULT` в объединяемых подзапросах применяются следующие правила:
+
+* `ORDER BY/LIMIT/INTO RESULT` допускается только после последнего подзапроса;
+* `DISCARD` допускается только перед первым подзапросом;
+* указанные операторы действуют на результат `UNION [ALL]`, а не на подзапрос;
+* чтобы применить оператор к подзапросу, подзапрос необходимо взять в скобки.
+
+
+## Обращение к нескольким таблицам в одном запросе
+
+В стандартном SQL для выполнения запроса по нескольким таблицам используется [UNION ALL](../select/union.md#union_all), который объединяет результаты двух и более `SELECT`. Это не совсем удобно для сценария использования, в котором требуется выполнить один и тот же запрос по нескольким таблицам (например, содержащим данные на разные даты). В YQL, чтобы было удобнее, в `SELECT` после `FROM` можно указывать не только одну таблицу или подзапрос, но и вызывать встроенные функции, позволяющие объединять данные нескольких таблиц.
+
+Для этих целей определены следующие функции:
+
+```CONCAT(`table1`, `table2`, `table3` VIEW view_name, ...)``` — объединяет все перечисленные в аргументах таблицы.
+
+`EACH($list_of_strings)` или `EACH($list_of_strings VIEW view_name)` — объединяет все таблицы, имена которых перечислены в списке строк. Опционально можно передать несколько списков в отдельных аргументах по аналогии с `CONCAT`.
+
+{% note warning %}
+
+Порядок, в котором будут объединены таблицы, всеми вышеперечисленными функциями не гарантируется.
+
+Список таблиц вычисляется **до** запуска самого запроса. Поэтому созданные в процессе запроса таблицы не попадут в результаты функции.
+
+{% endnote %}
+
+По умолчанию схемы всех участвующих таблиц объединяются по правилам [UNION ALL](../select/index.md#union_all). Если объединение схем не желательно, то можно использовать функции с суффиксом `_STRICT`, например `CONCAT_STRICT`, которые работают полностью аналогично оригинальным, но считают любое расхождение в схемах таблиц ошибкой.
+
+Все аргументы описанных выше функций могут быть объявлены отдельно через [именованные выражения](../expressions.md#named-nodes). В этом случае в них также допустимы и простые выражения посредством неявного вызова [EvaluateExpr](../../builtins/basic.md#evaluate_expr_atom).
+
+Имя исходной таблицы, из которой изначально была получена каждая строка, можно получить при помощи функции [TablePath()](../../builtins/basic.md#tablepath).
+
+### Примеры
+
+```yql
+USE some_cluster;
+SELECT * FROM CONCAT(
+ `table1`,
+ `table2`,
+ `table3`);
+```
+
+```yql
+USE some_cluster;
+$indices = ListFromRange(1, 4);
+$tables = ListMap($indices, ($index) -> {
+ RETURN "table" || CAST($index AS String);
+});
+SELECT * FROM EACH($tables); -- идентично предыдущему примеру
+```
+
+## Поддерживаемые конструкции в SELECT
+
+* [FROM](from.md)
+* [FROM AS_TABLE](from_as_table.md)
+* [FROM SELECT](from_select.md)
+* [DISTINCT](distinct.md)
+* [UNIQUE DISTINCT](unique_distinct_hints.md)
+* [UNION](union.md)
+* [WITH](with.md)
+* [WITHOUT](without.md)
+* [WHERE](where.md)
+* [ORDER BY](order_by.md)
+* [ASSUME ORDER BY](assume_order_by.md)
+* [LIMIT OFFSET](limit_offset.md)
+* [SAMPLE](sample.md)
+* [TABLESAMPLE](sample.md)
+* [CONCAT](concat.md)
diff --git a/yql/essentials/docs/ru/syntax/select/limit_offset.md b/yql/essentials/docs/ru/syntax/select/limit_offset.md
new file mode 100644
index 0000000000..e347f4f48c
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/limit_offset.md
@@ -0,0 +1,28 @@
+
+# LIMIT и OFFSET
+
+`LIMIT` ограничивает вывод указанным количеством строк. Если значение лимита равно `NULL`, или `LIMIT` не указан, то вывод не ограничен.
+
+`OFFSET` указывает отступ от начала (в строках). Если значение отступа равно `NULL`, или `OFFSET` не указан, то используется значение ноль.
+
+## Примеры
+
+```yql
+SELECT key FROM my_table
+LIMIT 7;
+```
+
+```yql
+SELECT key FROM my_table
+LIMIT 7 OFFSET 3;
+```
+
+```yql
+SELECT key FROM my_table
+LIMIT 3, 7; -- эквивалентно предыдущему примеру
+```
+
+```yql
+SELECT key FROM my_table
+LIMIT NULL OFFSET NULL; -- эквивалентно SELECT key FROM my_table
+```
diff --git a/yql/essentials/docs/ru/syntax/select/order_by.md b/yql/essentials/docs/ru/syntax/select/order_by.md
new file mode 100644
index 0000000000..772507e622
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/order_by.md
@@ -0,0 +1,20 @@
+# ORDER BY
+
+Сортировка результата `SELECT` по разделенному запятыми перечню критериев сортировки. В качестве критерия может выступать значение столбца, или выражение над столбцами. Не поддерживается указание порядкового номера колонки выборки (`ORDER BY N`, где `N` - номер).
+
+Направление сортировки может быть указано после каждого критерия:
+
+- `ASC` — по возрастанию. Применяется по умолчанию.
+- `DESC` — по убыванию.
+
+Несколько критериев сортировки будут применены слева направо.
+
+## Пример
+
+```yql
+SELECT key, string_column
+FROM my_table
+ORDER BY key DESC, LENGTH(string_column) ASC;
+```
+
+Ключевое слово `ORDER BY` также может использоваться в механизме [оконных функций](../window.md).
diff --git a/yql/essentials/docs/ru/syntax/select/sample.md b/yql/essentials/docs/ru/syntax/select/sample.md
new file mode 100644
index 0000000000..09fc5d89ad
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/sample.md
@@ -0,0 +1,38 @@
+# TABLESAMPLE и SAMPLE
+
+Построение случайной выборки из указанного во `FROM` источника данных.
+
+`TABLESAMPLE` является частью SQL стандарта и работает следующим образом:
+
+* Указывается режим работы:
+
+ * `BERNOULLI` означает «медленно, честно просмотрев все данные, но по-настоящему случайно»;
+ * `SYSTEM` должен использовать знание о физическом хранении данных, чтобы избежать полного их чтения частично жертвуя случайностью выборки.
+
+Данные разбиваются на достаточно большие блоки, и происходит сэмплирование данных блоков целиком. Для прикладных расчётов на достаточно больших таблицах результат вполне может оказаться состоятельным.
+
+* Размер случайной выборки указывается в процентах следом за режимом в круглых скобках.
+* Если при семплировании размер результата получается меньше одного блока, то выдается пустой результат.
+* Опционально далее указывается ключевое слово `REPEATABLE` и целое число в скобках, которое будет использовано как seed для генератора псевдослучайных чисел.
+
+`SAMPLE` является более коротким алиасом, где нет сложных настроек, а размер выборки указывается в долях. На данный момент он соответствует режиму `BERNOULLI`.
+
+## Примеры
+
+```yql
+SELECT *
+FROM my_table
+TABLESAMPLE BERNOULLI(1.0) REPEATABLE(123); -- один процент таблицы
+```
+
+```yql
+SELECT *
+FROM my_table
+TABLESAMPLE SYSTEM(1.0); -- примерно один процент таблицы
+```
+
+```yql
+SELECT *
+FROM my_table
+SAMPLE 1.0 / 3; -- треть таблицы
+```
diff --git a/yql/essentials/docs/ru/syntax/select/toc_i.yaml b/yql/essentials/docs/ru/syntax/select/toc_i.yaml
new file mode 100644
index 0000000000..96a97add04
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/toc_i.yaml
@@ -0,0 +1,17 @@
+items:
+- { name: Обзор, href: index.md }
+- { name: FROM, href: from.md }
+- { name: FROM AS_TABLE, href: from_as_table.md }
+- { name: FROM SELECT, href: from_select.md }
+- { name: DISTINCT, href: distinct.md }
+- { name: UNIQUE DISTINCT, href: unique_distinct_hints.md }
+- { name: UNION, href: union.md }
+- { name: CONCAT, href: concat.md }
+- { name: WITH, href: with.md }
+- { name: WITHOUT, href: without.md }
+- { name: WHERE, href: where.md }
+- { name: ORDER BY, href: order_by.md }
+- { name: ASSUME ORDER BY, href: assume_order_by.md }
+- { name: LIMIT OFFSET, href: limit_offset.md }
+- { name: SAMPLE, href: sample.md }
+- { name: TABLESAMPLE, href: sample.md }
diff --git a/yql/essentials/docs/ru/syntax/select/toc_p.yaml b/yql/essentials/docs/ru/syntax/select/toc_p.yaml
new file mode 100644
index 0000000000..5bfec4365d
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/toc_p.yaml
@@ -0,0 +1,2 @@
+items:
+- include: { mode: link, path: toc_i.yaml } \ No newline at end of file
diff --git a/yql/essentials/docs/ru/syntax/select/union.md b/yql/essentials/docs/ru/syntax/select/union.md
new file mode 100644
index 0000000000..ff5c0da5a9
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/union.md
@@ -0,0 +1,68 @@
+# Объединение результатов подзапросов (UNION)
+
+## UNION {#union}
+
+Объединение результатов нескольких подзапросов с удалением дубликатов.
+Поведение идентично последовательному исполнению `UNION ALL` и `SELECT DISTINCT *`.
+См. [UNION ALL](#union-all) для информации о деталях поведения.
+
+### Примеры
+
+```yql
+SELECT key FROM T1
+UNION
+SELECT key FROM T2 -- возвращает таблицу различных ключей, лежащих хотя бы в одной из исходных таблиц
+```
+
+
+## UNION ALL {#union-all}
+
+Конкатенация результатов нескольких `SELECT` (или подзапросов).
+
+Поддерживаются два режима выполнения `UNION ALL` – по именам колонок (режим по умолчанию) и по позициям колонок (соответствует стандарту ANSI SQL и включается через соответствующую [PRAGMA](../pragma.md#positionalunionall)).
+
+В режиме "по именам" результирующая схема данных выводится по следующим правилам:
+
+* в результирующую таблицу включаются все колонки, которые встречались хоть в одной из входных таблиц;
+* если колонка присутствовала не во всех входных таблицах, то ей автоматически присваивается [опциональный тип данных](../../types/optional.md) (допускающий значение `NULL`);
+* если колонка в разных входных таблицах имела разные типы, то выводится общий тип (наиболее широкий);
+* если колонка в разных входных таблицах имела разнородный тип, например строку и число, то это считается ошибкой.
+
+Порядок выходных колонок в этом режиме выводится как наибольший общий префикс порядка входов, после чего следуют все остальные колонки в алфавитном порядке.
+Если наибольший общий префикс пуст (в том числе и из-за отсутствия порядка на одном из входов), то порядок выхода не определен.
+
+В режиме "по позициям" результирующая схема данных выводится по следующим правилам:
+
+* число колонок во всех входах должно быть одинаковым
+* порядок колонок во всех входах должен быть определен
+* имена результирующих колонок совпадают с именами колонок первой таблицы
+* тип результирующих колонок выводится как общий (наиболее широкий) тип из типов входных колонок стоящих на одинаковых позициях
+
+Порядок выходных колонок в этом режиме совпадает с порядком колонок первого входа.
+
+### Примеры
+
+```yql
+SELECT 1 AS x
+UNION ALL
+SELECT 2 AS y
+UNION ALL
+SELECT 3 AS z;
+```
+
+В результате выполнения данного запроса в режиме по-умолчанию будет сформирована выборка с тремя колонками x, y, и z. При включенной `PRAGMA PositionalUnionAll;` в выборке будет одна колонка x.
+
+```yql
+PRAGMA PositionalUnionAll;
+
+SELECT 1 AS x, 2 as y
+UNION ALL
+SELECT * FROM AS_TABLE([<|x:3, y:4|>]); -- ошибка: порядок колонок в AS_TABLE не определен
+```
+
+```yql
+SELECT * FROM T1
+UNION ALL
+(SELECT * FROM T2 ORDER BY key LIMIT 100); -- при отсутствии скобок ORDER BY/LIMIT применится к результату всего UNION ALL
+```
+
diff --git a/yql/essentials/docs/ru/syntax/select/unique_distinct_hints.md b/yql/essentials/docs/ru/syntax/select/unique_distinct_hints.md
new file mode 100644
index 0000000000..8346499857
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/unique_distinct_hints.md
@@ -0,0 +1,23 @@
+# UNIQUE DISTINCT hints
+
+Непосредственно после `SELECT` возможно добавить [SQL хинты](../lexer.md#sql-hints) `unique` или `distinct`, которые заявляют, что эта проекция порождает данные, содержащие уникальные значения в указанном наборе колонок таблицы. Это может, использоваться для оптимизации следующих подзапросов, выполняющихся над этой проекцией, или для записи в мета-атрибуты таблицы при `INSERT`.
+
+* Колонки указываются в значениях хинта через пробел.
+* Если набор колонок не задан, значит уникальность распространяется на полный набор колонок этой проекции.
+* `unique` - означает уникальные либо `null` значения. По стандарту SQL каждый null уникален: NULL = NULL -> NULL
+* `distinct` - означает полностью уникальные значение включая `null`: NULL IS DISTINCT FROM NULL -> FALSE
+* Можно указать несколько наборов колонок в нескольких хинтах у одной проекции.
+* Если хинт содержит колонку, которой нет в проекции, он будет проигнорирован.
+
+## Примеры
+
+```yql
+SELECT /*+ unique() */ * FROM Input;
+SELECT /*+ distinct() */ * FROM Input;
+
+SELECT /*+ distinct(key subkey) */ * FROM Input;
+SELECT /*+ unique(key) distinct(subkey value) */ * FROM Input;
+
+-- Missed column - ignore hint.
+SELECT /*+ unique(subkey value) */ key, value FROM Input;
+```
diff --git a/yql/essentials/docs/ru/syntax/select/where.md b/yql/essentials/docs/ru/syntax/select/where.md
new file mode 100644
index 0000000000..a71068c61f
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/where.md
@@ -0,0 +1,10 @@
+# WHERE
+
+Фильтрация строк в результате выполнения `SELECT` по условию в таблице.
+
+## Пример
+
+```yql
+SELECT key FROM my_table
+WHERE value > 0;
+```
diff --git a/yql/essentials/docs/ru/syntax/select/with.md b/yql/essentials/docs/ru/syntax/select/with.md
new file mode 100644
index 0000000000..2d762f100b
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/with.md
@@ -0,0 +1,32 @@
+# WITH
+
+Задается после источника данных во `FROM` и используется для указания дополнительных подсказок использования таблиц. Подсказки нельзя задать для подзапросов и [именованных выражений](../expressions.md#named-nodes).
+
+Поддерживаются следующие значения:
+
+* `INLINE` — указание на то, что содержимое таблицы небольшое и нужно использовать его представление в памяти для обработки запроса. Реальный объем таблицы при этом не контролируется, и если он большой, то запрос может упасть по превышению памяти.
+* `UNORDERED` — подавляет использование исходной сортировки таблицы.
+* `SCHEMA` type — указание на то, что следует использовать указанную схему таблицы целиком, игнорируя схему в метаданных.
+* `COLUMNS` type — указание на то, что следует использовать указанные типы для колонок, чьи имена совпадают с именами колонок таблицы в метаданных, а также какие колонки дополнительно присутствуют в таблице.
+
+При задании подсказок `SCHEMA` и `COLUMNS` в качестве значения типа type должен быть задан тип [структуры](../../types/containers.md).
+
+Если задана подсказка `SCHEMA`, то при использовании табличных функций (например, [EACH](#each)) допускается пустой список таблиц, который обрабатывается как пустая таблица с колонками, описанными в `SCHEMA`.
+
+## Примеры
+
+```yql
+SELECT key FROM my_table WITH INLINE;
+```
+
+```yql
+SELECT key, value FROM my_table WITH SCHEMA Struct<key:String, value:Int32>;
+```
+
+```yql
+SELECT key, value FROM my_table WITH COLUMNS Struct<value:Int32?>;
+```
+
+```yql
+SELECT key, value FROM EACH($my_tables) WITH SCHEMA Struct<key:String, value:List<Int32>>;
+```
diff --git a/yql/essentials/docs/ru/syntax/select/without.md b/yql/essentials/docs/ru/syntax/select/without.md
new file mode 100644
index 0000000000..1f0f47146f
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/select/without.md
@@ -0,0 +1,15 @@
+# WITHOUT
+
+Исключение столбцов из результата запроса `SELECT *`.
+
+## Примеры
+
+```yql
+SELECT * WITHOUT foo, bar FROM my_table;
+```
+
+```yql
+PRAGMA simplecolumns;
+SELECT * WITHOUT t.foo FROM my_table AS t
+CROSS JOIN (SELECT 1 AS foo) AS v;
+```
diff --git a/yql/essentials/docs/ru/syntax/subquery.md b/yql/essentials/docs/ru/syntax/subquery.md
new file mode 100644
index 0000000000..6c068f05d2
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/subquery.md
@@ -0,0 +1,193 @@
+
+# Шаблоны подзапросов (subquery)
+
+## DEFINE SUBQUERY {#define-subquery}
+
+`DEFINE SUBQUERY` позволяет объявить шаблон подзапроса (subquery), который представляет собой параметризуемый блок из нескольких выражений верхнего уровня (statements), и затем многократно его использовать путем применения в секции `FROM` выражения [SELECT](select/index.md) или входных данных в [PROCESS](process.md)/[REDUCE](reduce.md) с указанием параметров.
+В отличие от [действий](action.md) шаблон подзапроса должен заканчиваться выражением `SELECT`/`PROCESS`/`REDUCE`, чей результат и является возвращаемым значением подзапроса. При этом выражение верхнего уровня `SELECT`/`PROCESS`/`REDUCE` нельзя использовать более одного раза, как и модифицирующие выражения (например, `INSERT`).
+
+ После `DEFINE SUBQUERY` указывается:
+
+1. [Именованное выражение](expressions.md#named-nodes), по которому объявляемый шаблон будет доступен далее в запросе;
+2. В круглых скобках список именованных выражений, по которым внутри шаблона подзапроса можно обращаться к параметрам;
+3. Ключевое слово `AS`;
+4. Сам список выражений верхнего уровня;
+5. `END DEFINE` выступает в роли маркера, обозначающего последнее выражение внутри шаблона подзапроса.
+
+Один или более последних параметров subquery могут быть помечены вопросиком как необязательные — если они не были указаны при вызове subquery, то им будет присвоено значение `NULL`.
+
+{% note info %}
+
+В больших запросах объявление шаблонов подзапросов можно выносить в отдельные файлы и подключать их в основной запрос с помощью [EXPORT](export_import.md#export) + [IMPORT](export_import.md#import), чтобы вместо одного длинного текста получилось несколько логических частей, в которых проще ориентироваться. Важный нюанс: директива `USE my_cluster;` в импортирующем запросе не влияет на поведение объявленных в других файлах подзапросов.
+
+{% endnote %}
+
+Даже если список параметров в определении шаблона подзапроса пустой при использовании его во `FROM` секции нужно указать скобки `()`. Такое может быть удобно использовать, чтобы ограничить область видимости именованных выражений, используемых только в одном подзапросе.
+
+В некоторых случаях вместо операции `DEFINE SUBQUERY` удобнее использовать эквивалентную форму в виде [лямбда функции](expressions.md#lambda).
+В этом случае лямбда функция должна принимать первым аргументом специальный объект `world`, через который передаются зависимости о том, какие видны PRAGMA или COMMIT в точке использования шаблона запроса. Также этот объект нужно передавать первым аргументом вместе с остальными аргументами при их наличии другим шаблонам запросов, если они используются в лямбда функции.
+Возвращаемым значением лямбда функции должно быть значение с типом список структур (выходная таблица) или список вариантов над кортежом из структур (несколько выходных таблиц). В последнем случае в точке использования шаблона запроса обычно используется распаковка вида
+
+```yql
+$out1, $out2 = PROCESS $mySubquery($myParam1, $myParam2);
+-- используем далее $out1 и $out2 как отдельные таблицы.
+```
+
+### Примеры
+
+```yql
+DEFINE SUBQUERY $hello_world($name, $suffix?) AS
+ $name = $name ?? ($suffix ?? "world");
+ SELECT "Hello, " || $name || "!";
+END DEFINE;
+
+SELECT * FROM $hello_world(NULL); -- Hello, world!
+SELECT * FROM $hello_world("John"); -- Hello, John!
+SELECT * FROM $hello_world(NULL, "Earth"); -- Hello, Earth!
+```
+
+```yql
+DEFINE SUBQUERY $dup($x) AS
+ SELECT * FROM $x(1) -- применяем переданный шаблон запроса с одним аргументом
+ UNION ALL
+ SELECT * FROM $x(2); -- ... и с другим аргументом
+END DEFINE;
+
+DEFINE SUBQUERY $sub($n) AS
+ SELECT $n * 10;
+END DEFINE;
+
+SELECT * FROM $dup($sub); -- передаем шаблон запроса $sub как параметр
+-- Результат:
+-- 10
+-- 20
+```
+
+```yql
+/* Уберем используемые именованные выражения $a и $b в отдельную область видимости */
+DEFINE SUBQUERY $clean() AS
+ $a = 10;
+ $b = $a * $a;
+ SELECT $a AS a, $b AS b;
+END DEFINE;
+
+SELECT * FROM $clean(); -- a: 10, b: 100
+```
+
+```yql
+USE my_cluster;
+
+DEFINE SUBQUERY $input() as
+ SELECT * FROM `home/yql/tutorial/users`;
+END DEFINE;
+
+DEFINE SUBQUERY $myProcess1($nestedQuery, $lambda) AS
+ PROCESS $nestedQuery() -- использование скобок () тут обязательно
+ USING $lambda(TableRow());
+END DEFINE;
+
+$myProcess2 = ($world, $nestedQuery, $lambda) -> {
+ -- Если использовать ListFlatMap или YQL::OrderedFlatMap, то получится Ordered YT Map операция
+ return YQL::FlatMap($nestedQuery($world), $lambda);
+};
+
+-- При таком использовании реализации $myProcess1 и $myProcess2 идентичны
+SELECT * FROM $myProcess1($input, ($x) -> { RETURN AsList($x, $x) });
+SELECT * FROM $myProcess2($input, ($x) -> { RETURN AsList($x, $x) });
+```
+
+```yql
+USE my_cluster;
+
+DEFINE SUBQUERY $runPartition($table) AS
+ $paritionByAge = ($row) -> {
+ $recordType = TypeOf($row);
+ $varType = VariantType(TupleType($recordType, $recordType));
+ RETURN If($row.age % 2 == 0,
+ Variant($row, "0", $varType),
+ Variant($row, "1", $varType),
+ );
+ };
+
+ PROCESS $table USING $paritionByAge(TableRow());
+END DEFINE;
+
+-- Распаковка двух результатов
+$i, $j = (PROCESS $runPartition("home/yql/tutorial/users"));
+
+SELECT * FROM $i;
+
+SELECT * FROM $j;
+```
+
+## Объединение шаблонов подзапросов SubqueryExtend, SubqueryUnionAll, SubqueryMerge, SubqueryUnionMerge {#subquery-extend} {#subquery-unionall} {#subquery-merge} {#subquery-unionmerge}
+
+Эти функции объединяют результаты одного и более шаблонов подзапросов, переданных аргументами. Требуется совпадение количества параметров в этих шаблонах подзапросов.
+
+* `SubqueryExtend` требует совпадение схем подзапросов;
+* `SubqueryUnionAll` работает по тем же правилам, что и [ListUnionAll](../builtins/list.md#ListUnionAll);
+* `SubqueryMerge` использует те же ограничения, что и `SubqueryExtend`, а также выдает сортированный результат в случае если все подзапросы одинаково отсортированны;
+* `SubqueryUnionMerge` использует те же ограничения, что и `SubqueryUnionAll`, а также выдает сортированный результат в случае если все подзапросы одинаково отсортированны.
+
+### Примеры
+
+```yql
+DEFINE SUBQUERY $sub1() as
+ SELECT 1 as x;
+END DEFINE;
+
+DEFINE SUBQUERY $sub2() as
+ SELECT 2 as x;
+END DEFINE;
+
+$s = SubqueryExtend($sub1,$sub2);
+PROCESS $s();
+```
+
+## Объединение шаблонов подзапросов после подстановки элемента списка SubqueryExtendFor, SubqueryUnionAllFor, SubqueryMergeFor, SubqueryUnionMergeFor {#subquery-extend-for} {#subquery-unionall-for} {#subquery-merge-for} {#subquery-unionmerge-for}
+
+Эти функции принимают аргументы:
+
+* Непустой список значений;
+* Шаблон подзапроса, в котором должен быть ровно один параметр.
+
+И выполняют подстановку в шаблон подзапроса в качестве параметра каждый элемент из списка, после чего объединяют полученные подзапросы.
+
+* `SubqueryExtendFor` требует совпадение схем подзапросов;
+* `SubqueryUnionAllFor` работает по тем же правилам, что и [ListUnionAll](../builtins/list.md#ListUnionAll);
+* `SubqueryMergeFor` использует те же ограничения, что и `SubqueryExtendFor`, а также выдает сортированный результат в случае если все подзапросы одинаково отсортированны;
+* `SubqueryUnionMergeFor` использует те же ограничения, что и `SubqueryUnionAllFor`, а также выдает сортированный результат в случае если все подзапросы одинаково отсортированны.
+
+### Примеры
+
+```yql
+DEFINE SUBQUERY $sub($i) as
+ SELECT $i as x;
+END DEFINE;
+
+$s = SubqueryExtendFor([1,2,3],$sub);
+PROCESS $s();
+```
+
+## Добавление сортировки в шаблон подзапроса SubqueryOrderBy или указание о наличии таковой SubqueryAssumeOrderBy
+
+Эти функции принимают аргументы:
+
+* Шаблон подзапроса без параметров;
+* Список пар: строка - имя колонки, булево значение - true для сортировки по возрастанию или false для сортировки по убыванию.
+
+И выполняют построение нового шаблона запроса без параметров, в котором выполняется сортировка или добавляется указание о наличии сортировки к результату. Для использования полученного шаблона запроса необходимо использовать функцию `PROCESS`, так как при использовании `SELECT` сортировка будет проигнорирована.
+
+### Примеры
+
+```yql
+DEFINE SUBQUERY $sub() as
+ SELECT * FROM (VALUES (1,'c'), (1,'a'), (3,'b')) AS a(x,y);
+end define;
+
+$sub2 = SubqueryOrderBy($sub, [('x',false), ('y',true)]);
+
+PROCESS $sub2();
+```
+
+
diff --git a/yql/essentials/docs/ru/syntax/toc_i.yaml b/yql/essentials/docs/ru/syntax/toc_i.yaml
new file mode 100644
index 0000000000..524351d132
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/toc_i.yaml
@@ -0,0 +1,23 @@
+items:
+- { name: Обзор, href: index.md }
+- { name: Лексическая структура, href: lexer.md }
+- { name: Выражения, href: expressions.md }
+- { name: ACTION, href: action.md }
+- { name: COMMIT, href: commit.md }
+- { name: DECLARE, href: declare.md }
+- { name: DISCARD, href: discard.md }
+- { name: GROUP BY, href: group_by.md }
+- { name: EXPORT и IMPORT, href: export_import.md }
+- { name: FLATTEN, href: flatten.md }
+- { name: INSERT, href: insert_into.md }
+- { name: INTO RESULT, href: into_result.md }
+- { name: JOIN, href: join.md }
+- { name: PRAGMA, href: pragma.md }
+- { name: PROCESS, href: process.md }
+- { name: REDUCE, href: reduce.md }
+- { name: SELECT, include: { mode: link, path: select/toc_p.yaml } }
+- { name: SUBQUERY, href: subquery.md }
+- { name: USE, href: use.md }
+- { name: VALUES, href: values.md }
+- { name: WINDOW, href: window.md }
+- { name: Неподдерживаемые конструкции, href: not_yet_supported.md }
diff --git a/yql/essentials/docs/ru/syntax/use.md b/yql/essentials/docs/ru/syntax/use.md
new file mode 100644
index 0000000000..384794b618
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/use.md
@@ -0,0 +1,23 @@
+# USE
+
+Указать «базу данных». Как правило, в её роли выступает один из кластеров. Это указание будет использоваться по умолчанию для поиска таблиц в тех случаях, где база данных не указана явно.
+
+Если в запросе не используется `USE`, то кластер следует указывать в начале пути к таблице в формате ``` cluster.`path/to/table` ```, например ``` cluster.`home/yql/test` ```. Backticks используются для автоматического экранирования спецсимволов, в данном случае слешей.
+
+Обычно имя кластера указывается непосредственно, но есть возможность указать его в виде выражения. В частности, это позволит использовать параметры, объявленные через [DECLARE](declare.md).
+В этом случае для `USE` должна использоваться запись ```USE yt:$cluster_name```, где `$cluster_name` - [именованное выражение](expressions.md#named-nodes) типа `String`.
+Либо можно указывать кластер прямо в начале пути к таблице в формате ``` yt:$cluster_name.`path/to/table` ```.
+
+Сам `USE` при этом можно использовать внутри [действий](action.md) или [шаблонов подзапросов](subquery.md). Значение текущего кластера наследуется на объявления вложенных действий или подзапросов. Область влияния `USE` прекращается по окончании действия или шаблона подзапроса, в котором оно объявлено.
+
+## Примеры
+
+```yql
+USE my_cluster;
+```
+
+{% note info "Примечание" %}
+
+`USE` **не** гарантирует, что запрос обязательно будет выполнен именно на указанном кластере. Запрос может быть выполнен на другом кластере, если в нем не используются входные данные (например, `USE foo; SELECT 2 + 2;` ) или если указан полный путь к таблице на другом кластере (например, `USE foo; SELECT * FROM bar.``path/to/table``;`).
+
+{% endnote %}
diff --git a/yql/essentials/docs/ru/syntax/values.md b/yql/essentials/docs/ru/syntax/values.md
new file mode 100644
index 0000000000..8314c273b6
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/values.md
@@ -0,0 +1,45 @@
+# Базовый синтаксис VALUES в YQL
+
+## VALUES как оператор верхнего уровня
+
+Позволяет сформировать таблицу из указанных значений. Например, данное выражение формирует таблицу из k колонок и n строк:
+
+```yql
+VALUES (expr_11, expr_12, ..., expr_1k),
+ (expr_21, expr_22, ..., expr_2k),
+ ....
+ (expr_n1, expr_n2, ..., expr_nk);
+
+```
+
+Это выражение полностью эквивалентно следующему:
+
+```yql
+SELECT expr_11, expr_12, ..., expr_1k UNION ALL
+SELECT expr_21, expr_22, ..., expr_2k UNION ALL
+....
+SELECT expr_n1, expr_n2, ..., expr_nk;
+```
+
+### Пример
+
+```yql
+VALUES (1,2), (3,4);
+```
+
+## VALUES после FROM
+
+`VALUES` может использоваться и в подзапросе после FROM. В частности, эти два запроса эквивалентны:
+
+```yql
+VALUES (1,2), (3,4);
+SELECT * FROM (VALUES (1,2), (3,4));
+```
+
+Во всех примерах выше имена колонок назначаются YQL и имеют вид `column0 ... columnN`. Для того, чтобы назначить произвольные имена колонок, можно воспользоваться следующей конструкцией:
+
+```yql
+SELECT * FROM (VALUES (1,2), (3,4)) as t(x,y);
+```
+
+В данном случае колонки получат имена `x`, `y`.
diff --git a/yql/essentials/docs/ru/syntax/window.md b/yql/essentials/docs/ru/syntax/window.md
new file mode 100644
index 0000000000..b3d80305b1
--- /dev/null
+++ b/yql/essentials/docs/ru/syntax/window.md
@@ -0,0 +1,156 @@
+# OVER, PARTITION BY и WINDOW
+
+Механизм оконных функций, появившийся в стандарте SQL:2003 и расширенный в стандарте SQL:2011, позволяет выполнять вычисления над набором строк таблицы, который некоторым образом соотносится с текущей строкой.
+
+В отличие от [агрегатных функций](../builtins/aggregation.md) при этом не происходит группировка нескольких строк в одну – после применения оконных функций число строк в результирующей таблице всегда совпадает с числом строк в исходной.
+
+При наличии в запросе агрегатных и оконных функций сначала производится группировка и вычисляются значения агрегатных функций. Вычисленные значения агрегатных функций могут использоваться в качестве аргументов оконных (но не наоборот). Порядок, в котором вычисляются оконные функции относительно других элементов запроса, описан в разеделе [SELECT](select/index.md).
+
+## Синтаксис {#syntax}
+
+Общий синтаксис вызова оконной функции имеет вид
+
+```yql
+function_name([expression [, expression ...]]) OVER (window_definition)
+```
+
+или
+
+```yql
+function_name([expression [, expression ...]]) OVER window_name
+```
+
+Здесь `window_name` (*имя окна*) – произвольный идентификатор, уникальный в рамках запроса, `expression` – произвольное выражение не содержащее вызова оконных функций.
+
+В запросе каждому имени окна должно быть сопоставлено *определение окна* (`window_definition`):
+
+```yql
+SELECT
+ F0(...) OVER (window_definition_0),
+ F1(...) OVER w1,
+ F2(...) OVER w2,
+ ...
+FROM my_table
+WINDOW
+ w1 AS (window_definition_1),
+ ...
+ w2 AS (window_definition_2)
+;
+```
+
+Здесь `window_definition` записывается в виде
+
+```antlr
+[ PARTITION BY (expression AS column_identifier | column_identifier) [, ...] ]
+[ ORDER BY expression [ASC | DESC] ]
+[ frame_definition ]
+```
+
+Необязательное *определение рамки* (`frame_definition`) может быть задано одним из двух способов:
+
+* ```ROWS frame_begin```
+* ```ROWS BETWEEN frame_begin AND frame_end```
+
+*Начало рамки* (`frame_begin`) и *конец рамки* (`frame_end`) задаются одним из следующих способов:
+
+* ```UNBOUNDED PRECEDING```
+* ```offset PRECEDING```
+* ```CURRENT ROW```
+* ```offset FOLLOWING```
+* ```UNBOUNDED FOLLOWING```
+
+Здесь *смещение рамки* (`offset`) – неотрицательный числовой литерал. Если конец рамки не задан, то подразумевается `CURRENT ROW`.
+
+Все выражения внутри определения окна не должны содержать вызовов оконных функций.
+
+## Алгоритм вычисления
+
+### Разбиение {#partition}
+
+Указание `PARTITION BY` группирует строки исходной таблицы в *разделы*, которые затем обрабатываются независимо друг от друга.
+Если `PARTITION BY` не указан, то все строки исходной таблицы попадают в один раздел. Указание `ORDER BY` определяет порядок строк в разделе.
+В `PARTITION BY`, как и в [GROUP BY](group_by.md) можно использовать алиасы и [SessionWindow](group_by.md#session-window).
+
+При отсутствии `ORDER BY` порядок строк в разделе не определен.
+
+### Рамка {#frame}
+
+Определение рамки `frame_definition` задает множество строк раздела, попадающих в *рамку окна* связанную с текущей строкой.
+
+В режиме `ROWS` (в YQL пока поддерживается только он) в рамку окна попадают строки с указанными смещениями относительно текущей строки раздела. Например, для `ROWS BETWEEN 3 PRECEDING AND 5 FOLLOWING` в рамку окна попадут три строки перед текущей, текущая строка и пять строк после текущей строки.
+
+Множество строк в рамке окна может меняться в зависимости от того, какая строка является текущей. Например, для первой строки раздела в рамку окна `ROWS BETWEEN 3 PRECEDING AND 1 PRECEDING` не попадет ни одной строки.
+
+Указание `UNBOUNDED PRECEDING` в качестве начала рамки означает "от первой строки раздела", `UNBOUNDED FOLLOWING` в качестве конца рамки – "до последней строки раздела", `CURRENT ROW` – "от/до текущей строки".
+
+Если `определение_рамки` не указано, то в множество строк попадающих в рамку окна определяется наличием `ORDER BY` в `определении_окна`.
+А именно, при наличии `ORDER BY` неявно подразумевается `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`, а при отсутствии – `ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING`.
+
+Далее, в зависимости от конкретной оконной функции производится ее вычисление либо на множестве строк раздела, либо на множестве строк рамки окна.
+
+[Список доступных оконных функций](../builtins/window.md)
+
+### Примеры
+
+```yql
+SELECT
+ COUNT(*) OVER w AS rows_count_in_window,
+ some_other_value -- доступ к текущей строке
+FROM `my_table`
+WINDOW w AS (
+ PARTITION BY partition_key_column
+ ORDER BY int_column
+);
+```
+
+```yql
+SELECT
+ LAG(my_column, 2) OVER w AS row_before_previous_one
+FROM `my_table`
+WINDOW w AS (
+ PARTITION BY partition_key_column
+);
+```
+
+```yql
+SELECT
+ -- AVG (как и все агрегатные функции, используемые в качестве оконных)
+ -- вычисляется на рамке окна
+ AVG(some_value) OVER w AS avg_of_prev_current_next,
+ some_other_value -- доступ к текущей строке
+FROM my_table
+WINDOW w AS (
+ PARTITION BY partition_key_column
+ ORDER BY int_column
+ ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
+);
+```
+
+```yql
+SELECT
+ -- LAG не зависит от положения рамки окна
+ LAG(my_column, 2) OVER w AS row_before_previous_one
+FROM my_table
+WINDOW w AS (
+ PARTITION BY partition_key_column
+ ORDER BY my_column
+);
+```
+
+## Особенности реализации
+
+* Функции, вычисляемые на рамке окна `ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING` либо `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`, реализованы эффективно (не требуют дополнительной памяти и вычисляются на разделе за O(размер раздела)).
+
+* Для рамки окна `ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING` есть возможность выбрать стратегию выполнения в оперативной памяти, указав [хинт](lexer.md#sql-hints) `COMPACT` после ключевого слова `PARTITION`.
+
+ Например: `PARTITION /*+ COMPACT() */ BY key` или `PARTITION /*+ COMPACT() */ BY ()` (в случае если `PARTITION BY` изначально отсутствовал).
+
+ При наличии хинта `COMPACT` потребуется дополнительная память в размере O(размер раздела), но при этом не возникнет дополнительной `JOIN` операции.
+
+* Если рамка окна не начинается с `UNBOUNDED PRECEDING`, то для вычисления оконных функций на таком окне потребуется дополнительная память в размере O(максимальное расстояние от границ окна до текущей строки), а время вычисления будет равно O(число_строк_в_разделе * размер_окна).
+
+* Для рамки окна, начинающейся с `UNBOUNDED PRECEDING` и заканчивающейся на `N`, где `N` не равен `CURRENT ROW` или `UNBOUNDED FOLLOWING`, потребуется дополнительная память в размере O(N), а время вычисления будет O(N * число_строк_в_разделе).
+
+* Функции `LEAD(expr, N)` и `LAG(expr, N)` всегда потребуют O(N) памяти.
+
+Учитывая вышесказанное, запрос с `ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING` по возможности стоит переделать в `ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW`, поменяв порядок сортировки в `ORDER BY` на обратный.
diff --git a/yql/essentials/docs/ru/toc.yaml b/yql/essentials/docs/ru/toc.yaml
new file mode 100644
index 0000000000..82343f6140
--- /dev/null
+++ b/yql/essentials/docs/ru/toc.yaml
@@ -0,0 +1,2 @@
+items:
+- include: { mode: link, path: toc_i.yaml }
diff --git a/yql/essentials/docs/ru/toc_i.yaml b/yql/essentials/docs/ru/toc_i.yaml
new file mode 100644
index 0000000000..844d8bb685
--- /dev/null
+++ b/yql/essentials/docs/ru/toc_i.yaml
@@ -0,0 +1,11 @@
+title: Справочник YQL ядра
+href: index.md
+items:
+- name: Типы данных
+ include: { mode: link, path: types/toc_i.yaml }
+- name: Синтаксис
+ include: { mode: link, path: syntax/toc_i.yaml }
+- name: Встроенные функции
+ include: { mode: link, path: builtins/toc_i.yaml }
+- name: Репецпты
+ include: { mode: link, path: recipes/toc_i.yaml }
diff --git a/yql/essentials/docs/ru/types/cast.md b/yql/essentials/docs/ru/types/cast.md
new file mode 100644
index 0000000000..a3a9ab616f
--- /dev/null
+++ b/yql/essentials/docs/ru/types/cast.md
@@ -0,0 +1,73 @@
+# Правила преобразования типов через оператор [CAST](../syntax/expressions.md#cast)
+
+## Правила преобразования примитивных типов данных
+
+* В процессе преобразования примитивных типов данных часть исходной информации может быть отброшена, если она не содержится в целевом типе. Например:
+
+ * Дробная часть `Float`/`Double` при преобразовании в целочисленные типы;
+ * Время `Datetime`/`Timestamp` при преобразовании в `Date`.
+ * Таймзона при преобразовании из типов с таймзоной к типу даты/времени без таймзоны.
+
+* Если для определённого сочетания исходного и целевого типа преобразование не может быть выполнено для всех возможных значений исходного типа, то при неудачном преобразовании `CAST` вернёт `NULL`. В таких случаях к типу возвращаемого значения добавляется один уровень `Optional`, если его не было. Например, конструкции: `CAST("3.14" AS Float?)` и `CAST("3.14" AS Float)` полностью эквиваленты и возвращают `Float?`.
+* Если же преобразование возможно для всех значений исходного типа, то добавление '?' работает как `Just` сверху: `CAST(3.14 AS Utf8?)` то же, что и `Just(CAST(3.14 AS Utf8))`
+
+Все сочетания примитивных типов, для которых возможен `CAST` описаны [тут](primitive.md).
+
+## Правила преобразований для контейнеров
+
+### Правила для Optional
+
+* Если для целевого типа задан больший уровень `Optional` чем для исходного то это эквивалентно добавлению `Just` поверх `CAST` с меньшим уровнем `Optional`.
+* Если же больший уровень `Optional` у исходного типа, то `NULL` на любом уровне больше целевого приводит к `NULL` в результате.
+* При равных уровнях `Optional` значение `NULL` остаётся на том же уровне.
+
+```yql
+SELECT
+ CAST(1 AS Int32?), -- тоже что и Just(1)
+ CAST(Just(2/1) AS Float??), -- [2]
+ CAST(Just(3/0) AS Float??) IS NULL; -- false: результат Just(NULL)
+```
+
+### Правила для List/Dict
+
+* Список формируется путём выполнения `CAST` для каждого элемента исходного списка в тип элемента целевого типа.
+* Если тип элемента целевого типа не опциональный, а `CAST` элемента может быть неуспешным, то такие преобразования отбрасываются. В этом случае список в результате может быть меньшей длины или вовсе пустой, если успешных преобразований не было.
+* Для словарей преобразование выполняется полностью аналогично спискам, выполняя `CAST` для ключей и значений.
+
+```yql
+SELECT
+ CAST([-1, 0, 1] AS List<Uint8?>), -- [null, 0, 1]
+ CAST(["3.14", "bad", "42"] AS List<Float>), -- [3.14, 42]
+
+ CAST({-1:3.14, 7:1.6} AS Dict<Uint8, Utf8>), -- {7: "1.6"}
+ CAST({-1:3.14, 7:1.6} AS Dict<Uint8?, Utf8>); -- {7: "1.6", null:"3.14"}
+```
+
+### Правила для Struct/Tuple
+
+* Структура или кортеж формируется путём выполнения `CAST` для каждого элемента исходного типа в элемент с тем же именем или индексом целевого типа.
+* Если какое-то поле отсутствует в целевом типе, оно просто отбрасывается.
+* Если какое-то поле отсутствует в типе исходного значения, то оно может быть добавлено только если является опциональным, и получает значение `NULL`.
+* Если какое-то поле не является опциональным в целевом типе, но его преобразование может быть неуспешным, то `CAST` добавляет опциональность на уровень структуры или кортежа и может вернуть `NULL` для всего результата.
+
+```yql
+SELECT
+ CAST((-1, 0, 1) AS Tuple<Uint16?, Uint16?, Utf8>), -- (null, 0, "1")
+ CAST((-2, 0) AS Tuple<Uint16, Utf8>), -- null
+ CAST((3, 4) AS Tuple<Uint16, String>), -- (3, "4") тип Tuple<Uint16, String>?
+ CAST(("4",) AS Tuple<Uint16, String?>), -- (4, null)
+ CAST((5, 6, null) AS Tuple<Uint8?>); -- (5,) элементы удалены.
+
+SELECT -- Одно поле удалено и одно добавлено: ("three":null, "two": "42")
+ CAST(<|one:"8912", two:42|> AS Struct<two:Utf8, three:Date?>);
+```
+
+### Правила для Variant
+
+* Для варианта с определёнными именем или индексом выполняется преобразование в вариант с тем же именем или индексом.
+* Если преобразование для варианта может быть неуспешным и тип этого варианта не опциональный, то `CAST` добавляет опциональность на верхний уровень и может вернуть `NULL`.
+* Если какой-то вариант отсутствует в целевом типе, то `CAST` добавляет опциональность на верхний уровень и для такого значения возвращает `NULL`.
+
+### Вложенные контейнеры
+
+* Все вышеперечисленные правила работают рекурсивно для вложенных контейнеров.
diff --git a/yql/essentials/docs/ru/types/containers.md b/yql/essentials/docs/ru/types/containers.md
new file mode 100644
index 0000000000..9832aa0241
--- /dev/null
+++ b/yql/essentials/docs/ru/types/containers.md
@@ -0,0 +1,26 @@
+# Контейнеры
+
+YQL поддерживает контейнерные типы для определения сложных структур данных различной организации.
+Значения контейнерных типов могут быть переданы в запросы YQL в качестве входных параметров, либо возвращены из запросов YQL в качестве выходных колонок набора результатов.
+
+| Тип | Объявление,<br/>пример | Описание |
+| ------------ | ---------------- | ------------- |
+| Список | `List<Type>`,<br/>`List<Int32>` | Последовательность переменной длины, состоящая из элементов одного типа.|
+| Словарь | `Dict<KeyType, ValueType>`,<br/>`Dict<String,Int32>` | Набор пар ключ—значение с фиксированным типом ключей и значений. |
+| Множество | `Set<KeyType>`,<br/>`Set<String>` | Набор элементов с фиксированным типом, является частным случаем словаря с типом значения `Void`. |
+| Кортеж | `Tuple<Type1, ..., TypeN>`,<br/>`Tuple<Int32,Double>` | Набор безымянных элементов фиксированной длины с указанными типами всех элементов. |
+| Структура | `Struct<Name1:Type1, ..., NameN:TypeN>`,<br/> `Struct<Name:String,Age:Int32>` | Набор именованных полей с указанными типами значений, фиксированный на момент начала запроса (то есть обязательно не зависящий от данных). |
+| Поток | `Stream<Type>`,<br/> `Stream<Int32>` | Однопроходной итератор по значениям одного типа. Не является сериализуемым. |
+| Вариант над кортежем | `Variant<Type1, Type2>`,<br/> `Variant<Int32,String>` | Кортеж, про который известно, что заполнен ровно один элемент. |
+| Вариант над структурой | `Variant<Name1:Type1, Name2:Type2>`,<br/>`Variant<value:Int32,error:String>` | Структура, про которую известно, что заполнен ровно один элемент. |
+| Перечисление | `Enum<Name1, Name2>`,<br/>`Enum<value,error>` | Контейнер, в котором выбран ровно один элемент перечисления, который определяется только своим именем. |
+
+При необходимости контейнеры можно вкладывать друг в друга в произвольных комбинациях, например `List<Tuple<Int32,Int32>>`.
+
+[Опциональные значения](optional.md) в некоторых контекстах также могут рассматриваться как один из видов контейнеров (`Optional<Type>`), который ведёт себя как список длины 0 или 1.
+
+Для создания литералов контейнеров списка, словаря, множества, кортежа, структуры можно использовать [операторную запись](../builtins/basic.md#containerliteral).
+Для создания литерала варианта над кортежем или структурой используется функция [Variant](../builtins/basic.md#variant).
+Для создания литерала перечисления используется функция [Enum](../builtins/basic.md#enum).
+
+Для обращения к элементам контейнера используется [точка или квадратные скобки](../syntax/expressions.md#items-access), в зависимости от его типа.
diff --git a/yql/essentials/docs/ru/types/index.md b/yql/essentials/docs/ru/types/index.md
new file mode 100644
index 0000000000..99dbc2fe47
--- /dev/null
+++ b/yql/essentials/docs/ru/types/index.md
@@ -0,0 +1,12 @@
+# Типы данных YQL
+
+В данном разделе размещены статьи по типам данных YQL:
+
+- [Простые/примитивные типы](primitive.md)
+- [Опциональные типы](optional.md)
+- [Контейнеры](containers.md)
+- [Специальные типы](special.md)
+- [Преобразования типов](cast.md)
+- [Текстовое представление типов данных](type_string.md)
+- [Представление данных в формате JSON](json.md)
+- [Представление данных в формате YSON](yson.md)
diff --git a/yql/essentials/docs/ru/types/json.md b/yql/essentials/docs/ru/types/json.md
new file mode 100644
index 0000000000..d13c56004c
--- /dev/null
+++ b/yql/essentials/docs/ru/types/json.md
@@ -0,0 +1,196 @@
+
+# Передача параметров и данных в формате JSON
+
+YQL позволяет задавать параметры используя DECLARE выражение. Сами параметры передаются с помощью restricted JSON формата.
+Ниже дано описание формата передачи различных типов данных.
+Этот формат также используется для ответов из API.
+
+## Числовые типы
+
+### Bool {#bool}
+
+Логическое значение.
+
+* Тип в JSON — `bool`.
+* Пример значения JSON — `true`.
+
+### Int, Uint, Float, Double, Decimal {#numbers}
+
+* Тип в JSON — `string`.
+* Числа передаются в строковом представлении.
+* Пример значения JSON — `"123456"`, `"-42"`, `"0.12345679"`, `"-320.789"`.
+
+## Строковые типы
+
+### String {#string}
+
+Бинарные строки.
+
+* при наличии невалидных utf-8 символов, например, `\xFF`, строка кодируется в base64 и оборачивается в массив с одним элементом
+* если нет специальных символов, то передается как есть
+* Тип в JSON - `string` или `array`
+* Пример значения JSON - `"AB"`, `["qw6="]` (для строки `\xAB\xAC`)
+
+### Utf8 {#utf}
+
+Строковые типы в utf-8. Такие строки представляются в JSON строками с escaping'ом JSON-символов: `\\`, `\"`, `\n`, `\r`, `\t`, `\f`.
+
+* Тип в JSON — `string`.
+* Пример значения JSON — `"Escaped characters: \\ \" \f \b \t \r\nNon-escaped characters: / ' < > & []() "`.
+
+### Uuid {#uuid}
+
+Универсальный идентификатор UUID.
+
+* бинарный формат UUID кодируется с помощью base64 и оборачивается в лист
+* Тип в JSON - `array`
+* Пример значения JSON - `["AIQOVZvi1EGnFkRmVUQAAA=="]` для `550e8400-e29b-41d4-a716-446655440000`
+
+### Yson {#yson}
+
+* Тип в JSON - `object`.
+* YSON более богатый язык, чем JSON, поэтому есть необходимость предоставлять дополнительные атрибуты, поэтому задаются поля `$value`, `$type`, `$attributes`.
+* Строки, числа и логические значения заменяются на объект с двумя ключами: `$value` и `$type`. Типы могут быть: `boolean`, `int64`, `uint64`, `double`, `string`.
+* Каждый байт бинарной строки переводится в юникодный символ с соответствующим номером и кодируется в UTF-8 (такой же механизм использует YT при преобразовании Yson в Json).
+* Yson атрибуты добавляются в виде отдельного объекта c ключом `$attributes` и значениями атрибутов.
+* если какое имя начинается с `$`, то он экранируется с помощью удваивания `$$`.
+* Пример YSON:
+
+```yql
+{ "$a" = 2;
+ b = {
+ c = <attr1=val1;attr2=5>12.5;
+ d = [ "el"; # ]
+ }
+}
+```
+
+* Пример значения JSON:
+
+```json
+{
+ "$$a" : { "$value": "2", "$type": "int64" },
+ "b" : {
+ "c": {
+ "$value" : "12.5",
+ "$type" : "double",
+ "$attributes" :
+ {
+ "attr1": { "$value": "b", "$type": "string" },
+ "attr2": { "$value": "5", "$type": "int64" }
+ }
+ },
+ "d": [ { "$value": "el", "$type": "string" }, null ]
+ }
+}
+```
+
+### Json {#json}
+
+* Тип в JSON - `object`.
+* Пример значения JSON - `{ "a" : 12.5, "c" : 25 }`.
+
+## Дата и время
+
+### Date {#date}
+
+Дата, внутреннее представление - Uint16, количество дней c unix epoch.
+
+* Тип в JSON — `string`.
+* Пример значения JSON — `"19509"` для даты `2023-06-01`.
+
+### Datetime {#datetime}
+
+Дата и время, внутреннее представление - Uint32, количество секунд c unix epoch.
+
+* Тип в JSON — `string`.
+* Пример значения JSON — `"1686966302"`для даты `"2023-06-17T01:45:02Z"`.
+
+### Timestamp {#timestamp}
+
+Дата и время, внутреннее представление - Uint64, количество микросекунд c unix epoch.
+
+* Тип в JSON — `string`.
+* Пример значения JSON — `"1685577600000000"` для `2023-06-01T00:00:00.000000Z`.
+
+### Interval {#interval}
+
+Временной интервал, внутреннее представление - Int64, точность до микросекунд.
+
+* Тип в JSON — `string`.
+* Пример значения JSON — `"12345678910"`.
+
+### TzDate, TzDateTime, TzTimestamp {#tzdate}
+
+Временные типы с меткой временной зоны.
+
+* Тип в JSON - `string`.
+* Значение представляется как строковое представление времени и временная зона через запятую.
+* Пример значения JSON - `"2023-06-29,Europe/Moscow"`, `""2023-06-29T17:14:11,Europe/Moscow""`, `""2023-06-29T17:15:36.645735,Europe/Moscow""` для TzDate, TzDateTime и TzTimestamp соответственно.
+
+## Контейнеры
+
+В контейнерах все элементы кодируются согласно их типу.
+
+### List {#list}
+
+Список. Упорядоченный набор значений заданного типа, значения передаются как строки.
+
+* Тип в JSON — `array`.
+* Пример значения JSON для `List<Int32>` — `["1","10","100"]`.
+
+### Struct {#struct}
+
+Структура. Неупорядоченный набор значений с заданными именами и типом.
+
+* Тип в JSON — `object` или `array`.
+* Может передоваться как объект или как массив, где порядок элементов должен совпадать с соответствующими полями структуры.
+* Пример значения JSON `{"a": "-100", "b": "foo"}`, `{"a": "-100", "b": "foo", "c": null}` или `["-100", "foo", null]` для `Struct<a:Int32, b:String, c:Optional<String>>`.
+
+### Tuple {#tuple}
+
+Кортеж. Упорядоченный набор значений заданных типов.
+
+* Тип в JSON — `array`.
+* Пример значения JSON для типа Tuple<Int32, String, Float?> — `[-1,"Some string",null]`.
+
+### Dict {#dict}
+
+Словарь. Неупорядоченный набор пар ключ-значение.
+
+* Тип в JSON — `object` или `array`.
+* для ключей типа `String` и `Utf8` можно передавать объект, для остальных типов надо передавать массив массивов, состоящих из двух элементов (ключа и значения).
+* Пример значения JSON — `[["1","123"],["2","456"]]` для `Dict<Int32, Interval>`, `{ "foo": "123", "bar": "456" }` для `Dict<String, Int32>`.
+
+### Enum {#enum}
+
+Перечисление.
+
+* Тип в JSON - `string`.
+* Пример значения JSON - `"b"` для `Enum<a,b>`.
+
+## Variant {#variant}
+
+Кортеж или структура, про которые известно, что заполнен ровно один элемент.
+
+* Тип в JSON - `array`.
+* Первый способ передачи - массив из поля структуры, обернутый в массив, и значения. Способ подходит только для варианта над структурами.
+* Второй способ передачи - массив из индекса поля структуры/кортежа и само значение.
+* Пример значения JSON - `[["foo"], false]`, `[["bar"], "6"]` или `["0", false]`, `["1", "6"]` для `Variant<foo: Int32, bar: Bool>`.
+
+## Специальные типы
+
+## Optional {#optional}
+
+Означает, что значение может быть `null`.
+
+* Тип в JSON — `array` или `null`.
+* Значения обертываются в массив, `null` значение представляется пустым массивом или `null`.
+* Пример значения JSON - `[["1"], ["2"], ["3"], []]` или `[["1"], ["2"], ["3"], null]` для `List<Optional<Int32>>`.
+
+## Void {#void}
+
+Сингулярный тип данных с единственным возможным значением `null`.
+
+* Тип в JSON - `string`.
+* Значение JSON - `"Void"`.
diff --git a/yql/essentials/docs/ru/types/optional.md b/yql/essentials/docs/ru/types/optional.md
new file mode 100644
index 0000000000..cfbf13ee37
--- /dev/null
+++ b/yql/essentials/docs/ru/types/optional.md
@@ -0,0 +1,53 @@
+
+## Типы данных, допускающие значение NULL
+
+Любые типизированные данные в YQL, включая столбцы таблиц, бывают как гарантированно имеющие значение, так и потенциально пустые (что обозначается как `NULL`). Типы данных, которые могут содержать значения `NULL`, называются *опциональными* или, в терминах SQL, — *nullable*.
+
+Опциональные типы данных в [текстовом виде](type_string.md) обозначаются вопросительным знаком в конце (например, `String?`) или как `Optional<...>`.
+Наиболее часто на опциональных типах данных выполняются следующие операции:
+
+* [IS NULL](../syntax/expressions.md#is-null) - проверка на пустое значение
+* [COALESCE](../builtins/basic.md#coalesce) - оставить заполненные значения без изменений, а `NULL` заменить на указанное следом значение по умолчанию
+* [UNWRAP](../builtins/basic.md#optional-ops) - извлечь значение оригинального типа из опционального, `T?` преобразуется в `T`
+* [JUST](../builtins/basic#optional-ops) — добавить опциональность к текущему типу, `T` преобразуется в `T?`
+* [NOTHING](../builtins/basic.md#optional-ops) — создать пустое значение с указанным типом.
+
+`Optional` (nullable) является не свойством типа данных или колонки, а одним из видов [контейнеров](containers.md), которые могут быть произвольным образом вложены друг в друга. Так, например, столбец с типом `Optional<Optional<Boolean>>` может принимать 4 значения - `NULL` всего контейнера, `NULL` внутреннего контейнера, `TRUE` и `FALSE`. Описанный тип отличается от `List<List<Boolean>>` тем, что роль пустого списка в нем играет `NULL` и отсутствует возможность положить больше одного содержательного элемента. Также значения типа `Optional<Optional<T>>` возвращаются в качестве результата поиска по ключу в словаре `Dict(k,v)` со значениями типа `Optional<T>`. Такой тип данных результата позволяет отличать лежащий в словаре `NULL` от ситуации отсутствия ключа.
+
+### Пример
+
+```yql
+$dict = {"a":1, "b":null};
+$found = $dict["b"];
+select if($found is not null, unwrap($found), -1);
+```
+
+Результат:
+
+```text
+# column0
+null
+```
+
+## Логические и арифметические операции с NULL {#null_expr}
+
+Литерал `NULL` имеет отдельный сингулярный тип `Null` и может быть неявно сконвертирован к любому опциональному типу (в том числе и вложенному `Optional<Optional<...Optional<T>...>>`). В ANSI SQL `NULL` имеет семантику "неизвестное значение" – поэтому логические и арифметические операции с `NULL` или с незаполненными `Optional` имеют некоторые особенности.
+
+### Примеры
+
+```yql
+SELECT
+ True OR NULL, -- Just(True) (работает как True OR <неизвестное значение типа Bool>)
+ False AND NULL, -- Just(False)
+ True AND NULL, -- NULL (точнее Nothing<Bool?> – <неизвестное значение типа Bool>)
+ NULL OR NOT NULL, -- NULL (все NULL-ы "разные")
+ 1 + NULL, -- NULL (Nothing<Int32?>) - результат сложения 1 с
+ -- неизвестным значением типа Int)
+ 1 == NULL, -- NULL (результат сравнения 1 с неизвестным значением типа Int)
+ (1, NULL) == (1, 2), -- NULL (сравнение композитных элементов производится покомпонентно
+ -- через `AND`)
+ (2, NULL) == (1, 3), -- Just(False) (выражение эквивалентно 2 == 1 AND NULL == 3)
+
+```
+
+
diff --git a/yql/essentials/docs/ru/types/primitive.md b/yql/essentials/docs/ru/types/primitive.md
new file mode 100644
index 0000000000..7cd07db98f
--- /dev/null
+++ b/yql/essentials/docs/ru/types/primitive.md
@@ -0,0 +1,209 @@
+# Примитивные типы данных
+
+<!-- markdownlint-disable blanks-around-fences -->
+
+Термины «простые», «примитивные» и «элементарные» типы данных используются как синонимы.
+
+## Числовые типы {#numeric}
+
+Тип | Описание | Примечания
+----- | ----- | -----
+`Bool` | Логическое значение. |
+`Int8` | Целое число со знаком.<br/>Допустимые значения: от –2<sup>7</sup> до 2<sup>7</sup>–1. |
+`Int16` | Целое число со знаком.<br/>Допустимые значения: от –2<sup>15</sup> до 2<sup>15</sup>–1. |
+`Int32` | Целое число со знаком.<br/>Допустимые значения: от –2<sup>31</sup> до 2<sup>31</sup>–1. |
+`Int64` | Целое число со знаком.<br/>Допустимые значения: от –2<sup>63</sup> до 2<sup>63</sup>–1. |
+`Uint8` | Беззнаковое целое число.<br/>Допустимые значения: от 0 до 2<sup>8</sup>–1. |
+`Uint16` | Беззнаковое целое число.<br/>Допустимые значения: от 0 до 2<sup>16</sup>–1. |
+`Uint32` | Беззнаковое целое число.<br/>Допустимые значения: от 0 до 2<sup>32</sup>–1. |
+`Uint64` | Беззнаковое целое число.<br/>Допустимые значения: от 0 до 2<sup>64</sup>–1. |
+`Float` | Вещественное число с переменной точностью размером 4 байта. |
+`Double` | Вещественное число с переменной точностью размером 8 байт. |
+`Decimal` | Вещественное число с указанной точностью, до 35 десятичных знаков |
+`DyNumber` | Бинарное представление вещественного числа точностью до 38 знаков.<br/>Допустимые значения: положительные от 1×10<sup>-130</sup> до 1×10<sup>126</sup>–1, отрицательные от -1×10<sup>126</sup>–1 до -1×10<sup>-130</sup> и 0.<br/>Совместим с типом `Number` AWS DynamoDB. |
+
+
+## Строковые типы {#string}
+
+Тип | Описание | Примечания
+----- | ----- | -----
+`String` | Строка, может содержать произвольные бинарные данные |
+`Utf8` | Текст в кодировке [UTF-8](https://en.wikipedia.org/wiki/UTF-8) |
+`Json` | [JSON](https://en.wikipedia.org/wiki/JSON) в текстовом представлении | Не поддерживает возможность сравнения
+`JsonDocument` | [JSON](https://en.wikipedia.org/wiki/JSON) в бинарном индексированном представлении | Не поддерживает возможность сравнения
+`Yson` | [YSON](yson.md) в текстовом или бинарном представлении | Не поддерживает возможность сравнения
+`Uuid` | Универсальный идентификатор [UUID](https://tools.ietf.org/html/rfc4122) |
+
+В отличие от типа данных `Json`, который хранит исходное текстовое представление, переданное пользователем, `JsonDocument` использует бинарное индексированное представление. Важное отличие с точки зрения семантики состоит в том, что `JsonDocument` не сохраняет форматирование, порядок ключей в объектах и их дубликаты.
+
+За счет индексированного представления `JsonDocument` позволяет обходить документную модель с использованием `JsonPath` без необходимости парсинга всего содержимого. Это позволяет эффективно выполнять операции из [JSON API](../builtins/json.md), уменьшая задержки и стоимость пользовательских запросов. Выполнение запросов над `JsonDocument` может быть до нескольких раз эффективнее в зависимости от типа нагрузки.
+
+Из-за добавленной избыточности `JsonDocument` менее эффективен в хранении. Дополнительные накладные расходы на хранение зависят от конкретного содержимого и в среднем составляют 20–30% от исходного объема. Сохранение данных в формате `JsonDocument` требует дополнительной конвертации из текстового представления, что делает его запись менее эффективной. Тем не менее, для большинства read-intensive сценариев, подразумевающих обработку данных из JSON, этот тип данных является предпочтительным и рекомендуется к использованию.
+
+{% note warning %}
+
+Для хранения чисел (JSON Number) в `JsonDocument`, а также для арифметических операций над ними в [JSON API](../builtins/json.md) используется тип [Double](https://en.wikipedia.org/wiki/Double-precision_floating-point_format). Возможна потеря точности при использовании нестандартных представлений чисел в исходном JSON-документе.
+
+{% endnote %}
+
+## Дата и время {#datetime}
+
+Тип | Описание | Примечания
+----- | ----- | -----
+`Date` | Дата, точность до дней | Диапазон значений для всех временных типов кроме `Interval` - от нуля часов 01.01.1970 до нуля часов 01.01.2106. Внутреннее представление `Date` – беззнаковое целое 16 бит |
+`Datetime` | Дата/время, точность до секунд | Внутреннее представление – беззнаковое целое 32 бит |
+`Timestamp` | Дата/время, точность до микросекунд | Внутреннее представление – беззнаковое целое 64 бит |
+`Interval` | Интервал времени (знаковый), точность до микросекунд | Диапазон значений – от -136 лет до +136 лет. Внутреннее представление – знаковое целое 64 бит.
+`TzDate` | Дата с меткой временной зоны, точность до дней | Не поддерживается в столбцах таблиц
+`TzDateTime` | Дата/время с меткой временной зоны, точность до секунд | Не поддерживается в столбцах таблиц
+`TzTimestamp` | Дата/время с меткой временной зоны, точность до микросекунд | Не поддерживается в столбцах таблиц
+
+### Особенности поддержки типов с меткой временной зоны
+
+Метка временной зоны у типов `TzDate`, `TzDatetime`, `TzTimestamp` это атрибут, который используется:
+
+* При преобразовании ([CAST](../syntax/expressions.md#cast), [DateTime::Parse](../udf/list/datetime.md#parse), [DateTime::Format](../udf/list/datetime.md#format)) в строку и из строки.
+* В [DateTime::Split](../udf/list/datetime.md#split) - появляется компонент таймзоны в `Resource<TM>`.
+
+Само значение позиции во времени у этих типов хранится в UTC, и метка таймзоны никак не участвует в прочих расчётах. Например:
+
+```yql
+SELECT --эти выражения всегда true для любых таймзон: таймзона не влияет на точку во времени.
+ AddTimezone(CurrentUtcDate(), "Europe/Moscow") ==
+ AddTimezone(CurrentUtcDate(), "America/New_York"),
+ AddTimezone(CurrentUtcDatetime(), "Europe/Moscow") ==
+ AddTimezone(CurrentUtcDatetime(), "America/New_York");
+```
+
+Важно понимать, что при преобразованиях между `TzDate` и `TzDatetime` или `TzTimestamp` дате соответствует не полночь по локальному времени таймзоны, а полночь по UTC для даты в UTC.
+
+
+## Приведение простых типов данных {#cast}
+
+### Явное приведение {#explicit-cast}
+
+Явное приведение при помощи [CAST](../syntax/expressions.md#cast):
+
+#### Приведение к численным типам
+
+Тип | Bool | Int8 | Int16 | Int32 | Int64 | Uint8 | Uint16 | Uint32 | Uint64 | Float | Double | Decimal
+--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
+**Bool** | — | Да<sup>1</sup> | Да<sup>1</sup> | Да<sup>1</sup> | Да<sup>1</sup> | Да<sup>1</sup> | Да<sup>1</sup> | Да<sup>1</sup> | Да<sup>1</sup> | Да<sup>1</sup> | Да<sup>1</sup> | Нет
+**Int8** | Да<sup>2</sup> | — | Да | Да | Да | Да<sup>3</sup> | Да<sup>3</sup> | Да<sup>3</sup> | Да<sup>3</sup> | Да | Да | Да
+**Int16** | Да<sup>2</sup> | Да<sup>4</sup> | — | Да | Да | Да<sup>3,4</sup> | Да<sup>3</sup> | Да<sup>3</sup> | Да<sup>3</sup> | Да | Да | Да
+**Int32** | Да<sup>2</sup> | Да<sup>4</sup> | Да<sup>4</sup> | — | Да | Да<sup>3,4</sup> | Да<sup>3,4</sup> | Да<sup>3</sup> | Да<sup>3</sup> | Да | Да | Да
+**Int64** | Да<sup>2</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | — | Да<sup>3,4</sup> | Да<sup>3,4</sup> | Да<sup>3,4</sup> | Да<sup>3</sup> | Да | Да | Да
+**Uint8** | Да<sup>2</sup> | Да<sup>4</sup> | Да | Да | Да | — | Да | Да | Да | Да | Да | Да
+**Uint16** | Да<sup>2</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да | Да | Да<sup>4</sup> | — | Да | Да | Да | Да | Да
+**Uint32** | Да<sup>2</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да | Да<sup>4</sup> | Да<sup>4</sup> | — | Да | Да | Да | Да
+**Uint64** | Да<sup>2</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | — | Да | Да | Да
+**Float** | Да<sup>2</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>3,4</sup> | Да<sup>3,4</sup> | Да<sup>3,4</sup> | Да<sup>3,4</sup> | — | Да | Нет
+**Double** | Да<sup>2</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>3,4</sup> | Да<sup>3,4</sup> | Да<sup>3,4</sup> | Да<sup>3,4</sup> | Да | — | Нет
+**Decimal** | Нет | Да | Да | Да | Да | Да | Да | Да | Да | Да | Да | —
+**String** | Да | Да | Да | Да | Да | Да | Да | Да | Да | Да | Да | Да
+**Utf8** | Да | Да | Да | Да | Да | Да | Да | Да | Да | Да | Да | Да
+**Json** | Нет | Нет | Нет | Нет | Нет | Нет | Нет | Нет | Нет | Нет | Нет | Нет
+**Yson** | Да<sup>5</sup> | Да<sup>5</sup> | Да<sup>5</sup> | Да<sup>5</sup> | Да<sup>5</sup> | Да<sup>5</sup> | Да<sup>5</sup> | Да<sup>5</sup> | Да<sup>5</sup> | Да<sup>5</sup> | Да<sup>5</sup> | Нет
+**Uuid** | Нет | Нет | Нет | Нет | Нет | Нет | Нет | Нет | Нет | Нет | Нет | Нет
+**Date** | Нет | Да<sup>4</sup> | Да<sup>4</sup> | Да | Да | Да<sup>4</sup> | Да | Да | Да | Да | Да | Да | Нет
+**Datetime** | Нет | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да | Да<sup>4</sup> | Да<sup>4</sup> | Да | Да | Да | Да | Нет
+**Timestamp** | Нет | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да | Да | Да | Нет
+**Interval** | Нет | Да<sup>4</sup> | Да<sup>4</sup> | Да<sup>4</sup> | Да | Да<sup>3,4</sup> | Да<sup>3,4</sup> | Да<sup>3,4</sup> | Да<sup>3</sup> | Да | Да | Нет
+
+<sup>1</sup> `True` преобразуется в `1`, `False` преобразуется в `0`.
+<sup>2</sup> Любое значение кроме `0` преобразуется в `True`, `0` преобразуется в `False`.
+<sup>3</sup> Возможно только в случае неотрицательного значения.
+<sup>4</sup> Возможно только в случае попадания в диапазон допустимых значений.
+<sup>5</sup> При помощи встроенной функции [Yson::ConvertTo](../udf/list/yson.md#ysonconvertto).
+
+#### Приведение к типам данных даты и времени
+
+Тип | Date | Datetime | Timestamp | Interval
+--- | --- | --- | --- | ---
+**Bool** | Нет | Нет | Нет | Нет
+**Int8** | Да | Да | Да | Да
+**Int16** | Да | Да | Да | Да
+**Int32** | Да | Да | Да | Да
+**Int64** | Да | Да | Да | Да
+**Uint8** | Да | Да | Да | Да
+**Uint16** | Да | Да | Да | Да
+**Uint32** | Да | Да | Да | Да
+**Uint64** | Да | Да | Да | Да
+**Float** | Нет | Нет | Нет | Нет
+**Double** | Нет | Нет | Нет | Нет
+**Decimal** | Нет | Нет | Нет | Нет
+**String** | Да | Да | Да | Да
+**Utf8** | Да | Да | Да | Да
+**Json** | Нет | Нет | Нет | Нет
+**Yson** | Нет | Нет | Нет | Нет
+**Uuid** | Нет | Нет | Нет | Нет
+**Date** | — | Да | Да | Нет
+**Datetime** | Да | — | Да | Нет
+**Timestamp** | Да | Да | — | Нет
+**Interval** | Нет | Нет | Нет | — | —
+
+#### Приведение к другим типам данных
+
+Тип | String | Utf8 | Json | Yson | Uuid
+--- | --- | --- | --- | --- | ---
+**Bool** | Да | Нет | Нет | Нет | Нет |
+**Int8** | Да | Нет | Нет | Нет | Нет
+**Int16** | Да | Нет | Нет | Нет | Нет
+**Int32** | Да | Нет | Нет | Нет | Нет
+**Int64** | Да | Нет | Нет | Нет | Нет
+**Uint8** | Да | Нет | Нет | Нет | Нет
+**Uint16** | Да | Нет | Нет | Нет | Нет
+**Uint32** | Да | Нет | Нет | Нет | Нет
+**Uint64** | Да | Нет | Нет | Нет | Нет
+**Float** | Да | Нет | Нет | Нет | Нет
+**Double** | Да | Нет | Нет | Нет | Нет
+**Decimal** | Да | Нет | Нет | Нет | Нет
+**String** | — | Да | Да | Да | Да
+**Utf8** | Да | — | Нет | Нет | Нет
+**Json** | Да | Да | — | Нет | Нет
+**Yson** | Да<sup>1</sup> | Нет | Нет | Нет | Нет
+**Uuid** | Да | Да | Нет | Нет | —
+**Date** | Да | Да | Нет | Нет | Нет
+**Datetime** | Да | Да | Нет | Нет | Нет
+**Timestamp** | Да | Да | Нет | Нет | Нет
+**Interval** | Да | Да | Нет | Нет | Нет
+
+<sup>1</sup> При помощи встроенной функции [Yson::ConvertTo](../udf/list/yson.md#ysonconvertto).
+
+##### Примеры
+
+{% include [x](../_includes/cast_examples.md) %}
+
+### Неявное приведение {#implicit-cast}
+
+Неявное приведение типов, которое возникает в базовых операциях (`+`, `-`, `*`, `/`, `%`) между разными типами данных. В ячейках таблицы указан тип результата операции, если она возможна:
+
+#### Численные типы
+
+При несовпадении численных типов сначала выполняется BitCast обоих аргументов к типу результата, а потом уже операция.
+
+Тип | Int8 | Int16 | Int32 | Int64 | Uint8 | Uint16 | Uint32 | Uint64 | Float | Double
+--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
+**Int8** | — | `Int16` | `Int32` | `Int64` | `Int8` | `Uint16` | `Uint32` | `Uint64` | `Float` | `Double`
+**Int16** | `Int16` | — | `Int32` | `Int64` | `Int16` | `Int16` | `Uint32` | `Uint64` | `Float` | `Double`
+**Int32** | `Int32` | `Int32` | — | `Int64` | `Int32` | `Int32` | `Int32` | `Uint64` | `Float` | `Double`
+**Int64** | `Int64` | `Int64` | `Int64` | — | `Int64` | `Int64` | `Int64` | `Int64` | `Float` | `Double`
+**Uint8** | `Int8` | `Int16` | `Int32` | `Int64` | — | `Uint16` | `Uint32` | `Uint64` | `Float` | `Double`
+**Uint16** | `Uint16` | `Int16` | `Int32` | `Int64` | `Uint16` | — | `Uint32` | `Uint64` | `Float` | `Double`
+**Uint32** | `Uint32` | `Uint32` | `Int32` | `Int64` | `Uint32` | `Uint32` | — | `Uint64` | `Float` | `Double`
+**Uint64** | `Uint64` | `Uint64` | `Uint64` | `Int64` | `Uint64` | `Uint64` | `Uint64` | — | `Float` | `Double`
+**Float** | `Float` | `Float` | `Float` | `Float` | `Float` | `Float` | `Float` | `Float` | — | `Double`
+**Double** | `Double` | `Double` | `Double` | `Double` | `Double` | `Double` | `Double` | `Double` | `Double` | —
+
+
+#### Типы даты и времени
+
+Тип | Date | Datetime | Timestamp | Interval | TzDate | TzDatetime | TzTimestamp
+--- | --- | --- | --- | --- | --- | --- | ---
+**Date** | — | — | — | `Date` | — | — | —
+**Datetime** | — | — | — | `Datetime` | — | — | —
+**Timestamp** | — | — | — | `Timestamp` | — | — | —
+**Interval** | `Date` | `Datetime` | `Timestamp` | — | `TzDate` | `TzDatetime` | `TzTimestamp`
+**TzDate** | — | — | — | `TzDate` | — | — | —
+**TzDatetime** | — | — | — | `TzDatetime` | — | — | —
+**TzTimestamp** | — | — | — | `TzTimestamp` | — | — | —
diff --git a/yql/essentials/docs/ru/types/special.md b/yql/essentials/docs/ru/types/special.md
new file mode 100644
index 0000000000..201fa43471
--- /dev/null
+++ b/yql/essentials/docs/ru/types/special.md
@@ -0,0 +1,16 @@
+
+# Специальные типы данных
+
+Тип | Описание
+----- | -----
+`Callable` | Вызываемое значение, которое можно исполнить, передав аргументы в круглых скобках в SQL-синтаксисе YQL, либо с помощью функции `Apply` при использовании [s-expressions](/docs/s_expressions) синтаксиса.
+`Resource` | Непрозрачный указатель на ресурс, который можно передавать между пользовательскими функциями (UDF, user defined function). Тип возвращаемого и принимаемого ресурса объявляется внутри функции строковой меткой. При передаче ресурса YQL проверяет совпадение меток, чтобы предотвратить передачу ресурсов между несовместимыми функциями. В случае несовпадения меток происходит ошибка типизации.
+`Tagged` | Возможность дать прикладное имя какому-либо другому типу.
+`Generic` | Тип данных у типа данных.
+`Unit` | Тип данных у невычисляемых сущностей (источники и приемники данных, атомы и т.&nbsp;п.).
+`Null` | Сингулярный тип данных с единственным возможным значением null. Является типом литерала `NULL` и может преобразовываться к любому `Optional` типу.
+`Void` | Сингулярный тип данных с единственным возможным значением `null`.
+`EmptyList` | сингулярный тип данных с единственным возможным значением []; является типом литерала `[]` и может преобразовываться к любому `List` типу.
+`EmptyDict` | сингулярный тип данных с единственным возможным значением {}; является типом литерала `{}` и может преобразовываться к любому `Dict` или `Set` типу.
+
+
diff --git a/yql/essentials/docs/ru/types/toc_i.yaml b/yql/essentials/docs/ru/types/toc_i.yaml
new file mode 100644
index 0000000000..af3cb084f7
--- /dev/null
+++ b/yql/essentials/docs/ru/types/toc_i.yaml
@@ -0,0 +1,20 @@
+items:
+- name: Обзор
+ href: index.md
+- name: Простые
+ href: primitive.md
+- name: Опциональные
+ href: optional.md
+- name: Контейнеры
+ href: containers.md
+- name: Специальные
+ href: special.md
+- name: Преобразования типов
+ href: cast.md
+- name: Текстовое представление типов данных
+ href: type_string.md
+- name: Передача параметров в формате JSON
+ href: json.md
+- name: YSON
+ hidden: true
+ href: yson.md
diff --git a/yql/essentials/docs/ru/types/type_string.md b/yql/essentials/docs/ru/types/type_string.md
new file mode 100644
index 0000000000..5b0d6342bc
--- /dev/null
+++ b/yql/essentials/docs/ru/types/type_string.md
@@ -0,0 +1,70 @@
+# Работа с текстовым представлением типов данных
+
+## Введение {#intro}
+
+Так как YQL является строго типизированным языком, во многих аспектах работы с ним тип данных имеет большое значение. Для удобства работы с типами существует конвенция описания типов данных YQL в текстовом виде. Она используется в разных местах документации, а также существует библиотека, предоставляющая функции для построения типа данных по текстовому описанию (например, при ручном описании сигнатуры вызываемого значения) или для сериализации типа данных в строку для отладки.
+
+Функции для работы с типами данных [описаны в статье](../builtins/types.md), а ниже описан сам формат текстового представления типов данных.
+
+## Общие правила {#rules}
+
+* [Примитивные типы данных](primitive.md) представляются в текстовом виде просто своим именем.
+* Сложный тип данных представляет собой композицию из других типов данных. Если представить эту композицию в виде дерева, то на листьях окажутся [примитивные типы данных](primitive.md), а в остальных узлах — [контейнеры](containers.md). [Специальные типы данных](special.md) можно рассматривать как исключение, они могут находиться и там и там.
+* Текстовое представление повторяет структуру этого дерева в порядке от корня к листьям: в каждом узле дерева указывается имя текущего типа данных, а переход на уровень глубже обозначается различными видами скобок.
+* Допустимо использование пробелов и переносов строк, если это облегчает чтение.
+* Если идентификатор состоит не только из английских букв и цифр, то его нужно записывать в одиночных кавычках и использовать C-escaping.
+
+## Контейнеры {#containers}
+
+* Для указания типов элементов контейнера используются угловые скобки.
+
+ Пример: `List<Int32>`.
+
+* Если контейнер предполагает несколько разнородных элементов, то они перечисляются внутри угловых скобок через запятую.
+
+ Пример: `Tuple<Int32, String>`.
+
+* Если контейнер предполагает именованные элементы, то вместо типов данных через запятую используются пары из имени и типа через двоеточие.
+
+ Пример: `Struct<a:Int32, b:String>`.
+
+* Нижележащий тип контейнера `Variant` выбирается в зависимости от наличия имён в аргументах.
+
+ Пример: `Variant<Int32, String>` — вариант над кортежем, `Variant<a:Int32, b:String>` — вариант над структурой.
+
+## Типы, допускающие NULL {#optional}
+
+* В терминах YQL это называется `Optional`, в терминах классического SQL — nullable.
+
+* Формально этот тип является контейнером, т.е. запись `Optional<...>` допустима, но обычно вместо неё используется shortcut в виде суффикса из знака вопроса.
+
+ Пример: `String?`.
+
+## Вызываемые значения {#callable}
+
+* Базовая форма вызываемых значений выглядит следующим образом: `(arg1, arg2, ...) -> result`.
+
+ Пример описания сигнатуры функции, принимающей две строки и возвращающей число: `(String, String) -> Int64`.
+
+* Вызываемые значения могут возвращать вызываемые значения, в этом случае они образуют цепочку необходимой длины.
+
+ Пример: `(String, String) -> (String, String) -> Int64`.
+
+* Опциональные аргументы должны иметь на верхнем уровне тип `Optional` и обрамляются в квадратные скобки.
+
+ Пример: `(String, [String?, Double?]) -> Int64`.
+
+* У аргументов вызываемых значений могут быть указаны флаги.
+
+ На текущий момент возможен только один флаг — `AutoMap`, который означает, что если в этот аргумент передали NULL, то результат нужно сделать тоже NULL, а саму функцию не запускать.
+
+ Пример: `(String{Flags: AutoMap}) -> Int64`.
+
+* Если нужен `Optional<Callable<...>>`, то нужно использовать именно такую форму, т.к. знак вопроса в конце относится к результату вызываемого значения.
+
+## Ресурсы {#resources}
+
+* В отличие от контейнеров, ресурс параметризуется не типом элемента (ресурс является указателем в памяти и YQL ничего не знает о его содержимом), а строковой меткой, которая может использоваться для защиты от передачи ресурсов между несовместимыми функциями.
+
+ Пример: `Resource<Foo>`.
+
diff --git a/yql/essentials/docs/ru/types/yson.md b/yql/essentials/docs/ru/types/yson.md
new file mode 100644
index 0000000000..da1b958943
--- /dev/null
+++ b/yql/essentials/docs/ru/types/yson.md
@@ -0,0 +1,457 @@
+# Yson
+
+В данном разделе собрана информация про YSON — JSON-подобный формат данных, разработанный в Яндексе.
+
+{% note info %}
+
+SQL-функции для работы с YSON описаны [здесь](../udf/list/yson.md)
+
+{% endnote %}
+
+## Введение {#intro}
+
+К основным **отличиям YSON от JSON** относится:
+
+1. Поддержка бинарного представления скалярных типов (чисел, строк и булевого типа);
+2. [Атрибуты](#attributes): произвольный словарь, который можно установить дополнительно на литерал любого (даже скалярного) типа.
+
+Кроме того существуют **синтаксические отличия**:
+
+1. Вместо запятой в качестве разделителя используется точка с запятой;
+2. В словарях ключ от значения отделяется не двоеточием, а знаком равенства: `=`;
+3. Строковые литералы не обязательно всегда заключать в кавычки (только если иначе возникает неоднозначность при парсинге).
+
+Имеется следующий набор **скалярных** типов:
+
+1. [Строки](#string) (`string`);
+2. [Знаковые](#int) и [беззнаковые](#uint) 64-битные целые числа (`int64` и `uint64` );
+3. [Числа с плавающей точкой](#double) двойной точности (`double`);
+4. [Булев](#boolean) (логический) тип (`boolean`);
+5. [Специальный тип entity](#entity), имеющий всего один литерал (`#`).
+
+Скалярные типы обычно имеют как текстовое, так и бинарное представление.
+
+Есть два **композитных** типа:
+
+1. [Список](#list) (`list`);
+2. [Словарь](#map) (`map`).
+
+## Скалярные типы {#scalar_types}
+
+### Строки {#string}
+
+Токены строк бывают трех видов:
+
+1. **Идентификаторы** задаются регулярным выражением `[A-Za-z_][A-Za-z0-9_.\-]*` (Первый символ - буква или нижнее подчеркивание, со второго символа могут быть дополнительно использованы цифры и символы `-`,`.`). Идентификатор задает строку с идентичным ему содержимым и используется в первую очередь для краткости (не нужно ставить кавычки).
+
+ Примеры:
+
+ - `abc123`;
+ - `_`;
+ - `a-b`.
+
+2. **Текстовые строки** — [C-escaped](https://en.wikipedia.org/wiki/Escape_sequences_in_C) строки в двойных кавычках.
+
+ Примеры:
+
+ - `"abc123"`;
+ - `""`;
+ - `"quotation-mark: \", backslash: \\, tab: \t, unicode: \xEA"`.
+
+3. **Бинарные строки**: `\x01 + length (protobuf sint32 wire format) + data (<length> bytes)`.
+
+### Знаковые 64-битные целые числа (`int64`) {#int}
+
+Два способа записи:
+
+1. **Текстовый**: (`0`, `123`, `-123`, `+123`);
+2. **Бинарный**: `\x02 + value (protobuf sint64 wire format)`.
+
+### Беззнаковые 64-битные целые числа (`uint64`) {#uint}
+
+Два способа записи:
+
+1. **Текстовый**: (`10000000000000`, `123u`);
+2. **Бинарный**: `\x06 + value (protobuf uint64 wire format)`.
+
+### Числа с плавающей точкой (`double`) {#double}
+
+Два способа записи:
+
+1. **Текстовый**: (`0.0`, `-1.0`, `1e-9`, `1.5E+9`, `32E1`, `%inf`, `%-inf`, `%nan`);
+2. **Бинарный**: `\x03 + protobuf double wire format`.
+
+{% note warning %}
+
+Текстовое представление чисел с плавающей точкой включает в себя округление, которое может привести к тому, что при обратном парсинге значение окажется иным. В случае, если вам важна точность, следует использовать бинарное представление.
+
+{% endnote %}
+
+{% note warning %}
+
+Значения `%inf`, `%-inf`, `%nan` не существуют в JSON, поэтому вызов `Yson::SerializeJson` с содержащим эти значения YSON приведет к ошибке
+
+{% endnote %}
+
+### Булевы литералы (`boolean`) {#boolean}
+
+Два способа записи:
+
+1. **Текстовый** (`%false`, `%true`);
+2. **Бинарный** (`\x04`, `\x05`).
+
+### Entity (`entity`) {#entity}
+
+Entity представляет собой атомарное скалярное значение, не имеющее никакого собственного содержимого. Сценарии, в которых данный тип может быть полезен, разнообразны. Например, часто `entity` обозначает `null`. При этом `entity` может иметь аттрибуты
+
+Лексически entity кодируется символом решетки: `#`.
+
+### Выделенные литералы {#special_literals}
+
+Специальные токены:
+
+`;`, `=`, `#`, `[`, `]`, `{`, `}`, `<`, `>`, `)`, `/`, `@`, `!`, `+`, `^`, `:`, `,`, `~`.
+
+Не все эти символы используются в YSON, некоторые используются в [YPath](#ypath).
+
+## Композитные типы {#composite_types}
+
+### Список (`list`) {#list}
+
+Задается следующим образом: `[value; ...; value]`, где `value` — литералы произвольных скалярных или композитных типов.
+
+Пример: `[1; "hello"; {a=1; b=2}]`.
+
+### Словарь (`map`) {#map}
+
+Задается следующим образом: `{key = value; ...; key = value}`. Здесь `*key*` — литералы строкового типа, а `value` — литералы произвольных скалярных или композитных типов.
+
+Пример: `{a = "hello"; "38 parrots" = [38]}`.
+
+### Атрибуты {#attributes}
+
+На любой литерал в YSON можно установить **атрибуты**. Записывается это так: `<key = value; ...; key = value> value`. Внутри угловых скобок синтаксис аналогичен словарю. Например, `<a = 10; b = [7,7,8]>"some-string"` или `<"44" = 44>44`. Но чаще всего атрибуты можно встретить на литералах типа `entity`, например, `<id="aaad6921-b5704588-17990259-7b88bad3">#`.
+
+## Грамматика {#grammar}
+
+YSON-данные бывают трех типов:
+
+ 1. **Node** (одно дерево, в примере — `<tree>`)
+ 2. **ListFragment** (значения, разделенные `;`, в примере — `<list-fragment>`)
+ 3. **MapFragment** (пары ключ-значение, разделенные `;`, в примере — `<map-fragment>`)
+
+
+Грамматика (определяется с точностью до пробельных символов, которые могут быть в произвольном количестве добавлены и удалены между токенами):
+
+```antlr
+ <tree> = [ <attributes> ], <object>;
+ <object> = <scalar> | <map> | <list> | <entity>;
+
+ <scalar> = <string> | <int64> | <uint64> | <double> | <boolean>;
+ <list> = "[", <list-fragment>, "]";
+ <map> = "{", <map-fragment>, "}";
+ <entity> = "#";
+ <attributes> = "<", <map-fragment>, ">";
+
+ <list-fragment> = { <list-item>, ";" }, [ <list-item> ];
+ <list-item> = <tree>;
+
+ <map-fragment> = { <key-value-pair>, ";" }, [ <key-value-pair> ];
+<key-value-pair> = <string>, "=", <tree>; % Key cannot be empty
+```
+
+Символ `;` после последнего элемента внутри `<list-fragment>` и `<map-fragment>` может быть опущен. Следующие конструкции следует считать валидными при чтении:
+
+#|
+|| C `;` на конце | Сокращенная запись ||
+||
+
+```yson
+<a=b;>c
+{a=b;}
+1;2;3;
+```
+
+|
+
+```yson
+<a=b>c
+{a=b}
+1;2;3
+```
+
+ ||
+|#
+
+
+## Примеры {#examples}
+
+- Map (Node)
+
+```yson
+{ performance = 1 ; precision = 0.78 ; recall = 0.21 }
+```
+
+- Map (Node)
+
+```yson
+{ cv-precision = [ 0.85 ; 0.24 ; 0.71 ; 0.70 ] }
+```
+
+
+- List (Node)
+
+```yson
+[ 1; 2; 3; 4; 5 ]
+```
+
+
+- String (Node)
+
+```yson
+foobar
+```
+
+```yson
+"hello world"
+```
+
+- Int64 (Node) `42`
+
+- Double (Node) `3.1415926`
+
+- ListFragment
+
+```yson
+{ key = a; value = 0 };
+{ key = b; value = 1 };
+{ key = c; value = 2; unknown_value = [] }
+```
+
+- MapFragment
+
+```yson
+do = create; type = table; scheme = {}
+```
+
+- HomeDirectory (Node)
+
+```yson
+{ home = { sandello = { mytable = <type = table> # ; anothertable = <type = table> # } ; monster = { } } }
+```
+
+## YPATH {#ypath}
+
+В данном разделе собрана информация про YPath — язык, описывающий пути к объектам в YSON.
+
+YPath представляет собой язык описания путей, которые идентифицирует объекты в YSON. Язык позволяет обращаться к узлам и указывать аннотации, которые могут быть полезны при совершении операций над узлами, такими как запись и чтение свойств.
+
+Например:
+
+- `/0-25-3ec012f-406daf5c/@type` — путь к атрибуту `type` объекта с идентификатором `0-25-3ec012f-406daf5c`;
+
+Существует несколько разновидностей YPath. В самом простом случае YPath представляет собой строку, кодирующую путь.
+
+### Лексика {#simple_ypath_lexis}
+
+Строка, кодирующая простой YPath, разбивается на следующие **токены**:
+
+1. **Специальные символы**: прямой слеш (`/`), "собака" (`@`), амперсанд (`&`), звездочка (`*`);
+2. **Литералы**: максимальная непустая последовательность неспециальных символов. В литералах разрешен escaping вида `\<escape-sequence>`, где в качестве `<escape-sequence>` может выступать один из символов `\`, `/`, `@`, `&`, `*`, `[`, `{`, а также выражение вида `x<hex1><hex2>`, где `<hex1>` и `<hex2>` — шестнадцатеричные цифры.
+
+### Синтаксис и семантика {#simple_ypath_syntax}
+
+Структурно YPath имеет вид `/<relative-path>`. `<relative-path>` разбирается последовательно слева направо, в результате чего возникают шаги перемещения по дереву следующих видов:
+
+- **Переход к потомку**: последовательность из токена `/` и литерала.
+ Данный тип шагов применим к словарям и спискам. В случае словаря литерал должен содержать имя потомка. Пример: `/child` — переход к потомку с именем `child`.
+ В случае списка литерал должен содержать целое число в десятичной системе счисления — номер потомка. Потомки в списке нумеруются с нуля. Разрешены также отрицательные номера, которые нумеруют потомков с конца списка. Примеры: `/1` — переход ко второму потомку в списке, `/-1` — переход к последнему потомку в списке;
+- **Переход к атрибуту**: последовательность из токенов `/@` и литерала.
+ Данный тип шагов применим в любой точке пути и означает переход к атрибуту с данными именем. Пример: `/@attr` — переход к атрибуту с именем `attr`.
+
+{% note info %}
+
+В YPath относительные пути начинаются со слешей. Тем самым, слеш служит не разделителем (как в случае файловых систем), а полноправным членом команды перемещения по дереву. В частности, для склейки двух YPath достаточно обычной конкатенации строк. Это свойство может показаться необычным, но во многих местах оно удобно, и к нему достаточно легко привыкнуть.
+
+{% endnote %}
+
+### Примеры {#simple_ypath_examples}
+
+```yql
+$data = Yson(@@{"0-25-3ec012f-406daf5c" = {a=<why="I can just do it">1;b=2}}@@);
+SELECT Yson::SerializeJson($data), Yson::SerializeJson(Yson::YPath($data, "/0-25-3ec012f-406daf5c/a/@/why"));
+```
+
+Результат:
+
+#|
+|| column0 | column1 ||
+||
+
+```json
+{
+ "0-25-3ec012f-406daf5c": {
+ "a": {
+ "$attributes": {
+ "why": "I can just do it"
+ },
+ "$value": 1
+ },
+ "b": 2
+ }
+}
+```
+
+| `"I can just do it"` ||
+|#
+
+
+```yql
+$data = Yson(@@{
+ a = <a=z;x=y>[
+ {abc=123; def=456};
+ {abc=234; xyz=789; entity0123 = #};
+ ];
+ b = {str = <it_is_string=%true>"hello"; "38 parrots" = [38]};
+ entity0 = <here_you_can_store=something>#;
+ }
+@@);
+
+SELECT Yson::ConvertToStringDict(Yson::YPath($data, "/a/@")) AS attrs_root,
+Yson::SerializeJson(Yson::YPath($data, "/b/str/@")) AS attrs_b_str,
+Yson::SerializeJson(Yson::YPath($data, "/b/str/@/it_is_string")) AS attr_exact,
+Yson::SerializeJson(Yson::YPath($data, "/a/0")) as array_index0,
+Yson::SerializeJson(Yson::YPath($data, "/a/-1")) as array_last,
+Yson::SerializeJson(Yson::YPath($data, "/entity0")) as entity,
+Yson::SerializeJson(Yson::YPath($data, "/a/#entity0123/abc")) as entity1,
+Yson::SerializeJson(Yson::YPath($data, "/a")) AS whole_a,
+Yson::SerializeJson($data) AS whole_data;
+```
+
+Результат:
+
+#|
+|| attrs_root | attrs_b_str | attr_exact | array_index0 | array_last | entity | entity1 | whole_a | whole_data ||
+||
+
+```json
+{
+ "a": "z",
+ "x": "y"
+}
+```
+
+|
+
+```json
+{
+ "it_is_string": true
+}
+```
+
+|
+
+```json
+true
+```
+
+|
+
+```json
+{
+ "abc": 123,
+ "def": 456
+}
+```
+
+|
+
+```json
+{
+ "abc": 234,
+ "entity0123": null,
+ "xyz": 789
+}
+```
+
+|
+
+```json
+{
+ "$attributes": {
+ "here_you_can_store": "something"
+ },
+ "$value": null
+}
+```
+
+|
+
+```json
+null
+```
+
+|
+
+```json
+{
+ "$attributes": {
+ "a": "z",
+ "x": "y"
+ },
+ "$value": [
+ {
+ "abc": 123,
+ "def": 456
+ },
+ {
+ "abc": 234,
+ "entity0123": null,
+ "xyz": 789
+ }
+ ]
+}
+```
+
+|
+
+```json
+{
+ "a": {
+ "$attributes": {
+ "a": "z",
+ "x": "y"
+ },
+ "$value": [
+ {
+ "abc": 123,
+ "def": 456
+ },
+ {
+ "abc": 234,
+ "xyz": 789
+ }
+ ]
+ },
+ "b": {
+ "38 parrots": [
+ 38
+ ],
+ "str": {
+ "$attributes": {
+ "it_is_string": true
+ },
+ "$value": "hello"
+ }
+ }
+}
+```
+
+||
+|#
+
+
+
+
+
+
diff --git a/yql/essentials/docs/ru/udf/list/datetime.md b/yql/essentials/docs/ru/udf/list/datetime.md
new file mode 100644
index 0000000000..56b4b056c1
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/datetime.md
@@ -0,0 +1,507 @@
+# DateTime
+
+В модуле DateTime основным внутренним форматом представления является `Resource<TM>`, хранящий следующие компоненты даты:
+
+* Year (12 бит);
+* Month (4 бита);
+* Day (5 бит);
+* Hour (5 бит);
+* Minute (6 бит);
+* Second (6 бит);
+* Microsecond (20 бит);
+* TimezoneId (16 бит);
+* DayOfYear (9 бит) — день от начала года;
+* WeekOfYear (6 бит) — неделя от начала года, 1 января всегда относится к первой неделе;
+* WeekOfYearIso8601 (6 бит) — неделя года согласно ISO 8601 (первой неделей считается та, в которой 4 января);
+* DayOfWeek (3 бита) — день недели.
+
+Если таймзона не GMT, то в компонентах хранится локальное время в соответствующей таймзоне.
+
+## Split {#split}
+
+Преобразование из простого типа во внутреннее представление. Всегда успешно при непустом входе.
+
+### Список функций
+
+* `DateTime::Split(Date{Flags:AutoMap}) -> Resource<TM>`
+* `DateTime::Split(Datetime{Flags:AutoMap}) -> Resource<TM>`
+* `DateTime::Split(Timestamp{Flags:AutoMap}) -> Resource<TM>`
+* `DateTime::Split(TzDate{Flags:AutoMap}) -> Resource<TM>`
+* `DateTime::Split(TzDatetime{Flags:AutoMap}) -> Resource<TM>`
+* `DateTime::Split(TzTimestamp{Flags:AutoMap}) -> Resource<TM>`
+
+Функции, принимающие на вход `Resource<TM>`, могут быть вызваны непосредственно от простого типа даты/времени. В этом случае будет сделано неявное преобразование через вызов соответствующей функции `Split`.
+
+## Make... {#make}
+
+Сборка простого типа из внутреннего представления. Всегда успешна при непустом входе.
+
+### Список функций
+
+* `DateTime::MakeDate(Resource<TM>{Flags:AutoMap}) -> Date`
+* `DateTime::MakeDatetime(Resource<TM>{Flags:AutoMap}) -> Datetime`
+* `DateTime::MakeTimestamp(Resource<TM>{Flags:AutoMap}) -> Timestamp`
+* `DateTime::MakeTzDate(Resource<TM>{Flags:AutoMap}) -> TzDate`
+* `DateTime::MakeTzDatetime(Resource<TM>{Flags:AutoMap}) -> TzDatetime`
+* `DateTime::MakeTzTimestamp(Resource<TM>{Flags:AutoMap}) -> TzTimestamp`
+
+### Примеры
+
+```yql
+SELECT
+ DateTime::MakeTimestamp(DateTime::Split(Datetime("2019-01-01T15:30:00Z"))),
+ -- 2019-01-01T15:30:00.000000Z
+ DateTime::MakeDate(Datetime("2019-01-01T15:30:00Z")),
+ -- 2019-01-01
+ DateTime::MakeTimestamp(DateTime::Split(TzDatetime("2019-01-01T00:00:00,Europe/Moscow"))),
+ -- 2018-12-31T21:00:00Z (конвертация в UTC)
+ DateTime::MakeDate(TzDatetime("2019-01-01T12:00:00,GMT"))
+ -- 2019-01-01 (Datetime -> Date с неявным Split)
+```
+
+## Get... {#get}
+
+Взятие компоненты внутреннего представления.
+
+### Список функций
+
+* `DateTime::GetYear(Resource<TM>{Flags:AutoMap}) -> Uint16`
+* `DateTime::GetDayOfYear(Resource<TM>{Flags:AutoMap}) -> Uint16`
+* `DateTime::GetMonth(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetMonthName(Resource<TM>{Flags:AutoMap}) -> String`
+* `DateTime::GetWeekOfYear(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetWeekOfYearIso8601(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetDayOfMonth(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetDayOfWeek(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetDayOfWeekName(Resource<TM>{Flags:AutoMap}) -> String`
+* `DateTime::GetHour(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetMinute(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetSecond(Resource<TM>{Flags:AutoMap}) -> Uint8`
+* `DateTime::GetMillisecondOfSecond(Resource<TM>{Flags:AutoMap}) -> Uint32`
+* `DateTime::GetMicrosecondOfSecond(Resource<TM>{Flags:AutoMap}) -> Uint32`
+* `DateTime::GetTimezoneId(Resource<TM>{Flags:AutoMap}) -> Uint16`
+* `DateTime::GetTimezoneName(Resource<TM>{Flags:AutoMap}) -> String`
+
+### Примеры
+
+```yql
+$tm = DateTime::Split(TzDatetime("2019-01-09T00:00:00,Europe/Moscow"));
+
+SELECT
+ DateTime::GetDayOfMonth($tm) as Day, -- 9
+ DateTime::GetMonthName($tm) as Month, -- "January"
+ DateTime::GetYear($tm) as Year, -- 2019
+ DateTime::GetTimezoneName($tm) as TzName, -- "Europe/Moscow"
+ DateTime::GetDayOfWeekName($tm) as WeekDay; -- "Wednesday"
+```
+
+## Update {#update}
+
+Обновление одной или нескольких компонент во внутреннем представлении. Возвращает либо обновлённую копию, либо NULL, если после обновления получается некорректная дата или возникают другие противоречия.
+
+### Список функций
+
+```yql
+DateTime::Update( Resource<TM>{Flags:AutoMap}, [ Year:Uint16?, Month:Uint8?, Day:Uint8?, Hour:Uint8?, Minute:Uint8?, Second:Uint8?, Microsecond:Uint32?, Timezone:String? ]) -> Resource<TM>?
+```
+
+### Примеры
+
+```yql
+$tm = DateTime::Split(Timestamp("2019-01-01T01:02:03.456789Z"));
+
+SELECT
+ DateTime::MakeDate(DateTime::Update($tm, 2012)), -- 2012-01-01
+ DateTime::MakeDate(DateTime::Update($tm, 2000, 6, 6)), -- 2000-06-06
+ DateTime::MakeDate(DateTime::Update($tm, NULL, 2, 30)), -- NULL (30 февраля)
+ DateTime::MakeDatetime(DateTime::Update($tm, NULL, NULL, 31)), -- 2019-01-31T01:02:03Z
+ DateTime::MakeDatetime(DateTime::Update($tm, 15 as Hour, 30 as Minute)), -- 2019-01-01T15:30:03Z
+ DateTime::MakeTimestamp(DateTime::Update($tm, 999999 as Microsecond)), -- 2019-01-01T01:02:03.999999Z
+ DateTime::MakeTimestamp(DateTime::Update($tm, "Europe/Moscow" as Timezone)), -- 2018-12-31T22:02:03.456789Z (конвертация в UTC)
+ DateTime::MakeTzTimestamp(DateTime::Update($tm, "Europe/Moscow" as Timezone)); -- 2019-01-01T01:02:03.456789,Europe/Moscow
+```
+
+## From... {#from}
+
+Получение Timestamp из количества секунд/миллисекунд/микросекунд от начала эпохи в UTC. При выходе за границы Timestamp возвращается NULL.
+
+### Список функций
+
+* `DateTime::FromSeconds(Uint32{Flags:AutoMap}) -> Timestamp`
+* `DateTime::FromMilliseconds(Uint64{Flags:AutoMap}) -> Timestamp`
+* `DateTime::FromMicroseconds(Uint64{Flags:AutoMap}) -> Timestamp`
+
+## To... {#to}
+
+Получение количества секунд/миллисекунд/микросекунд от начала эпохи в UTC из простого типа.
+
+### Список функций
+
+* `DateTime::ToSeconds(Date/DateTime/Timestamp/TzDate/TzDatetime/TzTimestamp{Flags:AutoMap}) -> Uint32`
+* `DateTime::ToMilliseconds(Date/DateTime/Timestamp/TzDate/TzDatetime/TzTimestamp{Flags:AutoMap}) -> Uint64`
+* `DateTime::ToMicroseconds(Date/DateTime/Timestamp/TzDate/TzDatetime/TzTimestamp{Flags:AutoMap}) -> Uint64`
+
+### Примеры
+
+```yql
+SELECT
+ DateTime::FromSeconds(1546304523), -- 2019-01-01T01:02:03.000000Z
+ DateTime::ToMicroseconds(Timestamp("2019-01-01T01:02:03.456789Z")); -- 1546304523456789
+```
+
+## Interval... {#interval}
+
+Преобразования между `Interval` и различными единицами измерения времени.
+
+### Список функций
+
+* `DateTime::ToDays(Interval{Flags:AutoMap}) -> Int16`
+* `DateTime::ToHours(Interval{Flags:AutoMap}) -> Int32`
+* `DateTime::ToMinutes(Interval{Flags:AutoMap}) -> Int32`
+* `DateTime::ToSeconds(Interval{Flags:AutoMap}) -> Int32`
+* `DateTime::ToMilliseconds(Interval{Flags:AutoMap}) -> Int64`
+* `DateTime::ToMicroseconds(Interval{Flags:AutoMap}) -> Int64`
+* `DateTime::IntervalFromDays(Int16{Flags:AutoMap}) -> Interval`
+* `DateTime::IntervalFromHours(Int32{Flags:AutoMap}) -> Interval`
+* `DateTime::IntervalFromMinutes(Int32{Flags:AutoMap}) -> Interval`
+* `DateTime::IntervalFromSeconds(Int32{Flags:AutoMap}) -> Interval`
+* `DateTime::IntervalFromMilliseconds(Int64{Flags:AutoMap}) -> Interval`
+* `DateTime::IntervalFromMicroseconds(Int64{Flags:AutoMap}) -> Interval`
+
+{% note warning %}
+
+Функция `DateTime::ToSeconds` не поддерживает работу с интервалами с длительностью большей чем 68 лет, в этом случае можно использовать выражение `DateTime::ToMilliseconds(x) / 1000`
+
+{% endnote %}
+
+AddTimezone никак не влияет на вывод ToSeconds(), поскольку ToSeconds() всегда возвращают время в таймзоне GMT.
+
+Interval также можно создавать из строкового литерала в формате [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601%23Durations).
+
+### Примеры
+
+```yql
+SELECT
+ DateTime::ToDays(Interval("PT3000M")), -- 2
+ DateTime::IntervalFromSeconds(1000000), -- 11 days 13 hours 46 minutes 40 seconds
+ DateTime::ToDays(cast('2018-01-01' as date) - cast('2017-12-31' as date)); --1
+```
+
+## StartOf... / EndOf... / TimeOfDay {#startof}
+
+Получить начало (конец) периода, содержащего дату/время. При некорректном результате возвращается NULL. Если таймзона не GMT, то начало (конец) периода будет в указанной временной зоне.
+
+### Список функций
+
+* `DateTime::StartOfYear(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::EndOfYear(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::StartOfQuarter(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::EndOfQuarter(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::StartOfMonth(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::EndOfMonth(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::StartOfWeek(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::EndOfWeek(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::StartOfDay(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::EndOfDay(Resource<TM>{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::StartOf(Resource<TM>{Flags:AutoMap}, Interval{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::EndOf(Resource<TM>{Flags:AutoMap}, Interval{Flags:AutoMap}) -> Resource<TM>?`
+
+Функции `StartOf`/`EndOf` предназначены для группировки в пределах суток по произвольному периоду. Результат отличается от входного значения только компонентами времени. Период более суток трактуется как сутки (эквивалентно `StartOfDay`/`EndOfDay`). Если в сутках не содержится целого числа периодов, производится округление к ближайшему времени от начала суток, кратному указанному периоду. При нулевом интервале выход совпадает со входом. Отрицательный интервал трактуется как положительный.
+
+Функции `EndOf...` предназначены для получения последнего момента времени, находящегося в том же выбранном интервале, что и заданный.
+
+Поведение функций с периодами больше дня отличается от поведения одноимённых функций в старой библиотеке. Компоненты времени всегда обнуляются (это логично, поскольку эти функции в основном используются для группировки по периоду). Отдельно существует возможность выделить время в пределах суток:
+
+* `DateTime::TimeOfDay(Resource<TM>{Flags:AutoMap}) -> Interval`
+
+### Примеры
+
+```yql
+SELECT
+ DateTime::MakeDate(DateTime::StartOfYear(Date("2019-06-06"))),
+ -- 2019-01-01 (неявный Split здесь и дальше)
+ DateTime::MakeDatetime(DateTime::StartOfQuarter(Datetime("2019-06-06T01:02:03Z"))),
+ -- 2019-04-01T00:00:00Z (компоненты времени обнулены)
+ DateTime::MakeDate(DateTime::StartOfMonth(Timestamp("2019-06-06T01:02:03.456789Z"))),
+ -- 2019-06-01
+ DateTime::MakeDate(DateTime::StartOfWeek(Date("1970-01-01"))),
+ -- NULL (начало эпохи - четверг, начало недели - 1969-12-29, выход за границы)
+ DateTime::MakeTimestamp(DateTime::StartOfWeek(Date("2019-01-01"))),
+ -- 2018-12-31T00:00:00Z
+ DateTime::MakeDatetime(DateTime::StartOfDay(Datetime("2019-06-06T01:02:03Z"))),
+ -- 2019-06-06T00:00:00Z
+ DateTime::MakeTzDatetime(DateTime::StartOfDay(TzDatetime("1970-01-01T05:00:00,Europe/Moscow"))),
+ -- NULL (в GMT выход за эпоху)
+ DateTime::MakeTzTimestamp(DateTime::StartOfDay(TzTimestamp("1970-01-02T05:00:00.000000,Europe/Moscow"))),
+ -- 1970-01-02T00:00:00,Europe/Moscow (начало дня по Москве)
+ DateTime::MakeDatetime(DateTime::StartOf(Datetime("2019-06-06T23:45:00Z"), Interval("PT7H"))),
+ -- 2019-06-06T21:00:00Z
+ DateTime::MakeDatetime(DateTime::StartOf(Datetime("2019-06-06T23:45:00Z"), Interval("PT20M"))),
+ -- 2019-06-06T23:40:00Z
+ DateTime::TimeOfDay(Timestamp("2019-02-14T01:02:03.456789Z"));
+ -- 1 hour 2 minutes 3 seconds 456789 microseconds
+```
+
+## Shift... {#shift}
+
+Прибавить/вычесть заданное количество единиц к компоненте во внутреннем представлении и обновить остальные поля.
+Возвращает либо обновлённую копию, либо NULL, если после обновления получается некорректная дата или возникают другие противоречия.
+
+### Список функций
+
+* `DateTime::ShiftYears(Resource<TM>{Flags:AutoMap}, Int32) -> Resource<TM>?`
+* `DateTime::ShiftQuarters(Resource<TM>{Flags:AutoMap}, Int32) -> Resource<TM>?`
+* `DateTime::ShiftMonths(Resource<TM>{Flags:AutoMap}, Int32) -> Resource<TM>?`
+
+Если в результате номер дня в месяце превышает максимально возможный, то в поле `Day` будет записан последний день месяца,
+время при этом не изменится (см. примеры).
+
+### Примеры
+
+```yql
+$tm1 = DateTime::Split(DateTime("2019-01-31T01:01:01Z"));
+$tm2 = DateTime::Split(TzDatetime("2049-05-20T12:34:50,Europe/Moscow"));
+
+SELECT
+ DateTime::MakeDate(DateTime::ShiftYears($tm1, 10)), -- 2029-01-31T01:01:01
+ DateTime::MakeDate(DateTime::ShiftYears($tm2, -10000)), -- NULL (выход за границы)
+ DateTime::MakeDate(DateTime::ShiftQuarters($tm2, 0)), -- 2049-05-20T12:34:50,Europe/Moscow
+ DateTime::MakeDate(DateTime::ShiftQuarters($tm1, -3)), -- 2018-04-30T01:01:01
+ DateTime::MakeDate(DateTime::ShiftMonths($tm1, 1)), -- 2019-02-28T01:01:01
+ DateTime::MakeDate(DateTime::ShiftMonths($tm1, -35)), -- 2016-02-29T01:01:01
+```
+
+## Format {#format}
+
+Получить строковое представление момента времени, используя произвольную строку форматирования.
+
+### Список функций
+
+* `DateTime::Format(String, alwaysWriteFractionalSeconds:Bool?) -> (Resource<TM>{Flags:AutoMap}) -> String`
+
+Для строки форматирования реализовано множество спецификаторов:
+
+* `%%` - символ %;
+* `%Y` - год 4 цифры;
+* `%m` - месяц 2 цифры;
+* `%d` - день 2 цифры;
+* `%H` - час 2 цифры;
+* `%M` - минуты 2 цифры;
+* `%S` - секунды 2 цифры -- или xx.xxxxxx в случае непустых микросекунд (и только если флаг `alwaysWriteFractionalSeconds` не выставлен в `True`);
+* `%z` - +hhmm or -hhmm;
+* `%Z` - IANA имя таймзоны;
+* `%b` - короткое трехбуквенное английское название месяца (Jan);
+* `%B` - полное английское название месяца (January).
+
+Все остальные символы строки форматирования переносятся без изменений.
+
+### Примеры
+
+```yql
+$format = DateTime::Format("%Y-%m-%d %H:%M:%S %Z");
+
+SELECT
+ $format(DateTime::Split(TzDatetime("2019-01-01T01:02:03,Europe/Moscow")));
+ -- "2019-01-01 01:02:03 Europe/Moscow"
+```
+
+## Parse {#parse}
+
+Распарсить строку во внутреннее представление, используя произвольную строку форматирования. Для незаполненных полей используются значения по умолчанию. При возникновении ошибок возвращается NULL.
+
+### Список функций
+
+* `DateTime::Parse(String) -> (String{Flags:AutoMap}) -> Resource<TM>?`
+
+Реализованные спецификаторы:
+
+* `%%` - символ %;
+* `%Y` - год 4 цифры (1970);
+* `%m` - месяц 2 цифры (1);
+* `%d` - день 2 цифры (1);
+* `%H` - час 2 цифры (0);
+* `%M` - минуты 2 цифры (0);
+* `%S` - секунды (0), может принимать и микросекунды в форматах от xx. до xx.xxxxxx
+* `%Z` - IANA имя таймзоны (GMT).
+* `%b` - короткое трехбуквенное регистронезависимое английское название месяца (Jan);
+* `%B` - полное регистронезависимое английское название месяца (January).
+
+### Примеры
+
+```yql
+$parse1 = DateTime::Parse("%H:%M:%S");
+$parse2 = DateTime::Parse("%S");
+$parse3 = DateTime::Parse("%m/%d/%Y");
+$parse4 = DateTime::Parse("%Z");
+
+SELECT
+ DateTime::MakeDatetime($parse1("01:02:03")), -- 1970-01-01T01:02:03Z
+ DateTime::MakeTimestamp($parse2("12.3456")), -- 1970-01-01T00:00:12.345600Z
+ DateTime::MakeTimestamp($parse3("02/30/2000")), -- NULL (Feb 30)
+ DateTime::MakeTimestamp($parse4("Canada/Central")); -- 1970-01-01T06:00:00Z (конвертация в UTC)
+```
+
+## Parse конкретных форматов
+
+Для распространённых форматов есть врапперы вокруг соответствующих методов util. Можно получить только TM с компонентами в UTC таймзоне.
+
+### Список функций
+
+* `DateTime::ParseRfc822(String{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::ParseIso8601(String{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::ParseHttp(String{Flags:AutoMap}) -> Resource<TM>?`
+* `DateTime::ParseX509(String{Flags:AutoMap}) -> Resource<TM>?`
+
+### Примеры
+
+```yql
+SELECT
+ DateTime::MakeTimestamp(DateTime::ParseRfc822("Fri, 4 Mar 2005 19:34:45 EST")),
+ -- 2005-03-05T00:34:45Z
+ DateTime::MakeTimestamp(DateTime::ParseIso8601("2009-02-14T02:31:30+0300")),
+ -- 2009-02-13T23:31:30Z
+ DateTime::MakeTimestamp(DateTime::ParseHttp("Sunday, 06-Nov-94 08:49:37 GMT")),
+ -- 1994-11-06T08:49:37Z
+ DateTime::MakeTimestamp(DateTime::ParseX509("20091014165533Z"))
+ -- 2009-10-14T16:55:33Z
+```
+
+## Типовые сценарии
+
+### Преобразования между строками и секундами
+
+Преобразование строковой даты (в таймзоне Москвы) в секунды (в таймзоне GMT):
+
+```yql
+$datetime_parse = DateTime::Parse("%Y-%m-%d %H:%M:%S");
+$datetime_parse_tz = DateTime::Parse("%Y-%m-%d %H:%M:%S %Z");
+
+SELECT
+ DateTime::ToSeconds(TzDateTime("2019-09-16T00:00:00,Europe/Moscow")) AS md_us1, -- 1568581200
+ DateTime::ToSeconds(DateTime::MakeDatetime($datetime_parse_tz("2019-09-16 00:00:00" || " Europe/Moscow"))), -- 1568581200
+ DateTime::ToSeconds(DateTime::MakeDatetime(DateTime::Update($datetime_parse("2019-09-16 00:00:00"), "Europe/Moscow" as Timezone))), -- 1568581200
+
+ -- НЕПРАВИЛЬНО (Date импортирует время как GMT, а AddTimezone никак не влияет на ToSeconds, которая всегда возвращает время в таймзоне GMT)
+ DateTime::ToSeconds(AddTimezone(Date("2019-09-16"), 'Europe/Moscow')) AS md_us2, -- 1568592000
+```
+
+Преобразование строковой даты (в таймзоне Москвы) в секунды (в таймзоне Москвы). Поскольку `DateTime::ToSeconds()` экспортирует только GMT, придется временно забыть о таймзонах и работать только в GMT (выглядит это так, как будто временно мы считаем, что в Москве таймзона GMT):
+
+```yql
+$date_parse = DateTime::Parse("%Y-%m-%d");
+$datetime_parse = DateTime::Parse("%Y-%m-%d %H:%M:%S");
+$datetime_parse_tz = DateTime::Parse("%Y-%m-%d %H:%M:%S %Z");
+
+SELECT
+ DateTime::ToSeconds(Datetime("2019-09-16T00:00:00Z")) AS md_ms1, -- 1568592000
+ DateTime::ToSeconds(Date("2019-09-16")) AS md_ms2, -- 1568592000
+ DateTime::ToSeconds(DateTime::MakeDatetime($date_parse("2019-09-16"))) AS md_ms3, -- 1568592000
+ DateTime::ToSeconds(DateTime::MakeDatetime($datetime_parse("2019-09-16 00:00:00"))) AS md_ms4, -- 1568592000
+ DateTime::ToSeconds(DateTime::MakeDatetime($datetime_parse_tz("2019-09-16 00:00:00 GMT"))) AS md_ms5, -- 1568592000
+
+ -- НЕПРАВИЛЬНО (импортирует время в таймзоне Москвы, а RemoveTimezone никак не влияет на ToSeconds)
+ DateTime::ToSeconds(RemoveTimezone(TzDatetime("2019-09-16T00:00:00,Europe/Moscow"))) AS md_ms6, -- 1568581200
+ DateTime::ToSeconds(DateTime::MakeDatetime($datetime_parse_tz("2019-09-16 00:00:00 Europe/Moscow"))) AS md_ms7 -- 1568581200
+```
+
+Преобразование секунд (в таймзоне GMT) в строковую дату (в таймзоне Москвы):
+
+```yql
+$date_format = DateTime::Format("%Y-%m-%d %H:%M:%S %Z");
+SELECT
+ $date_format(AddTimezone(DateTime::FromSeconds(1568592000), 'Europe/Moscow')) -- "2019-09-16 03:00:00 Europe/Moscow"
+```
+
+Преобразование секунд (в таймзоне Москвы) в строковую дату (в таймзоне Москвы). Здесь таймзона `%Z` выводится для справки - обычно выводить ее не нужно, потому что она будет равна "GMT" и может сбить с толку.
+
+```yql
+$date_format = DateTime::Format("%Y-%m-%d %H:%M:%S %Z");
+SELECT
+ $date_format(DateTime::FromSeconds(1568592000)) -- "2019-09-16 00:00:00 GMT"
+```
+
+Преобразование секунд (в таймзоне GMT) в трехбуквенное название дня недели (в таймзоне Москвы):
+
+```yql
+SELECT
+ SUBSTRING(DateTime::GetDayOfWeekName(AddTimezone(DateTime::FromSeconds(1568581200), "Europe/Moscow")), 0, 3) -- "Mon"
+```
+
+### Форматирование даты и времени
+
+Обычно для форматирования времени используется отдельное именованное выражение, но можно обойтись и без него:
+
+```yql
+$date_format = DateTime::Format("%Y-%m-%d %H:%M:%S %Z");
+
+SELECT
+
+ -- Вариант с именованным выражением
+
+ $date_format(AddTimezone(DateTime::FromSeconds(1568592000), 'Europe/Moscow')),
+
+ -- Вариант без именованного выражения
+
+ DateTime::Format("%Y-%m-%d %H:%M:%S %Z")
+ (AddTimezone(DateTime::FromSeconds(1568592000), 'Europe/Moscow'))
+;
+```
+
+### Преобразование типов
+
+Так можно преобразовывать только константы:
+
+```yql
+SELECT
+ TzDateTime("2019-09-16T00:00:00,Europe/Moscow"), -- 2019-09-16T00:00:00,Europe/Moscow
+ Date("2019-09-16") -- 2019-09-16
+```
+
+А так - константу, именованное выражение или поле таблицы:
+
+```yql
+SELECT
+ CAST("2019-09-16T00:00:00,Europe/Moscow" AS TzDateTime), -- 2019-09-16T00:00:00,Europe/Moscow
+ CAST("2019-09-16" AS Date) -- 2019-09-16
+```
+
+### Преобразование времени в дату
+
+`CAST` в `Date` или `TzDate` дает такую дату в таймзоне GMT, в которую происходит полночь по локальному времени (например, для московского времени 2019-10-22 00:00:00, будет возвращена дата 2019-10-21). Для получения даты в локальной таймзоне можно использовать DateTime::Format.
+
+```yql
+$x = DateTime("2019-10-21T21:00:00Z");
+select
+ AddTimezone($x, "Europe/Moscow"), -- 2019-10-22T00:00:00,Europe/Moscow
+ cast($x as TzDate), -- 2019-10-21,GMT
+ cast(AddTimezone($x, "Europe/Moscow") as TzDate), -- 2019-10-21,Europe/Moscow
+ cast(AddTimezone($x, "Europe/Moscow") as Date), -- 2019-10-21
+ DateTime::Format("%Y-%m-%d %Z")(AddTimezone($x, "Europe/Moscow")), -- 2019-10-22 Europe/Moscow
+```
+
+Стоит отметить, что некоторые значения в типaх TzDatetime и TzTimestamp, имеющие положительное смещение таймзоны, не могут быть преобразованы в тип TzDate. Рассмотрим следующий пример:
+
+```yql
+SELECT CAST(TzDatetime("1970-01-01T23:59:59,Europe/Moscow") as TzDate);
+/* Fatal: Timestamp 1970-01-01T23:59:59.000000,Europe/Moscow cannot be casted to TzDate */
+```
+
+Не существует такого значения, начиная с Unix epoch, которым можно представить полночь 01.01.1970 для московского времени. В результате, такое преобразование считается невозможным и генерирует ошибку времени выполнения.
+
+В то же время, значения, имеющие отрицательное смещение таймзоны, возвращают корректный результат:
+
+```yql
+SELECT CAST(TzDatetime("1970-01-01T23:59:59,America/Los_Angeles") as TzDate);
+/* 1970-01-01,America/Los_Angeles */
+```
+
+### Летнее время
+
+Обратите внимание, что летнее время зависит от года:
+
+```yql
+SELECT
+ RemoveTimezone(TzDatetime("2019-09-16T10:00:00,Europe/Moscow")) as DST1, -- 2019-09-16T07:00:00Z
+ RemoveTimezone(TzDatetime("2008-12-03T10:00:00,Europe/Moscow")) as DST2, -- 2008-12-03T07:00:00Z
+ RemoveTimezone(TzDatetime("2008-07-03T10:00:00,Europe/Moscow")) as DST3, -- 2008-07-03T06:00:00Z (DST)
+```
diff --git a/yql/essentials/docs/ru/udf/list/digest.md b/yql/essentials/docs/ru/udf/list/digest.md
new file mode 100644
index 0000000000..837c1c9ccf
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/digest.md
@@ -0,0 +1,126 @@
+# Digest
+
+Модуль Digest вычисляют хеши (aka fingerprint'ы) от исходных сообщений. Хеши представляют собой (обычно) некоторую строку небольшого / фиксированного размера. Фактический размер хеша зависит от используемого алгоритма. Результат представляет собой последовательность бит.
+Модуль содержит как криптографические, так и некриптографические функции.
+
+Важным свойством алгоритмов является то, что хеш, вероятно, изменится, если сообщение каким-то образом изменится. Другим свойством является то, что функции дайджеста являются односторонними функциями, то есть должно быть трудно найти сообщение, соответствующее некоторому заданному дайджесту.
+
+## Список функций
+
+* `Digest::Crc32c(String{Flags::AutoMap}) -> Uint32`
+* `Digest::Crc64(String{Flags::AutoMap}) -> Uint64`
+* `Digest::Fnv32(String{Flags::AutoMap}) -> Uint32`
+* `Digest::Fnv64(String{Flags::AutoMap}) -> Uint64`
+* `Digest::MurMurHash(String{Flags:AutoMap}) -> Uint64`
+* `Digest::MurMurHash32(String{Flags:AutoMap}) -> Uint32`
+* `Digest::MurMurHash2A(String{Flags:AutoMap}) -> Uint64`
+* `Digest::MurMurHash2A32(String{Flags:AutoMap}) -> Uint32`
+* `Digest::CityHash(String{Flags:AutoMap}, [Uint64?]) -> Uint64`: Второй опциональный аргумент задает seed
+* `Digest::CityHash128(String{Flags:AutoMap}) -> Tuple<Uint64,Uint64>`
+
+CityHash функция для байтовой строки с результатом типа uint128. Результат представлен как пара из двух uint64 чисел `<low, high>`
+
+```yql
+SELECT Digest::CityHash128("Who set this ancient quarrel new abroach?"); -- (11765163929838407746,2460323961016211789)
+```
+
+* `Digest::NumericHash(Uint64{Flags:AutoMap}) -> Uint64`
+
+```yql
+SELECT Digest::NumericHash(123456789); -- 1734215268924325803
+```
+
+* `Digest::Md5Hex(String{Flags:AutoMap}) -> String`
+* `Digest::Md5Raw(String{Flags:AutoMap}) -> String`
+* `Digest::Md5HalfMix(String{Flags:AutoMap}) -> Uint64`
+
+MD5 - широко распространенный, 128-битный алгоритм хеширования.
+
+Md5Hex - возращает хеш в виде ASCII строки закодировавнной в 16 битной кодировке
+
+Md5Raw - возращает хеш в виде байтовой строки
+
+Md5HalfMix - вариант огрубления MD5 до размера Uint64
+
+```yql
+SELECT
+ Digest::Md5Hex("Who set this ancient quarrel new abroach?"), -- "644e98bae764871650f2d93e14c6488d"
+ Digest::Md5Raw("Who set this ancient quarrel new abroach?"), -- Binary String: 64 4e 98 ba e7 64 87 16 50 f2 d9 3e 14 c6 48 8d
+ Digest::Md5HalfMix("Who set this ancient quarrel new abroach?"); -- 17555822562955248004
+```
+
+* `Digest::Argon2(string:String{Flags:AutoMap}, salt:String{Flags:AutoMap}) -> String`
+
+Argon2 - функция формирования ключа, направленная на высокую скорость заполнения памяти и эффективное использование нескольких вычислительных блоков.
+
+Параметры:
+
+- string - исходная строка
+- salt - строка которая будет использоавться в качестве соли для хеш функции
+
+```yql
+SELECT Digest::Argon2("Who set this ancient quarrel new abroach?", "zcIvVcuHEIL8"); -- Binary String: fa 50 34 d3 c3 23 a4 de 22 c7 7c e1 9c 65 64 88 25 b3 59 75 c5 b8 8c 73 da 88 eb 79 31 70 e8 f1
+SELECT Digest::Argon2("Who set this ancient quarrel new abroach?", "M78P42R8HA=="); -- Binary String: d2 0e f1 3e 72 5a e9 32 65 ed 28 4b 12 1f 39 70 e5 10 aa 1a 15 67 6d 96 5d e8 19 b3 bd d5 04 e9
+```
+
+* `Digest::Blake2B(string:String{Flags:AutoMap},[key:String?]) -> String`
+
+BLAKE2 — криптографическая хеш-функция, создана как альтернатива MD5 и SHA-1 алгоритмам, в которых были найдены уязвимости.
+
+Параметры:
+
+- string - исходная строка
+- key - ключ, используемый для шифроавния исходной строки (может быть использован как разделяемый секрет между источником и приемником)
+
+```yql
+SELECT Digest::Blake2B("Who set this ancient quarrel new abroach?"); -- Binary String: 62 21 91 d8 11 5a da ad 5e 7c 86 47 41 02 7f 8f a8 a6 82 07 47 d8 f8 30 ab b4 c3 00 db 9c 24 2f
+```
+
+* `Digest::SipHash(low:Uint64,high:Uint64,string:String{Flags:AutoMap}) -> Uint64`
+
+Функция для хеширования исходного сообщения (`string`) с помощью 128 битного ключа. Ключ представлен парой uint64 чисел low, high
+
+```yql
+SELECT Digest::SipHash(0,0,"Who set this ancient quarrel new abroach?"); -- 14605466535756698285
+```
+
+* `Digest::HighwayHash(key0:Uint64,key1:Uint64,key2:Uint64,key3:Uint64,string:String{Flags:AutoMap}) -> Uint64`
+
+Функция для хеширования исходного сообщения (`string`) с ключом длиной в 256 бит.
+
+Ключ формируется как:
+
+- key0 - первые 8 байт ключа
+- key1 - последующие 8 байт ключа
+- key2 - последующие 8 байт ключа
+- key3 - последние 8 байт ключа
+
+* `Digest::FarmHashFingerprint(source:Uint64{Flags:AutoMap}) -> Uint64`
+* `Digest::FarmHashFingerprint2(low:Uint64{Flags:AutoMap}, high:Uint64{Flags:AutoMap}) -> Uint64`
+
+FarmHash функция для 128 битного числа. 128 битное число получается путем объединения битов из двух uit64 чисел.
+
+* `Digest::FarmHashFingerprint32(string:String{Flags:AutoMap}) -> Uint32`
+* `Digest::FarmHashFingerprint64(string:String{Flags:AutoMap}) -> Uint64`
+* `Digest::FarmHashFingerprint128(string:String{Flags:AutoMap}) -> Tuple<Uint64,Uint64>`
+
+FarmHash функция для байтовой строки с результатом типа uint128. Результат представлен как пара из двух uint64 чисел `<low, high>`
+
+```yql
+SELECT Digest::FarmHashFingerprint2(31880,6990065); -- 237693065644851126
+SELECT Digest::FarmHashFingerprint128("Who set this ancient quarrel new abroach?"); -- (17165761740714960035, 5559728965407786337)
+```
+
+* `Digest::SuperFastHash(String{Flags:AutoMap}) -> Uint32`
+* `Digest::Sha1(String{Flags:AutoMap}) -> String`
+* `Digest::Sha256(String{Flags:AutoMap}) -> String`
+* `Digest::IntHash64(Uint64{Flags:AutoMap}) -> Uint64`
+
+* `Digest::XXH3(String{Flags:AutoMap}) -> Uint64`
+* `Digest::XXH3_128(String{Flags:AutoMap}) -> Tuple<Uint64,Uint64>`
+
+XXH3 - некриптографическая хеш-функция из семейста xxxHash. XXH3_128 генерит 128 битный хеш, результат представлен как пара из двух uint64 чисел `<low, high>`
+
+```yql
+SELECT Digest::XXH3_128("Who set this ancient quarrel new abroach?"); -- (17117571879768798812, 14282600258804776266)
+```
diff --git a/yql/essentials/docs/ru/udf/list/histogram.md b/yql/essentials/docs/ru/udf/list/histogram.md
new file mode 100644
index 0000000000..050ce3d6bf
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/histogram.md
@@ -0,0 +1,19 @@
+# Histogram
+
+Набор вспомогательных функций для [агрегатной функции HISTOGRAM](../../builtins/aggregation.md). В описании сигнатур ниже под HistogramStruct подразумевается результат работы агрегатной функции `HISTOGRAM`, `LinearHistogram` или `LogarithmicHistogram`, который является структурой определенного вида.
+
+## Список функций
+
+* `Histogram::Print(HistogramStruct{Flags:AutoMap}, Byte?) -> String`
+* `Histogram::Normalize(HistogramStruct{Flags:AutoMap}, [Double?]) -> HistogramStruct` - во втором аргументе желаемая площадь гистограммы, по умолчанию 100.
+* `Histogram::ToCumulativeDistributionFunction(HistogramStruct{Flags:AutoMap}) -> HistogramStruct`
+* `Histogram::GetSumAboveBound(HistogramStruct{Flags:AutoMap}, Double) -> Double`
+* `Histogram::GetSumBelowBound(HistogramStruct{Flags:AutoMap}, Double) -> Double`
+* `Histogram::GetSumInRange(HistogramStruct{Flags:AutoMap}, Double, Double) -> Double`
+* `Histogram::CalcUpperBound(HistogramStruct{Flags:AutoMap}, Double) -> Double`
+* `Histogram::CalcLowerBound(HistogramStruct{Flags:AutoMap}, Double) -> Double`
+* `Histogram::CalcUpperBoundSafe(HistogramStruct{Flags:AutoMap}, Double) -> Double`
+* `Histogram::CalcLowerBoundSafe(HistogramStruct{Flags:AutoMap}, Double) -> Double`
+
+У `Histogram::Print` есть опциональный числовой аргумент, который задает максимальную длину столбцов гистограммы (в символах, так как гистограмма рисуется в технике ASCII-арт). Значение по умолчанию — 25. Данная функция предназначена в первую очередь для просмотра гистограмм в консоли.
+
diff --git a/yql/essentials/docs/ru/udf/list/hyperscan.md b/yql/essentials/docs/ru/udf/list/hyperscan.md
new file mode 100644
index 0000000000..54266827a7
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/hyperscan.md
@@ -0,0 +1,104 @@
+# Hyperscan
+
+[Hyperscan](https://www.hyperscan.io) является opensource библиотекой для поиска по регулярным выражениям, разработанной компанией Intel.
+
+Библиотека имеет 4 реализации с использованием разных наборов процессорных инструкций (SSE3, SSE4.2, AVX2 и AVX512), среди которых автоматически выбирается нужная в соответствии с текущим процессором.
+
+По умолчанию все функции работают в однобайтовом режиме, но если регулярное выражение является валидной UTF-8 строкой, но не является валидной ASCII строкой, — автоматически включается режим UTF-8.
+
+## Список функций
+
+* `Hyperscan::Grep(pattern:String) -> (string:String?) -> Bool`
+* `Hyperscan::Match(pattern:String) -> (string:String?) -> Bool`
+* `Hyperscan::BacktrackingGrep(pattern:String) -> (string:String?) -> Bool`
+* `Hyperscan::BacktrackingMatch(pattern:String) -> (string:String?) -> Bool`
+* `Hyperscan::MultiGrep(pattern:String) -> (string:String?) -> Tuple<Bool, Bool, ...>`
+* `Hyperscan::MultiMatch(pattern:String) -> (string:String?) -> Tuple<Bool, Bool, ...>`
+* `Hyperscan::Capture(pattern:String) -> (string:String?) -> String?`
+* `Hyperscan::Replace(pattern:String) -> (string:String?, replacement:String) -> String?`
+
+## Синтаксис вызова {#syntax}
+
+При вызове напрямую, чтобы избежать компиляции регулярного выражения на каждой строке таблицы, необходимо обернуть вызов функции в [именованное выражение](../../syntax/expressions.md#named-nodes):
+
+```yql
+$re = Hyperscan::Grep("\\d+"); -- создаем вызываемое значение для проверки конкретного регулярного выражения
+SELECT * FROM table WHERE $re(key); -- используем его для фильтрации таблицы
+```
+
+**Обратите внимание** на экранирование спецсимволов в регулярном выражении. Второй слеш нужен, так как все стандартные строковые литералы в SQL могут принимать С-escaped строки, а последовательность `\d` не является валидной последовательностью, и даже если бы являлась — не приводила бы к ожидаемому эффекту поиска чисел.
+
+Есть возможность отключить чувствительность к регистру (то есть включить case-insensitive режим), указав в начале регулярного выражения флаг `(?i)`.
+
+## Grep {#grep}
+
+Проверяет совпадение регулярного выражения с **частью строки** (произвольной подстрокой).
+
+## Match {#match}
+
+Проверяет совпадение регулярного выражения **со строкой целиком**.
+
+Чтобы получить результат аналогичный `Grep` (где учитывается совпадение с подстрокой), нужно обрамлять регулярное выражение с обеих сторон в `.*` (`.*foo.*` вместо `foo`). Однако, с точки зрения читабельности кода, обычно лучше поменять функцию.
+
+## BacktrackingGrep / BacktrackingMatch {#backtrackinggrep}
+
+По принципу работы данные функции полностью совпадают с одноимёнными функциями без префикса `Backtracking`, но поддерживают более широкий ассортимент регулярных выражений. Это происходит за счет того, что если конкретное регулярное выражение в полном объёме не поддерживается Hyperscan, то библиотека переключается в режим предварительной фильтрации (prefilter). В этом случае она отвечает не «да» или «нет», а «точно нет» или «может быть да». Ответы «может быть да» затем автоматически перепроверяются с помощью медленной, но более функциональной библиотеки [libpcre](https://www.pcre.org).
+
+## MultiGrep / MultiMatch {#multigrep}
+
+Библиотека Hyperscan предоставляет возможность за один проход по тексту проверить несколько регулярных выражений и получить по каждому из них отдельный ответ.
+
+Однако, если необходимо проверить совпадение строки с любым из перечисленных выражений (результаты объединялись бы через «или»), то эффективнее сделать одно регулярное выражение, объединив части с помощью оператора `|`, и использовать для поиска обычный `Grep` или `Match`.
+
+При вызове функций `MultiGrep`/`MultiMatch` регулярные выражения передаются по одному на строку с использованием [многострочных строковых литералов](../../syntax/expressions.md#named-nodes):
+
+### Пример
+
+```yql
+$multi_match = Hyperscan::MultiMatch(@@a.*
+.*x.*
+.*axa.*@@);
+
+SELECT
+ $multi_match("a") AS a, -- (true, false, false)
+ $multi_match("axa") AS axa; -- (true, true, true)
+```
+
+## Capture и Replace {#capture}
+
+`Hyperscan::Capture` при совпадении строки с указанным регулярным выражением возвращает последнюю подстроку, совпавшую с регулярным выражением. `Hyperscan::Replace` заменяет все вхождения указанного регулярного выражения на заданную строку.
+
+В библиотеке Hyperscan отсутствует развитая функциональность для подобных операций, так что `Hyperscan::Capture` и `Hyperscan::Replace` хоть и реализованы для единообразия, но для сколько-либо нетривиальных поисков и замен лучше использовать одноимённые функции из библиотеки Re2:
+
+* [Re2::Capture](re2.md#capture);
+* [Re2::Replace](re2.md#replace).
+
+
+## Пример использования
+
+```yql
+$value = "xaaxaaXaa";
+
+$match = Hyperscan::Match("a.*");
+$grep = Hyperscan::Grep("axa");
+$insensitive_grep = Hyperscan::Grep("(?i)axaa$");
+$multi_match = Hyperscan::MultiMatch(@@a.*
+.*a.*
+.*a
+.*axa.*@@);
+
+$capture = Hyperscan::Capture(".*a{2}.*");
+$capture_many = Hyperscan::Capture(".*x(a+).*");
+$replace = Hyperscan::Replace("xa");
+
+SELECT
+ $match($value) AS match, -- false
+ $grep($value) AS grep, -- true
+ $insensitive_grep($value) AS insensitive_grep, -- true
+ $multi_match($value) AS multi_match, -- (false, true, true, true)
+ $multi_match($value).0 AS some_multi_match, -- false
+ $capture($value) AS capture, -- "xaa"
+ $capture_many($value) AS capture_many, -- "xa"
+ $replace($value, "b") AS replace -- "babaXaa"
+;
+```
diff --git a/yql/essentials/docs/ru/udf/list/index.md b/yql/essentials/docs/ru/udf/list/index.md
new file mode 100644
index 0000000000..e7f2290b5f
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/index.md
@@ -0,0 +1,18 @@
+# Функции встроенных C++ библиотек
+
+Многие прикладные функции, которые с одной стороны слишком специфичны, чтобы стать частью ядра YQL, а с другой — могут быть полезны широкому кругу пользователей, доступны через встроенные C++ библиотеки.
+
+* [DateTime](datetime.md)
+* [Digest](digest.md)
+* [Histogram](histogram.md)
+* [Hyperscan](hyperscan.md)
+* [Ip](ip.md)
+* [Math](math.md)
+* [Pcre](pcre.md)
+* [Pire](pire.md)
+* [PostgreSQL](postgres.md)
+* [Re2](re2.md)
+* [String](string.md)
+* [Unicode](unicode.md)
+* [Url](url.md)
+* [Yson](yson.md)
diff --git a/yql/essentials/docs/ru/udf/list/ip.md b/yql/essentials/docs/ru/udf/list/ip.md
new file mode 100644
index 0000000000..8ec01015c9
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/ip.md
@@ -0,0 +1,46 @@
+# Ip
+
+В модуле `Ip` поддерживаются как IPv4, так и IPv6 адреса. По умолчанию они представляются в виде бинарных строк длиной 4 и 16 байт, соответственно.
+
+## Список функций
+
+* `Ip::FromString(String{Flags:AutoMap}) -> String?` - из человекочитаемого представления в бинарное
+* `Ip::SubnetFromString(String{Flags:AutoMap}) -> String?` - из человекочитаемого представления подсети в бинарное
+* `Ip::ToString(String{Flags:AutoMap}) -> String?` - из бинарного представления в человекочитаемое
+* `Ip::ToString(String{Flags:AutoMap}) -> String?` - из бинарного представления подсети в человекочитаемое
+* `Ip::IsIPv4(String?) -> Bool`
+* `Ip::IsIPv6(String?) -> Bool`
+* `Ip::IsEmbeddedIPv4(String?) -> Bool`
+* `Ip::ConvertToIPv6(String{Flags:AutoMap}) -> String` - IPv6 остается без изменений, а IPv4 становится embedded в IPv6
+* `Ip::GetSubnet(String{Flags:AutoMap}, [Uint8?]) -> String` - во втором аргументе размер подсети, по умолчанию 24 для IPv4 и 64 для IPv6
+* `Ip::GetSubnetByMask(String{Flags:AutoMap}, String{Flags:AutoMap}) -> String` - во втором аргументе битовая маска подсети
+* `Ip::SubnetMatch(String{Flags:AutoMap}, String{Flags:AutoMap}) -> Bool` - в первом аргументе подсеть, во втором аргументе подсеть или адрес
+
+## Примеры
+
+```yql
+SELECT Ip::IsEmbeddedIPv4(
+ Ip::FromString("::ffff:77.75.155.3")
+); -- true
+
+SELECT
+ Ip::ToString(
+ Ip::GetSubnet(
+ Ip::FromString("213.180.193.3")
+ )
+ ); -- "213.180.193.0"
+
+SELECT
+ Ip::SubnetMatch(
+ Ip::SubnetFromString("192.168.0.1/16"),
+ Ip::FromString("192.168.1.14"),
+ ); -- true
+
+SELECT
+ Ip::ToString(
+ Ip::GetSubnetByMask(
+ Ip::FromString("192.168.0.1"),
+ Ip::FromString("255.255.0.0")
+ )
+ ); -- "192.168.0.0"
+```
diff --git a/yql/essentials/docs/ru/udf/list/math.md b/yql/essentials/docs/ru/udf/list/math.md
new file mode 100644
index 0000000000..72b60e363b
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/math.md
@@ -0,0 +1,174 @@
+# Math
+
+Набор обёрток вокруг функций из библиотеки libm, а также утилит Яндекс.
+
+## Константы {#constants}
+
+### Список функций
+
+* `Math::Pi() -> Double`
+* `Math::E() -> Double`
+* `Math::Eps() -> Double`
+
+### Примеры
+
+```yql
+SELECT Math::Pi(); -- 3.141592654
+SELECT Math::E(); -- 2.718281828
+SELECT Math::Eps(); -- 2.220446049250313e-16
+```
+
+## (Double) -> Bool {#double-bool}
+
+### Список функций
+
+* `Math::IsInf(Double{Flags:AutoMap}) -> Bool`
+* `Math::IsNaN(Double{Flags:AutoMap}) -> Bool`
+* `Math::IsFinite(Double{Flags:AutoMap}) -> Bool`
+
+### Примеры
+
+```yql
+SELECT Math::IsNaN(0.0/0.0); -- true
+SELECT Math::IsFinite(1.0/0.0); -- false
+```
+
+## (Double) -> Double {#double-double}
+
+### Список функций
+
+* `Math::Abs(Double{Flags:AutoMap}) -> Double`
+* `Math::Acos(Double{Flags:AutoMap}) -> Double`
+* `Math::Asin(Double{Flags:AutoMap}) -> Double`
+* `Math::Asinh(Double{Flags:AutoMap}) -> Double`
+* `Math::Atan(Double{Flags:AutoMap}) -> Double`
+* `Math::Cbrt(Double{Flags:AutoMap}) -> Double`
+* `Math::Ceil(Double{Flags:AutoMap}) -> Double`
+* `Math::Cos(Double{Flags:AutoMap}) -> Double`
+* `Math::Cosh(Double{Flags:AutoMap}) -> Double`
+* `Math::Erf(Double{Flags:AutoMap}) -> Double`
+* `Math::ErfInv(Double{Flags:AutoMap}) -> Double`
+* `Math::ErfcInv(Double{Flags:AutoMap}) -> Double`
+* `Math::Exp(Double{Flags:AutoMap}) -> Double`
+* `Math::Exp2(Double{Flags:AutoMap}) -> Double`
+* `Math::Fabs(Double{Flags:AutoMap}) -> Double`
+* `Math::Floor(Double{Flags:AutoMap}) -> Double`
+* `Math::Lgamma(Double{Flags:AutoMap}) -> Double`
+* `Math::Rint(Double{Flags:AutoMap}) -> Double`
+* `Math::Sigmoid(Double{Flags:AutoMap}) -> Double`
+* `Math::Sin(Double{Flags:AutoMap}) -> Double`
+* `Math::Sinh(Double{Flags:AutoMap}) -> Double`
+* `Math::Sqrt(Double{Flags:AutoMap}) -> Double`
+* `Math::Tan(Double{Flags:AutoMap}) -> Double`
+* `Math::Tanh(Double{Flags:AutoMap}) -> Double`
+* `Math::Tgamma(Double{Flags:AutoMap}) -> Double`
+* `Math::Trunc(Double{Flags:AutoMap}) -> Double`
+* `Math::Log(Double{Flags:AutoMap}) -> Double`
+* `Math::Log2(Double{Flags:AutoMap}) -> Double`
+* `Math::Log10(Double{Flags:AutoMap}) -> Double`
+
+### Примеры
+
+```yql
+SELECT Math::Sqrt(256); -- 16
+SELECT Math::Trunc(1.2345); -- 1
+```
+
+## (Double, Double) -> Double {#doubledouble-double}
+
+### Список функций
+
+* `Math::Atan2(Double{Flags:AutoMap}, Double{Flags:AutoMap}) -> Double`
+* `Math::Fmod(Double{Flags:AutoMap}, Double{Flags:AutoMap}) -> Double`
+* `Math::Hypot(Double{Flags:AutoMap}, Double{Flags:AutoMap}) -> Double`
+* `Math::Pow(Double{Flags:AutoMap}, Double{Flags:AutoMap}) -> Double`
+* `Math::Remainder(Double{Flags:AutoMap}, Double{Flags:AutoMap}) -> Double`
+
+### Примеры
+
+```yql
+SELECT Math::Atan2(1, 0); -- 1.570796327
+SELECT Math::Remainder(2.1, 2); -- 0.1
+```
+
+## (Double, Int32) -> Double {#doubleint32-double}
+
+### Список функций
+
+* `Math::Ldexp(Double{Flags:AutoMap}, Int32{Flags:AutoMap}) -> Double`
+* `Math::Round(Double{Flags:AutoMap}, [Int32?]) -> Double` - во втором аргументе указывается степень 10, до которой округляем (отрицательная для знаков после запятой и положительная для округления до десятков—тысяч—миллионов); по умолчанию 0
+
+### Примеры
+
+```yql
+SELECT Math::Pow(2, 10); -- 1024
+SELECT Math::Round(1.2345, -2); -- 1.23
+```
+
+## (Double, Double, \[Double?\]) -> Bool {#doubledouble-bool}
+
+### Список функций
+
+* `Math::FuzzyEquals(Double{Flags:AutoMap}, Double{Flags:AutoMap}, [Double?]) -> Bool` - сравнивает два Double на нахождение внутри окрестности, задаваемой третьим аргументом; по умолчанию 1.0e-13. Окрестность указывается в относительных единицах от минимального по модулю аргумента.
+
+{% note alert %}
+
+Если один из сравниваемых аргументов равен `0.0`, то функция всегда возвращает `false`.
+
+{% endnote %}
+
+### Примеры
+
+```yql
+SELECT Math::FuzzyEquals(1.01, 1.0, 0.05); -- true
+```
+
+## Функции взятия остатка
+
+### Список функций
+
+* `Math::Mod(Int64{Flags:AutoMap}, Int64) -> Int64?`
+* `Math::Rem(Int64{Flags:AutoMap}, Int64) -> Int64?`
+
+Ведут себя аналогично встроенному оператору % в случае неотрицательных аргументов. Различия заметны при отрицательных аргументах:
+
+* Math::Mod сохраняет знак второго аргумента (делителя).
+* Math::Rem сохраняет знак первого аргумента (делимого).
+
+Функции возвращают null, если делитель равен нулю.
+
+### Примеры
+
+```yql
+SELECT Math::Mod(-1, 7); -- 6
+SELECT Math::Rem(-1, 7); -- -1
+```
+
+## Функции округления до целого числа в заданном режиме
+
+### Список функций
+
+* `Math::RoundDownward() -> Tagged<Uint32, MathRoundingMode>` -- rounding towards negative infinity
+* `Math::RoundToNearest() -> Tagged<Uint32, MathRoundingMode>` -- rounding towards nearest representable value
+* `Math::RoundTowardZero() -> Tagged<Uint32, MathRoundingMode>` -- rounding towards zero
+* `Math::RoundUpward() -> Tagged<Uint32, MathRoundingMode>` -- rounding towards positive infinity
+* `Math::NearbyInt(AutoMap<Double>, Tagged<Uint32, MathRoundingMode>) -> Optional<Int64>`
+
+Функция `Math::NearbyInt` округляет первый аргумент до целого числа в соответсвии с режимом, заданным вторым аргументом.
+
+Если результат выходит за пределы 64-битного целого числа, возращается NULL.
+
+### Примеры
+
+```yql
+SELECT Math::NearbyInt(1.5, Math::RoundDownward()); -- 1
+SELECT Math::NearbyInt(1.5, Math::RoundToNearest()); -- 2
+SELECT Math::NearbyInt(2.5, Math::RoundToNearest()); -- 2
+SELECT Math::NearbyInt(1.5, Math::RoundTowardZero()); -- 1
+SELECT Math::NearbyInt(1.5, Math::RoundUpward()); -- 2
+SELECT Math::NearbyInt(-1.5, Math::RoundDownward()); -- -2
+SELECT Math::NearbyInt(-1.5, Math::RoundToNearest()); -- -2
+SELECT Math::NearbyInt(-2.5, Math::RoundToNearest()); -- -2
+SELECT Math::NearbyInt(-1.5, Math::RoundTowardZero()); -- -1
+SELECT Math::NearbyInt(-1.5, Math::RoundUpward()); -- -1
+```
diff --git a/yql/essentials/docs/ru/udf/list/pcre.md b/yql/essentials/docs/ru/udf/list/pcre.md
new file mode 100644
index 0000000000..ac4f12a4fb
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/pcre.md
@@ -0,0 +1,21 @@
+# Pcre
+
+Библиотека Pcre на данный момент является алиасом к [Hyperscan](hyperscan.md).
+
+Если вы завязываетесь на какие-либо особенности конкретного движка, реализующего регулярные выражения, то лучше использовать UDF с определённой библиотекой внутри, а Pcre рассматривать как текущий наиболее рекомендуемый вариант для простых проверок на соответствие, который может в будущем поменяться.
+
+На данный момент доступны:
+
+* [Hyperscan](hyperscan.md) <span style="color: gray;">(Intel)</span>
+* [Pire](pire.md) <span style="color: gray;">(Яндекс)</span>
+* [Re2](re2.md) <span style="color: gray;">(Google)</span>
+
+Все три модуля предоставляют примерно одинаковый набор функций с идентичным интерфейсом, что позволяет переключаться между ними с минимальными изменениями запроса.
+
+HyperScan внутри имеет несколько реализаций с использованием разных наборов процессорных инструкций, среди которых автоматически выбирается нужная в соответствии с текущим процессором. В Hyperscan также доступны отдельные функции с backtracking (возможность сослаться на предыдущую найденную часть строки), которые реализованы через гибридное использование двух библиотек Hyperscan и libpcre.
+
+[Pire](https://github.com/yandex/pire) (Perl Incompatible Regular Expressions) это разработанная в Яндексе очень быстрая библиотека регулярных выражений. На нижнем уровне она просматривает входную строку один раз, подряд, без откатов, и тратит (на x86 и x86_64) по 5 инструкций на символ. Но с 2011-2013 года эта библиотека практически не развивается и как намекает название («i» расшифровывается как incompatible), возможно потребуется адаптировать сами выражения.
+
+Hyperscan и Pire рассчитаны в первую очередь под Grep и Match.
+
+Модуль Re2 использует [google::RE2](https://github.com/google/re2), где реализован широкий ассортимент возможностей ([см. официальную документацию](https://github.com/google/re2/wiki/Syntax)). Основной плюс библиотеки Re2 — развитый функционал по Capture и Replace, если вам нужны эти функции, то рекомендуется пользоваться именно ей.
diff --git a/yql/essentials/docs/ru/udf/list/pire.md b/yql/essentials/docs/ru/udf/list/pire.md
new file mode 100644
index 0000000000..9611cedcbc
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/pire.md
@@ -0,0 +1,114 @@
+# Pire
+
+## Список функций
+
+* `Pire::Grep(pattern:String) -> (string:String?) -> Bool`
+* `Pire::Match(pattern:String) -> (string:String?) -> Bool`
+* `Pire::MultiGrep(pattern:String) -> (string:String?) -> Tuple<Bool, Bool, ...>`
+* `Pire::MultiMatch(pattern:String) -> (string:String?) -> Tuple<Bool, Bool, ...>`
+* `Pire::Capture(pattern:String) -> (string:String?) -> String?`
+* `Pire::Replace(pattern:String) -> (string:String?, replacement:String) -> String?`
+
+Одной из опций для поиска по регулярным выражениям в YQL является библиотека [Pire](https://github.com/yandex/pire) (Perl Incompatible Regular Expressions). Это разработанная в Яндексе очень быстрая библиотека регулярных выражений: на нижнем уровне она просматривает входную строку один раз, подряд, без откатов, и тратит (на x86 и x86_64) по 5 инструкций на символ.
+
+Скорость работы достигается за счет некоторых разумных ограничений:
+
+* Библиотека Pire ориентирована прежде всего на проверку на совпадение строки с регулярным выражением (Match).
+* Возможность вернуть совпавшую подстроку тоже поддерживается (Capture), но с ограничениями (возвращает совпадение только с одной группой).
+
+По умолчанию все функции работают в однобайтовом режиме, но если регулярное выражение является валидной UTF-8 строкой, но не является валидной ASCII строкой, — автоматически включается режим UTF-8.
+
+Чтобы включить Unicode-режим, можно вставить в выражение один символ за пределами ASCII с оператором `?`, например `\\w+я?`.
+
+## Синтаксис вызова {#call-syntax}
+
+Чтобы избежать компиляции регулярного выражения на каждой строке таблицы, необходимо обернуть вызов функции в [именованное выражение](../../syntax/expressions.md#named-nodes):
+
+```yql
+$re = Pire::Grep("\\d+"); -- создаем вызываемое значение для проверки конкретного регулярного выражения
+SELECT * FROM table WHERE $re(key); -- используем его для фильтрации таблицы
+```
+
+{% note alert %}
+
+При экранировании спецсимволов в регулярном выражении нужен второй слеш, так как все стандартные строковые литералы в SQL могут принимать С-escaped строки, а последовательность `\d` не является валидной последовательностью, и даже если бы являлась — не приводила бы к ожидаемому эффекту поиска чисел.
+
+{% endnote %}
+
+Есть возможность отключить чувствительность к регистру (то есть включить case-insensitive режим), указав в начале регулярного выражения флаг `(?i)`.
+
+### Примеры
+
+```yql
+$value = "xaaxaaxaa";
+$match = Pire::Match("a.*");
+$grep = Pire::Grep("axa");
+$insensitive_grep = Pire::Grep("(?i)axa");
+$multi_match = Pire::MultiMatch(@@a.*
+.*a.*
+.*a
+.*axa.*@@);
+$capture = Pire::Capture(".*x(a).*");
+$capture_many = Pire::Capture(".*x(a+).*");
+$replace = Pire::Replace(".*x(a).*");
+
+SELECT
+ $match($value) AS match, -- false
+ $grep($value) AS grep, -- true
+ $insensitive_grep($value) AS insensitive_grep, -- true
+ $multi_match($value) AS multi_match, -- (false, true, true, true)
+ $multi_match($value).0 AS some_multi_match, -- false
+ $capture($value) AS capture, -- "a"
+ $capture_many($value) AS capture_many, -- "aa"
+ $replace($value, "b") AS replace; -- "xaaxaaxba"
+```
+
+## Grep {#grep}
+
+Проверяет совпадение регулярного выражения с **частью строки** (произвольной подстрокой).
+
+## Match {#match}
+
+Проверяет совпадение регулярного выражения **со строкой целиком**.
+Чтобы получить результат, аналогичный `Grep` (где учитывается совпадение с подстрокой), нужно обернуть регулярное выражение с обоих сторон в `.*`, например `.*foo.*` вместо `foo`.
+
+## MultiGrep / MultiMatch {#multigrep}
+
+Библиотека Pire предоставляет возможность за один проход по тексту проверить несколько регулярных выражений и получить по каждому из них отдельный ответ.
+С помощью функций MultiGrep/MultiMatch можно оптимизировать скорость выполнения запроса, но это нужно делать осмотрительно, поскольку размер используемого для проверки конечного автомата растет экспоненциально с числом регулярных выражений:
+
+* Если вас интересует совпадение строки с любым из перечисленных выражений (результаты объединяются через «или»), то намного эффективнее сделать одно регулярное выражение, объединив части с помощью оператора `|`, и использовать для поиска обычный Grep или Match.
+* В библиотеке Pire установлен лимит на размер конечного автомата (в YQL используется значение этого лимита, установленное по умолчанию в библиотеке). Если лимит превышен, при запуске запроса вернется ошибка `Failed to glue up regexes, probably the finite state machine appeared to be too large`.
+
+При вызове функций MultiGrep/MultiMatch регулярные выражения передаются по одному на строку с использованием [многострочных строковых литералов](../../syntax/expressions.md#multiline-string-literals):
+
+### Примеры
+
+```yql
+$multi_match = Pire::MultiMatch(@@a.*
+.*x.*
+.*axa.*@@);
+
+SELECT
+ $multi_match("a") AS a, -- (true, false, false)
+ $multi_match("axa") AS axa; -- (true, true, true)
+```
+
+## Capture {#capture}
+
+При совпадении строки с указанным регулярным выражением возвращает подстроку, совпавшую с группой, отмеченной в регулярном выражении круглыми скобками.
+Capture работает НЕ в жадном режиме, то есть возвращается самая короткая подстрока из возможных.
+
+{% note alert %}
+
+В выражении должна быть ровно **одна** группа, обозначенная круглыми скобками. В случае отсутствия совпадения возвращается `NULL` (пустой Optional).
+
+{% endnote %}
+
+Если описанные выше ограничения и особенности по каким-либо причинам выглядят неприемлемыми, рекомендуется рассмотреть возможность использования [Re2::Capture](re2.md#capture).
+
+## Replace {#replace}
+
+В библиотеке Pire отсутствует функция замены по регулярному выражению. Функция `Pire::Replace` в YQL представляет собой упрощенную эмуляцию, реализованную с помощью `Capture`. Может работать некорректно, если найденная подстрока встречается в исходной более одного раза.
+
+Как правило, лучше воспользоваться [Re2::Replace](re2.md#replace) вместо неё.
diff --git a/yql/essentials/docs/ru/udf/list/postgres.md b/yql/essentials/docs/ru/udf/list/postgres.md
new file mode 100644
index 0000000000..b36e91ce3b
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/postgres.md
@@ -0,0 +1,300 @@
+# PostgreSQL UDF
+
+<!-- markdownlint-disable blanks-around-fences -->
+
+YQL предоставляет возможность доступа к [функциям](https://www.postgresql.org/docs/16/functions.html) и [типам данных](https://www.postgresql.org/docs/16/datatype.html) PostgreSQL.
+
+Имена PostgreSQL типов в YQL получаются добавлением префикса `Pg` к исходному имени типа.
+Например `PgVarchar`, `PgInt4`, `PgText`. Имена pg типов (как и вообще всех типов) в YQL являются case-insensitive. На данный момент поддерживаются все простые типы данных из PostgreSQL, а также массивы.
+
+Если исходный тип является типом массива (в PostgreSQL такие типы начинаются с подчеркивания: `_int4` - массив 32-битных целых), то имя типа в YQL тоже начинается с подчеркивания – `_PgInt4`.
+
+## Литералы {#literals}
+
+Строковые и числовые литералы Pg типов можно создавать с помощью специальных суффиксов (аналогично простым [строковым](../../syntax/lexer.md#string-literals) и [числовым](../../syntax/lexer.md#literal-numbers) литералам).
+
+### Целочисленные литералы {#intliterals}
+
+Суффикс | Тип | Комментарий
+----- | ----- | -----
+`p` | `PgInt4` | 32-битное знаковое целое (в PostgreSQL нет беззнаковых типов)
+`ps`| `PgInt2` | 16-битное знаковое целое
+`pi`| `PgInt4` |
+`pb`| `PgInt8` | 64-битное знаковое цело
+`pn`| `PgNumeric` | знаковое целое произвольной точности (до 131072 цифр)
+
+### Литералы с плавающей точкой {#floatliterals}
+
+Суффикс | Тип | Комментарий
+----- | ----- | -----
+`p` | `PgFloat8` | число с плавающей точкой (64 бит double)
+`pf4`| `PgFloat4` | число с плавающей точкой (32 бит float)
+`pf8`| `PgFloat8` |
+`pn` | `PgNumeric` | число с плавающей точкой произвольной точности (до 131072 цифр перед запятой, до 16383 цифр после запятой)
+
+### Строковые литералы {#stringliterals}
+
+Суффикс | Тип | Комментарий
+----- | ----- | -----
+`p` | `PgText` | текстовая строка
+`pt`| `PgText` |
+`pv`| `PgVarchar` | текстовая строка
+`pb`| `PgBytea` | бинарная строка
+
+{% note warning "Внимание" %}
+
+Значения строковых/числовых литералов (т.е. то что идет перед суффиксом) должны быть валидной строкой/числом с точки зрения YQL.
+В частности, должны соблюдаться правила эскейпинга YQL, а не PostgreSQL.
+
+{% endnote %}
+
+Пример:
+
+```yql
+SELECT
+ 1234p, -- pgint4
+ 0x123pb, -- pgint8
+ "тест"pt, -- pgtext
+ 123e-1000pn; -- pgnumeric
+;
+```
+
+### Литерал массива
+
+Для построения литерала массива используется функция `PgArray`:
+
+```yql
+SELECT
+ PgArray(1p, NULL ,2p) -- {1,NULL,2}, тип _int4
+;
+```
+
+### Конструктор литералов произвольного типа {#literals_constructor}
+
+Литералы всех типов (в том числе и Pg типов) могут создаваться с помощью конструктора литералов со следующей сигнатурой:
+`Имя_типа(<строковая константа>)`.
+
+Напрмер:
+
+```yql
+DECLARE $foo AS String;
+SELECT
+ PgInt4("1234"), -- то же что и 1234p
+ PgInt4(1234), -- в качестве аргумента можно использовать литеральные константы
+ PgInt4($foo), -- и declare параметры
+ PgBool(true),
+ PgInt8(1234),
+ PgDate("1932-01-07"),
+;
+```
+
+Также поддерживается встроенная функция `PgConst` со следующей сигнатурой: `PgConst(<строковое значение>, <тип>)`.
+Такой способ более удобен для кодогенерации.
+
+Например:
+
+```yql
+SELECT
+ PgConst("1234", PgInt4), -- то же что и 1234p
+ PgConst("true", PgBool)
+;
+```
+
+Для некоторых типов в функции `PgConst` можно указать дополнительные модификаторы. Возможные модификаторы для типа `pginterval` перечислены в [документации PostgreSQL](https://www.postgresql.org/docs/16/datatype-datetime.html).
+
+```yql
+SELECT
+ PgConst(90, pginterval, "day"), -- 90 days
+ PgConst(13.45, pgnumeric, 10, 1); -- 13.5
+;
+```
+
+
+## Операторы {#operators}
+
+Операторы PostgreSQL (унарные и бинарные) доступны через встроенную функцию `PgOp(<оператор>, <операнды>)`:
+
+```yql
+SELECT
+ PgOp("*", 123456789987654321pn, 99999999999999999999pn), -- 12345678998765432099876543210012345679
+ PgOp('|/', 10000.0p), -- 100.0p (квадратный корень)
+ PgOp("-", 1p), -- -1p
+ -1p, -- унарный минус для литералов работает и без PgOp
+;
+```
+
+## Оператор приведения типа {#cast_operator}
+
+Для приведения значения одного Pg типа к другому используется встроенная функция `PgCast(<исходное значение>, <желаемый тип>)`:
+
+```yql
+SELECT
+ PgCast(123p, PgText), -- преобразуем число в строку
+;
+```
+
+При преобразовании из строковых Pg типов в некоторые целевые типы можно указать дополнительные модификаторы. Возможные модификаторы для типа `pginterval` перечислены в [документации](https://www.postgresql.org/docs/16/datatype-datetime.html).
+
+```yql
+SELECT
+ PgCast('90'p, pginterval, "day"), -- 90 days
+ PgCast('13.45'p, pgnumeric, 10, 1); -- 13.5
+;
+```
+
+## Преобразование значений Pg типов в значения YQL типов и обратно {#frompgtopg}
+
+Для некоторых Pg типов возможна конвертация в YQL типы и обратно. Конвертация осуществляется с помощью встроенных функций
+`FromPg(<значение Pg типа>)` и `ToPg(<значение YQL типа>)`:
+
+```yql
+SELECT
+ FromPg("тест"pt), -- Just(Utf8("тест")) - pg типы всегда nullable
+ ToPg(123.45), -- 123.45pf8
+;
+```
+
+### Список псевдонимов типов PostgreSQL при их использовании в YQL {#pgyqltypes}
+
+Ниже приведены типы данных YQL, соответствующие им логические типы PostgreSQL и названия типов PostgreSQL при их использовании в YQL:
+
+| YQL | PostgreSQL | Название PostgreSQL-типа в YQL|
+|---|---|---|
+| `Bool` | `bool` |`pgbool` |
+| `Int8` | `int2` |`pgint2` |
+| `Uint8` | `int2` |`pgint2` |
+| `Int16` | `int2` |`pgint2` |
+| `Uint16` | `int4` |`pgint4` |
+| `Int32` | `int4` |`pgint4` |
+| `Uint32` | `int8` |`pgint8` |
+| `Int64` | `int8` |`pgint8` |
+| `Uint64` | `numeric` |`pgnumeric` |
+| `Float` | `float4` |`pgfloat4` |
+| `Double` | `float8` |`pgfloat8` |
+| `String` | `bytea` |`pgbytea` |
+| `Utf8` | `text` |`pgtext` |
+| `Yson` | `bytea` |`pgbytea` |
+| `Json` | `json` |`pgjson` |
+| `Uuid` | `uuid` |`pguuid` |
+| `JsonDocument` | `jsonb` |`pgjsonb` |
+| `Date` | `date` |`pgdate` |
+| `Datetime` | `timestamp` |`pgtimestamp` |
+| `Timestamp` | `timestamp` |`pgtimestamp` |
+| `Interval` | `interval` | `pginterval` |
+| `TzDate` | `text` |`pgtext` |
+| `TzDatetime` | `text` |`pgtext` |
+| `TzTimestamp` | `text` |`pgtext` |
+| `Date32` | `date` | `pgdate`|
+| `Datetime64` | `timestamp` |`pgtimestamp` |
+| `Timestamp64` | `timestamp` |`pgtimestamp` |
+| `Interval64`| `interval` |`pginterval` |
+| `TzDate32` | `text` | |`pgtext` |
+| `TzDatetime64` | `text` | |`pgtext` |
+| `TzTimestamp64` | `text` | |`pgtext` |
+| `Decimal` | `numeric` |`pgnumeric` |
+| `DyNumber` | `numeric` |`pgnumeric` |
+
+
+### Таблица соответствия типов `ToPg` {#topg}
+
+Таблица соответствия типов данных YQL и PostgreSQL при использовании функции `ToPg`:
+
+{% include [topg](../../_includes/topg.md) %}
+
+### Таблица соответствия типов `FromPg` {#frompg}
+
+Таблица соответствия типов данных PostgreSQL и YQL при использовании функции `FromPg`:
+
+{% include [frompg](../../_includes/frompg.md) %}
+
+## Вызов PostgreSQL функций {#callpgfunction}
+
+Чтобы вызвать PostgreSQL функцию, необходимо добавить префикс `Pg::` к ее имени:
+
+```yql
+SELECT
+ Pg::extract('isodow'p,PgCast('1961-04-12'p,PgDate)), -- 3pn (среда) - работа с датами до 1970 года
+ Pg::generate_series(1p,5p), -- [1p,2p,3p,4p,5p] - для функций-генераторов возвращается ленивый список
+;
+```
+
+Существует также альтернативный способ вызова функций через встроенную функцию `PgCall(<имя функции>, <операнды>)`:
+
+```yql
+SELECT
+ PgCall('lower', 'Test'p), -- 'test'p
+;
+```
+
+При вызове функции, возвращающей набор `pgrecord`, можно распаковать результат в список структур, используя функцию `PgRangeCall(<имя функции>, <операнды>)`:
+
+```yql
+SELECT * FROM
+ AS_TABLE(PgRangeCall("json_each", pgjson('{"a":"foo", "b":"bar"}')));
+ --- 'a'p,pgjson('"foo"')
+ --- 'b'p,pgjson('"bar"')
+;
+```
+
+## Вызов агрегационных PostgreSQL функций {#pgaggrfunction}
+
+Чтобы вызвать агрегационную PostgreSQL функцию, необходимо добавить префикс `Pg::` к ее имени:
+
+```yql
+SELECT
+Pg::string_agg(x,','p)
+FROM (VALUES ('a'p),('b'p),('c'p)) as a(x); -- 'a,b,c'p
+
+SELECT
+Pg::string_agg(x,','p) OVER (ORDER BY x)
+FROM (VALUES ('a'p),('b'p),('c'p)) as a(x); -- 'a'p,'a,b'p,'a,b,c'p
+;
+```
+
+Также можно использовать агрегационную PostgreSQL функцию для построения фабрики агрегационных функций с последующим применением в `AGGREGATE_BY`:
+
+```yql
+$agg_max = AggregationFactory("Pg::max");
+
+SELECT
+AGGREGATE_BY(x,$agg_max)
+FROM (VALUES ('a'p),('b'p),('c'p)) as a(x); -- 'c'p
+
+SELECT
+AGGREGATE_BY(x,$agg_max) OVER (ORDER BY x),
+FROM (VALUES ('a'p),('b'p),('c'p)) as a(x); -- 'a'p,'b'p,'c'p
+```
+
+В этом случае вызов `AggregationFactory` принимает только имя функции с префиксом `Pg::`, а все аргументы функции передаются в `AGGREGATE_BY`.
+
+Если в агрегационной функции не один аргумент, а ноль или два и более, необходимо использовать кортеж при вызове `AGGREGATE_BY`:
+
+```yql
+$agg_string_agg = AggregationFactory("Pg::string_agg");
+
+SELECT
+AGGREGATE_BY((x,','p),$agg_string_agg)
+FROM (VALUES ('a'p),('b'p),('c'p)) as a(x); -- 'a,b,c'p
+
+SELECT
+AGGREGATE_BY((x,','p),$agg_string_agg) OVER (ORDER BY x)
+FROM (VALUES ('a'p),('b'p),('c'p)) as a(x); -- 'a'p,'a,b'p,'a,b,c'p
+```
+
+{% note warning "Внимание" %}
+
+Не поддерживается режим `DISTINCT` над аргументами при вызове агрегационных PostgreSQL функций, а также использование `MULTI_AGGREGATE_BY`.
+
+{% endnote %}
+
+## Логические операции
+
+Для выполнения логических операций используются функции `PgAnd`, `PgOr`, `PgNot`:
+
+```yql
+SELECT
+ PgAnd(PgBool(true), PgBool(true)), -- PgBool(true)
+ PgOr(PgBool(false), null), -- PgCast(null, pgbool)
+ PgNot(PgBool(true)), -- PgBool(false)
+;
+```
diff --git a/yql/essentials/docs/ru/udf/list/re2.md b/yql/essentials/docs/ru/udf/list/re2.md
new file mode 100644
index 0000000000..bece305308
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/re2.md
@@ -0,0 +1,121 @@
+# Re2
+
+## Список функций
+
+```yql
+Re2::Grep(pattern:String, options:Struct<...>?) -> (string:String?) -> Bool
+Re2::Match(pattern:String, options:Struct<...>?) -> (string:String?) -> Bool
+Re2::Capture(pattern:String, options:Struct<...>?) -> (string:String?) -> Struct<_1:String?,foo:String?,...>
+Re2::FindAndConsume(pattern:String, options:Struct<...>?) -> (string:String?) -> List<String>
+Re2::Replace(pattern:String, options:Struct<...>?) -> (string:String?, replacement:String) -> String?
+Re2::Count(pattern:String, options:Struct<...>?) -> (string:String?) -> Uint32
+Re2::Options([CaseSensitive:Bool?,DotNl:Bool?,Literal:Bool?,LogErrors:Bool?,LongestMatch:Bool?,MaxMem:Uint64?,NeverCapture:Bool?,NeverNl:Bool?,OneLine:Bool?,PerlClasses:Bool?,PosixSyntax:Bool?,Utf8:Bool?,WordBoundary:Bool?]) -> Struct<CaseSensitive:Bool,DotNl:Bool,Literal:Bool,LogErrors:Bool,LongestMatch:Bool,MaxMem:Uint64,NeverCapture:Bool,NeverNl:Bool,OneLine:Bool,PerlClasses:Bool,PosixSyntax:Bool,Utf8:Bool,WordBoundary:Bool>
+```
+
+Модуль Re2 реализует поддержку регулярных выражений на основе [google::RE2](https://github.com/google/re2), где предоставляется широкий ассортимент возможностей ([см. официальную документацию](https://github.com/google/re2/wiki/Syntax)).
+
+По умолчанию UTF-8 режим включается автоматически, если регулярное выражение является валидной строкой в кодировке UTF-8, но не является валидной ASCII-строкой. Вручную настройками библиотеки re2 можно управлять с помощью передачи результата функции `Re2::Options` вторым аргументом другим функциям модуля, рядом с регулярным выражением.
+
+{% note warning %}
+
+Все обратные слеши в регулярных выражениях (если они записаны в строке с кавычками) нужно удваивать, так как стандартные строковые литералы в SQL рассматриваются как С-escaped строки. Также можно записывать регулярное выражение в форме raw строки `@@regexp@@` — в этом случае удвоение слешей не требуется.
+
+{% endnote %}
+
+## Примеры
+
+```yql
+$value = "xaaxaaxaa";
+$options = Re2::Options(false AS CaseSensitive);
+$match = Re2::Match("[ax]+\\d");
+$grep = Re2::Grep("a.*");
+$capture = Re2::Capture(".*(?P<foo>xa?)(a{2,}).*");
+$replace = Re2::Replace("x(a+)x");
+$count = Re2::Count("a", $options);
+
+SELECT
+ $match($value) AS match, -- false
+ $grep($value) AS grep, -- true
+ $capture($value) AS capture, -- (_0: 'xaaxaaxaa', _1: 'aa', foo: 'x')
+ $capture($value)._1 AS capture_member, -- "aa"
+ $replace($value, "b\\1z") AS replace, -- "baazaaxaa"
+ $count($value) AS count; -- 6
+```
+
+## Re2::Grep / Re2::Match {#match}
+
+Если вынести за скобки детали реализации и синтаксиса регулярных выражений, эти функции полностью аналогичны [одноименным функциям](pire.md#match) из модуля Pire. При прочих равных и отсутствии каких-либо специфических предпочтений мы рекомендуем пользоваться `Pire::Grep / Pire::Match`.
+
+Функцию `Re2::Grep` можно вызвать с помощью выражения `REGEXP` (см. [описание базового синтаксиса выражений](../../syntax/expressions.md#regexp)).
+
+Например, следующие два запроса эквивалентны (в том числе по эффективности вычислений):
+
+* `$grep = Re2::Grep("b+"); SELECT $grep("aaabccc");`
+* `SELECT "aaabccc" REGEXP "b+";`
+
+## Re2::Capture {#capture}
+
+В отличие от [Pire::Capture](pire.md#capture) в `Re2::Capture` поддерживаются множественные и именованные группы захвата (capturing groups).
+Тип результата: структура с полями типа `String?`.
+
+* Каждое поле соответствует группе захвата с соответствующим именем.
+* Для неименованных групп генерируются имена вида: `_1`, `_2` и т.д.
+* В результат всегда включается поле `_0`, в котором доступна вся совпавшая с регулярным выражением подстрока.
+
+Подробнее про работу со структурами в YQL см. в [разделе про контейнеры](../../types/containers.md).
+
+## Re2::FindAndConsume {#findandconsume}
+
+Ищет все вхождения регулярного выражения в переданный текст и возвращает список значений, соответствующих обрамленной в круглые скобки части регулярного выражения для каждого вхождения.
+
+## Re2::Replace {#replace}
+
+Работает следующим образом:
+
+* Во входной строке (первый аргумент) все непересекающиеся подстроки, совпавшие с регулярным выражением, заменяются на указанную строку (второй аргумент).
+* В строке с заменой можно использовать содержимое групп захвата (capturing groups) из регулярного выражения с помощью ссылок вида: `\\1`, `\\2` и т.д. Ссылка `\\0` обозначает всю совпавшую с регулярным выражением подстроку.
+
+## Re2::Count {#count}
+
+Возвращает количество совпавших с регулярным выражением непересекающихся подстрок во входной строке.
+
+## Re2::Options {#options}
+
+Пояснения к параметрам Re2::Options из официального [репозитория](https://github.com/google/re2/blob/main/re2/re2.h#L595-L617)
+
+| Параметр | По умолчанию | Комментарий |
+|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|-------------------------------------------------------------------------------------|
+| CaseSensitive:Bool? | true | match is case-sensitive (regexp can override with (?i) unless in posix_syntax mode) |
+| DotNl:Bool? | false | let `.` match `\n` (default ) |
+| Literal:Bool? | false | interpret string as literal, not regexp |
+| LogErrors:Bool? | true | log syntax and execution errors to ERROR |
+| LongestMatch:Bool? | false | search for longest match, not first match |
+| MaxMem:Uint64? | - | (see below) approx. max memory footprint of RE2 |
+| NeverCapture:Bool? | false | parse all parens as non-capturing |
+| NeverNl:Bool? | false | never match \n, even if it is in regexp |
+| PosixSyntax:Bool? | false | restrict regexps to POSIX egrep syntax |
+| Utf8:Bool? | true | text and pattern are UTF-8; otherwise Latin-1 |
+| The following options are only consulted when PosixSyntax == true. <bt>When PosixSyntax == false, these features are always enabled and cannot be turned off; to perform multi-line matching in that case, begin the regexp with (?m). ||
+| PerlClasses:Bool? | false | allow Perl's \d \s \w \D \S \W |
+| WordBoundary:Bool? | false | allow Perl's \b \B (word boundary and not) |
+| OneLine:Bool? | false | ^ and $ only match beginning and end of text |
+
+Не рекомендуется Re2::Options использовать в коде. Большинство параметров можно заменить на флаги регулярного выражения.
+
+### Пример использования флагов
+
+```yql
+$value = "Foo bar FOO"u;
+-- включить режим без учета регистра
+$capture = Re2::Capture(@@(?i)(foo)@@);
+
+SELECT
+ $capture($value) AS capture; -- ("_0": "Foo", "_1": "Foo")
+
+$capture = Re2::Capture(@@(?i)(?P<foo>FOO).*(?P<bar>bar)@@);
+
+SELECT
+ $capture($value) AS capture; -- ("_0": "Foo bar", "bar": "bar", "foo": "Foo")
+```
+
+В обоих случаях слово FOO будет найдено. Применение raw строки @@regexp@@ позволяет не удваивать слеши.
diff --git a/yql/essentials/docs/ru/udf/list/string.md b/yql/essentials/docs/ru/udf/list/string.md
new file mode 100644
index 0000000000..4ddcd1dbcc
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/string.md
@@ -0,0 +1,152 @@
+# String
+
+Функции для работы с ASCII-строками.
+
+## Список функций
+
+* `String::Base32Encode(string:String{Flags:AutoMap}) -> String`
+* `String::Base32Decode(string:String) -> String?`
+* `String::Base32StrictDecode(string:String) -> String?`
+* `String::Base64Encode(string:String{Flags:AutoMap}) -> String`
+* `String::Base64Decode(string:String) -> String?`
+* `String::Base64StrictDecode(string:String) -> String?`
+* `String::EscapeC(string:String{Flags:AutoMap}) -> String`
+* `String::UnescapeC(string:String{Flags:AutoMap}) -> String`
+* `String::HexEncode(string:String{Flags:AutoMap}) -> String`
+* `String::HexDecode(string:String) -> String?`
+* `String::EncodeHtml(string:String{Flags:AutoMap}) -> String`
+* `String::DecodeHtml(string:String{Flags:AutoMap}) -> String`
+* `String::CgiEscape(string:String{Flags:AutoMap}) -> String`
+* `String::CgiUnescape(string:String{Flags:AutoMap}) -> String`
+
+Кодирует или декодирует строку указанным образом.
+
+## Примеры
+
+```yql
+SELECT String::Base64Encode("YQL"); -- "WVFM"
+```
+
+`String::Strip(string:String{Flags:AutoMap}) -> String`
+
+Вырезает из строки крайние пробелы.
+
+```yql
+SELECT String::Strip("YQL "); -- "YQL"
+```
+
+* `String::Collapse(string:String{Flags:AutoMap}) -> String`
+
+ Заменяет множественные пробелы внутри строки одиночными.
+
+* `String::CollapseText(string:String{Flags:AutoMap}, limit:Uint64) -> String`
+
+ Укорачивает текст до указанного размера с добавлением троеточия.
+
+* `String::Contains(string:String?, substring:String) -> Bool`
+
+ Проверяет наличие подстроки в строке.
+
+* `String::Find(string:String{Flags:AutoMap}, String, [Uint64?]) -> Int64` - Устаревшая: используйте встроенную функцию [Find](../../builtins/basic.md#find)
+* `String::ReverseFind(string:String{Flags:AutoMap}, String, [Uint64?]) -> Int64` - Устаревшая: используйте встроенную функцию [RFind](../../builtins/basic.md#rfind)
+* `String::Substring(string:String{Flags:AutoMap}, [Uint64?, Uint64?]) -> String` - Устаревшая: используйте встроенную функцию [Substring](../../builtins/basic.md#substring)
+* `String::HasPrefix(string:String?, prefix:String) -> Bool` - Устаревшая: используйте встроенную функцию [StartsWith](../../builtins/basic.md#starts_ends_with)
+* `String::StartsWith(string:String?, prefix:String) -> Bool` - Устаревшая: используйте встроенную функцию [StartsWith](../../builtins/basic.md#starts_ends_with)
+* `String::HasSuffix(string:String?, suffix:String) -> Bool` - Устаревшая: используйте встроенную функцию [EndsWith](../../builtins/basic.md#starts_ends_with)
+* `String::EndsWith(string:String?, suffix:String) -> Bool` - Устаревшая: используйте встроенную функцию [EndsWith](../../builtins/basic.md#starts_ends_with)
+* `String::Reverse(string:String?) -> String?` - Устаревшая: используйте [Unicode::Reverse](unicode.md)
+
+ Устаревшие функции, к использованию не рекомендуются.
+
+* `String::HasPrefixIgnoreCase(string:String?, prefix:String) -> Bool`
+* `String::StartsWithIgnoreCase(string:String?, prefix:String) -> Bool`
+* `String::HasSuffixIgnoreCase(string:String?, suffix:String) -> Bool`
+* `String::EndsWithIgnoreCase(string:String?, suffix:String) -> Bool`
+
+ Проверяют наличие префикса или суффикса в строке без учёта региста символов.
+
+* `String::AsciiToLower(string:String{Flags:AutoMap}) -> String` - меняет только латинские символы. Для работы с другими алфавитами см. Unicode::ToLower
+* `String::AsciiToUpper(string:String{Flags:AutoMap}) -> String` - меняет только латинские символы. Для работы с другими алфавитами см. Unicode::ToUpper
+* `String::AsciiToTitle(string:String{Flags:AutoMap}) -> String` - меняет только латинские символы. Для работы с другими алфавитами см. Unicode::ToTitle
+
+ Переводят регистр ascii символов строки к ВЕРХНЕМУ, нижнему или Заглавному виду.
+
+* `String::SplitToList(string:String?, delimeter:String, [ DelimeterString:Bool?, SkipEmpty:Bool?, Limit:Uint64? ]) -> List<String>`
+
+ Разбивает строку на подстроки по разделителю.
+ `string` -- исходная строка
+ `delimeter` -- разделитель
+ Именованные параметры:
+
+ - `DelimeterString:Bool?` — считать разделитель строкой (true, по умолчанию) или набором символов "любой из" (false)
+ - `SkipEmpty:Bool?` - пропускать ли пустые строки в результате, по умолчанию false
+ - `Limit:Uint64?` - ограничение на число извлекаемых компонент, по умолчанию не ограничено; необработанный суффикс оригинальной строки возвращается последним элементом при превышении лимита
+
+```yql
+SELECT String::SplitToList("1,2,3,4,5,6,7", ",", 3 as Limit); -- ["1", "2", "3", "4,5,6,7"]
+```
+
+* `String::JoinFromList(strings:List<String>{Flags:AutoMap}, separator:String) -> String`
+
+ Конкатенирует список строк через разделитель в единую строку.
+
+* `String::ToByteList(string:String) -> List<Byte>`
+
+ Разбивает строку на список байт.
+
+* `String::FromByteList(bytes:List<Uint8>) -> String`
+
+ Собирает список байт в строку.
+
+* `String::ReplaceAll(input:String{Flags:AutoMap}, find:String, replacement:String) -> String`
+* `String::ReplaceFirst(input:String{Flags:AutoMap}, find:String, replacement:String) -> String`
+* `String::ReplaceLast(input:String{Flags:AutoMap}, find:String, replacement:String) -> String`
+
+ Заменяют все/первое/последнее вхождения(е) строки `find` в `input` на `replacement`.
+
+* `String::RemoveAll(input:String{Flags:AutoMap}, symbols:String) -> String`
+* `String::RemoveFirst(input:String{Flags:AutoMap}, symbols:String) -> String`
+* `String::RemoveLast(input:String{Flags:AutoMap}, symbols:String) -> String`
+
+ Удаляют все/первое/последнее вхождения(е) символа в наборе `symbols` из `input`. Второй аргумент интерпретируется как неупорядоченный набор символов для удаления.
+
+* `String::IsAscii(string:String{Flags:AutoMap}) -> Bool`
+
+ Проверяет, является ли строка валидной ascii последовательностью.
+
+* `String::IsAsciiSpace(string:String{Flags:AutoMap}) -> Bool`
+* `String::IsAsciiUpper(string:String{Flags:AutoMap}) -> Bool`
+* `String::IsAsciiLower(string:String{Flags:AutoMap}) -> Bool`
+* `String::IsAsciiAlpha(string:String{Flags:AutoMap}) -> Bool`
+* `String::IsAsciiAlnum(string:String{Flags:AutoMap}) -> Bool`
+* `String::IsAsciiHex(string:String{Flags:AutoMap}) -> Bool`
+
+ Проверяют, отвечает ли ascii строка указанному условию.
+
+* `String::LevensteinDistance(stringOne:String{Flags:AutoMap}, stringTwo:String{Flags:AutoMap}) -> Uint64`
+
+ Вычисляет расстояние Левенштейна для переданных строк.
+
+* `String::LeftPad(string:String{Flags:AutoMap}, size:Uint64, filler:[String?]) -> String`
+* `String::RightPad(string:String{Flags:AutoMap}, size:Uint64, filler:[String?]) -> String`
+
+ Выравнивает текст до указанного размера с дополнением указанным символом или пробелами.
+
+* `String::Hex(value:Uint64{Flags:AutoMap}) -> String`
+* `String::SHex(value:Int64{Flags:AutoMap}) -> String`
+* `String::Bin(value:Uint64{Flags:AutoMap}) -> String`
+* `String::SBin(value:Int64{Flags:AutoMap}) -> String`
+* `String::HexText(string:String{Flags:AutoMap}) -> String`
+* `String::BinText(string:String{Flags:AutoMap}) -> String`
+* `String::HumanReadableDuration(value:Uint64{Flags:AutoMap}) -> String`
+* `String::HumanReadableQuantity(value:Uint64{Flags:AutoMap}) -> String`
+* `String::HumanReadableBytes(value:Uint64{Flags:AutoMap}) -> String`
+* `String::Prec(Double{Flags:AutoMap}, digits:Uint64) -> String`
+
+ Распечатывает значение указанным образом.
+
+{% note alert %}
+
+Функции из библиотеки String не поддерживают кириллицу и умеют работать только с ASCII символами. Для работы со строками в кодировке UTF-8 используйте функции из [Unicode](unicode.md).
+
+{% endnote %}
diff --git a/yql/essentials/docs/ru/udf/list/toc_base.yaml b/yql/essentials/docs/ru/udf/list/toc_base.yaml
new file mode 100644
index 0000000000..02cf3d294f
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/toc_base.yaml
@@ -0,0 +1,17 @@
+items:
+- name: Обзор
+ href: index.md
+- { name: DateTime, href: datetime.md }
+- { name: Digest, href: digest.md }
+- { name: Histogram, href: histogram.md }
+- { name: Hyperscan, href: hyperscan.md }
+- { name: Ip, href: ip.md }
+- { name: Math, href: math.md }
+- { name: Pcre, href: pcre.md }
+- { name: Pire, href: pire.md }
+- { name: PostgreSQL, href: postgres.md }
+- { name: Re2, href: re2.md }
+- { name: String, href: string.md }
+- { name: Unicode, href: unicode.md }
+- { name: Url, href: url.md }
+- { name: Yson, href: yson.md }
diff --git a/yql/essentials/docs/ru/udf/list/toc_i.yaml b/yql/essentials/docs/ru/udf/list/toc_i.yaml
new file mode 100644
index 0000000000..28325999d2
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/toc_i.yaml
@@ -0,0 +1,2 @@
+items:
+- include: { mode: link, path: toc_base.yaml } \ No newline at end of file
diff --git a/yql/essentials/docs/ru/udf/list/unicode.md b/yql/essentials/docs/ru/udf/list/unicode.md
new file mode 100644
index 0000000000..2dd33c2fd5
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/unicode.md
@@ -0,0 +1,180 @@
+# Unicode
+
+Функции для работы с Unicode строками.
+
+## Список функций
+
+* `Unicode::IsUtf(String) -> Bool`
+
+ Проверяет является ли строка валидной utf-8 последовательностью. Например, строка `"\xF0"` не является валидной utf-8 последовательностью, а строка `"\xF0\x9F\x90\xB1"` корректно описывает utf-8 emoji с котиком.
+
+* `Unicode::GetLength(Utf8{Flags:AutoMap}) -> Uint64`
+
+ Возвращает длину utf-8 строки в символах (unicode code points). Суррогатные пары учитываются как один символ.
+
+```yql
+SELECT Unicode::GetLength("жніўня"); -- 6
+```
+
+* `Unicode::Find(string:Utf8{Flags:AutoMap}, subString:Utf8, [pos:Uint64?]) -> Uint64?`
+* `Unicode::RFind(string:Utf8{Flags:AutoMap}, subString:Utf8, [pos:Uint64?]) -> Uint64?`
+
+ Поиск первого(`RFind` - последнего) вхождения подстроки в строку начиная с позиции `pos`. Возвращает позицию первого символа от найденной подстроки, в случае неуспеха возвращается Null.
+
+```yql
+SE``LECT Unicode::Find("aaa", "bb"); -- Null
+```
+
+* `Unicode::Substring(string:Utf8{Flags:AutoMap}, from:Uint64?, len:Uint64?) -> Utf8`
+
+ Возвращает подстроку от `string` начиная с символа `from` длиной в `len` символов. Если аргумент `len` опущен, то подстрока берется до конца исходной строки.
+ В случае `from` больше длины исходной строки, возвращается пустая строка `""`
+
+```yql
+SELECT Unicode::Substring("0123456789abcdefghij", 10); -- "abcdefghij"
+```
+
+* Функции `Unicode::Normalize...` приводят переданную utf-8 строку в одну из [нормальных форм](https://unicode.org/reports/tr15/#Norm_Forms):
+
+ * `Unicode::Normalize(Utf8{Flags:AutoMap}) -> Utf8` -- NFC
+ * `Unicode::NormalizeNFD(Utf8{Flags:AutoMap}) -> Utf8`
+ * `Unicode::NormalizeNFC(Utf8{Flags:AutoMap}) -> Utf8`
+ * `Unicode::NormalizeNFKD(Utf8{Flags:AutoMap}) -> Utf8`
+ * `Unicode::NormalizeNFKC(Utf8{Flags:AutoMap}) -> Utf8`
+
+
+* `Unicode::Translit(string:Utf8{Flags:AutoMap}, [lang:String?]) -> Utf8`
+
+ Транслитерирует в латинский алфавит слова переданной строки, целиком состоящие из символов алфавита языка, переданного вторым аргументом. Если язык не указан, то транслитерация ведется с русского. Доступные языки: "kaz", "rus", "tur", "ukr".
+
+```yql
+SELECT Unicode::Translit("Тот уголок земли, где я провел"); -- "Tot ugolok zemli, gde ya provel"
+```
+
+* `Unicode::LevensteinDistance(stringA:Utf8{Flags:AutoMap}, stringB:Utf8{Flags:AutoMap}) -> Uint64`
+
+ Вычисляет расстояние Левенштейна для переданных строк.
+
+* `Unicode::Fold(Utf8{Flags:AutoMap}, [ Language:String?, DoLowerCase:Bool?, DoRenyxa:Bool?, DoSimpleCyr:Bool?, FillOffset:Bool? ]) -> Utf8`
+
+ Выполняет [case folding](https://www.w3.org/TR/charmod-norm/#definitionCaseFolding) для переданной строки.
+ Параметры:
+
+ - `Language` задается по тем же правилам, что и в `Unicode::Translit()`
+ - `DoLowerCase` приводит строку к нижнему регистру, по умолчанию `true`
+ - `DoRenyxa` приводить символы с диокрифами к аналогичным латинским символам, по умолчанию `true`
+ - `DoSimpleCyr` приводить кирилические символы с диокрифами к аналогичным латинским символам, по умолчанию `true`
+ - `FillOffset` параметр не используется
+
+```yql
+SELECT Unicode::Fold("Kongreßstraße", false AS DoSimpleCyr, false AS DoRenyxa); -- "kongressstrasse"
+SELECT Unicode::Fold("ҫурт"); -- "сурт"
+SELECT Unicode::Fold("Eylül", "Turkish" AS Language); -- "eylul"
+```
+
+* `Unicode::ReplaceAll(input:Utf8{Flags:AutoMap}, find:Utf8, replacement:Utf8) -> Utf8`
+* `Unicode::ReplaceFirst(input:Utf8{Flags:AutoMap}, find:Utf8, replacement:Utf8) -> Utf8`
+* `Unicode::ReplaceLast(input:Utf8{Flags:AutoMap}, find:Utf8, replacement:Utf8) -> Utf8`
+
+ Заменяет все/первое/последнее вхождения строки `find` в `input` на `replacement`.
+
+* `Unicode::RemoveAll(input:Utf8{Flags:AutoMap}, symbols:Utf8) -> Utf8`
+* `Unicode::RemoveFirst(input:Utf8{Flags:AutoMap}, symbols:Utf8) -> Utf8`
+* `Unicode::RemoveLast(input:Utf8{Flags:AutoMap}, symbols:Utf8) -> Utf8`
+
+ Удаляются все/первое/последнее вхождения символов в наборе `symbols` из `input`. Второй аргумент интерпретируется как неупорядоченный набор символов для удаления.
+
+```yql
+SELECT Unicode::ReplaceLast("absence", "enc", ""); -- "abse"
+SELECT Unicode::RemoveAll("abandon", "an"); -- "bdo"
+```
+
+* `Unicode::ToCodePointList(Utf8{Flags:AutoMap}) -> List<Uint32>`
+
+ Разбить строку на unicode'ую последовательность codepoint'ов.
+* `Unicode::FromCodePointList(List<Uint32>{Flags:AutoMap}) -> Utf8`
+
+ Сформировать unicode строку из codepoint'ов.
+
+```yql
+SELECT Unicode::ToCodePointList("Щавель"); -- [1065, 1072, 1074, 1077, 1083, 1100]
+SELECT Unicode::FromCodePointList(AsList(99,111,100,101,32,112,111,105,110,116,115,32,99,111,110,118,101,114,116,101,114)); -- "code points converter"
+```
+
+* `Unicode::Reverse(Utf8{Flags:AutoMap}) -> Utf8`
+
+ Перевернуть строку.
+
+* `Unicode::ToLower(Utf8{Flags:AutoMap}) -> Utf8`
+* `Unicode::ToUpper(Utf8{Flags:AutoMap}) -> Utf8`
+* `Unicode::ToTitle(Utf8{Flags:AutoMap}) -> Utf8`
+
+ Привести регистр строки к ВЕРХНЕМУ, нижнему или Заглавному виду.
+
+* `Unicode::SplitToList( string:Utf8?, separator:Utf8, [ DelimeterString:Bool?, SkipEmpty:Bool?, Limit:Uint64? ]) -> List<Utf8>`
+
+ Разбиение строки на подстроки по разделителю.
+ `string` -- исходная строка
+ `separator` -- разделитель
+ Параметры:
+
+ - DelimeterString:Bool? — считать разделитель строкой (true, по умолчанию) или набором символов "любой из" (false)
+ - SkipEmpty:Bool? - пропускать ли пустые строки в результате, по умолчанию false
+ - Limit:Uint64? - ограничение на число извлекаемых компонент, по умолчанию не ограничено; необработанный суффикс оригинальной строки возвращается последним элементом при превышении лимита
+
+* `Unicode::JoinFromList(List<Utf8>{Flags:AutoMap}, separator:Utf8) -> Utf8`
+
+ Конкатенация списка строк через `separator` в единую строку.
+
+```yql
+SELECT Unicode::SplitToList("One, two, three, four, five", ", ", 2 AS Limit); -- ["One", "two", "three, four, five"]
+SELECT Unicode::JoinFromList(["One", "two", "three", "four", "five"], ";"); -- "One;two;three;four;five"
+```
+
+* `Unicode::ToUint64(string:Utf8{Flags:AutoMap}, [prefix:Uint16?]) -> Uint64`
+
+ Конвертация из строки в число.
+ Второй опциональный аргумент задает систему счисления, по умолчанию 0 - автоматическое определение по префиксу.
+ Поддерживаемые префиксы : `0x(0X)` - base-16, `0` - base-8. Система по умолчанию - base-10.
+ Знак `-` перед числом интерпретируется как в беззнаковой арифметике языка C, например `-0x1` -> UI64_MAX.
+ В случае наличия в строке некорректных символов или выхода числа за границы ui64 функция завершается с ошибкой.
+
+* `Unicode::TryToUint64(string:Utf8{Flags:AutoMap}, [prefix:Uint16?]) -> Uint64?`
+
+ Аналогично функции `Unicode::ToUint64()`, но вместо ошибки возвращает `NULL`.
+
+```yql
+SELECT Unicode::ToUint64("77741"); -- 77741
+SELECT Unicode::ToUint64("-77741"); -- 18446744073709473875
+SELECT Unicode::TryToUint64("asdh831"); -- Null
+```
+
+* `Unicode::Strip(string:Utf8{Flags:AutoMap}) -> Utf8`
+
+ Вырезает из строки крайние символы Unicode-категории Space.
+
+```yql
+SELECT Unicode::Strip("\u200ыкль\u2002"u); -- "ыкль"
+```
+
+* `Unicode::IsAscii(string:Utf8{Flags:AutoMap}) -> Bool`
+
+ Проверяет, состоит ли utf-8 строка исключительно из символов ascii.
+
+* `Unicode::IsSpace(string:Utf8{Flags:AutoMap}) -> Bool`
+* `Unicode::IsUpper(string:Utf8{Flags:AutoMap}) -> Bool`
+* `Unicode::IsLower(string:Utf8{Flags:AutoMap}) -> Bool`
+* `Unicode::IsAlpha(string:Utf8{Flags:AutoMap}) -> Bool`
+* `Unicode::IsAlnum(string:Utf8{Flags:AutoMap}) -> Bool`
+* `Unicode::IsHex(string:Utf8{Flags:AutoMap}) -> Bool`
+
+ Проверяют, отвечает ли utf-8 строка указанному условию.
+
+* `Unicode::IsUnicodeSet(string:Utf8{Flags:AutoMap}, unicode_set:Utf8) -> Bool`
+
+ Проверяет, состоит ли utf-8 строка `string` исключительно из символов, указанных в `unicode_set`. Символы в `unicode_set` нужно указывать в квадратных скобках.
+
+```yql
+SELECT Unicode::IsUnicodeSet("ваоао"u, "[вао]"u); -- true
+SELECT Unicode::IsUnicodeSet("ваоао"u, "[ваб]"u); -- false
+```
diff --git a/yql/essentials/docs/ru/udf/list/url.md b/yql/essentials/docs/ru/udf/list/url.md
new file mode 100644
index 0000000000..3d6e434cf2
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/url.md
@@ -0,0 +1,196 @@
+# Url
+
+## Normalize {#normalize}
+
+* `Url::Normalize(String) -> String?`
+
+Нормализует URL удобным для Web-роботов образом: приводит hostname в нижний регистр, выкидывает фрагмент и т.п.
+Результат нормализации зависит только от самого URL. В процессе нормализации **НЕ** выполняются операции, зависящие от внешних данных: приведение по дублям, зеркалам и т.п.
+
+Возвращаемое значение:
+
+* нормализованный URL;
+* `NULL`, если переданный строковый аргумент не удалось распарсить как URL.
+
+### Примеры
+
+```yql
+SELECT Url::Normalize("hTTp://wWw.yDb.TECH/"); -- "http://www.ydb.tech/"
+SELECT Url::Normalize("http://ydb.tech#foo"); -- "http://ydb.tech/"
+```
+
+## NormalizeWithDefaultHttpScheme {#normalizewithdefaulthttpscheme}
+
+* `Url::NormalizeWithDefaultHttpScheme(String?) -> String?`
+
+Выполняет нормализацию аналогично `Url::Normalize`, но подставляет схему `http://` в случае, если схемы нет.
+
+Возвращаемое значение:
+
+* нормализованный URL;
+* исходный URL, если нормализация не удалась.
+
+### Примеры
+
+```yql
+SELECT Url::NormalizeWithDefaultHttpScheme("wWw.yDb.TECH"); -- "http://www.ydb.tech/"
+SELECT Url::NormalizeWithDefaultHttpScheme("http://ydb.tech#foo"); -- "http://ydb.tech/"
+```
+
+## Encode / Decode {#encode}
+
+Кодируют UTF-8 строку в urlencoded формат (`Url::Encode`) и обратно (`Url::Decode`).
+
+### Список функций
+
+* `Url::Encode(String?) -> String?`
+* `Url::Decode(String?) -> String?`
+
+### Примеры
+
+```yql
+SELECT Url::Decode("http://ydb.tech/%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0");
+ -- "http://ydb.tech/страница"
+SELECT Url::Encode("http://ydb.tech/страница");
+ -- "http://ydb.tech/%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0"
+```
+
+## Parse {#parse}
+
+Разбирает URL на составные части.
+
+```yql
+Url::Parse(Parse{Flags:AutoMap}) -> Struct< Frag: String?, Host: String?, ParseError: String?, Pass: String?, Path: String?, Port: String?, Query: String?, Scheme: String?, User: String? >
+```
+
+### Примеры
+
+```yql
+SELECT Url::Parse(
+ "https://en.wikipedia.org/wiki/Isambard_Kingdom_Brunel?s=24&g=h-24#Great_Western_Railway");
+/*
+(
+ "Frag": "Great_Western_Railway",
+ "Host": "en.wikipedia.org",
+ "ParseError": null,
+ "Pass": null,
+ "Path": "/wiki/Isambard_Kingdom_Brunel",
+ "Port": null,
+ "Query": "s=24&g=h-24",
+ "Scheme": "https",
+ "User": null
+)
+*/
+```
+
+## Get... {#get}
+
+Получение компонента URL.
+
+### Список функций
+
+* `Url::GetScheme(String{Flags:AutoMap}) -> String`
+* `Url::GetHost(String?) -> String?`
+* `Url::GetHostPort(String?) -> String?`
+* `Url::GetSchemeHost(String?) -> String?`
+* `Url::GetSchemeHostPort(String?) -> String?`
+* `Url::GetPort(String?) -> String?`
+* `Url::GetTail(String?) -> String?` -- всё после хоста: path + query + fragment
+* `Url::GetPath(String?) -> String?`
+* `Url::GetFragment(String?) -> String?`
+* `Url::GetCGIParam(String?, String) -> String?` -- второй параметр — имя нужного CGI параметра
+* `Url::GetDomain(String?, Uint8) -> String?` -- второй параметр — необходимый уровень домена
+* `Url::GetTLD(String{Flags:AutoMap}) -> String`
+* `Url::IsKnownTLD(String{Flags:AutoMap}) -> Bool` -- зарегистрирован на [iana.org](http://www.iana.org/).
+* `Url::IsWellKnownTLD(String{Flags:AutoMap}) -> Bool` -- находится в небольшом whitelist из com, net, org, ru и пр.
+* `Url::GetDomainLevel(String{Flags:AutoMap}) -> Uint64`
+* `Url::GetSignificantDomain(String{Flags:AutoMap}, [List<String>?]) -> String`
+ Возвращает домен второго уровня в большинстве случаев и домен третьего уровня для хостеймов вида: ***.XXX.YY, где XXX — одно из com, net, org, co, gov, edu. Этот список можно переопределить через опциональный второй аргумент
+* `Url::GetOwner(String{Flags:AutoMap}) -> String`
+ Возвращает домен, которым с наибольшей вероятностью владеет отдельный человек или организация. В отличие от Url::GetSignificantDomain работает по специальному разрешительному списку, и помимо доменов из серии ***.co.uk возвращает домен третьего уровня для, например, бесплатных хостингов и блогов, например something.livejournal.com
+
+### Примеры
+
+```yql
+SELECT Url::GetScheme("https://ydb.tech"); -- "https://"
+SELECT Url::GetDomain("http://www.ydb.tech", 2); -- "ydb.tech"
+```
+
+## Cut... {#cut}
+
+* `Url::CutScheme(String?) -> String?`
+ Возвращает переданный URL уже без схемы (http://, https:// и т.п.).
+
+* `Url::CutWWW(String?) -> String?`
+ Возвращает переданный домен без префикса "www.", если он присутствовал.
+
+* `Url::CutWWW2(String?) -> String?`
+ Возвращает переданный домен без префикса "www.", "www2.", "wwww777." и тому подобных, если он присутствовал.
+
+* `Url::CutQueryStringA­ndFragment(String{Flags:AutoMap}) -> String`
+ Возращает копию переданного URL с удаленными всеми CGI параметрами и фрагментами ("?foo=bar" и/или "#baz").
+
+### Примеры
+
+```yql
+SELECT Url::CutScheme("http://www.ydb.tech"); -- "www.ydb.tech"
+SELECT Url::CutWWW("www.ydb.tech"); -- "ydb.tech"
+```
+
+## ...Punycode... {#punycode}
+
+Преобразования [Punycode](https://en.wikipedia.org/wiki/Punycode).
+
+### Список функций
+
+* `Url::HostNameToPunycode(String{Flag:AutoMap}) -> String?`
+* `Url::ForceHostNameToPunycode(String{Flag:AutoMap}) -> String`
+* `Url::PunycodeToHostName(String{Flag:AutoMap}) -> String?`
+* `Url::ForcePunycodeToHostName(String{Flag:AutoMap}) -> String`
+* `Url::CanBePunycodeHostName(String{Flag:AutoMap}) -> Bool`
+
+### Примеры
+
+```yql
+SELECT Url::PunycodeToHostName("xn--80aniges7g.xn--j1aef"); -- "экзампл.ком"
+```
+
+## ...Query... {#query}
+
+Преобразования [Query](https://docs.python.org/3/library/urllib.parse.html).
+
+### Список функций
+
+```yql
+Url::QueryStringToList(String{Flag:AutoMap}, [
+ KeepBlankValues:Bool?, -- пустые значения в percent-encoded запросах интерпретируются как пустыe строки; по умолчанию false
+ Strict:Bool?, -- если false - ошибки парсинга игнорируются, ошибочные поля пропускаются; по умолчанию true
+ MaxFields:Uint32?, -- максимальное количество полей, при превышении кидается исключение; по умолчанию Max<Uint32>
+ Separator:String? -- разделитель пар ключ-значение; по умолчанию '&'
+]) -> List<Tuple<String, String>>
+Url::QueryStringToDict(String{Flag:AutoMap}, [
+ KeepBlankValues:Bool?, -- пустые значения в percent-encoded запросах интерпретируются как пустыe строки; по умолчанию false
+ Strict:Bool?, -- если false - ошибки парсинга игнорируются, ошибочные поля пропускаются; по умолчанию true
+ MaxFields:Uint32?, -- максимальное количество полей, при превышении кидается исключение; по умолчанию Max<Uint32>
+ Separator:String? -- разделитель пар ключ-значение; по умолчанию '&'
+]) -> Dict<String, List<String>>
+Url::BuildQueryString(Dict<String, List<String?>>{Flag:AutoMap}, [
+ Separator:String? -- разделитель пар ключ-значение; по умолчанию '&'
+]) -> String
+Url::BuildQueryString(Dict<String, String?>{Flag:AutoMap}, [
+ Separator:String? -- разделитель пар ключ-значение; по умолчанию '&'
+]) -> String
+Url::BuildQueryString(List<Tuple<String, String?>>{Flag:AutoMap}, [
+ Separator:String? -- разделитель пар ключ-значение; по умолчанию '&'
+]) -> String
+```
+
+### Примеры
+
+```yql
+SELECT Url::QueryStringToList("a=1&b=2&a=3"); -- [("a", "1"), ("b", "2"), ("a", "3")]
+SELECT Url::QueryStringToDict("a=1&b=2&a=3"); -- {"b" : ["2"], "a" : ["1", "3"]}
+SELECT Url::BuildQueryString([("a", "1"), ("a", "3"), ("b", "2")]); -- "a=1&a=3&b=2"
+SELECT Url::BuildQueryString({"a" : "1", "b" : "2"}); -- "b=2&a=1"
+SELECT Url::BuildQueryString({"a" : ["1", "3"], "b" : ["2", "4"]}); -- "b=2&b=4&a=1&a=3"
+```
diff --git a/yql/essentials/docs/ru/udf/list/yson.md b/yql/essentials/docs/ru/udf/list/yson.md
new file mode 100644
index 0000000000..634a78d2dd
--- /dev/null
+++ b/yql/essentials/docs/ru/udf/list/yson.md
@@ -0,0 +1,309 @@
+# Yson
+
+<!-- markdownlint-disable no-trailing-punctuation -->
+
+YSON — разработанный в Яндексе формат данных, похожий на JSON.
+
+* Сходства с JSON:
+
+ * не имеет строгой схемы;
+ * помимо простых типов данных поддерживает словари и списки в произвольных комбинациях.
+
+* Некоторые отличия от JSON:
+
+ * Помимо текстового представления имеет и бинарное;
+ * В текстовом представлении вместо запятых — точки с запятой, а вместо двоеточий — равно;
+
+* Поддерживается концепция «атрибутов», то есть именованных свойств, которые могут быть присвоены узлу в дереве.
+
+Особенности реализации и функциональность модуля:
+
+* Наравне с YSON данный модуль поддерживает и стандартный JSON, что несколько расширяет область его применения.
+* Работает с DOM представлением YSON в памяти, которое в терминах YQL передается между функциями как «ресурс» (см. [описание специальных типов данных](../../types/special.md)). Большинство функций модуля имеют семантику запроса на выполнение указанной операции с ресурсом и возвращают пустой [optional](../../types/optional.md), если операция не удалась из-за несоответствия фактического типа данных ожидаемому.
+* Предоставляет несколько основных классов функций (полный список и подробное описание функций см. ниже):
+
+ * `Yson::Parse***` — получение ресурса с DOM-объектом из сериализованных данных, все дальнейшие операции выполняются уже над полученным ресурсом;
+ * `Yson::From` — получение ресурса с DOM-объектом из простых типов данных YQL или контейнеров (списков или словарей);
+ * `Yson::ConvertTo***` — преобразовать ресурс к [простым типам данных](../../types/primitive.md) или [контейнерам](../../types/containers.md);
+ * `Yson::Lookup***` — получение одного элемента списка или словаря с опциональным преобразованием в нужный тип данных;
+ * `Yson::YPath***` — получение одного элемента дерева документа по указанному относительному пути с опциональным преобразованием в нужный тип данных;
+ * `Yson::Serialize***` — получить из ресурса копию его данных, сериализованную в одном из форматов;
+
+* Для удобства при передаче сериализованного Yson и Json в функции, ожидающие на входе ресурс с DOM-объектом, неявное преобразование через `Yson::Parse` или `Yson::ParseJson` происходит автоматически. Также в SQL синтаксисе оператор точки или квадратных скобок автоматически добавляет вызов `Yson::Lookup`. Для сериализации ресурса по-прежнему нужно вызывать `Yson::ConvertTo***` или `Yson::Serialize***`. Таким образом, например, получение элемента "foo" словаря из колонки mycolumn типа Yson в виде строки может выглядеть так: `SELECT Yson::ConvertToString(mycolumn["foo"]) FROM mytable;` или `SELECT Yson::ConvertToString(mycolumn.foo) FROM mytable;`. В варианте с точкой можно экранировать спецсимволы по [общим правилам для индентификаторов](../../syntax/expressions.md#escape).
+
+Функции модуля стоит рассматривать как «кубики», из которых можно собирать разные конструкции, например:
+
+* `Yson::Parse*** -> Yson::Serialize***` — конвертация из одного формата в другой;
+* `Yson::Parse*** -> Yson::Lookup -> Yson::Serialize***` — извлечение значения указанного поддерева в исходном дереве YSON;
+* `Yson::Parse*** -> Yson::ConvertToList -> ListMap -> Yson::Lookup***` — извлечение элементов по ключу из YSON списка.
+
+
+
+## Примеры
+
+```yql
+$node = Json(@@
+ {"abc": {"def": 123, "ghi": "привет"}}
+@@);
+SELECT Yson::SerializeText($node.abc) AS `yson`;
+-- {"def"=123;"ghi"="\xD0\xBF\xD1\x80\xD0\xB8\xD0\xB2\xD0\xB5\xD1\x82"}
+```
+
+```yql
+$node = Yson(@@
+ <a=z;x=y>[
+ {abc=123; def=456};
+ {abc=234; xyz=789};
+ ]
+@@);
+$attrs = Yson::YPath($node, "/@");
+
+SELECT
+ ListMap(Yson::ConvertToList($node), ($x) -> { return Yson::LookupInt64($x, "abc") }) AS abcs,
+ Yson::ConvertToStringDict($attrs) AS attrs,
+ Yson::SerializePretty(Yson::Lookup($node, "7", Yson::Options(false AS Strict))) AS miss;
+
+/*
+- abcs: `[123; 234]`
+- attrs: `{"a"="z";"x"="y"}`
+- miss: `NULL`
+*/
+```
+
+## Yson::Parse... {#ysonparse}
+
+```yql
+Yson::Parse(Yson{Flags:AutoMap}) -> Resource<'Yson2.Node'>
+Yson::ParseJson(Json{Flags:AutoMap}) -> Resource<'Yson2.Node'>
+Yson::ParseJsonDecodeUtf8(Json{Flags:AutoMap}) -> Resource<'Yson2.Node'>
+
+Yson::Parse(String{Flags:AutoMap}) -> Resource<'Yson2.Node'>? -- принимает YSON в любом формате
+Yson::ParseJson(String{Flags:AutoMap}) -> Resource<'Yson2.Node'>?
+Yson::ParseJsonDecodeUtf8(String{Flags:AutoMap}) -> Resource<'Yson2.Node'>?
+```
+
+Результат всех трёх функций является несериализуемым: его можно только передать на вход другой функции из библиотеки Yson, но нельзя сохранить в таблицу или вернуть на клиент в результате операции — попытка так сделать приведет к ошибке типизации. Также запрещено возвращать его за пределы [подзапросов](../../syntax/select/index.md): если это требуется, то надо вызвать [Yson::Serialize](#ysonserialize), а оптимизатор уберёт лишнюю сериализию и десериализацию, если материализация в конечном счёте не потребуется.
+
+{% note info %}
+
+Функция `Yson::ParseJsonDecodeUtf8` ожидает, что символы, выходящие за пределы ASCII, должны быть дополнительно заэкранированы.
+
+{% endnote %}
+
+## Yson::From {#ysonfrom}
+
+```yql
+Yson::From(T) -> Resource<'Yson2.Node'>
+```
+
+`Yson::From` является полиморфной функцией, преобразующей в Yson ресурс большинство примитивных типов данных и контейнеров (списки, словари, кортежи, структуры и т.п.). Тип исходного объекта должен быть совместим с Yson. Например, в ключах словарей допустимы только типы `String` или `Utf8`, а вот `String?` или `Utf8?` уже нет.
+
+### Пример
+
+```yql
+SELECT Yson::Serialize(Yson::From(TableRow())) FROM table1;
+```
+
+## Yson::WithAttributes
+
+```yql
+Yson::WithAttributes(Resource<'Yson2.Node'>{Flags:AutoMap}, Resource<'Yson2.Node'>{Flags:AutoMap}) -> Resource<'Yson2.Node'>?
+```
+
+Добавляет к узлу Yson (первый аргумент) атрибуты (второй аргумент). Атрибуты должны представлять из себя узел map.
+
+## Yson::Equals
+
+```yql
+Yson::Equals(Resource<'Yson2.Node'>{Flags:AutoMap}, Resource<'Yson2.Node'>{Flags:AutoMap}) -> Bool
+```
+
+Проверка деревьев в памяти на равенство, толерантная к исходному формату сериализации и порядку перечисления ключей в словарях.
+
+## Yson::GetHash
+
+```yql
+Yson::GetHash(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Uint64
+```
+
+Вычисление 64-битного хэша от дерева объектов.
+
+## Yson::Is...
+
+```yql
+Yson::IsEntity(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsString(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsDouble(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsUint64(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsInt64(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsBool(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsList(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+Yson::IsDict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> bool
+```
+
+Проверка, что текущий узел имеет соответствующий тип. Entity это `#`.
+
+## Yson::GetLength
+
+```yql
+Yson::GetLength(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Uint64?
+```
+
+Получение числа элементов в списке или словаре.
+
+## Yson::ConvertTo... {#ysonconvertto}
+
+```yql
+Yson::ConvertTo(Resource<'Yson2.Node'>{Flags:AutoMap}, Type<T>) -> T
+Yson::ConvertToBool(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Bool?
+Yson::ConvertToInt64(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Int64?
+Yson::ConvertToUint64(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Uint64?
+Yson::ConvertToDouble(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Double?
+Yson::ConvertToString(Resource<'Yson2.Node'>{Flags:AutoMap}) -> String?
+Yson::ConvertToList(Resource<'Yson2.Node'>{Flags:AutoMap}) -> List<Resource<'Yson2.Node'>>
+Yson::ConvertToBoolList(Resource<'Yson2.Node'>{Flags:AutoMap}) -> List<Bool>
+Yson::ConvertToInt64List(Resource<'Yson2.Node'>{Flags:AutoMap}) -> List<Int64>
+Yson::ConvertToUint64List(Resource<'Yson2.Node'>{Flags:AutoMap}) -> List<Uint64>
+Yson::ConvertToDoubleList(Resource<'Yson2.Node'>{Flags:AutoMap}) -> List<Double>
+Yson::ConvertToStringList(Resource<'Yson2.Node'>{Flags:AutoMap}) -> List<String>
+Yson::ConvertToDict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,Resource<'Yson2.Node'>>
+Yson::ConvertToBoolDict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,Bool>
+Yson::ConvertToInt64Dict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,Int64>
+Yson::ConvertToUint64Dict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,Uint64>
+Yson::ConvertToDoubleDict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,Double>
+Yson::ConvertToStringDict(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,String>
+```
+
+{% note warning %}
+
+Данные функции по умолчанию не делают неявного приведения типов, то есть значение в аргументе должно в точности соответствовать вызываемой функции.
+
+{% endnote %}
+
+`Yson::ConvertTo` является полиморфной функцией, преобразующей Yson ресурс в указанный во втором аргументе тип данных с поддержкой вложенных контейнеров (списки, словари, кортежи, структуры и т.п.).
+
+### Пример
+
+```yql
+$data = Yson(@@{
+ "name" = "Anya";
+ "age" = 15u;
+ "params" = {
+ "ip" = "95.106.17.32";
+ "last_time_on_site" = 0.5;
+ "region" = 213;
+ "user_agent" = "Mozilla/5.0"
+ }
+}@@);
+SELECT Yson::ConvertTo($data,
+ Struct<
+ name: String,
+ age: Uint32,
+ params: Dict<String,Yson>
+ >
+);
+```
+
+## Yson::Contains {#ysoncontains}
+
+```yql
+Yson::Contains(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Bool?
+```
+
+Проверяет наличие ключа в словаре. Если тип объекта map, то ищем среди ключей.
+Если тип объекта список, то ключ должен быть десятичным числом - индексом в списке.
+
+
+## Yson::Lookup... {#ysonlookup}
+
+```yql
+Yson::Lookup(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Resource<'Yson2.Node'>?
+Yson::LookupBool(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Bool?
+Yson::LookupInt64(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Int64?
+Yson::LookupUint64(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Uint64?
+Yson::LookupDouble(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Double?
+Yson::LookupString(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> String?
+Yson::LookupDict(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Dict<String,Resource<'Yson2.Node'>>?
+Yson::LookupList(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> List<Resource<'Yson2.Node'>>?
+```
+
+Перечисленные выше функции представляют собой краткую форму записи для типичного сценария использования: `Yson::YPath` — переход в словарь на один уровень с последующим извлечением значения — `Yson::ConvertTo***`. Второй аргумент для всех перечисленных функций — имя ключа в словаре (в отличие от YPath, без префикса `/`) или индекс в списке (например, `7`). Упрощают запрос и дают небольшой выигрыш в скорости работы.
+
+## Yson::YPath {#ysonypath}
+
+```yql
+Yson::YPath(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Resource<'Yson2.Node'>?
+Yson::YPathBool(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Bool?
+Yson::YPathInt64(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Int64?
+Yson::YPathUint64(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Uint64?
+Yson::YPathDouble(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Double?
+Yson::YPathString(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> String?
+Yson::YPathDict(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> Dict<String,Resource<'Yson2.Node'>>?
+Yson::YPathList(Resource<'Yson2.Node'>{Flags:AutoMap}, String) -> List<Resource<'Yson2.Node'>>?
+```
+
+Позволяет по входному ресурсу и пути на языке YPath получить ресурс, указывающий на соответствующую пути часть исходного ресурса.
+
+
+
+## Yson::Attributes {#ysonattributes}
+
+```yql
+Yson::Attributes(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Dict<String,Resource<'Yson2.Node'>>
+```
+
+Получение всех атрибутов узла в виде словаря.
+
+## Yson::Serialize... {#ysonserialize}
+
+```yql
+Yson::Serialize(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Yson -- бинарное представление
+Yson::SerializeText(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Yson
+Yson::SerializePretty(Resource<'Yson2.Node'>{Flags:AutoMap}) -> Yson -- чтобы увидеть именно текстовый результат, можно обернуть его в ToBytes(...)
+```
+
+## Yson::SerializeJson {#ysonserializejson}
+
+```yql
+Yson::SerializeJson(Resource<'Yson2.Node'>{Flags:AutoMap}, [Resource<'Yson2.Options'>?, SkipMapEntity:Bool?, EncodeUtf8:Bool?, WriteNanAsString:Bool?]) -> Json?
+```
+
+* `SkipMapEntity` отвечает за сериализацию значений в словарях, имеющих значение `#`. На значение атрибутов флаг не влияет. По умолчанию `false`.
+* `EncodeUtf8` отвечает за экранирование символов, выходящих за пределы ASCII. По умолчанию `false`.
+* `WriteNanAsString` разрешает сериализацию значений `NaN` и `Inf` в json в виде строк. По умолчанию `false`.
+
+Типы данных `Yson` и `Json`, возвращаемые функциями сериализации, представляет собой частный случай строки, про которую известно, что в ней находятся данные в соответствующем формате (Yson/Json).
+
+## Yson::Options {#ysonoptions}
+
+```yql
+Yson::Options([AutoConvert:Bool?, Strict:Bool?]) -> Resource<'Yson2.Options'>
+```
+
+Передаётся последним опциональным аргументом (который для краткости не указан) в методы `Parse...`, `ConvertTo...`, `Contains`, `Lookup...` и `YPath...`, которые принимают результат вызова `Yson::Options`. По умолчанию все поля `Yson::Options` выключены (false), а при включении (true) модифицируют поведение следующим образом:
+
+* **AutoConvert** — если переданное в Yson значение не в точности соответствует типу данных результата, то значение будет по возможности сконвертировано. Например, `Yson::ConvertToInt64` в этом режиме будет делать Int64 даже из чисел типа Double.
+* **Strict** — по умолчанию все функции из библиотеки Yson возвращают ошибку в случае проблем в ходе выполнения запроса (например, попытка парсинга строки не являющейся Yson/Json, или попытка поиска по ключу в скалярном типе, или запрошено преобразование в несовместимый тип данных, и т.п.), а если отключить строгий режим, то вместо ошибки в большинстве случаев будет возвращаться `NULL`. При преобразовании в словарь или список (`ConvertTo<Type>Dict` или `ConvertTo<Type>List`) плохие элементы будут выброшены из полученной коллекции.
+
+### Пример
+
+```yql
+$yson = @@{y = true; x = 5.5}@@y;
+SELECT Yson::LookupBool($yson, "z"); --- null
+SELECT Yson::LookupBool($yson, "y"); --- true
+
+SELECT Yson::LookupInt64($yson, "x"); --- Ошибка
+SELECT Yson::LookupInt64($yson, "x", Yson::Options(false as Strict)); --- null
+SELECT Yson::LookupInt64($yson, "x", Yson::Options(true as AutoConvert)); --- 5
+
+SELECT Yson::ConvertToBoolDict($yson); --- Ошибка
+SELECT Yson::ConvertToBoolDict($yson, Yson::Options(false as Strict)); --- { "y": true }
+SELECT Yson::ConvertToDoubleDict($yson, Yson::Options(false as Strict)); --- { "x": 5.5 }
+```
+
+Если во всём запросе требуется применять одинаковые значения настроек библиотеки Yson, то удобнее воспользоваться [PRAGMA yson.AutoConvert;](../../syntax/pragma.md#yson.autoconvert) и/или [PRAGMA yson.Strict;](../../syntax/pragma.md#yson.strict). Также эти `PRAGMA` являются единственным способом повлиять на неявные вызовы библиотеки Yson, которые возникают при работе с типами данных Yson/Json.
+
+## Смотрите также
+
+* [{#T}](../../recipes/accessing-json.md)
+* [{#T}](../../recipes/modifying-json.md)
diff --git a/yql/essentials/docs/scripts/doc_upgrade_arc.sh b/yql/essentials/docs/scripts/doc_upgrade_arc.sh
new file mode 100755
index 0000000000..a165d4ad29
--- /dev/null
+++ b/yql/essentials/docs/scripts/doc_upgrade_arc.sh
@@ -0,0 +1,88 @@
+#!/bin/bash
+set -eu
+
+TARGET_INFO_FILE="$(realpath $1)"
+
+if [ ! -f $TARGET_INFO_FILE ]; then
+ echo "File $TARGET_INFO_FILE doesn't exist. Creating new one"
+
+ if [ "$2" == "" ]; then
+ echo "Expected source folder as the second argument" >&2
+ exit
+ fi
+
+ if [ ! -d "$2" ]; then
+ echo "Expected $2 to be a directory" >&2
+ exit
+ fi
+
+ FROM=$(realpath $2)
+ ARC_ROOT=$(cd $FROM; arc root)
+ HEAD=$(cd $FROM; arc rev-parse HEAD)
+ # Normalize FROM relativly to the arc root
+ FROM=${FROM#$ARC_ROOT/}
+ echo "$HEAD;$FROM" > $TARGET_INFO_FILE
+ echo "Filled in $TARGET_INFO_FILE"
+ exit
+fi
+
+IFS=';' read -r BASE_REV INFO_FROM < "$TARGET_INFO_FILE"
+TO=$(dirname $(realpath "$TARGET_INFO_FILE"))
+HEAD_REV=$(cd $TO; arc rev-parse HEAD)
+ARC_ROOT=$(cd $TO; arc root)
+FROM="$ARC_ROOT/$INFO_FROM"
+
+echo "Base revision: $BASE_REV"
+echo "Head revision: $HEAD_REV"
+echo "Arc root: $ARC_ROOT"
+echo "Source: $FROM"
+echo "Target: $TO"
+
+if [ "$(cd $TO; arc status -s -u all | wc -l)" != "0" ]; then
+ echo "Target $TO has uncommited changes" >&2
+ exit
+fi
+
+cd $ARC_ROOT
+
+CURRENT_BRANCH=$(arc info | grep 'branch:')
+CURRENT_BRANCH=${CURRENT_BRANCH#branch: }
+PATCH_FILE=$(mktemp)
+BRANCH=upgrade-$(date '+%Y-%m-%d-%H-%M-%S')
+
+clean_up () {
+ ARG=$?
+ echo "Deleting patch file"
+ rm $PATCH_FILE
+ exit $ARG
+}
+trap clean_up EXIT
+
+echo "Use $BRANCH temporary branch, $PATCH_FILE patch file"
+arc co $BASE_REV -b $BRANCH
+rsync -r --delete --filter='. -' -v $TO/ $FROM << EOF
++ /*/
++ *.md
++ toc_*.yaml
+- /*
+EOF
+
+arc add -A $INFO_FROM
+
+arc diff --cached --relative=$INFO_FROM > $PATCH_FILE
+arc reset
+arc co $INFO_FROM
+arc clean -d
+arc st
+arc co "$CURRENT_BRANCH"
+arc br -D $BRANCH
+rsync -r --delete --filter='. -' -v $FROM/ $TO << EOF
++ /*/
++ *.md
++ toc_*.yaml
+- /*
+EOF
+
+patch -d $TO -p0 -N -E --no-backup-if-mismatch --merge -i $PATCH_FILE -t
+
+echo "$HEAD_REV;$INFO_FROM" > $TARGET_INFO_FILE
diff --git a/yql/essentials/docs/ya.make b/yql/essentials/docs/ya.make
new file mode 100644
index 0000000000..3ca5392a25
--- /dev/null
+++ b/yql/essentials/docs/ya.make
@@ -0,0 +1,5 @@
+DOCS()
+
+SUBSCRIBER(g:yql)
+
+END()
diff --git a/yql/essentials/ya.make b/yql/essentials/ya.make
index 7c34bf60b7..1f2489820c 100644
--- a/yql/essentials/ya.make
+++ b/yql/essentials/ya.make
@@ -3,6 +3,7 @@ SUBSCRIBER(g:yql)
RECURSE(
ast
core
+ docs
minikql
parser
protos