aboutsummaryrefslogtreecommitdiffstats
path: root/yql/essentials/tests/s-expressions/suites/EquiJoin
diff options
context:
space:
mode:
authorAlexander Smirnov <alex@ydb.tech>2024-11-20 11:14:58 +0000
committerAlexander Smirnov <alex@ydb.tech>2024-11-20 11:14:58 +0000
commit31773f157bf8164364649b5f470f52dece0a4317 (patch)
tree33d0f7eef45303ab68cf08ab381ce5e5e36c5240 /yql/essentials/tests/s-expressions/suites/EquiJoin
parent2c7938962d8689e175574fc1e817c05049f27905 (diff)
parenteff600952d5dfe17942f38f510a8ac2b203bb3a5 (diff)
downloadydb-31773f157bf8164364649b5f470f52dece0a4317.tar.gz
Merge branch 'rightlib' into mergelibs-241120-1113
Diffstat (limited to 'yql/essentials/tests/s-expressions/suites/EquiJoin')
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491.cfg4
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input1.txt4
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input1.txt.attr30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input2.txt4
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input2.txt.attr30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716.cfg4
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716.yql305
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input1.txt6
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input1.txt.attr3
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input2.txt3
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input2.txt.attr3
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1924.sql38
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1924.yql117
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug2566.sql5
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/Bug2566.yql56
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/DoAllJoinsExceptCross.yql.txt48
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiConvertToCommonTypeAlias.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiCrossSelfStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiExclusionSelfStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullCross3OptStr.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullCross3Str.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullExclusion3OptStr.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullExclusion3Str.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullFull3OptStr.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullFull3Str.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullInner3OptStr.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullInner3Str.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeft3OptStr.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeft3Str.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftOnly3OptStr.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftOnly3Str.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftSemi3OptStr.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftSemi3Str.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRight3OptStr.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRight3Str.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightOnly3OptStr.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightOnly3Str.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightSemi3OptStr.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightSemi3Str.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnNoOpt1Opt2Str.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnOpt1NoOpt2Str.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnOpt1Opt2Str.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnOptPartial1OptPartial2Str.yql29
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerCross3OptStr.yql37
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerCross3Str.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerDiffIntTypes.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerExclusion3OptStr.yql38
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerExclusion3Str.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerFull3OptStr.yql37
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerFull3Str.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerInner3OptStr.yql37
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerInner3Str.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerInner3StrRename.yql24
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeft3OptStr.yql37
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeft3Str.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftOnly3OptStr.yql38
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftOnly3Str.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftSemi3OptStr.yql37
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftSemi3Str.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerOptDiffIntTypes.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerOptDiffIntTypesTwoColumn.yql25
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRight3OptStr.yql37
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRight3Str.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightOnly3OptStr.yql38
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightOnly3Str.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightSemi3OptStr.yql37
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightSemi3Str.yql23
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfIntSameDiff.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfIntTakeDiff.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfStr.yql12
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfStrRename.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnNoOpt1Opt2Str.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1NoOpt2Str.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2Str.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasOne1.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasOne12.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasOne2.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasTwo.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOptPartial1OptPartial2Str.yql29
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U32.cfg4
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U32.yql9
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U8.cfg6
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U8.yql12
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U32.cfg4
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U32.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U8.cfg6
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U8.yql14
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftOnlySelfStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnNoOpt1Opt2Str.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnOpt1NoOpt2Str.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnOpt1Opt2Str.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnOptPartial1OptPartial2Str.yql29
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSemiSelfStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12FullSelfInt.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12FullSelfStr.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12InnerSelfInt.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12InnerSelfStr.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12LeftSelfInt.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12LeftSelfStr.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12RightSelfInt.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12RightSelfStr.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1FullSelfInt.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1FullSelfStr.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1InnerSelfInt.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1InnerSelfStr.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1LeftSelfInt.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1LeftSelfStr.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1RightSelfInt.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1RightSelfStr.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2FullSelfInt.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2FullSelfStr.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2InnerSelfInt.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2InnerSelfStr.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2LeftSelfInt.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2LeftSelfStr.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2RightSelfInt.yql27
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2RightSelfStr.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightOnlySelfStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnNoOpt1Opt2Str.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnOpt1NoOpt2Str.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnOpt1Opt2Str.yql20
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnOptPartial1OptPartial2Str.yql29
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSemiSelfStr.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/ExtractRenameFromFlatMapOverJoin.yql42
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenInner.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenInner3.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenInnerTwoColumns.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeft.cfg3
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeft.yql26
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeftSemi.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeftSemi3.yql39
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/HintLeftSmallInnerJoin.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/HintLeftSmallInnerJoinFat.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/HintLeftUniqueRightMap.yql29
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightSmallInnerJoin.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightSmallInnerJoinFat.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightUniqueInnerMap.yql29
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightUniqueLeftMap.yql29
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightUniqueLeftSemiShardedMap.yql30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InOutSettings.cfg3
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InOutSettings.yql26
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8.txt5
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8.txt.attr6
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8Opt.txt5
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8Opt.txt.attr6
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf.txt8
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf.txt.attr30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf2.txt8
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf2.txt.attr30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint32.txt5
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint32.txt.attr6
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8.txt5
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8.txt.attr6
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8Opt.txt5
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8Opt.txt.attr6
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem.yql42
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem3.yql79
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem3Alias12.yql71
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem3Rename.yql36
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasOne1.yql43
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasOne12.yql43
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasOne2.yql43
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasTwo12.yql43
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemDiffIntTypes.yql43
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemOpt1.yql45
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemOpt1Opt2.yql48
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemOpt2.yql45
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemRename.yql28
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumns.yql43
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumnsOpt1.yql41
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumnsOpt1Opt2.yql43
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumnsOpt2.yql43
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.cfg2
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.txt3
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.txt.attr30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinMergeFields.yql17
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/SqlInToJoin.yql59
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiCrossSelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiExclusionSelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiFullSelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiFullTwoFieldsSelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested1EatOptSelf.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested1Self.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested1bSelf.yql13
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested2Self.yql15
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerSelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerTwoFieldsSelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftOnlySelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftSelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftSemiSelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftTwoFieldsSelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptFullSelf.yql15
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptInnerSelf.yql15
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptLeftSelf.yql15
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptRightSelf.yql15
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightOnlySelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightSelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightSemiSelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightTwoFieldsSelf.yql11
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/default.cfg6
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/input1.txt4
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/input1.txt.attr30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/input2.txt4
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/input2.txt.attr30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/input3.txt4
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/input3.txt.attr30
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/input4.txt2
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/input4.txt.attr35
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/input5.txt2
-rw-r--r--yql/essentials/tests/s-expressions/suites/EquiJoin/input5.txt.attr35
219 files changed, 5374 insertions, 0 deletions
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491.cfg b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491.cfg
new file mode 100644
index 0000000000..0db7c8a4b8
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491.cfg
@@ -0,0 +1,4 @@
+res result.txt
+in Input1 Bug15491_Input1.txt
+in Input2 Bug15491_Input2.txt
+out Output output.txt
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491.yql
new file mode 100644
index 0000000000..89a1e02765
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491.yql
@@ -0,0 +1,30 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey1 (Just (Member item 'subkey)))
+ '('value1 (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Member item 'key))
+ '('subkey2 (Just (Member item 'subkey)))
+ '('value2 (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '('('flatten))))
+
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"key") (Member row '"subkey1"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input1.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input1.txt
new file mode 100644
index 0000000000..1dc1bcc60b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input1.txt
@@ -0,0 +1,4 @@
+{"key"="075";"subkey"="3";"value"="abd"};
+{"key"="800";"subkey"="3";"value"="ddd"};
+{"key"="021";"subkey"="3";"value"="q"};
+{"key"="151";"subkey"="3";"value"="qzz"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input1.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input1.txt.attr
new file mode 100644
index 0000000000..b6100e5fd0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input1.txt.attr
@@ -0,0 +1,30 @@
+{
+ "_yql_row_spec" = {
+ "Type" = [
+ "StructType";
+ [
+ [
+ "key";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "subkey";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "value";
+ [
+ "DataType";
+ "String"
+ ]
+ ]
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input2.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input2.txt
new file mode 100644
index 0000000000..1dc1bcc60b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input2.txt
@@ -0,0 +1,4 @@
+{"key"="075";"subkey"="3";"value"="abd"};
+{"key"="800";"subkey"="3";"value"="ddd"};
+{"key"="021";"subkey"="3";"value"="q"};
+{"key"="151";"subkey"="3";"value"="qzz"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input2.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input2.txt.attr
new file mode 100644
index 0000000000..e45f964f78
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug15491_Input2.txt.attr
@@ -0,0 +1,30 @@
+{
+ "_yql_row_spec" = {
+ "Type" = [
+ "StructType";
+ [
+ [
+ "key";
+ [
+ "DataType";
+ "Utf8"
+ ]
+ ];
+ [
+ "subkey";
+ [
+ "DataType";
+ "Utf8"
+ ]
+ ];
+ [
+ "value";
+ [
+ "DataType";
+ "Utf8"
+ ]
+ ]
+ ]
+ ]
+ }
+}
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716.cfg b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716.cfg
new file mode 100644
index 0000000000..c828977eed
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716.cfg
@@ -0,0 +1,4 @@
+res result.txt
+in Input1 Bug1716_Input1.txt
+in Input2 Bug1716_Input2.txt
+out Output output.txt
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716.yql
new file mode 100644
index 0000000000..7f37ba29ab
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716.yql
@@ -0,0 +1,305 @@
+(
+(let data.source (DataSource 'yt 'plato))
+(let data.sink (DataSink 'yt 'plato))
+
+(let first (String 'Input1))
+(let second (String 'Input2))
+(let output (String 'Output))
+
+(let first.read
+ (Read! world data.source
+ (Key '('table first))
+ (Void)
+ '('('infer_scheme))
+ )
+)
+
+(let world (Left! first.read))
+(let first.read (Right! first.read))
+
+(let second.read
+ (Read! world data.source
+ (Key '('table second))
+ (Void)
+ '('('infer_scheme))
+ )
+)
+
+(let world (Left! second.read))
+(let second.read (Right! second.read))
+
+(let data
+ (EquiJoin
+ '((RemoveSystemMembers first.read) 'left) '((RemoveSystemMembers second.read) 'right)
+ '('Inner
+ 'left
+ 'right
+ # '('left 'id 'left 'id.nonzero 'left 'name 'left 'name.nonzero)
+ '('left 'id 'left 'name)
+ # '('right 'id 'right 'id.nonzero 'right 'name 'right 'name.nonzero)
+ '('right 'id 'right 'name)
+ '('('left 'small) '('right 'small)))
+ '('('flatten))
+ )
+)
+
+(let data
+ (Sort data
+ '((Bool 'true) (Bool 'true))
+ (lambda '(row) '((Member row 'id) (Member row 'name)))
+ )
+)
+
+(let world
+ (Write! world (DataSink 'result)
+ (Key)
+ data
+ '('('type))
+ )
+)
+
+(let data
+ (EquiJoin
+ '((RemoveSystemMembers first.read) 'left) '((RemoveSystemMembers second.read) 'right)
+ '('Left
+ 'left
+ 'right
+ # '('left 'id 'left 'id.nonzero 'left 'name 'left 'name.nonzero)
+ '('left 'id 'left 'name)
+ # '('right 'id 'right 'id.nonzero 'right 'name 'right 'name.nonzero)
+ '('right 'id 'right 'name)
+ '('('left 'small) '('right 'small)))
+ '('('flatten))
+ )
+)
+
+(let data
+ (Sort data
+ '((Bool 'true) (Bool 'true))
+ (lambda '(row) '((Member row 'id) (Member row 'name)))
+ )
+)
+
+(let world
+ (Write! world (DataSink 'result)
+ (Key)
+ data
+ '('('type))
+ )
+)
+
+
+(let data
+ (EquiJoin
+ '((RemoveSystemMembers first.read) 'left) '((RemoveSystemMembers second.read) 'right)
+ '('Right
+ 'left
+ 'right
+ # '('left 'id 'left 'id.nonzero 'left 'name 'left 'name.nonzero)
+ '('left 'id 'left 'name)
+ # '('right 'id 'right 'id.nonzero 'right 'name 'right 'name.nonzero)
+ '('right 'id 'right 'name)
+ '('('left 'small) '('right 'small)))
+ '('('flatten))
+ )
+)
+
+(let data
+ (Sort data
+ '((Bool 'true) (Bool 'true))
+ (lambda '(row) '((Member row 'id) (Member row 'name)))
+ )
+)
+
+(let world
+ (Write! world (DataSink 'result)
+ (Key)
+ data
+ '('('type))
+ )
+)
+
+(let data
+ (EquiJoin
+ '((RemoveSystemMembers first.read) 'left) '((RemoveSystemMembers second.read) 'right)
+ '('Full
+ 'left
+ 'right
+ # '('left 'id 'left 'id.nonzero 'left 'name 'left 'name.nonzero)
+ '('left 'id 'left 'name)
+ # '('right 'id 'right 'id.nonzero 'right 'name 'right 'name.nonzero)
+ '('right 'id 'right 'name)
+ '('('left 'small) '('right 'small)))
+ '('('flatten))
+ )
+)
+
+(let data
+ (Sort data
+ '((Bool 'true) (Bool 'true))
+ (lambda '(row) '((Member row 'id) (Member row 'name)))
+ )
+)
+
+(let world
+ (Write! world (DataSink 'result)
+ (Key)
+ data
+ '('('type))
+ )
+)
+
+(let data
+ (EquiJoin
+ '((RemoveSystemMembers first.read) 'left) '((RemoveSystemMembers second.read) 'right)
+ '('LeftOnly
+ 'left
+ 'right
+ # '('left 'id 'left 'id.nonzero 'left 'name 'left 'name.nonzero)
+ '('left 'id 'left 'name)
+ # '('right 'id 'right 'id.nonzero 'right 'name 'right 'name.nonzero)
+ '('right 'id 'right 'name)
+ '('('left 'small) '('right 'small)))
+ '('('flatten))
+ )
+)
+
+(let data
+ (Sort data
+ '((Bool 'true) (Bool 'true))
+ (lambda '(row) '((Member row 'id) (Member row 'name)))
+ )
+)
+
+(let world
+ (Write! world (DataSink 'result)
+ (Key)
+ data
+ '('('type))
+ )
+)
+
+(let data
+ (EquiJoin
+ '((RemoveSystemMembers first.read) 'left) '((RemoveSystemMembers second.read) 'right)
+ '('LeftSemi
+ 'left
+ 'right
+ # '('left 'id 'left 'id.nonzero 'left 'name 'left 'name.nonzero)
+ '('left 'id 'left 'name)
+ # '('right 'id 'right 'id.nonzero 'right 'name 'right 'name.nonzero)
+ '('right 'id 'right 'name)
+ '('('left 'small) '('right 'small)))
+ '('('flatten))
+ )
+)
+
+(let data
+ (Sort data
+ '((Bool 'true) (Bool 'true))
+ (lambda '(row) '((Member row 'id) (Member row 'name)))
+ )
+)
+
+(let world
+ (Write! world (DataSink 'result)
+ (Key)
+ data
+ '('('type))
+ )
+)
+
+(let data
+ (EquiJoin
+ '((RemoveSystemMembers first.read) 'left) '((RemoveSystemMembers second.read) 'right)
+ '('RightOnly
+ 'left
+ 'right
+ # '('left 'id 'left 'id.nonzero 'left 'name 'left 'name.nonzero)
+ '('left 'id 'left 'name)
+ # '('right 'id 'right 'id.nonzero 'right 'name 'right 'name.nonzero)
+ '('right 'id 'right 'name)
+ '('('left 'small) '('right 'small)))
+ '('('flatten))
+ )
+)
+
+(let data
+ (Sort data
+ '((Bool 'true) (Bool 'true))
+ (lambda '(row) '((Member row 'id) (Member row 'name)))
+ )
+)
+
+(let world
+ (Write! world (DataSink 'result)
+ (Key)
+ data
+ '('('type))
+ )
+)
+
+(let data
+ (EquiJoin
+ '((RemoveSystemMembers first.read) 'left) '((RemoveSystemMembers second.read) 'right)
+ '('RightSemi
+ 'left
+ 'right
+ # '('left 'id 'left 'id.nonzero 'left 'name 'left 'name.nonzero)
+ '('left 'id 'left 'name)
+ # '('right 'id 'right 'id.nonzero 'right 'name 'right 'name.nonzero)
+ '('right 'id 'right 'name)
+ '('('left 'small) '('right 'small)))
+ '('('flatten))
+ )
+)
+
+(let data
+ (Sort data
+ '((Bool 'true) (Bool 'true))
+ (lambda '(row) '((Member row 'id) (Member row 'name)))
+ )
+)
+
+(let world
+ (Write! world (DataSink 'result)
+ (Key)
+ data
+ '('('type))
+ )
+)
+
+(let data
+ (EquiJoin
+ '((RemoveSystemMembers first.read) 'left) '((RemoveSystemMembers second.read) 'right)
+ '('Exclusion
+ 'left
+ 'right
+ # '('left 'id 'left 'id.nonzero 'left 'name 'left 'name.nonzero)
+ '('left 'id 'left 'name)
+ # '('right 'id 'right 'id.nonzero 'right 'name 'right 'name.nonzero)
+ '('right 'id 'right 'name)
+ '('('left 'small) '('right 'small)))
+ '('('flatten))
+ )
+)
+
+(let data
+ (Sort data
+ '((Bool 'true) (Bool 'true))
+ (lambda '(row) '((Member row 'id) (Member row 'name)))
+ )
+)
+
+(let world
+ (Write! world (DataSink 'result)
+ (Key)
+ data
+ '('('type))
+ )
+)
+
+(let world (Commit! world (DataSink 'result)))
+
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input1.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input1.txt
new file mode 100644
index 0000000000..7138a62f40
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input1.txt
@@ -0,0 +1,6 @@
+{"field1"="1_1";"field2"="2_1_1";"id"="1";"name"="name_1_1"};
+{"field1"="1_1";"field2"="2_1_2";"id"="1";"name"="name_1_1"};
+{"field1"="1_2";"field2"="2_1_1";"id"="1";"name"="name_1_2"};
+{"field1"="1_2";"field2"="2_1_2";"id"="1";"name"="name_1_2"};
+{"field1"="1_2";"id"="2";"name"="name_2_1"};
+{"field1"="1_3";"id"="3";"name"="name_3_1"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input1.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input1.txt.attr
new file mode 100644
index 0000000000..54366c43a1
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input1.txt.attr
@@ -0,0 +1,3 @@
+{
+ "_yql_row_spec"={"Type" = [ "StructType"; [["field1";["OptionalType";["DataType";"String"]]];["field2";["OptionalType";["DataType";"String"]]];["id";["OptionalType";["DataType";"String"]]];["name";["OptionalType";["DataType";"String"]]]]];"UniqueKeys" = %false}
+}
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input2.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input2.txt
new file mode 100644
index 0000000000..67606ea5fc
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input2.txt
@@ -0,0 +1,3 @@
+{"field3"="3_1";"id"="1";"name"="name_1_1"};
+{"field3"="3_2";"id"="2";"name"="name_2_1"};
+{"field3"="3_3";"id"="2";"name"="name_2_2"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input2.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input2.txt.attr
new file mode 100644
index 0000000000..268c3c5a6d
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1716_Input2.txt.attr
@@ -0,0 +1,3 @@
+{
+ "_yql_row_spec"={"Type" = [ "StructType"; [["field3";["OptionalType";["DataType";"String"]]];["id";["OptionalType";["DataType";"String"]]];["name";["OptionalType";["DataType";"String"]]]]];"UniqueKeys" = %false}
+}
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1924.sql b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1924.sql
new file mode 100644
index 0000000000..b14b63a04a
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1924.sql
@@ -0,0 +1,38 @@
+USE plato;
+
+$hash = (select key as devid, key as mmetric_devid from Input);
+$rutaxi = (select key as DeviceID from Input);
+$device = (select key as devid, key as yuid from Input);
+$cripta = (select key as yuid, value as phones from Input);
+
+$x =
+ (
+ select
+ hash.devid as devid
+ from $rutaxi as rutaxi
+ right semi join $hash as hash
+ on rutaxi.DeviceID = hash.mmetric_devid
+ );
+
+$y =
+ (
+ select
+ device.yuid as yuid
+ from $x as x
+ right semi join $device as device
+ using(devid)
+ );
+
+
+$z =
+ (
+ select
+ cripta.phones as phones
+ from $y as y
+ right semi join $cripta as cripta on
+ y.yuid = cripta.yuid || ""
+ );
+
+select
+ x.phones AS phone
+from $z AS x;
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1924.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1924.yql
new file mode 100644
index 0000000000..2247aa8e0b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug1924.yql
@@ -0,0 +1,117 @@
+(
+(import aggregate_module '"/lib/yql/aggregate.yql")
+(import window_module '"/lib/yql/window.yql")
+(let world (block '(
+ (let x (Read! world (DataSource '"yt" '"plato") (MrTableConcat (Key '('table (String '"InputSelf")))) '('"key" '"value") '()))
+ (let world (Left! x))
+ (let table0 (Right! x))
+ (let output (block '(
+ (let select (block '(
+ (let core (block '(
+ (let select (block '(
+ (let core (Map (EquiJoin '((block '(
+ (let select (block '(
+ (let core (EquiJoin '((block '(
+ (let select (block '(
+ (let core (EquiJoin '((block '(
+ (let select (block '(
+ (let core table0)
+ (let core (FlatMap core (lambda '(row) (block '(
+ (let res (AsStruct '('"DeviceID" (Member row '"key"))))
+ (let res (AsList res))
+ (return res)
+ )))))
+ (return core)
+ )))
+ (return select)
+ )) '"rutaxi") '((block '(
+ (let select (block '(
+ (let core table0)
+ (let core (FlatMap core (lambda '(row) (block '(
+ (let res (AsStruct '('"devid" (Member row '"key")) '('"mmetric_devid" (Member row '"key"))))
+ (let res (AsList res))
+ (return res)
+ )))))
+ (return core)
+ )))
+ (return select)
+ )) '"hash") '('RightSemi '"rutaxi" '"hash" '('"rutaxi" '"DeviceID") '('"hash" '"mmetric_devid") '()) '()))
+ (let core (FlatMap core (lambda '(row) (block '(
+ (let res (AsStruct '('"devid" (Member row '"hash.devid"))))
+ (let res (AsList res))
+ (return res)
+ )))))
+ (return core)
+ )))
+ (return select)
+ )) '"x") '((block '(
+ (let select (block '(
+ (let core table0)
+ (let core (FlatMap core (lambda '(row) (block '(
+ (let res (AsStruct '('"devid" (Member row '"key")) '('"yuid" (Member row '"key"))))
+ (let res (AsList res))
+ (return res)
+ )))))
+ (return core)
+ )))
+ (return select)
+ )) '"device") '('RightSemi '"x" '"device" '('"x" '"devid") '('"device" '"devid") '()) '()))
+ (let core (FlatMap core (lambda '(row) (block '(
+ (let res (AsStruct '('"yuid" (Member row '"device.yuid"))))
+ (let res (AsList res))
+ (return res)
+ )))))
+ (return core)
+ )))
+ (return select)
+ )) '"y") '((Map (block '(
+ (let select (block '(
+ (let core table0)
+ (let core (FlatMap core (lambda '(row) (block '(
+ (let res (AsStruct '('"yuid" (Member row '"key")) '('"phones" (Member row '"value"))))
+ (let res (AsList res))
+ (return res)
+ )))))
+ (return core)
+ )))
+ (return select)
+ )) (lambda '(row) (block '(
+ (let row (AddMember row '"_equijoin_column_0" ("Concat" (Member row '"yuid") (String '""))))
+ (return row)
+ )))) '"cripta") '('RightSemi '"y" '"cripta" '('"y" '"yuid") '('"cripta" '"_equijoin_column_0") '()) '()) (lambda '(row) (block '(
+ (let row (ForceRemoveMember row '"cripta._equijoin_column_0"))
+ (return row)
+ )))))
+ (let core (FlatMap core (lambda '(row) (block '(
+ (let res (AsStruct '('"phones" (Member row '"cripta.phones"))))
+ (let res (AsList res))
+ (return res)
+ )))))
+ (return core)
+ )))
+ (return select)
+ )))
+ (let core (FlatMap core (lambda '(row) (block '(
+ (let res (AsStruct '('"phone" (Member row '"phones"))))
+ (let res (AsList res))
+ (return res)
+ )))))
+ (return core)
+ )))
+ (let select (Sort select (Bool 'true) (lambda '(row) (Member row '"phone"))))
+ (return select)
+ )))
+ (let world (block '(
+ (let result_sink (DataSink 'result))
+ (let world (Write! world result_sink (Key) output '('('type) '('autoref) '('columns '('"phone")))))
+ (return (Commit! world result_sink))
+ )))
+ (return world)
+)))
+(let world (block '(
+ (let plato_sink (DataSink '"yt" '"plato"))
+ (let world (Commit! world plato_sink))
+ (return world)
+)))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug2566.sql b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug2566.sql
new file mode 100644
index 0000000000..b12f694803
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug2566.sql
@@ -0,0 +1,5 @@
+use plato;
+pragma yt.MapJoinLimit="1m";
+$a = (select cast(key as Uint64) as key,subkey from Input1);
+$b = (select cast(key as Uint32) as key,subkey from Input1);
+select * from $a as a join $b as b on a.key = b.key;
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug2566.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug2566.yql
new file mode 100644
index 0000000000..09a8847b4a
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/Bug2566.yql
@@ -0,0 +1,56 @@
+(
+(import aggregate_module '"/lib/yql/aggregate.yql")
+(import window_module '"/lib/yql/window.yql")
+(import core_module '"/lib/yql/core.yql")
+(let world (Configure! world (DataSource '"yt" '"$all") '"Attr" '"mapjoinlimit" '"1m"))
+(let world (block '(
+ (let x (Read! world (DataSource '"yt" '"plato") (MrTableConcat (Key '('table (String '"Input1")))) '('"key" '"subkey") '()))
+ (let world (Left! x))
+ (let table0 (Right! x))
+ (let output (block '(
+ (let select (block '(
+ (let core (EquiJoin '((block '(
+ (let select (block '(
+ (let core table0)
+ (let core (FlatMap core (lambda '(row) (block '(
+ (let res (AsStruct '('"key" (Cast (Member row '"key") 'Uint64)) '('"subkey" (Member row '"subkey"))))
+ (let res (AsList res))
+ (return res)
+ )))))
+ (return core)
+ )))
+ (return select)
+ )) '"a") '((block '(
+ (let select (block '(
+ (let core table0)
+ (let core (FlatMap core (lambda '(row) (block '(
+ (let res (AsStruct '('"key" (Cast (Member row '"key") 'Uint32)) '('"subkey" (Member row '"subkey"))))
+ (let res (AsList res))
+ (return res)
+ )))))
+ (return core)
+ )))
+ (return select)
+ )) '"b") '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key") '()) '()))
+ (let core (FlatMap core (lambda '(row) (block '(
+ (let res (AsList row))
+ (return res)
+ )))))
+ (return core)
+ )))
+ (return select)
+ )))
+ (let world (block '(
+ (let result_sink (DataSink 'result))
+ (let world (Write! world result_sink (Key) output '('('type) '('autoref))))
+ (return (Commit! world result_sink))
+ )))
+ (return world)
+)))
+(let world (block '(
+ (let plato_sink (DataSink '"yt" '"plato"))
+ (let world (Commit! world plato_sink))
+ (return world)
+)))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/DoAllJoinsExceptCross.yql.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/DoAllJoinsExceptCross.yql.txt
new file mode 100644
index 0000000000..9ef17f1842
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/DoAllJoinsExceptCross.yql.txt
@@ -0,0 +1,48 @@
+(
+
+(let doAllJoinsExceptCross (lambda '(world t1 t2) ( block '(
+
+ (let mr_source (DataSource 'yt 'plato))
+ (let x (Read! world mr_source (Key '('table (String t1))) (Void) '()))
+ (let world (Left! x))
+ (let list1 (Right! x))
+
+ (let x (Read! world mr_source (Key '('table (String t2))) (Void) '()))
+ (let world (Left! x))
+ (let list2 (Right! x))
+
+ (let joinInner (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key) '('b 'key) '()) '()))
+ (let joinLeft (EquiJoin '(list1 'a) '(list2 'b) '('Left 'a 'b '('a 'key) '('b 'key) '()) '()))
+ (let joinRight (EquiJoin '(list1 'a) '(list2 'b) '('Right 'a 'b '('a 'key) '('b 'key) '()) '()))
+ (let joinFull (EquiJoin '(list1 'a) '(list2 'b) '('Full 'a 'b '('a 'key) '('b 'key) '()) '()))
+ (let joinLeftOnly (EquiJoin '(list1 'a) '(list2 'b) '('LeftOnly 'a 'b '('a 'key) '('b 'key) '()) '()))
+ (let joinRightOnly (EquiJoin '(list1 'a) '(list2 'b) '('RightOnly 'a 'b '('a 'key) '('b 'key) '()) '()))
+ (let joinExclusion (EquiJoin '(list1 'a) '(list2 'b) '('Exclusion 'a 'b '('a 'key) '('b 'key) '()) '()))
+ (let joinLeftSemi (EquiJoin '(list1 'a) '(list2 'b) '('LeftSemi 'a 'b '('a 'key) '('b 'key) '()) '()))
+ (let joinRightSemi (EquiJoin '(list1 'a) '(list2 'b) '('RightSemi 'a 'b '('a 'key) '('b 'key) '()) '()))
+
+ (let sortDir2 '((Bool 'true) (Bool 'true)))
+ (let sortDir1 '((Bool 'true)))
+ (let keySelectorAB (lambda '(row) '((Member row '"a.key") (Member row '"b.key"))))
+ (let keySelectorA (lambda '(row) '((Member row '"a.key"))))
+ (let keySelectorB (lambda '(row) '((Member row '"b.key"))))
+
+ (let res_sink (DataSink 'result))
+ (let world (Write! world res_sink (Key) (Sort joinInner sortDir2 keySelectorAB) '('('type))))
+ (let world (Write! world res_sink (Key) (Sort joinLeft sortDir2 keySelectorAB) '('('type))))
+ (let world (Write! world res_sink (Key) (Sort joinRight sortDir2 keySelectorAB) '('('type))))
+ (let world (Write! world res_sink (Key) (Sort joinFull sortDir2 keySelectorAB) '('('type))))
+ (let world (Write! world res_sink (Key) (Sort joinLeftOnly sortDir1 keySelectorA) '('('type))))
+ (let world (Write! world res_sink (Key) (Sort joinRightOnly sortDir1 keySelectorB) '('('type))))
+ (let world (Write! world res_sink (Key) (Sort joinExclusion sortDir2 keySelectorAB) '('('type))))
+ (let world (Write! world res_sink (Key) (Sort joinLeftSemi sortDir1 keySelectorA) '('('type))))
+ (let world (Write! world res_sink (Key) (Sort joinRightSemi sortDir1 keySelectorB) '('('type))))
+
+ (let world (Commit! world res_sink))
+ (return world)
+
+))))
+
+(export doAllJoinsExceptCross)
+
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiConvertToCommonTypeAlias.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiConvertToCommonTypeAlias.yql
new file mode 100644
index 0000000000..655f2a8207
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiConvertToCommonTypeAlias.yql
@@ -0,0 +1,25 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('a.key1 (Int32 '-1)) '('k.value1 (Int32 '1)) '('k.s (String '"k1")))
+))
+
+(let list2 (AsList
+ (AsStruct '('b.key2 (Uint32 '4294967295)) '('l.value2 (Uint32 '1)) '('l.s (String '"l1")))
+))
+
+(let list3 (AsList
+ (AsStruct '('c.key3 (Int32 '1)) '('m.value3 (Uint16 '1)) '('m.s (String '"m1")))
+))
+
+(let joinInnerInner (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Inner '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('l 'value2) '('c 'key3) '()) '()))
+
+(let res_sink (DataSink 'result))
+
+(let world (Write! world res_sink (Key) joinInnerInner '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiCrossSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiCrossSelfStr.yql
new file mode 100644
index 0000000000..944bb5f6de
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiCrossSelfStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Cross '"a" '"b" '() '() '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiExclusionSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiExclusionSelfStr.yql
new file mode 100644
index 0000000000..0b94fa907f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiExclusionSelfStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Exclusion '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullCross3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullCross3OptStr.yql
new file mode 100644
index 0000000000..dc7718c806
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullCross3OptStr.yql
@@ -0,0 +1,39 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('Cross '"a" '"b" '() '() '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullCross3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullCross3Str.yql
new file mode 100644
index 0000000000..894e36e1b9
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullCross3Str.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('Cross '"a" '"b" '() '() '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullExclusion3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullExclusion3OptStr.yql
new file mode 100644
index 0000000000..b115bd6907
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullExclusion3OptStr.yql
@@ -0,0 +1,39 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('Exclusion '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullExclusion3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullExclusion3Str.yql
new file mode 100644
index 0000000000..0683a16ba8
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullExclusion3Str.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('Exclusion '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullFull3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullFull3OptStr.yql
new file mode 100644
index 0000000000..db3690c50a
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullFull3OptStr.yql
@@ -0,0 +1,39 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('Full '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullFull3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullFull3Str.yql
new file mode 100644
index 0000000000..2339478283
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullFull3Str.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('Full '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullInner3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullInner3OptStr.yql
new file mode 100644
index 0000000000..786062ec45
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullInner3OptStr.yql
@@ -0,0 +1,39 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullInner3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullInner3Str.yql
new file mode 100644
index 0000000000..4f4a0eda4d
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullInner3Str.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeft3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeft3OptStr.yql
new file mode 100644
index 0000000000..293639aa22
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeft3OptStr.yql
@@ -0,0 +1,39 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('Left '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeft3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeft3Str.yql
new file mode 100644
index 0000000000..5d7c766dc5
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeft3Str.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('Left '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftOnly3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftOnly3OptStr.yql
new file mode 100644
index 0000000000..0ed5172d92
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftOnly3OptStr.yql
@@ -0,0 +1,39 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('LeftOnly '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftOnly3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftOnly3Str.yql
new file mode 100644
index 0000000000..bb8bb2e523
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftOnly3Str.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('LeftOnly '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftSemi3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftSemi3OptStr.yql
new file mode 100644
index 0000000000..c5382a89c2
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftSemi3OptStr.yql
@@ -0,0 +1,39 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('LeftSemi '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftSemi3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftSemi3Str.yql
new file mode 100644
index 0000000000..0afd1f691e
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullLeftSemi3Str.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('LeftSemi '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRight3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRight3OptStr.yql
new file mode 100644
index 0000000000..89ca16a047
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRight3OptStr.yql
@@ -0,0 +1,39 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('Right '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRight3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRight3Str.yql
new file mode 100644
index 0000000000..b5016c4e11
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRight3Str.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('Right '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightOnly3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightOnly3OptStr.yql
new file mode 100644
index 0000000000..d6e1605074
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightOnly3OptStr.yql
@@ -0,0 +1,39 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('RightOnly '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"b" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightOnly3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightOnly3Str.yql
new file mode 100644
index 0000000000..97a13fa2b9
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightOnly3Str.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('RightOnly '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"b" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightSemi3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightSemi3OptStr.yql
new file mode 100644
index 0000000000..a64f8a6705
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightSemi3OptStr.yql
@@ -0,0 +1,39 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('RightSemi '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"b" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightSemi3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightSemi3Str.yql
new file mode 100644
index 0000000000..951e1d462b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullRightSemi3Str.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Full
+ '('RightSemi '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"b" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"b.key") (Member row '"b.subkey") (Member row '"c.key") (Member row '"c.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfStr.yql
new file mode 100644
index 0000000000..1d50eb5959
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Full '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnNoOpt1Opt2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnNoOpt1Opt2Str.yql
new file mode 100644
index 0000000000..af309a36eb
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnNoOpt1Opt2Str.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(table 'a) '(tableOpt3 'b) '('Full '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnOpt1NoOpt2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnOpt1NoOpt2Str.yql
new file mode 100644
index 0000000000..536807ec3d
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnOpt1NoOpt2Str.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(table 'b) '('Full '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnOpt1Opt2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnOpt1Opt2Str.yql
new file mode 100644
index 0000000000..cae4788bf3
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnOpt1Opt2Str.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(tableOpt3 'b) '('Full '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnOptPartial1OptPartial2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnOptPartial1OptPartial2Str.yql
new file mode 100644
index 0000000000..08748168f6
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnOptPartial1OptPartial2Str.yql
@@ -0,0 +1,29 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt1a (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Member row 'subkey))
+ '('value (Member row 'value))
+ ))
+)))))
+
+(let tableOpt1b (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Member row 'key))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Member row 'value))
+ ))
+)))))
+
+(let join (EquiJoin '(tableOpt1a 'a) '(tableOpt1b 'b) '('Full '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnStr.yql
new file mode 100644
index 0000000000..8f7d2e40d2
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiFullSelfTwoColumnStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Full '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerCross3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerCross3OptStr.yql
new file mode 100644
index 0000000000..9f014d1580
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerCross3OptStr.yql
@@ -0,0 +1,37 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Cross '"a" '"b" '() '() '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerCross3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerCross3Str.yql
new file mode 100644
index 0000000000..b9c69bf087
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerCross3Str.yql
@@ -0,0 +1,23 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Cross '"a" '"b" '() '() '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerDiffIntTypes.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerDiffIntTypes.yql
new file mode 100644
index 0000000000..6d7b8198a6
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerDiffIntTypes.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableKVInt64 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Int64) (Int64 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Member row 'value))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Member row 'key))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableKVInt64 'a) '(tableKVInt 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerExclusion3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerExclusion3OptStr.yql
new file mode 100644
index 0000000000..7f144be37f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerExclusion3OptStr.yql
@@ -0,0 +1,38 @@
+# ignore runonopt plan diff
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Exclusion '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerExclusion3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerExclusion3Str.yql
new file mode 100644
index 0000000000..769cfb1657
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerExclusion3Str.yql
@@ -0,0 +1,23 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Exclusion '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerFull3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerFull3OptStr.yql
new file mode 100644
index 0000000000..5b0febe8af
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerFull3OptStr.yql
@@ -0,0 +1,37 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Full '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerFull3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerFull3Str.yql
new file mode 100644
index 0000000000..b2436aff7f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerFull3Str.yql
@@ -0,0 +1,23 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Full '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerInner3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerInner3OptStr.yql
new file mode 100644
index 0000000000..0c12e21175
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerInner3OptStr.yql
@@ -0,0 +1,37 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerInner3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerInner3Str.yql
new file mode 100644
index 0000000000..598c2ef4ec
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerInner3Str.yql
@@ -0,0 +1,23 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerInner3StrRename.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerInner3StrRename.yql
new file mode 100644
index 0000000000..a3258f553c
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerInner3StrRename.yql
@@ -0,0 +1,24 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '())
+ '('('rename '"a.key" 'col1) '('rename '"b.subkey" '"") '('rename '"c.value" 'ccc))))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeft3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeft3OptStr.yql
new file mode 100644
index 0000000000..be7f6267c8
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeft3OptStr.yql
@@ -0,0 +1,37 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Left '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeft3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeft3Str.yql
new file mode 100644
index 0000000000..03aa454da5
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeft3Str.yql
@@ -0,0 +1,23 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Left '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftOnly3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftOnly3OptStr.yql
new file mode 100644
index 0000000000..5ec5cd9a3f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftOnly3OptStr.yql
@@ -0,0 +1,38 @@
+# ignore runonopt plan diff
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('LeftOnly '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftOnly3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftOnly3Str.yql
new file mode 100644
index 0000000000..a081fd1505
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftOnly3Str.yql
@@ -0,0 +1,23 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('LeftOnly '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftSemi3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftSemi3OptStr.yql
new file mode 100644
index 0000000000..eebaf0acbd
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftSemi3OptStr.yql
@@ -0,0 +1,37 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('LeftSemi '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftSemi3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftSemi3Str.yql
new file mode 100644
index 0000000000..4b40b0c009
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerLeftSemi3Str.yql
@@ -0,0 +1,23 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('LeftSemi '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerOptDiffIntTypes.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerOptDiffIntTypes.yql
new file mode 100644
index 0000000000..8a259534c3
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerOptDiffIntTypes.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableKVInt64 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Int64))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Member row 'value))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Member row 'key))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let join (EquiJoin '(tableKVInt64 'a) '(tableKVInt 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerOptDiffIntTypesTwoColumn.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerOptDiffIntTypesTwoColumn.yql
new file mode 100644
index 0000000000..9abc122fd9
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerOptDiffIntTypesTwoColumn.yql
@@ -0,0 +1,25 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableKVInt64 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Int64))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Member row 'value))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Member row 'key))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let join (EquiJoin '(tableKVInt64 'a) '(tableKVInt 'b) '('Inner '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRight3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRight3OptStr.yql
new file mode 100644
index 0000000000..b4b825991e
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRight3OptStr.yql
@@ -0,0 +1,37 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Right '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRight3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRight3Str.yql
new file mode 100644
index 0000000000..4e11a1b8c0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRight3Str.yql
@@ -0,0 +1,23 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Right '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightOnly3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightOnly3OptStr.yql
new file mode 100644
index 0000000000..2bf637ce0d
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightOnly3OptStr.yql
@@ -0,0 +1,38 @@
+# ignore runonopt plan diff
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('RightOnly '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"b" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightOnly3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightOnly3Str.yql
new file mode 100644
index 0000000000..f1f3eec7ac
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightOnly3Str.yql
@@ -0,0 +1,23 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('RightOnly '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"b" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightSemi3OptStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightSemi3OptStr.yql
new file mode 100644
index 0000000000..6e5d4d95d0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightSemi3OptStr.yql
@@ -0,0 +1,37 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('RightSemi '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"b" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightSemi3Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightSemi3Str.yql
new file mode 100644
index 0000000000..808c44795b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerRightSemi3Str.yql
@@ -0,0 +1,23 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('RightSemi '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"b" '"key") '('"c" '"key") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfIntSameDiff.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfIntSameDiff.yql
new file mode 100644
index 0000000000..de061d0050
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfIntSameDiff.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '666)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '777)))
+ ))
+)))))
+(let tableKVInt1 (Take tableKVInt (Uint64 '6)))
+(let tableKVInt2 (Take tableKVInt (Uint64 '6)))
+(let join (EquiJoin '(tableKVInt1 'a) '(tableKVInt2 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfIntTakeDiff.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfIntTakeDiff.yql
new file mode 100644
index 0000000000..479d476017
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfIntTakeDiff.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '666)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '777)))
+ ))
+)))))
+(let tableKVInt1 (Take tableKVInt (Uint64 '6)))
+(let tableKVInt2 (Take tableKVInt (Uint64 '7)))
+(let join (EquiJoin '(tableKVInt1 'a) '(tableKVInt2 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfStr.yql
new file mode 100644
index 0000000000..9de2396e4d
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfStr.yql
@@ -0,0 +1,12 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfStrRename.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfStrRename.yql
new file mode 100644
index 0000000000..932539b39a
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfStrRename.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '())
+ '('('rename '"a.key" 'col1) '('rename '"b.subkey" '""))))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.subkey") (Member row '"a.value"))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnNoOpt1Opt2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnNoOpt1Opt2Str.yql
new file mode 100644
index 0000000000..d02d26aafb
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnNoOpt1Opt2Str.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(table 'a) '(tableOpt3 'b) '('Inner '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1NoOpt2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1NoOpt2Str.yql
new file mode 100644
index 0000000000..168fab831b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1NoOpt2Str.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(table 'b) '('Inner '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2Str.yql
new file mode 100644
index 0000000000..110a3b617b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2Str.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(tableOpt3 'b) '('Inner '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasOne1.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasOne1.yql
new file mode 100644
index 0000000000..5a9f9ca659
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasOne1.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let tableOpt3a (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('a.key (Just (Member row 'key)))
+ '('a.subkey (Just (Member row 'subkey)))
+ '('a.value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3a '('a)) '(tableOpt3 'b) '('Inner '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasOne12.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasOne12.yql
new file mode 100644
index 0000000000..0d5b7d1601
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasOne12.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3a (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('a.key (Just (Member row 'key)))
+ '('a.subkey (Just (Member row 'subkey)))
+ '('a.value (Just (Member row 'value)))
+ ))
+)))))
+(let tableOpt3b (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('b.key (Just (Member row 'key)))
+ '('b.subkey (Just (Member row 'subkey)))
+ '('b.value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3a '('a)) '(tableOpt3b '('b)) '('Inner '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasOne2.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasOne2.yql
new file mode 100644
index 0000000000..5d15a2bab8
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasOne2.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let tableOpt3b (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('b.key (Just (Member row 'key)))
+ '('b.subkey (Just (Member row 'subkey)))
+ '('b.value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(tableOpt3b '('b)) '('Inner '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasTwo.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasTwo.yql
new file mode 100644
index 0000000000..4c2225f7c5
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOpt1Opt2StrAliasTwo.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3a (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('a.key (Just (Member row 'key)))
+ '('a.subkey (Just (Member row 'subkey)))
+ '('c.value (Just (Member row 'value)))
+ ))
+)))))
+(let tableOpt3b (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('d.key (Just (Member row 'key)))
+ '('b.subkey (Just (Member row 'subkey)))
+ '('b.value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3a '('a 'c)) '(tableOpt3b '('b 'd)) '('Inner '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.value") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOptPartial1OptPartial2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOptPartial1OptPartial2Str.yql
new file mode 100644
index 0000000000..c6d7543ed3
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnOptPartial1OptPartial2Str.yql
@@ -0,0 +1,29 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt1a (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Member row 'subkey))
+ '('value (Member row 'value))
+ ))
+)))))
+
+(let tableOpt1b (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Member row 'key))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Member row 'value))
+ ))
+)))))
+
+(let join (EquiJoin '(tableOpt1a 'a) '(tableOpt1b 'b) '('Inner '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnStr.yql
new file mode 100644
index 0000000000..7444baa207
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiInnerSelfTwoColumnStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Inner '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U32.cfg b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U32.cfg
new file mode 100644
index 0000000000..27d3c78b8e
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U32.cfg
@@ -0,0 +1,4 @@
+res result.txt
+file joins.yql DoAllJoinsExceptCross.yql.txt
+in InputInt8 InputInt8.txt
+in InputUint32 InputUint32.txt
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U32.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U32.yql
new file mode 100644
index 0000000000..c07a92aa2a
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U32.yql
@@ -0,0 +1,9 @@
+(
+
+(library "joins.yql")
+(import join_module '"joins.yql")
+
+(let world (Apply (bind join_module 'doAllJoinsExceptCross) world 'InputInt8 'InputUint32))
+
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U8.cfg b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U8.cfg
new file mode 100644
index 0000000000..a4a0bb2fd7
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U8.cfg
@@ -0,0 +1,6 @@
+res result.txt
+file joins.yql DoAllJoinsExceptCross.yql.txt
+in InputInt8 InputInt8.txt
+in InputInt8Opt InputInt8Opt.txt
+in InputUint8 InputUint8.txt
+in InputUint8Opt InputUint8Opt.txt
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U8.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U8.yql
new file mode 100644
index 0000000000..8fdfeda61a
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertCommonI8U8.yql
@@ -0,0 +1,12 @@
+(
+
+(library "joins.yql")
+(import join_module '"joins.yql")
+
+(let world (Apply (bind join_module 'doAllJoinsExceptCross) world 'InputInt8 'InputUint8))
+(let world (Apply (bind join_module 'doAllJoinsExceptCross) world 'InputInt8Opt 'InputUint8))
+(let world (Apply (bind join_module 'doAllJoinsExceptCross) world 'InputInt8 'InputUint8Opt))
+(let world (Apply (bind join_module 'doAllJoinsExceptCross) world 'InputInt8Opt 'InputUint8Opt))
+
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U32.cfg b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U32.cfg
new file mode 100644
index 0000000000..27d3c78b8e
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U32.cfg
@@ -0,0 +1,4 @@
+res result.txt
+file joins.yql DoAllJoinsExceptCross.yql.txt
+in InputInt8 InputInt8.txt
+in InputUint32 InputUint32.txt
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U32.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U32.yql
new file mode 100644
index 0000000000..f24772569c
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U32.yql
@@ -0,0 +1,11 @@
+(
+
+(library "joins.yql")
+(import join_module '"joins.yql")
+
+(let world (Configure! world (DataSource '"yt" '"$all") '"Attr" '"mapjoinlimit" '"1m"))
+
+(let world (Apply (bind join_module 'doAllJoinsExceptCross) world 'InputInt8 'InputUint32))
+
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U8.cfg b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U8.cfg
new file mode 100644
index 0000000000..a4a0bb2fd7
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U8.cfg
@@ -0,0 +1,6 @@
+res result.txt
+file joins.yql DoAllJoinsExceptCross.yql.txt
+in InputInt8 InputInt8.txt
+in InputInt8Opt InputInt8Opt.txt
+in InputUint8 InputUint8.txt
+in InputUint8Opt InputUint8Opt.txt
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U8.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U8.yql
new file mode 100644
index 0000000000..54c482a624
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiJoinConvertMapI8U8.yql
@@ -0,0 +1,14 @@
+(
+
+(library "joins.yql")
+(import join_module '"joins.yql")
+
+(let world (Configure! world (DataSource '"yt" '"$all") '"Attr" '"mapjoinlimit" '"1m"))
+
+(let world (Apply (bind join_module 'doAllJoinsExceptCross) world 'InputInt8 'InputUint8))
+(let world (Apply (bind join_module 'doAllJoinsExceptCross) world 'InputInt8Opt 'InputUint8))
+(let world (Apply (bind join_module 'doAllJoinsExceptCross) world 'InputInt8 'InputUint8Opt))
+(let world (Apply (bind join_module 'doAllJoinsExceptCross) world 'InputInt8Opt 'InputUint8Opt))
+
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftOnlySelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftOnlySelfStr.yql
new file mode 100644
index 0000000000..a7593fde40
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftOnlySelfStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('LeftOnly '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfStr.yql
new file mode 100644
index 0000000000..d589fcda91
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Left '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnNoOpt1Opt2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnNoOpt1Opt2Str.yql
new file mode 100644
index 0000000000..78921fa69b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnNoOpt1Opt2Str.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(table 'a) '(tableOpt3 'b) '('Left '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnOpt1NoOpt2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnOpt1NoOpt2Str.yql
new file mode 100644
index 0000000000..09a21c9a81
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnOpt1NoOpt2Str.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(table 'b) '('Left '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnOpt1Opt2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnOpt1Opt2Str.yql
new file mode 100644
index 0000000000..8f36e81eb5
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnOpt1Opt2Str.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(tableOpt3 'b) '('Left '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnOptPartial1OptPartial2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnOptPartial1OptPartial2Str.yql
new file mode 100644
index 0000000000..25e1eb9240
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnOptPartial1OptPartial2Str.yql
@@ -0,0 +1,29 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt1a (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Member row 'subkey))
+ '('value (Member row 'value))
+ ))
+)))))
+
+(let tableOpt1b (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Member row 'key))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Member row 'value))
+ ))
+)))))
+
+(let join (EquiJoin '(tableOpt1a 'a) '(tableOpt1b 'b) '('Left '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnStr.yql
new file mode 100644
index 0000000000..c644c56a26
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSelfTwoColumnStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Left '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSemiSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSemiSelfStr.yql
new file mode 100644
index 0000000000..e9aaf3442f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiLeftSemiSelfStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('LeftSemi '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12FullSelfInt.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12FullSelfInt.yql
new file mode 100644
index 0000000000..5409c45d54
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12FullSelfInt.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOptKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Uint32))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableOptKVInt 'a) '(tableOptKVInt 'b) '('Full '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12FullSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12FullSelfStr.yql
new file mode 100644
index 0000000000..64ba1df974
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12FullSelfStr.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(tableOpt3 'b) '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12InnerSelfInt.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12InnerSelfInt.yql
new file mode 100644
index 0000000000..ed5b9c6896
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12InnerSelfInt.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOptKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Uint32))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableOptKVInt 'a) '(tableOptKVInt 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12InnerSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12InnerSelfStr.yql
new file mode 100644
index 0000000000..9ed83ad59e
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12InnerSelfStr.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(tableOpt3 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12LeftSelfInt.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12LeftSelfInt.yql
new file mode 100644
index 0000000000..4896831f5a
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12LeftSelfInt.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOptKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Uint32))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableOptKVInt 'a) '(tableOptKVInt 'b) '('Left '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12LeftSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12LeftSelfStr.yql
new file mode 100644
index 0000000000..c7d3ee062d
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12LeftSelfStr.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(tableOpt3 'b) '('Left '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12RightSelfInt.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12RightSelfInt.yql
new file mode 100644
index 0000000000..69e10681b2
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12RightSelfInt.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOptKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Uint32))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableOptKVInt 'a) '(tableOptKVInt 'b) '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12RightSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12RightSelfStr.yql
new file mode 100644
index 0000000000..64ba1df974
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey12RightSelfStr.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(tableOpt3 'b) '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1FullSelfInt.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1FullSelfInt.yql
new file mode 100644
index 0000000000..e664996232
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1FullSelfInt.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOptKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Uint32))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableOptKVInt 'a) '(tableKVInt 'b) '('Full '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1FullSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1FullSelfStr.yql
new file mode 100644
index 0000000000..24de4a45d8
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1FullSelfStr.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(table 'b) '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1InnerSelfInt.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1InnerSelfInt.yql
new file mode 100644
index 0000000000..c2340bb816
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1InnerSelfInt.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOptKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Uint32))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableOptKVInt 'a) '(tableKVInt 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1InnerSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1InnerSelfStr.yql
new file mode 100644
index 0000000000..9fe63d8ec2
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1InnerSelfStr.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(table 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1LeftSelfInt.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1LeftSelfInt.yql
new file mode 100644
index 0000000000..4cfb26b64e
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1LeftSelfInt.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOptKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Uint32))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableOptKVInt 'a) '(tableKVInt 'b) '('Left '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1LeftSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1LeftSelfStr.yql
new file mode 100644
index 0000000000..5fa76d8942
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1LeftSelfStr.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(table 'b) '('Left '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1RightSelfInt.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1RightSelfInt.yql
new file mode 100644
index 0000000000..fed99eefc5
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1RightSelfInt.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOptKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Uint32))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableOptKVInt 'a) '(tableKVInt 'b) '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1RightSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1RightSelfStr.yql
new file mode 100644
index 0000000000..24de4a45d8
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey1RightSelfStr.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(table 'b) '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2FullSelfInt.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2FullSelfInt.yql
new file mode 100644
index 0000000000..02b042ac3a
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2FullSelfInt.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOptKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Uint32))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableKVInt 'a) '(tableOptKVInt 'b) '('Full '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2FullSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2FullSelfStr.yql
new file mode 100644
index 0000000000..ba2798678f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2FullSelfStr.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(table 'a) '(tableOpt3 'b) '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2InnerSelfInt.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2InnerSelfInt.yql
new file mode 100644
index 0000000000..435fdc1a9c
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2InnerSelfInt.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOptKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Uint32))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableKVInt 'a) '(tableOptKVInt 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2InnerSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2InnerSelfStr.yql
new file mode 100644
index 0000000000..d61db9da69
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2InnerSelfStr.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(table 'a) '(tableOpt3 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2LeftSelfInt.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2LeftSelfInt.yql
new file mode 100644
index 0000000000..924287c0f9
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2LeftSelfInt.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOptKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Uint32))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableKVInt 'a) '(tableOptKVInt 'b) '('Left '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2LeftSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2LeftSelfStr.yql
new file mode 100644
index 0000000000..3d1c3605fc
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2LeftSelfStr.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(table 'a) '(tableOpt3 'b) '('Left '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2RightSelfInt.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2RightSelfInt.yql
new file mode 100644
index 0000000000..a2a085a722
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2RightSelfInt.yql
@@ -0,0 +1,27 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOptKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (FromString (Member row 'key) 'Uint32))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (FromString (Member row 'value) 'Uint32))
+ ))
+)))))
+(let tableKVInt (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Coalesce (FromString (Member row 'key) 'Uint32) (Uint32 '888)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Coalesce (FromString (Member row 'value) 'Uint32) (Uint32 '999)))
+ ))
+)))))
+(let join (EquiJoin '(tableKVInt 'a) '(tableOptKVInt 'b) '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2RightSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2RightSelfStr.yql
new file mode 100644
index 0000000000..ba2798678f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiOptKey2RightSelfStr.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(table 'a) '(tableOpt3 'b) '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightOnlySelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightOnlySelfStr.yql
new file mode 100644
index 0000000000..b528c14467
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightOnlySelfStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('RightOnly '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfStr.yql
new file mode 100644
index 0000000000..76b372e52f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnNoOpt1Opt2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnNoOpt1Opt2Str.yql
new file mode 100644
index 0000000000..155db305bc
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnNoOpt1Opt2Str.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(table 'a) '(tableOpt3 'b) '('Right '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnOpt1NoOpt2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnOpt1NoOpt2Str.yql
new file mode 100644
index 0000000000..dc0928a52c
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnOpt1NoOpt2Str.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(table 'b) '('Right '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnOpt1Opt2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnOpt1Opt2Str.yql
new file mode 100644
index 0000000000..0d550e7db3
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnOpt1Opt2Str.yql
@@ -0,0 +1,20 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt3 (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))
+ ))
+)))))
+(let join (EquiJoin '(tableOpt3 'a) '(tableOpt3 'b) '('Right '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnOptPartial1OptPartial2Str.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnOptPartial1OptPartial2Str.yql
new file mode 100644
index 0000000000..9d539854bd
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnOptPartial1OptPartial2Str.yql
@@ -0,0 +1,29 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let tableOpt1a (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Member row 'subkey))
+ '('value (Member row 'value))
+ ))
+)))))
+
+(let tableOpt1b (Map table (lambda '(row) (block '(
+ (return (AsStruct
+ '('key (Member row 'key))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Member row 'value))
+ ))
+)))))
+
+(let join (EquiJoin '(tableOpt1a 'a) '(tableOpt1b 'b) '('Right '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnStr.yql
new file mode 100644
index 0000000000..5a6ff8cd0f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSelfTwoColumnStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Right '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true) (Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey") (Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSemiSelfStr.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSemiSelfStr.yql
new file mode 100644
index 0000000000..71c2d26461
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/EquiRightSemiSelfStr.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('RightSemi '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"b.key") (Member row '"b.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/ExtractRenameFromFlatMapOverJoin.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/ExtractRenameFromFlatMapOverJoin.yql
new file mode 100644
index 0000000000..33f059a964
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/ExtractRenameFromFlatMapOverJoin.yql
@@ -0,0 +1,42 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let list1 (AsList
+ (AsStruct '('key1 (Int32 '1)) '('value1 (String 'A)))
+ (AsStruct '('key1 (Int32 '7)) '('value1 (String 'B)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'C)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'D)))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2 (Int32 '9)) '('value2 (String 'Z)))
+ (AsStruct '('key2 (Int32 '4)) '('value2 (String 'Y)))
+ (AsStruct '('key2 (Int32 '3)) '('value2 (String 'X)))
+ (AsStruct '('key2 (Int32 '4)) '('value2 (String 'W)))
+ (AsStruct '('key2 (Int32 '8)) '('value2 (String 'V)))
+))
+
+(let joinInner (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let list (Map joinInner (lambda '(x) (block '(
+ (return (AsStruct
+ '('"a.key1" (Member x '"a.key1"))
+ '('"q" (Member x '"a.value1"))
+ '('"f.value2" (Member x '"b.value2"))
+ ))
+)))))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) list '('('type))))
+
+(let joinInner2 (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key1) '('b 'key2) '())
+ '('('rename '"a.key1" 'z) '('rename '"b.key2" '""))))
+(let list2 (Map joinInner2 (lambda '(x) (block '(
+ (return (AsStruct
+ '('"yy" (Member x '"z"))
+ '('"q" (Member x '"b.value2"))
+ ))
+)))))
+
+(let world (Write! world res_sink (Key) list2 '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenInner.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenInner.yql
new file mode 100644
index 0000000000..dee596e70a
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenInner.yql
@@ -0,0 +1,30 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey1 (Just (Member item 'subkey)))
+ '('value1 (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey2 (Just (Member item 'subkey)))
+ '('value2 (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '('('flatten))))
+
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"key") (Member row '"subkey1"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenInner3.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenInner3.yql
new file mode 100644
index 0000000000..ded633225d
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenInner3.yql
@@ -0,0 +1,39 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey1 (Just (Member item 'subkey)))
+ '('value1 (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey2 (Just (Member item 'subkey)))
+ '('value2 (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey3 (Just (Member item 'subkey)))
+ '('value3 (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key" ) '())
+ '('('flatten))))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenInnerTwoColumns.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenInnerTwoColumns.yql
new file mode 100644
index 0000000000..4cbe3482ed
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenInnerTwoColumns.yql
@@ -0,0 +1,30 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value1 (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value2 (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+ '('Inner '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"key" '"b" '"subkey") '())
+ '('('flatten))))
+
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"key") (Member row '"subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeft.cfg b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeft.cfg
new file mode 100644
index 0000000000..8402f5cd5f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeft.cfg
@@ -0,0 +1,3 @@
+res result.txt
+in Input4 input4.txt
+in Input5 input5.txt
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeft.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeft.yql
new file mode 100644
index 0000000000..9533ee9fb8
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeft.yql
@@ -0,0 +1,26 @@
+(
+ (let data.source (DataSource 'yt 'plato))
+ (let data.sink (DataSink 'yt 'plato))
+ (let input_left (Read! world data.source (Key '('table (String 'Input4))) (Void) '()))
+ (let world (Left! input_left))
+ (let input_left (Right! input_left))
+
+ (let input_right (Read! world data.source (Key '('table (String 'Input5))) (Void) '()))
+ (let world (Left! input_right))
+ (let input_right (Right! input_right))
+
+ (let output (EquiJoin '((RemoveSystemMembers input_left) 'left) '((RemoveSystemMembers input_right) 'right)
+ '('Left 'left 'right '('left 'id) '('right 'id) '()) '('('flatten))
+ ))
+
+ (let output (Map output (lambda '(item) (block '(
+ (let item (AddMember item 'val (String '"")))
+ (return item)
+ )))))
+
+ (let res_sink (DataSink 'result))
+ (let world (Write! world res_sink (Key) output '('('type))))
+ (let world (Commit! world res_sink))
+
+ (return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeftSemi.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeftSemi.yql
new file mode 100644
index 0000000000..2b3166643e
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeftSemi.yql
@@ -0,0 +1,30 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey1 (Just (Member item 'subkey)))
+ '('value1 (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey2 (Just (Member item 'subkey)))
+ '('value2 (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+ '('LeftSemi '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '('('flatten))))
+
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"key") (Member row '"subkey1"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeftSemi3.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeftSemi3.yql
new file mode 100644
index 0000000000..4572699337
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/FlattenLeftSemi3.yql
@@ -0,0 +1,39 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey1 (Just (Member item 'subkey)))
+ '('value1 (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey2 (Just (Member item 'subkey)))
+ '('value2 (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+(let table3 (Map table3 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey3 (Just (Member item 'subkey)))
+ '('value3 (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b) '(table3 'c)
+ '('Inner
+ '('LeftSemi '"a" '"b" '('"a" '"key") '('"b" '"key" ) '())
+ '"c" '('"a" '"key") '('"c" '"key" ) '())
+ '('('flatten))))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/HintLeftSmallInnerJoin.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintLeftSmallInnerJoin.yql
new file mode 100644
index 0000000000..d0c8c821b6
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintLeftSmallInnerJoin.yql
@@ -0,0 +1,30 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (String '1)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '(
+ '('left 'small)
+ ))
+ '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/HintLeftSmallInnerJoinFat.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintLeftSmallInnerJoinFat.yql
new file mode 100644
index 0000000000..94718f84d1
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintLeftSmallInnerJoinFat.yql
@@ -0,0 +1,30 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (String '1)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (String '800)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '(
+ '('left 'small)
+ ))
+ '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/HintLeftUniqueRightMap.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintLeftUniqueRightMap.yql
new file mode 100644
index 0000000000..d77b848dc7
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintLeftUniqueRightMap.yql
@@ -0,0 +1,29 @@
+(
+(let world (Configure! world (DataSource '"yt" '"$all") '"Attr" '"mapjoinlimit" '"1m"))
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+ '('Right '"a" '"b" '('"a" '"key") '('"b" '"key" ) '('('left 'unique)))
+ '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightSmallInnerJoin.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightSmallInnerJoin.yql
new file mode 100644
index 0000000000..6e842ae76b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightSmallInnerJoin.yql
@@ -0,0 +1,30 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (String '1)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '(
+ '('right 'small)
+ ))
+ '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightSmallInnerJoinFat.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightSmallInnerJoinFat.yql
new file mode 100644
index 0000000000..c9e4a7e0f6
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightSmallInnerJoinFat.yql
@@ -0,0 +1,30 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (String '800)))
+ '('subkey (Just (String '1)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '(
+ '('right 'small)
+ ))
+ '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightUniqueInnerMap.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightUniqueInnerMap.yql
new file mode 100644
index 0000000000..16a90e3314
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightUniqueInnerMap.yql
@@ -0,0 +1,29 @@
+(
+(let world (Configure! world (DataSource '"yt" '"$all") '"Attr" '"mapjoinlimit" '"1m"))
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"key" ) '('('right 'unique)))
+ '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightUniqueLeftMap.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightUniqueLeftMap.yql
new file mode 100644
index 0000000000..a3e4e456ea
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightUniqueLeftMap.yql
@@ -0,0 +1,29 @@
+(
+(let world (Configure! world (DataSource '"yt" '"$all") '"Attr" '"mapjoinlimit" '"1m"))
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+ '('Left '"a" '"b" '('"a" '"key") '('"b" '"key" ) '('('right 'unique)))
+ '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightUniqueLeftSemiShardedMap.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightUniqueLeftSemiShardedMap.yql
new file mode 100644
index 0000000000..c726a4c417
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/HintRightUniqueLeftSemiShardedMap.yql
@@ -0,0 +1,30 @@
+(
+(let world (Configure! world (DataSource '"yt" '"$all") '"Attr" '"mapjoinlimit" '"150"))
+(let world (Configure! world (DataSource '"yt" '"$all") '"Attr" '"mapjoinshardcount" '"2"))
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let table1 (Map table1 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let table2 (Map table2 (lambda '(item) (AsStruct
+ '('key (Just (Member item 'key)))
+ '('subkey (Just (Member item 'subkey)))
+ '('value (Just (Member item 'value)))))))
+
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+ '('LeftSemi '"a" '"b" '('"a" '"key") '('"b" '"key" ) '('('right 'unique)))
+ '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InOutSettings.cfg b/yql/essentials/tests/s-expressions/suites/EquiJoin/InOutSettings.cfg
new file mode 100644
index 0000000000..3673712415
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InOutSettings.cfg
@@ -0,0 +1,3 @@
+res result.txt
+in Input InputSelf.txt
+out Output output.txt
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InOutSettings.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/InOutSettings.yql
new file mode 100644
index 0000000000..707b389f4b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InOutSettings.yql
@@ -0,0 +1,26 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let mr_sink (DataSink 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let tableLeft (Right! x))
+
+(let sorted (Sort tableLeft (Bool 'true) (lambda '(item) (Member item '"key"))))
+(let world (Write! world mr_sink (Key '('table (String 'Output))) sorted '('('mode 'append))))
+(let world (Commit! world mr_sink))
+
+(let x (Read! world mr_source (Key '('table (String '"Output"))) (Void) '()))
+(let world (Left! x))
+(let tableRight (Right! x))
+
+(let tableLeft (Take tableLeft (Uint64 '3)))
+(let tableRight (Filter tableRight (lambda '(item) (Coalesce (< (Member item '"key") (String '"100")) (Bool 'false)))))
+
+(let join (EquiJoin '(tableLeft 'a) '(tableRight 'b) '('Inner '"a" '"b" '('"a" '"value") '('"b" '"value" ) '()) '()))
+(let join (Sort join (Bool 'true) (lambda '(item) (Member item '"a.key"))))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (Take join (Uint64 '2)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8.txt
new file mode 100644
index 0000000000..c059f46f5b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8.txt
@@ -0,0 +1,5 @@
+{"key"=-1;"value"="Int8_a"};
+{"key"=127;"value"="Int8_b"};
+{"key"=0;"value"="Int8_c"};
+{"key"=1;"value"="Int8_d"};
+{"key"=2;"value"="Int8_e"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8.txt.attr
new file mode 100644
index 0000000000..d89274ff75
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8.txt.attr
@@ -0,0 +1,6 @@
+{"_yql_row_spec"={
+ "Type"=["StructType";[
+ ["key";["DataType";"Int8"]];
+ ["value";["DataType";"String"]]]
+ ];
+}}
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8Opt.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8Opt.txt
new file mode 100644
index 0000000000..53ffddbb48
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8Opt.txt
@@ -0,0 +1,5 @@
+{"key"=-1;"value"="Int8Opt_a"};
+{"key"=127;"value"="Int8Opt_b"};
+{"key"=0;"value"="Int8Opt_c"};
+{"key"=1;"value"="Int8Opt_d"};
+{"key"=2;"value"="Int8Opt_e"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8Opt.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8Opt.txt.attr
new file mode 100644
index 0000000000..cbb7ba3fd9
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputInt8Opt.txt.attr
@@ -0,0 +1,6 @@
+{"_yql_row_spec"={
+ "Type"=["StructType";[
+ ["key";["OptionalType";["DataType";"Int8"]]];
+ ["value";["DataType";"String"]]]
+ ];
+}}
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf.txt
new file mode 100644
index 0000000000..8ed0317c19
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf.txt
@@ -0,0 +1,8 @@
+{"key"="075";"subkey"=".";"value"="abc"};
+{"key"="911";"subkey"=".";"value"="kkk"};
+{"key"="023";"subkey"=".";"value"="075"};
+{"key"="527";"subkey"=".";"value"="bbb"};
+{"key"="037";"subkey"=".";"value"="ddd"};
+{"key"="761";"subkey"=".";"value"="023"};
+{"key"="200";"subkey"=".";"value"="qqq"};
+{"key"="150";"subkey"=".";"value"="zzz"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf.txt.attr
new file mode 100644
index 0000000000..b6100e5fd0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf.txt.attr
@@ -0,0 +1,30 @@
+{
+ "_yql_row_spec" = {
+ "Type" = [
+ "StructType";
+ [
+ [
+ "key";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "subkey";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "value";
+ [
+ "DataType";
+ "String"
+ ]
+ ]
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf2.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf2.txt
new file mode 100644
index 0000000000..cf8cf7a1e9
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf2.txt
@@ -0,0 +1,8 @@
+{"key"="075";"subkey"="1";"value"="7"};
+{"key"="x911";"subkey"="2";"value"="6"};
+{"key"="x023";"subkey"="3";"value"="3"};
+{"key"="x527";"subkey"="4";"value"="x023"};
+{"key"="x037";"subkey"="5";"value"="075"};
+{"key"="x761";"subkey"="6";"value"="2"};
+{"key"="x200";"subkey"="7";"value"="075"};
+{"key"="150";"subkey"="8";"value"="2"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf2.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf2.txt.attr
new file mode 100644
index 0000000000..b6100e5fd0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputSelf2.txt.attr
@@ -0,0 +1,30 @@
+{
+ "_yql_row_spec" = {
+ "Type" = [
+ "StructType";
+ [
+ [
+ "key";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "subkey";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "value";
+ [
+ "DataType";
+ "String"
+ ]
+ ]
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint32.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint32.txt
new file mode 100644
index 0000000000..5508f63735
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint32.txt
@@ -0,0 +1,5 @@
+{"key"=255u;"value"="Uint32_a"};
+{"key"=383u;"value"="Uint32_b"};
+{"key"=0u;"value"="Uint32_c"};
+{"key"=1u;"value"="Uint32_d"};
+{"key"=2u;"value"="Uint32_e"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint32.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint32.txt.attr
new file mode 100644
index 0000000000..5ba9847c97
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint32.txt.attr
@@ -0,0 +1,6 @@
+{"_yql_row_spec"={
+ "Type"=["StructType";[
+ ["key";["DataType";"Uint32"]];
+ ["value";["DataType";"String"]]]
+ ];
+}}
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8.txt
new file mode 100644
index 0000000000..96864d084c
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8.txt
@@ -0,0 +1,5 @@
+{"key"=255u;"value"="Uint8_a"};
+{"key"=127u;"value"="Uint8_b"};
+{"key"=0u;"value"="Uint8_c"};
+{"key"=1u;"value"="Uint8_d"};
+{"key"=2u;"value"="Uint8_e"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8.txt.attr
new file mode 100644
index 0000000000..8d7e3bcc24
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8.txt.attr
@@ -0,0 +1,6 @@
+{"_yql_row_spec"={
+ "Type"=["StructType";[
+ ["key";["DataType";"Uint8"]];
+ ["value";["DataType";"String"]]]
+ ];
+}}
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8Opt.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8Opt.txt
new file mode 100644
index 0000000000..3468f1080f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8Opt.txt
@@ -0,0 +1,5 @@
+{"key"=255u;"value"="Uint8Opt_a"};
+{"key"=127u;"value"="Uint8Opt_b"};
+{"key"=0u;"value"="Uint8Opt_c"};
+{"key"=1u;"value"="Uint8Opt_d"};
+{"key"=2u;"value"="Uint8Opt_e"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8Opt.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8Opt.txt.attr
new file mode 100644
index 0000000000..e3b512108c
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/InputUint8Opt.txt.attr
@@ -0,0 +1,6 @@
+{"_yql_row_spec"={
+ "Type"=["StructType";[
+ ["key";["OptionalType";["DataType";"Uint8"]]];
+ ["value";["DataType";"String"]]]
+ ];
+}}
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem.yql
new file mode 100644
index 0000000000..59f07eb137
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem.yql
@@ -0,0 +1,42 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1 (Int32 '1)) '('value1 (String 'A)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'C)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'D)))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2 (Uint64 '2)) '('value2 (String 'U)))
+ (AsStruct '('key2 (Uint64 '4)) '('value2 (String 'Y)))
+ (AsStruct '('key2 (Uint64 '4)) '('value2 (String 'W)))
+))
+
+(let joinInner (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeft (EquiJoin '(list1 'a) '(list2 'b) '('Left 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRight (EquiJoin '(list1 'a) '(list2 'b) '('Right 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinFull (EquiJoin '(list1 'a) '(list2 'b) '('Full 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 'a) '(list2 'b) '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 'a) '(list2 'b) '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinExclusion (EquiJoin '(list1 'a) '(list2 'b) '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 'a) '(list2 'b) '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 'a) '(list2 'b) '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinCross (EquiJoin '(list1 'a) '(list2 'b) '('Cross 'a 'b '() '() '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinRightSemi '('('type))))
+(let world (Write! world res_sink (Key) joinCross '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem3.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem3.yql
new file mode 100644
index 0000000000..6245dd77bd
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem3.yql
@@ -0,0 +1,79 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1 (Int32 '1)) '('value1 (String 'A)))
+ (AsStruct '('key1 (Int32 '7)) '('value1 (String 'B)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'C)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'D)))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2 (Int32 '9)) '('value2 (String 'Z)))
+ (AsStruct '('key2 (Int32 '4)) '('value2 (String 'Y)))
+ (AsStruct '('key2 (Int32 '3)) '('value2 (String 'X)))
+ (AsStruct '('key2 (Int32 '4)) '('value2 (String 'W)))
+ (AsStruct '('key2 (Int32 '8)) '('value2 (String 'V)))
+))
+
+(let list3 (AsList
+ (AsStruct '('key3 (Int32 '1)) '('value3 (String 'G)))
+ (AsStruct '('key3 (Int32 '4)) '('value3 (String 'H)))
+ (AsStruct '('key3 (Int32 '2)) '('value3 (String 'I)))
+ (AsStruct '('key3 (Int32 '3)) '('value3 (String 'J)))
+ (AsStruct '('key3 (Int32 '3)) '('value3 (String 'K)))
+))
+
+(let joinInnerInner (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Inner '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerLeft (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Inner '('Left 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerRight (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Inner '('Right 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerFull (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Inner '('Full 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerLeftOnly (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Inner '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('a 'key1) '('c 'key3) '()) '()))
+(let joinInnerRightOnly (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Inner '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerExclusion (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Inner '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerLeftSemi (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Inner '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('a 'key1) '('c 'key3) '()) '()))
+(let joinInnerRightSemi (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Inner '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerCross (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Inner '('Cross 'a 'b '() '() '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+
+(let joinFullInner (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Full '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullLeft (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Full '('Left 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullRight (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Full '('Right 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullFull (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Full '('Full 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullLeftOnly (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Full '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('a 'key1) '('c 'key3) '()) '()))
+(let joinFullRightOnly (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Full '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullExclusion (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Full '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullLeftSemi (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Full '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('a 'key1) '('c 'key3) '()) '()))
+(let joinFullRightSemi (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Full '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullCross (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Full '('Cross 'a 'b '() '() '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+
+(let joinCrossCross (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Cross '('Cross 'a 'b '() '() '()) 'c '() '() '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInnerInner '('('type))))
+(let world (Write! world res_sink (Key) joinInnerLeft '('('type))))
+(let world (Write! world res_sink (Key) joinInnerRight '('('type))))
+(let world (Write! world res_sink (Key) joinInnerFull '('('type))))
+(let world (Write! world res_sink (Key) joinInnerLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinInnerRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinInnerExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinInnerLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinInnerRightSemi '('('type))))
+(let world (Write! world res_sink (Key) joinInnerCross '('('type))))
+
+(let world (Write! world res_sink (Key) joinFullInner '('('type))))
+(let world (Write! world res_sink (Key) joinFullLeft '('('type))))
+(let world (Write! world res_sink (Key) joinFullRight '('('type))))
+(let world (Write! world res_sink (Key) joinFullFull '('('type))))
+(let world (Write! world res_sink (Key) joinFullLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinFullRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinFullExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinFullLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinFullRightSemi '('('type))))
+(let world (Write! world res_sink (Key) joinFullCross '('('type))))
+
+(let world (Write! world res_sink (Key) joinCrossCross '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem3Alias12.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem3Alias12.yql
new file mode 100644
index 0000000000..0063b7b7ef
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem3Alias12.yql
@@ -0,0 +1,71 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('a.key1 (Int32 '1)) '('k.value1 (String 'A)))
+ (AsStruct '('a.key1 (Int32 '7)) '('k.value1 (String 'B)))
+ (AsStruct '('a.key1 (Int32 '4)) '('k.value1 (String 'C)))
+ (AsStruct '('a.key1 (Int32 '4)) '('k.value1 (String 'D)))
+))
+
+(let list2 (AsList
+ (AsStruct '('b.key2 (Int32 '9)) '('l.value2 (String 'Z)))
+ (AsStruct '('b.key2 (Int32 '4)) '('l.value2 (String 'Y)))
+ (AsStruct '('b.key2 (Int32 '3)) '('l.value2 (String 'X)))
+ (AsStruct '('b.key2 (Int32 '4)) '('l.value2 (String 'W)))
+ (AsStruct '('b.key2 (Int32 '8)) '('l.value2 (String 'V)))
+))
+
+(let list3 (AsList
+ (AsStruct '('c.key3 (Int32 '1)) '('m.value3 (String 'G)))
+ (AsStruct '('c.key3 (Int32 '4)) '('m.value3 (String 'H)))
+ (AsStruct '('c.key3 (Int32 '2)) '('m.value3 (String 'I)))
+ (AsStruct '('c.key3 (Int32 '3)) '('m.value3 (String 'J)))
+ (AsStruct '('c.key3 (Int32 '3)) '('m.value3 (String 'K)))
+))
+
+(let joinInnerInner (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Inner '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerLeft (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Inner '('Left 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerRight (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Inner '('Right 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerFull (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Inner '('Full 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerLeftOnly (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Inner '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('a 'key1) '('c 'key3) '()) '()))
+(let joinInnerRightOnly (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Inner '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerExclusion (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Inner '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinInnerLeftSemi (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Inner '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('a 'key1) '('c 'key3) '()) '()))
+(let joinInnerRightSemi (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Inner '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+
+(let joinFullInner (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Full '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullLeft (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Full '('Left 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullRight (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Full '('Right 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullFull (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Full '('Full 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullLeftOnly (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Full '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('a 'key1) '('c 'key3) '()) '()))
+(let joinFullRightOnly (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Full '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullExclusion (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Full '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+(let joinFullLeftSemi (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Full '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('a 'key1) '('c 'key3) '()) '()))
+(let joinFullRightSemi (EquiJoin '(list1 '('a 'k)) '(list2 '('b 'l)) '(list3 '('c 'm)) '('Full '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInnerInner '('('type))))
+(let world (Write! world res_sink (Key) joinInnerLeft '('('type))))
+(let world (Write! world res_sink (Key) joinInnerRight '('('type))))
+(let world (Write! world res_sink (Key) joinInnerFull '('('type))))
+(let world (Write! world res_sink (Key) joinInnerLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinInnerRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinInnerExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinInnerLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinInnerRightSemi '('('type))))
+
+(let world (Write! world res_sink (Key) joinFullInner '('('type))))
+(let world (Write! world res_sink (Key) joinFullLeft '('('type))))
+(let world (Write! world res_sink (Key) joinFullRight '('('type))))
+(let world (Write! world res_sink (Key) joinFullFull '('('type))))
+(let world (Write! world res_sink (Key) joinFullLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinFullRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinFullExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinFullLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinFullRightSemi '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem3Rename.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem3Rename.yql
new file mode 100644
index 0000000000..7807ba6e08
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMem3Rename.yql
@@ -0,0 +1,36 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1 (Int32 '1)) '('value1 (String 'A)))
+ (AsStruct '('key1 (Int32 '7)) '('value1 (String 'B)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'C)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'D)))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2 (Int32 '9)) '('value2 (String 'Z)))
+ (AsStruct '('key2 (Int32 '4)) '('value2 (String 'Y)))
+ (AsStruct '('key2 (Int32 '3)) '('value2 (String 'X)))
+ (AsStruct '('key2 (Int32 '4)) '('value2 (String 'W)))
+ (AsStruct '('key2 (Int32 '8)) '('value2 (String 'V)))
+))
+
+(let list3 (AsList
+ (AsStruct '('key3 (Int32 '1)) '('value3 (String 'G)))
+ (AsStruct '('key3 (Int32 '4)) '('value3 (String 'H)))
+ (AsStruct '('key3 (Int32 '2)) '('value3 (String 'I)))
+ (AsStruct '('key3 (Int32 '3)) '('value3 (String 'J)))
+ (AsStruct '('key3 (Int32 '3)) '('value3 (String 'K)))
+))
+
+(let joinInnerInner (EquiJoin '(list1 'a) '(list2 'b) '(list3 'c) '('Inner '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) 'c '('b 'key2) '('c 'key3) '())
+'('('rename '"a.key1" 'col1) '('rename '"b.value2" '"") '('rename '"c.key3" 'ccc))))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInnerInner '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasOne1.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasOne1.yql
new file mode 100644
index 0000000000..549fa2d302
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasOne1.yql
@@ -0,0 +1,43 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('a.key1 (Just (Int32 '1))) '('a.value1 (Just (String 'A))))
+ (AsStruct '('a.key1 (Just (Int32 '7))) '('a.value1 (Just (String 'B))))
+ (AsStruct '('a.key1 (Just (Int32 '4))) '('a.value1 (Just (String 'C))))
+ (AsStruct '('a.key1 (Just (Int32 '4))) '('a.value1 (Just (String 'D))))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2 (Just (Int32 '9))) '('value2 (Just (String 'Z))))
+ (AsStruct '('key2 (Just (Int32 '4))) '('value2 (Just (String 'Y))))
+ (AsStruct '('key2 (Just (Int32 '3))) '('value2 (Just (String 'X))))
+ (AsStruct '('key2 (Just (Int32 '4))) '('value2 (Just (String 'W))))
+ (AsStruct '('key2 (Just (Int32 '8))) '('value2 (Just (String 'V))))
+))
+
+(let joinInner (EquiJoin '(list1 '('a)) '(list2 'b) '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeft (EquiJoin '(list1 '('a)) '(list2 'b) '('Left 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRight (EquiJoin '(list1 '('a)) '(list2 'b) '('Right 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinFull (EquiJoin '(list1 '('a)) '(list2 'b) '('Full 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 '('a)) '(list2 'b) '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 '('a)) '(list2 'b) '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinExclusion (EquiJoin '(list1 '('a)) '(list2 'b) '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 '('a)) '(list2 'b) '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 '('a)) '(list2 'b) '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinRightSemi '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasOne12.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasOne12.yql
new file mode 100644
index 0000000000..50ee09cda0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasOne12.yql
@@ -0,0 +1,43 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('a.key1 (Just (Int32 '1))) '('a.value1 (Just (String 'A))))
+ (AsStruct '('a.key1 (Just (Int32 '7))) '('a.value1 (Just (String 'B))))
+ (AsStruct '('a.key1 (Just (Int32 '4))) '('a.value1 (Just (String 'C))))
+ (AsStruct '('a.key1 (Just (Int32 '4))) '('a.value1 (Just (String 'D))))
+))
+
+(let list2 (AsList
+ (AsStruct '('b.key2 (Just (Int32 '9))) '('b.value2 (Just (String 'Z))))
+ (AsStruct '('b.key2 (Just (Int32 '4))) '('b.value2 (Just (String 'Y))))
+ (AsStruct '('b.key2 (Just (Int32 '3))) '('b.value2 (Just (String 'X))))
+ (AsStruct '('b.key2 (Just (Int32 '4))) '('b.value2 (Just (String 'W))))
+ (AsStruct '('b.key2 (Just (Int32 '8))) '('b.value2 (Just (String 'V))))
+))
+
+(let joinInner (EquiJoin '(list1 '('a)) '(list2 '('b)) '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeft (EquiJoin '(list1 '('a)) '(list2 '('b)) '('Left 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRight (EquiJoin '(list1 '('a)) '(list2 '('b)) '('Right 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinFull (EquiJoin '(list1 '('a)) '(list2 '('b)) '('Full 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 '('a)) '(list2 '('b)) '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 '('a)) '(list2 '('b)) '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinExclusion (EquiJoin '(list1 '('a)) '(list2 '('b)) '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 '('a)) '(list2 '('b)) '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 '('a)) '(list2 '('b)) '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinRightSemi '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasOne2.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasOne2.yql
new file mode 100644
index 0000000000..374fafce96
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasOne2.yql
@@ -0,0 +1,43 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1 (Just (Int32 '1))) '('value1 (Just (String 'A))))
+ (AsStruct '('key1 (Just (Int32 '7))) '('value1 (Just (String 'B))))
+ (AsStruct '('key1 (Just (Int32 '4))) '('value1 (Just (String 'C))))
+ (AsStruct '('key1 (Just (Int32 '4))) '('value1 (Just (String 'D))))
+))
+
+(let list2 (AsList
+ (AsStruct '('b.key2 (Just (Int32 '9))) '('b.value2 (Just (String 'Z))))
+ (AsStruct '('b.key2 (Just (Int32 '4))) '('b.value2 (Just (String 'Y))))
+ (AsStruct '('b.key2 (Just (Int32 '3))) '('b.value2 (Just (String 'X))))
+ (AsStruct '('b.key2 (Just (Int32 '4))) '('b.value2 (Just (String 'W))))
+ (AsStruct '('b.key2 (Just (Int32 '8))) '('b.value2 (Just (String 'V))))
+))
+
+(let joinInner (EquiJoin '(list1 'a) '(list2 '('b)) '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeft (EquiJoin '(list1 'a) '(list2 '('b)) '('Left 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRight (EquiJoin '(list1 'a) '(list2 '('b)) '('Right 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinFull (EquiJoin '(list1 'a) '(list2 '('b)) '('Full 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 'a) '(list2 '('b)) '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 'a) '(list2 '('b)) '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinExclusion (EquiJoin '(list1 'a) '(list2 '('b)) '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 'a) '(list2 '('b)) '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 'a) '(list2 '('b)) '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinRightSemi '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasTwo12.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasTwo12.yql
new file mode 100644
index 0000000000..e9c47c9c76
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemAliasTwo12.yql
@@ -0,0 +1,43 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('a.key1 (Just (Int32 '1))) '('c.value1 (Just (String 'A))))
+ (AsStruct '('a.key1 (Just (Int32 '7))) '('c.value1 (Just (String 'B))))
+ (AsStruct '('a.key1 (Just (Int32 '4))) '('c.value1 (Just (String 'C))))
+ (AsStruct '('a.key1 (Just (Int32 '4))) '('c.value1 (Just (String 'D))))
+))
+
+(let list2 (AsList
+ (AsStruct '('b.key2 (Just (Int32 '9))) '('d.value2 (Just (String 'Z))))
+ (AsStruct '('b.key2 (Just (Int32 '4))) '('d.value2 (Just (String 'Y))))
+ (AsStruct '('b.key2 (Just (Int32 '3))) '('d.value2 (Just (String 'X))))
+ (AsStruct '('b.key2 (Just (Int32 '4))) '('d.value2 (Just (String 'W))))
+ (AsStruct '('b.key2 (Just (Int32 '8))) '('d.value2 (Just (String 'V))))
+))
+
+(let joinInner (EquiJoin '(list1 '('a 'c)) '(list2 '('b 'd)) '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeft (EquiJoin '(list1 '('a 'c)) '(list2 '('b 'd)) '('Left 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRight (EquiJoin '(list1 '('a 'c)) '(list2 '('b 'd)) '('Right 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinFull (EquiJoin '(list1 '('a 'c)) '(list2 '('b 'd)) '('Full 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 '('a 'c)) '(list2 '('b 'd)) '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 '('a 'c)) '(list2 '('b 'd)) '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinExclusion (EquiJoin '(list1 '('a 'c)) '(list2 '('b 'd)) '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 '('a 'c)) '(list2 '('b 'd)) '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 '('a 'c)) '(list2 '('b 'd)) '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinRightSemi '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemDiffIntTypes.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemDiffIntTypes.yql
new file mode 100644
index 0000000000..ef2ce92878
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemDiffIntTypes.yql
@@ -0,0 +1,43 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1 (Int32 '1)) '('value1 (String 'A)))
+ (AsStruct '('key1 (Int32 '7)) '('value1 (String 'B)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'C)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'D)))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2 (Uint64 '9)) '('value2 (String 'Z)))
+ (AsStruct '('key2 (Uint64 '4)) '('value2 (String 'Y)))
+ (AsStruct '('key2 (Uint64 '3)) '('value2 (String 'X)))
+ (AsStruct '('key2 (Uint64 '4)) '('value2 (String 'W)))
+ (AsStruct '('key2 (Uint64 '8)) '('value2 (String 'V)))
+))
+
+(let joinInner (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeft (EquiJoin '(list1 'a) '(list2 'b) '('Left 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRight (EquiJoin '(list1 'a) '(list2 'b) '('Right 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinFull (EquiJoin '(list1 'a) '(list2 'b) '('Full 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 'a) '(list2 'b) '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 'a) '(list2 'b) '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinExclusion (EquiJoin '(list1 'a) '(list2 'b) '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 'a) '(list2 'b) '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 'a) '(list2 'b) '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinRightSemi '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemOpt1.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemOpt1.yql
new file mode 100644
index 0000000000..7e0a5a7fc2
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemOpt1.yql
@@ -0,0 +1,45 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1 (Just (Int32 '1))) '('value1 (Just (String 'A))))
+ (AsStruct '('key1 (Just (Int32 '4))) '('value1 (Just (String 'C))))
+ (AsStruct '('key1 (Just (Int32 '4))) '('value1 (Just (String 'D))))
+ (AsStruct '('key1 (Nothing (OptionalType (DataType 'Int32)))) '('value1 (Just (String 'E))))
+ (AsStruct '('key1 (Nothing (OptionalType (DataType 'Int32)))) '('value1 (Just (String 'F))))
+ (AsStruct '('key1 (Nothing (OptionalType (DataType 'Int32)))) '('value1 (Just (String 'G))))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2 (Uint64 '2)) '('value2 (String 'U)))
+ (AsStruct '('key2 (Uint64 '4)) '('value2 (String 'Y)))
+ (AsStruct '('key2 (Uint64 '4)) '('value2 (String 'W)))
+))
+
+(let joinInner (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeft (EquiJoin '(list1 'a) '(list2 'b) '('Left 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRight (EquiJoin '(list1 'a) '(list2 'b) '('Right 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinFull (EquiJoin '(list1 'a) '(list2 'b) '('Full 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 'a) '(list2 'b) '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 'a) '(list2 'b) '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinExclusion (EquiJoin '(list1 'a) '(list2 'b) '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 'a) '(list2 'b) '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 'a) '(list2 'b) '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinCross (EquiJoin '(list1 'a) '(list2 'b) '('Cross 'a 'b '() '() '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinRightSemi '('('type))))
+(let world (Write! world res_sink (Key) joinCross '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemOpt1Opt2.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemOpt1Opt2.yql
new file mode 100644
index 0000000000..759d3983ac
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemOpt1Opt2.yql
@@ -0,0 +1,48 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1 (Just (Int32 '1))) '('value1 (Just (String 'A))))
+ (AsStruct '('key1 (Just (Int32 '4))) '('value1 (Just (String 'C))))
+ (AsStruct '('key1 (Just (Int32 '4))) '('value1 (Just (String 'D))))
+ (AsStruct '('key1 (Nothing (OptionalType (DataType 'Int32)))) '('value1 (Just (String 'E))))
+ (AsStruct '('key1 (Nothing (OptionalType (DataType 'Int32)))) '('value1 (Just (String 'F))))
+ (AsStruct '('key1 (Nothing (OptionalType (DataType 'Int32)))) '('value1 (Just (String 'G))))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2 (Just (Uint64 '2))) '('value2 (Just (String 'U))))
+ (AsStruct '('key2 (Just (Uint64 '4))) '('value2 (Just (String 'Y))))
+ (AsStruct '('key2 (Just (Uint64 '4))) '('value2 (Just (String 'W))))
+ (AsStruct '('key2 (Nothing (OptionalType (DataType 'Uint64)))) '('value2 (Just (String 'P))))
+ (AsStruct '('key2 (Nothing (OptionalType (DataType 'Uint64)))) '('value2 (Just (String 'Q))))
+ (AsStruct '('key2 (Nothing (OptionalType (DataType 'Uint64)))) '('value2 (Just (String 'R))))
+))
+
+(let joinInner (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeft (EquiJoin '(list1 'a) '(list2 'b) '('Left 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRight (EquiJoin '(list1 'a) '(list2 'b) '('Right 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinFull (EquiJoin '(list1 'a) '(list2 'b) '('Full 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 'a) '(list2 'b) '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 'a) '(list2 'b) '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinExclusion (EquiJoin '(list1 'a) '(list2 'b) '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 'a) '(list2 'b) '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 'a) '(list2 'b) '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinCross (EquiJoin '(list1 'a) '(list2 'b) '('Cross 'a 'b '() '() '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinRightSemi '('('type))))
+(let world (Write! world res_sink (Key) joinCross '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemOpt2.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemOpt2.yql
new file mode 100644
index 0000000000..861a63112f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemOpt2.yql
@@ -0,0 +1,45 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1 (Int32 '1)) '('value1 (String 'A)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'C)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'D)))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2 (Just (Uint64 '2))) '('value2 (Just (String 'U))))
+ (AsStruct '('key2 (Just (Uint64 '4))) '('value2 (Just (String 'Y))))
+ (AsStruct '('key2 (Just (Uint64 '4))) '('value2 (Just (String 'W))))
+ (AsStruct '('key2 (Nothing (OptionalType (DataType 'Uint64)))) '('value2 (Just (String 'P))))
+ (AsStruct '('key2 (Nothing (OptionalType (DataType 'Uint64)))) '('value2 (Just (String 'Q))))
+ (AsStruct '('key2 (Nothing (OptionalType (DataType 'Uint64)))) '('value2 (Just (String 'R))))
+))
+
+(let joinInner (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeft (EquiJoin '(list1 'a) '(list2 'b) '('Left 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRight (EquiJoin '(list1 'a) '(list2 'b) '('Right 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinFull (EquiJoin '(list1 'a) '(list2 'b) '('Full 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 'a) '(list2 'b) '('LeftOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 'a) '(list2 'b) '('RightOnly 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinExclusion (EquiJoin '(list1 'a) '(list2 'b) '('Exclusion 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 'a) '(list2 'b) '('LeftSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 'a) '(list2 'b) '('RightSemi 'a 'b '('a 'key1) '('b 'key2) '()) '()))
+(let joinCross (EquiJoin '(list1 'a) '(list2 'b) '('Cross 'a 'b '() '() '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinRightSemi '('('type))))
+(let world (Write! world res_sink (Key) joinCross '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemRename.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemRename.yql
new file mode 100644
index 0000000000..14636284d2
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemRename.yql
@@ -0,0 +1,28 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1 (Int32 '1)) '('value1 (String 'A)))
+ (AsStruct '('key1 (Int32 '7)) '('value1 (String 'B)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'C)))
+ (AsStruct '('key1 (Int32 '4)) '('value1 (String 'D)))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2 (Int32 '9)) '('value2 (String 'Z)))
+ (AsStruct '('key2 (Int32 '4)) '('value2 (String 'Y)))
+ (AsStruct '('key2 (Int32 '3)) '('value2 (String 'X)))
+ (AsStruct '('key2 (Int32 '4)) '('value2 (String 'W)))
+ (AsStruct '('key2 (Int32 '8)) '('value2 (String 'V)))
+))
+
+(let joinInner (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key1) '('b 'key2) '())
+ '('('rename '"a.key1" 'q) '('rename '"b.value2" '""))))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumns.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumns.yql
new file mode 100644
index 0000000000..0b21ecc24d
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumns.yql
@@ -0,0 +1,43 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1a (Int32 '1)) '('key1b (Uint32 '1)) '('value1 (String 'A)))
+ (AsStruct '('key1a (Int32 '7)) '('key1b (Uint32 '1)) '('value1 (String 'B)))
+ (AsStruct '('key1a (Int32 '4)) '('key1b (Uint32 '2)) '('value1 (String 'C)))
+ (AsStruct '('key1a (Int32 '4)) '('key1b (Uint32 '2)) '('value1 (String 'D)))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2a (Int32 '9)) '('key2b (Uint32 '3)) '('value2 (String 'Z)))
+ (AsStruct '('key2a (Int32 '4)) '('key2b (Uint32 '2)) '('value2 (String 'Y)))
+ (AsStruct '('key2a (Int32 '3)) '('key2b (Uint32 '3)) '('value2 (String 'X)))
+ (AsStruct '('key2a (Int32 '4)) '('key2b (Uint32 '2)) '('value2 (String 'W)))
+ (AsStruct '('key2a (Int32 '8)) '('key2b (Uint32 '1)) '('value2 (String 'V)))
+))
+
+(let joinInner (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinLeft (EquiJoin '(list1 'a) '(list2 'b) '('Left 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinRight (EquiJoin '(list1 'a) '(list2 'b) '('Right 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinFull (EquiJoin '(list1 'a) '(list2 'b) '('Full 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 'a) '(list2 'b) '('LeftOnly 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 'a) '(list2 'b) '('RightOnly 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinExclusion (EquiJoin '(list1 'a) '(list2 'b) '('Exclusion 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 'a) '(list2 'b) '('LeftSemi 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 'a) '(list2 'b) '('RightSemi 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinRightSemi '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumnsOpt1.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumnsOpt1.yql
new file mode 100644
index 0000000000..66060097b8
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumnsOpt1.yql
@@ -0,0 +1,41 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1a (Just (Int32 '1))) '('key1b (Just (Uint32 '1))) '('value1 (Just (String 'A))))
+ (AsStruct '('key1a (Just (Int32 '7))) '('key1b (Just (Uint32 '1))) '('value1 (Just (String 'B))))
+ (AsStruct '('key1a (Just (Int32 '4))) '('key1b (Just (Uint32 '2))) '('value1 (Just (String 'C))))
+ (AsStruct '('key1a (Just (Int32 '4))) '('key1b (Just (Uint32 '2))) '('value1 (Just (String 'D))))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2a (Int32 '9)) '('key2b (Uint32 '3)) '('value2 (String 'Z)))
+ (AsStruct '('key2a (Int32 '4)) '('key2b (Uint32 '2)) '('value2 (String 'Y)))
+ (AsStruct '('key2a (Int32 '3)) '('key2b (Uint32 '3)) '('value2 (String 'X)))
+ (AsStruct '('key2a (Int32 '4)) '('key2b (Uint32 '2)) '('value2 (String 'W)))
+ (AsStruct '('key2a (Int32 '8)) '('key2b (Uint32 '1)) '('value2 (String 'V)))
+))
+
+(let joinInner (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinLeft (EquiJoin '(list1 'a) '(list2 'b) '('Left 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinRight (EquiJoin '(list1 'a) '(list2 'b) '('Right 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinFull (EquiJoin '(list1 'a) '(list2 'b) '('Full 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 'a) '(list2 'b) '('LeftOnly 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 'a) '(list2 'b) '('RightOnly 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinExclusion (EquiJoin '(list1 'a) '(list2 'b) '('Exclusion 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 'a) '(list2 'b) '('LeftSemi 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 'a) '(list2 'b) '('RightSemi 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumnsOpt1Opt2.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumnsOpt1Opt2.yql
new file mode 100644
index 0000000000..15834403dd
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumnsOpt1Opt2.yql
@@ -0,0 +1,43 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1a (Just (Int32 '1))) '('key1b (Just (Uint32 '1))) '('value1 (Just (String 'A))))
+ (AsStruct '('key1a (Just (Int32 '7))) '('key1b (Just (Uint32 '1))) '('value1 (Just (String 'B))))
+ (AsStruct '('key1a (Just (Int32 '4))) '('key1b (Just (Uint32 '2))) '('value1 (Just (String 'C))))
+ (AsStruct '('key1a (Just (Int32 '4))) '('key1b (Just (Uint32 '2))) '('value1 (Just (String 'D))))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2a (Just (Int32 '9))) '('key2b (Just (Uint32 '3))) '('value2 (Just (String 'Z))))
+ (AsStruct '('key2a (Just (Int32 '4))) '('key2b (Just (Uint32 '2))) '('value2 (Just (String 'Y))))
+ (AsStruct '('key2a (Just (Int32 '3))) '('key2b (Just (Uint32 '3))) '('value2 (Just (String 'X))))
+ (AsStruct '('key2a (Just (Int32 '4))) '('key2b (Just (Uint32 '2))) '('value2 (Just (String 'W))))
+ (AsStruct '('key2a (Just (Int32 '8))) '('key2b (Just (Uint32 '1))) '('value2 (Just (String 'V))))
+))
+
+(let joinInner (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinLeft (EquiJoin '(list1 'a) '(list2 'b) '('Left 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinRight (EquiJoin '(list1 'a) '(list2 'b) '('Right 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinFull (EquiJoin '(list1 'a) '(list2 'b) '('Full 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 'a) '(list2 'b) '('LeftOnly 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 'a) '(list2 'b) '('RightOnly 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinExclusion (EquiJoin '(list1 'a) '(list2 'b) '('Exclusion 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 'a) '(list2 'b) '('LeftSemi 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 'a) '(list2 'b) '('RightSemi 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinRightSemi '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumnsOpt2.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumnsOpt2.yql
new file mode 100644
index 0000000000..0ddee9815b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/JoinInMemTwoColumnsOpt2.yql
@@ -0,0 +1,43 @@
+(
+(let config (DataSource 'config))
+(let world (Configure! world config 'PureDataSource 'yt))
+
+(let list1 (AsList
+ (AsStruct '('key1a (Int32 '1)) '('key1b (Uint32 '1)) '('value1 (String 'A)))
+ (AsStruct '('key1a (Int32 '7)) '('key1b (Uint32 '1)) '('value1 (String 'B)))
+ (AsStruct '('key1a (Int32 '4)) '('key1b (Uint32 '2)) '('value1 (String 'C)))
+ (AsStruct '('key1a (Int32 '4)) '('key1b (Uint32 '2)) '('value1 (String 'D)))
+))
+
+(let list2 (AsList
+ (AsStruct '('key2a (Just (Int32 '9))) '('key2b (Just (Uint32 '3))) '('value2 (Just (String 'Z))))
+ (AsStruct '('key2a (Just (Int32 '4))) '('key2b (Just (Uint32 '2))) '('value2 (Just (String 'Y))))
+ (AsStruct '('key2a (Just (Int32 '3))) '('key2b (Just (Uint32 '3))) '('value2 (Just (String 'X))))
+ (AsStruct '('key2a (Just (Int32 '4))) '('key2b (Just (Uint32 '2))) '('value2 (Just (String 'W))))
+ (AsStruct '('key2a (Just (Int32 '8))) '('key2b (Just (Uint32 '1))) '('value2 (Just (String 'V))))
+))
+
+(let joinInner (EquiJoin '(list1 'a) '(list2 'b) '('Inner 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinLeft (EquiJoin '(list1 'a) '(list2 'b) '('Left 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinRight (EquiJoin '(list1 'a) '(list2 'b) '('Right 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinFull (EquiJoin '(list1 'a) '(list2 'b) '('Full 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinLeftOnly (EquiJoin '(list1 'a) '(list2 'b) '('LeftOnly 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinRightOnly (EquiJoin '(list1 'a) '(list2 'b) '('RightOnly 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinExclusion (EquiJoin '(list1 'a) '(list2 'b) '('Exclusion 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinLeftSemi (EquiJoin '(list1 'a) '(list2 'b) '('LeftSemi 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+(let joinRightSemi (EquiJoin '(list1 'a) '(list2 'b) '('RightSemi 'a 'b '('a 'key1a 'a 'key1b) '('b 'key2a 'b 'key2b) '()) '()))
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) joinInner '('('type))))
+(let world (Write! world res_sink (Key) joinLeft '('('type))))
+(let world (Write! world res_sink (Key) joinRight '('('type))))
+(let world (Write! world res_sink (Key) joinFull '('('type))))
+(let world (Write! world res_sink (Key) joinLeftOnly '('('type))))
+(let world (Write! world res_sink (Key) joinRightOnly '('('type))))
+(let world (Write! world res_sink (Key) joinExclusion '('('type))))
+(let world (Write! world res_sink (Key) joinLeftSemi '('('type))))
+(let world (Write! world res_sink (Key) joinRightSemi '('('type))))
+
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.cfg b/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.cfg
new file mode 100644
index 0000000000..137266b187
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.cfg
@@ -0,0 +1,2 @@
+res result.txt
+in Input SelfJoinLimit1.txt
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.txt
new file mode 100644
index 0000000000..717bdfe825
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.txt
@@ -0,0 +1,3 @@
+{"key"="1";"subkey"="1";"value"="3"};
+{"key"="2";"subkey"="2";"value"="1"};
+{"key"="3";"subkey"="3";"value"="2"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.txt.attr
new file mode 100644
index 0000000000..b6100e5fd0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.txt.attr
@@ -0,0 +1,30 @@
+{
+ "_yql_row_spec" = {
+ "Type" = [
+ "StructType";
+ [
+ [
+ "key";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "subkey";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "value";
+ [
+ "DataType";
+ "String"
+ ]
+ ]
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.yql
new file mode 100644
index 0000000000..f142bfd3d6
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinLimit1.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'Input))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let table (Take table (Uint64 '2)))
+(let join (EquiJoin '(table 'a) '(table 'b)
+'('Inner '"a" '"b" '('"a" '"key") '('"b" '"value") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) join '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinMergeFields.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinMergeFields.yql
new file mode 100644
index 0000000000..e5a08be9c9
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/SelfJoinMergeFields.yql
@@ -0,0 +1,17 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+(let join (EquiJoin '(table1 'a) '(table2 'b)
+'('Inner '"a" '"b" '('"a" '"key") '('"b" '"value") '()) '()))
+(let res_sink (DataSink 'result))
+(let sortDir '((Bool 'true) (Bool 'true)))
+(let keySelector (lambda '(row) '((Member row '"a.key") (Member row '"a.subkey"))))
+(let world (Write! world res_sink (Key) (Sort join sortDir keySelector) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/SqlInToJoin.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/SqlInToJoin.yql
new file mode 100644
index 0000000000..46ad794a8b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/SqlInToJoin.yql
@@ -0,0 +1,59 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+
+(let x (Read! world mr_source (Key '('table (String 'Input1))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table1 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input2))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table2 (Right! x))
+
+(let x (Read! world mr_source (Key '('table (String 'Input3))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table3 (Right! x))
+
+
+(let list1 (AsList
+ (AsStruct '('k (String '800)))
+ (AsStruct '('k (String '020)))
+))
+
+(let list2 (AsList
+ (AsStruct '('k (String '020)))
+ (AsStruct '('k (String '800)))
+))
+
+(let list3 (AsList
+ (AsStruct '('k (String '021)))
+ (AsStruct '('k (String '800)))
+))
+
+
+(let filtered1 (FlatMap table1 (lambda '(item)
+ (OptionalIf (SqlIn list1 (Member item 'key) '('('tableSource)))
+ (AsStruct '('value (Member item 'value)) '('subkey (Member item 'subkey))))
+)))
+
+(let filtered2 (FlatMap table2 (lambda '(item) (block '(
+ (let sqlInPred (SqlIn list2 (Member item 'key) '('('tableSource))))
+ (return (OptionalIf (And sqlInPred (NotEqual (Member item 'value) (String 'ddd)))
+ (AsStruct '('value (Member item 'value)) '('subkey (Member item 'subkey)))))
+ ))
+)))
+
+(let filtered3 (FlatMap table3 (lambda '(item) (block '(
+ (let sqlInPred (SqlIn list3 (Member item 'key) '('('tableSource))))
+ (return (OptionalIf (And (NotEqual (Member item 'value) (String 'q)) sqlInPred)
+ (AsStruct '('value (Member item 'value)) '('subkey (Member item 'subkey)))))
+ ))
+)))
+
+
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (Sort filtered1 '((Bool 'true) (Bool 'true)) (lambda '(row) '((Member row 'value) (Member row 'subkey)))) '('('type))))
+(let world (Write! world res_sink (Key) (Sort filtered2 '((Bool 'true) (Bool 'true)) (lambda '(row) '((Member row 'value) (Member row 'subkey)))) '('('type))))
+(let world (Write! world res_sink (Key) (Sort filtered3 '((Bool 'true) (Bool 'true)) (lambda '(row) '((Member row 'value) (Member row 'subkey)))) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiCrossSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiCrossSelf.yql
new file mode 100644
index 0000000000..6d784c12f1
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiCrossSelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Cross '"a" '"b" '() '() '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiExclusionSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiExclusionSelf.yql
new file mode 100644
index 0000000000..b3e903ce7b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiExclusionSelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Exclusion '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiFullSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiFullSelf.yql
new file mode 100644
index 0000000000..cf1497bcef
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiFullSelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Full '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiFullTwoFieldsSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiFullTwoFieldsSelf.yql
new file mode 100644
index 0000000000..a682416eff
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiFullTwoFieldsSelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Full '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested1EatOptSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested1EatOptSelf.yql
new file mode 100644
index 0000000000..28be4deee9
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested1EatOptSelf.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '(table 'c) '('Inner
+ '('Full '"a" '"b" '('"a" '"key") '('"b" '"value" ) '())
+ '"c" '('"a" '"value") '('"c" '"subkey" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested1Self.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested1Self.yql
new file mode 100644
index 0000000000..005fca072a
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested1Self.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '(table 'c) '('Inner
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '())
+ '"c" '('"a" '"value") '('"c" '"subkey" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested1bSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested1bSelf.yql
new file mode 100644
index 0000000000..676843a418
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested1bSelf.yql
@@ -0,0 +1,13 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '(table 'c) '('Right
+ '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '())
+ '"c" '('"b" '"value") '('"c" '"subkey" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested2Self.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested2Self.yql
new file mode 100644
index 0000000000..ecfc4263ec
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerNested2Self.yql
@@ -0,0 +1,15 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '(table 'c) '(table 'd) '('Inner
+ '('Inner
+ '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '())
+ '"c" '('"b" '"key") '('"c" '"value" ) '())
+ '"d" '('"a" '"value") '('"d" '"subkey" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerSelf.yql
new file mode 100644
index 0000000000..633de6fcae
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerSelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerTwoFieldsSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerTwoFieldsSelf.yql
new file mode 100644
index 0000000000..793ee81306
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiInnerTwoFieldsSelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Inner '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftOnlySelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftOnlySelf.yql
new file mode 100644
index 0000000000..867c048f8b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftOnlySelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('LeftOnly '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftSelf.yql
new file mode 100644
index 0000000000..1fc31dc350
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftSelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Left '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftSemiSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftSemiSelf.yql
new file mode 100644
index 0000000000..15fa410fc6
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftSemiSelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('LeftSemi '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftTwoFieldsSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftTwoFieldsSelf.yql
new file mode 100644
index 0000000000..b305596d20
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiLeftTwoFieldsSelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Left '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptFullSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptFullSelf.yql
new file mode 100644
index 0000000000..2bb5d8dfc5
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptFullSelf.yql
@@ -0,0 +1,15 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let table (Map table (lambda '(row) (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))))))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Full '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptInnerSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptInnerSelf.yql
new file mode 100644
index 0000000000..d37d7f696b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptInnerSelf.yql
@@ -0,0 +1,15 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let table (Map table (lambda '(row) (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))))))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Inner '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptLeftSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptLeftSelf.yql
new file mode 100644
index 0000000000..74edcb9ae2
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptLeftSelf.yql
@@ -0,0 +1,15 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let table (Map table (lambda '(row) (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))))))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Left '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptRightSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptRightSelf.yql
new file mode 100644
index 0000000000..47f1a8923a
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiOptRightSelf.yql
@@ -0,0 +1,15 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let table (Map table (lambda '(row) (AsStruct
+ '('key (Just (Member row 'key)))
+ '('subkey (Just (Member row 'subkey)))
+ '('value (Just (Member row 'value)))))))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightOnlySelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightOnlySelf.yql
new file mode 100644
index 0000000000..0a0a502ca6
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightOnlySelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('RightOnly '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightSelf.yql
new file mode 100644
index 0000000000..9fe527324c
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightSelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Right '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightSemiSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightSemiSelf.yql
new file mode 100644
index 0000000000..4e69796c1f
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightSemiSelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('RightSemi '"a" '"b" '('"a" '"key") '('"b" '"value" ) '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightTwoFieldsSelf.yql b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightTwoFieldsSelf.yql
new file mode 100644
index 0000000000..d5145b4dec
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/TypeEquiRightTwoFieldsSelf.yql
@@ -0,0 +1,11 @@
+(
+(let mr_source (DataSource 'yt 'plato))
+(let x (Read! world mr_source (Key '('table (String 'InputSelf))) '('key 'subkey 'value) '()))
+(let world (Left! x))
+(let table (Right! x))
+(let join (EquiJoin '(table 'a) '(table 'b) '('Right '"a" '"b" '('"a" '"key" '"a" '"subkey") '('"b" '"value" '"b" '"subkey") '()) '()))
+(let res_sink (DataSink 'result))
+(let world (Write! world res_sink (Key) (FormatType (TypeOf join)) '('('type))))
+(let world (Commit! world res_sink))
+(return world)
+)
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/default.cfg b/yql/essentials/tests/s-expressions/suites/EquiJoin/default.cfg
new file mode 100644
index 0000000000..41fe7506e0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/default.cfg
@@ -0,0 +1,6 @@
+res result.txt
+in InputSelf InputSelf.txt
+in InputSelf2 InputSelf2.txt
+in Input1 input1.txt
+in Input2 input2.txt
+in Input3 input3.txt
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/input1.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/input1.txt
new file mode 100644
index 0000000000..f53757c309
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/input1.txt
@@ -0,0 +1,4 @@
+{"key"="075";"subkey"="1";"value"="abc"};
+{"key"="800";"subkey"="1";"value"="ddd"};
+{"key"="020";"subkey"="1";"value"="q"};
+{"key"="150";"subkey"="1";"value"="qzz"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/input1.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/input1.txt.attr
new file mode 100644
index 0000000000..b6100e5fd0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/input1.txt.attr
@@ -0,0 +1,30 @@
+{
+ "_yql_row_spec" = {
+ "Type" = [
+ "StructType";
+ [
+ [
+ "key";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "subkey";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "value";
+ [
+ "DataType";
+ "String"
+ ]
+ ]
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/input2.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/input2.txt
new file mode 100644
index 0000000000..07af3b4647
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/input2.txt
@@ -0,0 +1,4 @@
+{"key"="075";"subkey"="2";"value"="abc"};
+{"key"="800";"subkey"="2";"value"="ddd"};
+{"key"="020";"subkey"="2";"value"="q"};
+{"key"="150";"subkey"="2";"value"="qzz"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/input2.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/input2.txt.attr
new file mode 100644
index 0000000000..b6100e5fd0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/input2.txt.attr
@@ -0,0 +1,30 @@
+{
+ "_yql_row_spec" = {
+ "Type" = [
+ "StructType";
+ [
+ [
+ "key";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "subkey";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "value";
+ [
+ "DataType";
+ "String"
+ ]
+ ]
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/input3.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/input3.txt
new file mode 100644
index 0000000000..1dc1bcc60b
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/input3.txt
@@ -0,0 +1,4 @@
+{"key"="075";"subkey"="3";"value"="abd"};
+{"key"="800";"subkey"="3";"value"="ddd"};
+{"key"="021";"subkey"="3";"value"="q"};
+{"key"="151";"subkey"="3";"value"="qzz"};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/input3.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/input3.txt.attr
new file mode 100644
index 0000000000..b6100e5fd0
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/input3.txt.attr
@@ -0,0 +1,30 @@
+{
+ "_yql_row_spec" = {
+ "Type" = [
+ "StructType";
+ [
+ [
+ "key";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "subkey";
+ [
+ "DataType";
+ "String"
+ ]
+ ];
+ [
+ "value";
+ [
+ "DataType";
+ "String"
+ ]
+ ]
+ ]
+ ]
+ }
+} \ No newline at end of file
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/input4.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/input4.txt
new file mode 100644
index 0000000000..8852c0825e
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/input4.txt
@@ -0,0 +1,2 @@
+{"payload_left"="aaa";"id"=1;};
+{"payload_left"="bbb";"id"=2;};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/input4.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/input4.txt.attr
new file mode 100644
index 0000000000..4cd0c640ff
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/input4.txt.attr
@@ -0,0 +1,35 @@
+{
+ "_yql_row_spec" = {"Type" = [
+ "StructType";
+ [
+ [
+ "id";
+ [
+ "DataType";
+ "Int64"
+ ]
+ ];
+ [
+ "payload_left";
+ [
+ "DataType";
+ "String"
+ ]
+ ]
+ ]
+ ]};
+ "schema" = <
+ "strict" = %true;
+ "unique_keys" = %false
+ >
+ [
+ {
+ "name" = "payload_left";
+ "type" = "string"
+ };
+ {
+ "name" = "id";
+ "type" = "int64"
+ }
+ ];
+}
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/input5.txt b/yql/essentials/tests/s-expressions/suites/EquiJoin/input5.txt
new file mode 100644
index 0000000000..398caa9279
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/input5.txt
@@ -0,0 +1,2 @@
+{"payload_right"="ccc";"id"=1;};
+{"payload_right"="ddd";"id"=3;};
diff --git a/yql/essentials/tests/s-expressions/suites/EquiJoin/input5.txt.attr b/yql/essentials/tests/s-expressions/suites/EquiJoin/input5.txt.attr
new file mode 100644
index 0000000000..cfc68e11aa
--- /dev/null
+++ b/yql/essentials/tests/s-expressions/suites/EquiJoin/input5.txt.attr
@@ -0,0 +1,35 @@
+{
+ "_yql_row_spec" = {"Type" = [
+ "StructType";
+ [
+ [
+ "id";
+ [
+ "DataType";
+ "Int64"
+ ]
+ ];
+ [
+ "payload_right";
+ [
+ "DataType";
+ "String"
+ ]
+ ]
+ ]
+ ]};
+ "schema" = <
+ "strict" = %true;
+ "unique_keys" = %false
+ >
+ [
+ {
+ "name" = "payload_right";
+ "type" = "string"
+ };
+ {
+ "name" = "id";
+ "type" = "int64"
+ }
+ ];
+}