diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php
index a2242ff0f355b3bca9d332ca5b59ec052cd61cb7..5887c76e8ddc23ef1ce51e822b46f57400d513f6 100644
--- a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php
+++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider.php
@@ -3,10 +3,11 @@
  * Copyright © Magento, Inc. All rights reserved.
  * See COPYING.txt for license details.
  */
+
 namespace Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation;
 
 use Magento\Catalog\Model\Product;
-use Magento\CatalogInventory\Model\Stock;
+use Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider\QueryBuilder;
 use Magento\Customer\Model\Session;
 use Magento\Eav\Model\Config;
 use Magento\Framework\App\ResourceConnection;
@@ -19,7 +20,7 @@ use Magento\Framework\Search\Request\BucketInterface;
 use Magento\Framework\App\ObjectManager;
 
 /**
- * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * DataProvider for Catalog search Mysql.
  */
 class DataProvider implements DataProviderInterface
 {
@@ -48,23 +49,31 @@ class DataProvider implements DataProviderInterface
      */
     private $connection;
 
+    /**
+     * @var QueryBuilder;
+     */
+    private $queryBuilder;
+
     /**
      * @param Config $eavConfig
      * @param ResourceConnection $resource
      * @param ScopeResolverInterface $scopeResolver
      * @param Session $customerSession
+     * @param QueryBuilder|null $queryBuilder
      */
     public function __construct(
         Config $eavConfig,
         ResourceConnection $resource,
         ScopeResolverInterface $scopeResolver,
-        Session $customerSession
+        Session $customerSession,
+        QueryBuilder $queryBuilder = null
     ) {
         $this->eavConfig = $eavConfig;
         $this->resource = $resource;
         $this->connection = $resource->getConnection();
         $this->scopeResolver = $scopeResolver;
         $this->customerSession = $customerSession;
+        $this->queryBuilder = $queryBuilder ?: ObjectManager::getInstance()->get(QueryBuilder::class);
     }
 
     /**
@@ -79,47 +88,13 @@ class DataProvider implements DataProviderInterface
 
         $attribute = $this->eavConfig->getAttribute(Product::ENTITY, $bucket->getField());
 
-        $select = $this->getSelect();
-
-        $select->joinInner(
-            ['entities' => $entityIdsTable->getName()],
-            'main_table.entity_id  = entities.entity_id',
-            []
+        $select = $this->queryBuilder->build(
+            $attribute,
+            $entityIdsTable->getName(),
+            $currentScope,
+            $this->customerSession->getCustomerGroupId()
         );
 
-        if ($attribute->getAttributeCode() === 'price') {
-            /** @var \Magento\Store\Model\Store $store */
-            $store = $this->scopeResolver->getScope($currentScope);
-            if (!$store instanceof \Magento\Store\Model\Store) {
-                throw new \RuntimeException('Illegal scope resolved');
-            }
-            $table = $this->resource->getTableName('catalog_product_index_price');
-            $select->from(['main_table' => $table], null)
-                ->columns([BucketInterface::FIELD_VALUE => 'main_table.min_price'])
-                ->where('main_table.customer_group_id = ?', $this->customerSession->getCustomerGroupId())
-                ->where('main_table.website_id = ?', $store->getWebsiteId());
-        } else {
-            $currentScopeId = $this->scopeResolver->getScope($currentScope)
-                ->getId();
-            $table = $this->resource->getTableName(
-                'catalog_product_index_eav' . ($attribute->getBackendType() === 'decimal' ? '_decimal' : '')
-            );
-            $subSelect = $select;
-            $subSelect->from(['main_table' => $table], ['main_table.entity_id', 'main_table.value'])
-                ->distinct()
-                ->joinLeft(
-                    ['stock_index' => $this->resource->getTableName('cataloginventory_stock_status')],
-                    'main_table.source_id = stock_index.product_id',
-                    []
-                )
-                ->where('main_table.attribute_id = ?', $attribute->getAttributeId())
-                ->where('main_table.store_id = ? ', $currentScopeId)
-                ->where('stock_index.stock_status = ?', Stock::STOCK_IN_STOCK);
-            $parentSelect = $this->getSelect();
-            $parentSelect->from(['main_table' => $subSelect], ['main_table.value']);
-            $select = $parentSelect;
-        }
-
         return $select;
     }
 
@@ -130,12 +105,4 @@ class DataProvider implements DataProviderInterface
     {
         return $this->connection->fetchAssoc($select);
     }
-
-    /**
-     * @return Select
-     */
-    private function getSelect()
-    {
-        return $this->connection->select();
-    }
 }
diff --git a/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilder.php b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilder.php
new file mode 100644
index 0000000000000000000000000000000000000000..ca077ef7227d5822832005c57fe1ac7451c37e7c
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilder.php
@@ -0,0 +1,148 @@
+<?php
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider;
+
+use Magento\CatalogInventory\Model\Configuration as CatalogInventoryConfiguration;
+use Magento\CatalogInventory\Model\Stock;
+use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
+use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\App\ScopeResolverInterface;
+use Magento\Framework\DB\Adapter\AdapterInterface;
+use Magento\Framework\DB\Select;
+use Magento\Framework\Search\Request\BucketInterface;
+
+/**
+ *  Attribute query builder
+ */
+class QueryBuilder
+{
+    /**
+     * @var Resource
+     */
+    private $resource;
+
+    /**
+     * @var ScopeResolverInterface
+     */
+    private $scopeResolver;
+
+    /**
+     * @var CatalogInventoryConfiguration
+     */
+    private $inventoryConfig;
+
+    /**
+     * @param ResourceConnection $resource
+     * @param ScopeResolverInterface $scopeResolver
+     * @param CatalogInventoryConfiguration $inventoryConfig
+     */
+    public function __construct(
+        ResourceConnection $resource,
+        ScopeResolverInterface $scopeResolver,
+        CatalogInventoryConfiguration $inventoryConfig
+    ) {
+        $this->resource = $resource;
+        $this->scopeResolver = $scopeResolver;
+        $this->inventoryConfig = $inventoryConfig;
+    }
+
+    /**
+     * Build select.
+     *
+     * @param AbstractAttribute $attribute
+     * @param string $tableName
+     * @param int $currentScope
+     * @param int $customerGroupId
+     *
+     * @return Select
+     */
+    public function build(
+        AbstractAttribute $attribute,
+        string $tableName,
+        int $currentScope,
+        int $customerGroupId
+    ) : Select {
+        $select = $this->resource->getConnection()->select();
+        $select->joinInner(
+            ['entities' => $tableName],
+            'main_table.entity_id  = entities.entity_id',
+            []
+        );
+
+        if ($attribute->getAttributeCode() === 'price') {
+            return $this->buildQueryForPriceAttribute($currentScope, $customerGroupId, $select);
+        }
+
+        return $this->buildQueryForAttribute($currentScope, $attribute, $select);
+    }
+
+    /**
+     * Build select for price attribute.
+     *
+     * @param int $currentScope
+     * @param int $customerGroupId
+     * @param Select $select
+     *
+     * @return Select
+     */
+    private function buildQueryForPriceAttribute(
+        int $currentScope,
+        int $customerGroupId,
+        Select $select
+    ) : Select {
+        /** @var \Magento\Store\Model\Store $store */
+        $store = $this->scopeResolver->getScope($currentScope);
+        if (!$store instanceof \Magento\Store\Model\Store) {
+            throw new \RuntimeException('Illegal scope resolved');
+        }
+
+        $table = $this->resource->getTableName('catalog_product_index_price');
+        $select->from(['main_table' => $table], null)
+            ->columns([BucketInterface::FIELD_VALUE => 'main_table.min_price'])
+            ->where('main_table.customer_group_id = ?', $customerGroupId)
+            ->where('main_table.website_id = ?', $store->getWebsiteId());
+
+        return $select;
+    }
+
+    /**
+     * Build select for attribute.
+     *
+     * @param int $currentScope
+     * @param AbstractAttribute $attribute
+     * @param Select $select
+     *
+     * @return Select
+     */
+    private function buildQueryForAttribute(
+        int $currentScope,
+        AbstractAttribute $attribute,
+        Select $select
+    ) : Select {
+        $currentScopeId = $this->scopeResolver->getScope($currentScope)->getId();
+        $table = $this->resource->getTableName(
+            'catalog_product_index_eav' . ($attribute->getBackendType() === 'decimal' ? '_decimal' : '')
+        );
+        $select->from(['main_table' => $table], ['main_table.entity_id', 'main_table.value'])
+            ->distinct()
+            ->joinLeft(
+                ['stock_index' => $this->resource->getTableName('cataloginventory_stock_status')],
+                'main_table.source_id = stock_index.product_id',
+                []
+            )
+            ->where('main_table.attribute_id = ?', $attribute->getAttributeId())
+            ->where('main_table.store_id = ? ', $currentScopeId);
+
+        if (!$this->inventoryConfig->isShowOutOfStock($currentScopeId)) {
+            $select->where('stock_index.stock_status = ?', Stock::STOCK_IN_STOCK);
+        }
+
+        $parentSelect = $this->resource->getConnection()->select();
+        $parentSelect->from(['main_table' => $select], ['main_table.value']);
+        return $parentSelect;
+    }
+}
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilderTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilderTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b52664df749fe0954875a7241dc80636aae45b1f
--- /dev/null
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProvider/QueryBuilderTest.php
@@ -0,0 +1,154 @@
+<?php
+/**
+ * Copyright © Magento, Inc. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Aggregation\DataProvider;
+
+use Magento\CatalogInventory\Model\Configuration as CatalogInventoryConfiguration;
+use Magento\CatalogInventory\Model\Stock;
+use Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider\QueryBuilder;
+use Magento\Eav\Model\Entity\Attribute\AbstractAttribute;
+use Magento\Framework\App\ResourceConnection;
+use Magento\Framework\App\ScopeResolverInterface;
+use Magento\Framework\DB\Adapter\AdapterInterface;
+use Magento\Framework\DB\Select;
+use Magento\Store\Model\Store;
+
+/**
+ *  Test for Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider\QueryBuilder.
+ */
+class QueryBuilderTest extends \PHPUnit\Framework\TestCase
+{
+    /**
+     * @var QueryBuilder
+     */
+    private $model;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $resourceConnectionMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $scopeResolverMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $adapterMock;
+
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $inventoryConfigMock;
+
+    protected function setUp()
+    {
+        $this->resourceConnectionMock = $this->createMock(ResourceConnection::class);
+        $this->scopeResolverMock = $this->createMock(ScopeResolverInterface::class);
+        $this->adapterMock = $this->createMock(AdapterInterface::class);
+        $this->inventoryConfigMock = $this->createMock(CatalogInventoryConfiguration::class);
+
+        $this->resourceConnectionMock->expects($this->atLeastOnce())
+            ->method('getConnection')
+            ->willReturn($this->adapterMock);
+
+        $this->model = new QueryBuilder(
+            $this->resourceConnectionMock,
+            $this->scopeResolverMock,
+            $this->inventoryConfigMock
+        );
+    }
+
+    public function testBuildWithPriceAttributeCode()
+    {
+        $tableName = 'test_table';
+        $scope = 1;
+        $selectMock = $this->createMock(Select::class);
+        $attributeMock = $this->createMock(AbstractAttribute::class);
+        $storeMock = $this->createMock(Store::class);
+
+        $this->adapterMock->expects($this->atLeastOnce())->method('select')
+            ->willReturn($selectMock);
+        $selectMock->expects($this->once())->method('joinInner')
+            ->with(['entities' => $tableName], 'main_table.entity_id  = entities.entity_id', []);
+        $attributeMock->expects($this->once())->method('getAttributeCode')
+            ->willReturn('price');
+        $this->scopeResolverMock->expects($this->once())->method('getScope')
+            ->with($scope)->willReturn($storeMock);
+        $storeMock->expects($this->once())->method('getWebsiteId')->willReturn(1);
+        $this->resourceConnectionMock->expects($this->once())->method('getTableName')
+            ->with('catalog_product_index_price')->willReturn('catalog_product_index_price');
+        $selectMock->expects($this->once())->method('from')
+            ->with(['main_table' => 'catalog_product_index_price'], null)
+            ->willReturn($selectMock);
+        $selectMock->expects($this->once())->method('columns')
+            ->with(['value' => 'main_table.min_price'])
+            ->willReturn($selectMock);
+        $selectMock->expects($this->exactly(2))->method('where')
+            ->withConsecutive(
+                ['main_table.customer_group_id = ?', 1],
+                ['main_table.website_id = ?', 1]
+            )->willReturn($selectMock);
+
+        $this->model->build($attributeMock, $tableName, $scope, 1);
+    }
+
+    public function testBuildWithNotPriceAttributeCode()
+    {
+        $tableName = 'test_table';
+        $scope = 1;
+        $selectMock = $this->createMock(Select::class);
+        $attributeMock = $this->createMock(AbstractAttribute::class);
+        $storeMock = $this->createMock(Store::class);
+
+        $this->adapterMock->expects($this->atLeastOnce())->method('select')
+            ->willReturn($selectMock);
+        $selectMock->expects($this->once())->method('joinInner')
+            ->with(['entities' => $tableName], 'main_table.entity_id  = entities.entity_id', []);
+        $attributeMock->expects($this->once())->method('getBackendType')
+            ->willReturn('decimal');
+        $this->scopeResolverMock->expects($this->once())->method('getScope')
+            ->with($scope)->willReturn($storeMock);
+        $storeMock->expects($this->once())->method('getId')->willReturn(1);
+        $this->resourceConnectionMock->expects($this->exactly(2))->method('getTableName')
+            ->withConsecutive(
+                ['catalog_product_index_eav_decimal'],
+                ['cataloginventory_stock_status']
+            )->willReturnOnConsecutiveCalls(
+                'catalog_product_index_eav_decimal',
+                'cataloginventory_stock_status'
+            );
+
+        $selectMock->expects($this->exactly(2))->method('from')
+            ->withConsecutive(
+                [
+                    ['main_table' => 'catalog_product_index_eav_decimal'],
+                    ['main_table.entity_id', 'main_table.value']
+                ],
+                [['main_table' => $selectMock], ['main_table.value']]
+            )
+            ->willReturn($selectMock);
+        $selectMock->expects($this->once())->method('distinct')->willReturn($selectMock);
+        $selectMock->expects($this->once())->method('joinLeft')
+            ->with(
+                ['stock_index' => 'cataloginventory_stock_status'],
+                'main_table.source_id = stock_index.product_id',
+                []
+            )->willReturn($selectMock);
+        $attributeMock->expects($this->once())->method('getAttributeId')->willReturn(3);
+        $selectMock->expects($this->exactly(3))->method('where')
+            ->withConsecutive(
+                ['main_table.attribute_id = ?', 3],
+                ['main_table.store_id = ? ', 1],
+                ['stock_index.stock_status = ?', Stock::STOCK_IN_STOCK]
+            )->willReturn($selectMock);
+        $this->inventoryConfigMock->expects($this->once())->method('isShowOutOfStock')->with(1)->willReturn(false);
+
+        $this->model->build($attributeMock, $tableName, $scope, 1);
+    }
+}
diff --git a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProviderTest.php b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProviderTest.php
index 4305bc5cb0706c69ba4201e23360b75a80a08afd..7c558f60b7433b90b35060254cd94b5ffc0a38ac 100644
--- a/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProviderTest.php
+++ b/app/code/Magento/CatalogSearch/Test/Unit/Model/Adapter/Mysql/Aggregation/DataProviderTest.php
@@ -7,6 +7,7 @@
 namespace Magento\CatalogSearch\Test\Unit\Model\Adapter\Mysql\Aggregation;
 
 use Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider;
+use Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider\QueryBuilder;
 use Magento\Eav\Model\Config;
 use Magento\Customer\Model\Session;
 use Magento\Framework\App\ResourceConnection;
@@ -21,6 +22,8 @@ use Magento\Catalog\Model\Product;
 use Magento\Framework\DB\Ddl\Table;
 
 /**
+ * Test for Magento\CatalogSearch\Model\Adapter\Mysql\Aggregation\DataProvider.
+ *
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
 class DataProviderTest extends \PHPUnit\Framework\TestCase
@@ -55,6 +58,11 @@ class DataProviderTest extends \PHPUnit\Framework\TestCase
      */
     private $adapterMock;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $queryBuilderMock;
+
     protected function setUp()
     {
         $this->eavConfigMock = $this->createMock(Config::class);
@@ -63,72 +71,53 @@ class DataProviderTest extends \PHPUnit\Framework\TestCase
         $this->sessionMock = $this->createMock(Session::class);
         $this->adapterMock = $this->createMock(AdapterInterface::class);
         $this->resourceConnectionMock->expects($this->once())->method('getConnection')->willReturn($this->adapterMock);
+        $this->queryBuilderMock = $this->createMock(QueryBuilder::class);
 
         $this->model = new DataProvider(
             $this->eavConfigMock,
             $this->resourceConnectionMock,
             $this->scopeResolverMock,
-            $this->sessionMock
+            $this->sessionMock,
+            $this->queryBuilderMock
         );
     }
 
-    public function testGetDataSetUsesFrontendPriceIndexerTableIfAttributeIsPrice()
+    public function testGetDataSet()
     {
         $storeId = 1;
-        $attributeCode = 'price';
+        $attributeCode = 'my_decimal';
 
         $scopeMock = $this->createMock(Store::class);
         $scopeMock->expects($this->any())->method('getId')->willReturn($storeId);
+
         $dimensionMock = $this->createMock(Dimension::class);
         $dimensionMock->expects($this->any())->method('getValue')->willReturn($storeId);
+
         $this->scopeResolverMock->expects($this->any())->method('getScope')->with($storeId)->willReturn($scopeMock);
 
         $bucketMock = $this->createMock(BucketInterface::class);
         $bucketMock->expects($this->once())->method('getField')->willReturn($attributeCode);
+
         $attributeMock = $this->createMock(Attribute::class);
-        $attributeMock->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode);
-        $this->eavConfigMock->expects($this->once())
-            ->method('getAttribute')->with(Product::ENTITY, $attributeCode)
-            ->willReturn($attributeMock);
+        $this->eavConfigMock->expects($this->once())->method('getAttribute')
+            ->with(Product::ENTITY, $attributeCode)->willReturn($attributeMock);
 
-        $selectMock = $this->createMock(Select::class);
-        $selectMock->expects($this->any())->method('from')->willReturnSelf();
-        $selectMock->expects($this->any())->method('where')->willReturnSelf();
-        $selectMock->expects($this->any())->method('columns')->willReturnSelf();
-        $this->adapterMock->expects($this->once())->method('select')->willReturn($selectMock);
         $tableMock = $this->createMock(Table::class);
+        $tableMock->expects($this->once())->method('getName')->willReturn('test');
+
+        $this->sessionMock->expects($this->once())->method('getCustomerGroupId')->willReturn(1);
+
+        $this->queryBuilderMock->expects($this->once())->method('build')
+            ->with($attributeMock, 'test', $storeId, 1);
 
         $this->model->getDataSet($bucketMock, ['scope' => $dimensionMock], $tableMock);
     }
 
-    public function testGetDataSetUsesFrontendPriceIndexerTableForDecimalAttributes()
+    public function testExecute()
     {
-        $storeId = 1;
-        $attributeCode = 'my_decimal';
-
-        $scopeMock = $this->createMock(Store::class);
-        $scopeMock->expects($this->any())->method('getId')->willReturn($storeId);
-        $dimensionMock = $this->createMock(Dimension::class);
-        $dimensionMock->expects($this->any())->method('getValue')->willReturn($storeId);
-        $this->scopeResolverMock->expects($this->any())->method('getScope')->with($storeId)->willReturn($scopeMock);
-
-        $bucketMock = $this->createMock(BucketInterface::class);
-        $bucketMock->expects($this->once())->method('getField')->willReturn($attributeCode);
-        $attributeMock = $this->createMock(Attribute::class);
-        $attributeMock->expects($this->any())->method('getAttributeCode')->willReturn($attributeCode);
-        $this->eavConfigMock->expects($this->once())
-            ->method('getAttribute')->with(Product::ENTITY, $attributeCode)
-            ->willReturn($attributeMock);
-
         $selectMock = $this->createMock(Select::class);
-        $selectMock->expects($this->any())->method('from')->willReturnSelf();
-        $selectMock->expects($this->any())->method('distinct')->willReturnSelf();
-        $selectMock->expects($this->any())->method('where')->willReturnSelf();
-        $selectMock->expects($this->any())->method('columns')->willReturnSelf();
-        $selectMock->expects($this->any())->method('joinLeft')->willReturnSelf();
-        $selectMock->expects($this->any())->method('group')->willReturnSelf();
-        $this->adapterMock->expects($this->any())->method('select')->willReturn($selectMock);
-        $tableMock = $this->createMock(Table::class);
-        $this->model->getDataSet($bucketMock, ['scope' => $dimensionMock], $tableMock);
+        $this->adapterMock->expects($this->once())->method('fetchAssoc')->with($selectMock);
+
+        $this->model->execute($selectMock);
     }
 }
diff --git a/app/code/Magento/Directory/Setup/UpgradeData.php b/app/code/Magento/Directory/Setup/UpgradeData.php
index aa0f81a32fff06a84eeadc3636d1ef01b3f9b1d7..4ee9ea33673d736e253b7ac3b373365c5b9d6439 100644
--- a/app/code/Magento/Directory/Setup/UpgradeData.php
+++ b/app/code/Magento/Directory/Setup/UpgradeData.php
@@ -41,23 +41,21 @@ class UpgradeData implements UpgradeDataInterface
     public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
     {
         if (version_compare($context->getVersion(), '2.0.1', '<')) {
-            $this->addCroatia($setup);
+            $this->addCountryRegions($setup, $this->getDataForCroatia());
+        }
+        if (version_compare($context->getVersion(), '2.0.2', '<')) {
+            $this->addCountryRegions($setup, $this->getDataForIndia());
         }
     }
 
     /**
-     * Add Croatia and it's states to appropriate tables.
+     * Croatian states data.
      *
-     * @param ModuleDataSetupInterface $setup
-     * @return void
+     * @return array
      */
-    private function addCroatia($setup)
+    private function getDataForCroatia()
     {
-        /**
-         * Fill table directory/country_region
-         * Fill table directory/country_region_name for en_US locale
-         */
-        $data = [
+        return [
             ['HR', 'HR-01', 'Zagrebačka županija'],
             ['HR', 'HR-02', 'Krapinsko-zagorska županija'],
             ['HR', 'HR-03', 'Sisačko-moslavačka županija'],
@@ -80,6 +78,68 @@ class UpgradeData implements UpgradeDataInterface
             ['HR', 'HR-20', 'Međimurska županija'],
             ['HR', 'HR-21', 'Grad Zagreb']
         ];
+    }
+
+    /**
+     * Indian states data.
+     *
+     * @return array
+     */
+    private function getDataForIndia()
+    {
+        return [
+            ['IN', 'AN', 'Andaman and Nicobar Islands'],
+            ['IN', 'AP', 'Andhra Pradesh'],
+            ['IN', 'AR', 'Arunachal Pradesh'],
+            ['IN', 'AS', 'Assam'],
+            ['IN', 'BR', 'Bihar'],
+            ['IN', 'CH', 'Chandigarh'],
+            ['IN', 'CT', 'Chhattisgarh'],
+            ['IN', 'DN', 'Dadra and Nagar Haveli'],
+            ['IN', 'DD', 'Daman and Diu'],
+            ['IN', 'DL', 'Delhi'],
+            ['IN', 'GA', 'Goa'],
+            ['IN', 'GJ', 'Gujarat'],
+            ['IN', 'HR', 'Haryana'],
+            ['IN', 'HP', 'Himachal Pradesh'],
+            ['IN', 'JK', 'Jammu and Kashmir'],
+            ['IN', 'JH', 'Jharkhand'],
+            ['IN', 'KA', 'Karnataka'],
+            ['IN', 'KL', 'Kerala'],
+            ['IN', 'LD', 'Lakshadweep'],
+            ['IN', 'MP', 'Madhya Pradesh'],
+            ['IN', 'MH', 'Maharashtra'],
+            ['IN', 'MN', 'Manipur'],
+            ['IN', 'ML', 'Meghalaya'],
+            ['IN', 'MZ', 'Mizoram'],
+            ['IN', 'NL', 'Nagaland'],
+            ['IN', 'OR', 'Odisha'],
+            ['IN', 'PY', 'Puducherry'],
+            ['IN', 'PB', 'Punjab'],
+            ['IN', 'RJ', 'Rajasthan'],
+            ['IN', 'SK', 'Sikkim'],
+            ['IN', 'TN', 'Tamil Nadu'],
+            ['IN', 'TG', 'Telangana'],
+            ['IN', 'TR', 'Tripura'],
+            ['IN', 'UP', 'Uttar Pradesh'],
+            ['IN', 'UT', 'Uttarakhand'],
+            ['IN', 'WB', 'West Bengal']
+        ];
+    }
+
+    /**
+     * Add country regions data to appropriate tables.
+     *
+     * @param ModuleDataSetupInterface $setup
+     * @param array $data
+     * @return void
+     */
+    private function addCountryRegions(ModuleDataSetupInterface $setup, array $data)
+    {
+        /**
+         * Fill table directory/country_region
+         * Fill table directory/country_region_name for en_US locale
+         */
         foreach ($data as $row) {
             $bind = ['country_id' => $row[0], 'code' => $row[1], 'default_name' => $row[2]];
             $setup->getConnection()->insert($setup->getTable('directory_country_region'), $bind);
diff --git a/app/code/Magento/Directory/etc/module.xml b/app/code/Magento/Directory/etc/module.xml
index 2711a91577a9ab7ad6dc8b8c764f3306ba2b57c4..a3735ca6ddde1113cd012aab75564db342336b7f 100644
--- a/app/code/Magento/Directory/etc/module.xml
+++ b/app/code/Magento/Directory/etc/module.xml
@@ -6,7 +6,7 @@
  */
 -->
 <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Module/etc/module.xsd">
-    <module name="Magento_Directory" setup_version="2.0.1">
+    <module name="Magento_Directory" setup_version="2.0.2">
         <sequence>
             <module name="Magento_Store"/>
         </sequence>
diff --git a/lib/internal/Magento/Framework/View/Element/UiComponentFactory.php b/lib/internal/Magento/Framework/View/Element/UiComponentFactory.php
index 94d84dd0560df92adeb99c81d92fd627b1291288..93fe88a30f0650f0a400f8ad39322b7d5d80e7aa 100755
--- a/lib/internal/Magento/Framework/View/Element/UiComponentFactory.php
+++ b/lib/internal/Magento/Framework/View/Element/UiComponentFactory.php
@@ -147,6 +147,14 @@ class UiComponentFactory extends DataObject
         }
         $components = array_filter($components);
         $componentArguments['components'] = $components;
+
+       /**
+        * Prevent passing ACL restricted blocks to htmlContent constructor
+        */
+        if (isset($componentArguments['block']) && !$componentArguments['block']) {
+            return null;
+        }
+
         if (!isset($componentArguments['context'])) {
             $componentArguments['context'] = $renderContext;
         }
diff --git a/lib/internal/Magento/Framework/Webapi/Rest/Response/RendererFactory.php b/lib/internal/Magento/Framework/Webapi/Rest/Response/RendererFactory.php
index c86b97b0fa8e7f8a78ad4b16a434ad69d012446c..547b8fcb03640c43e38f6b3c309d76cfc0b87b61 100644
--- a/lib/internal/Magento/Framework/Webapi/Rest/Response/RendererFactory.php
+++ b/lib/internal/Magento/Framework/Webapi/Rest/Response/RendererFactory.php
@@ -72,14 +72,9 @@ class RendererFactory
             $acceptTypes = [$acceptTypes];
         }
         foreach ($acceptTypes as $acceptType) {
-            foreach ($this->_renders as $rendererConfig) {
-                $rendererType = $rendererConfig['type'];
-                if ($acceptType == $rendererType || $acceptType == current(
-                    explode('/', $rendererType)
-                ) . '/*' || $acceptType == '*/*'
-                ) {
-                    return $rendererConfig['model'];
-                }
+            $renderer = $this->getRendererConfig($acceptType);
+            if ($renderer !== null) {
+                return $renderer['model'];
             }
         }
         /** If server does not have renderer for any of the accepted types it SHOULD send 406 (not acceptable). */
@@ -93,4 +88,30 @@ class RendererFactory
             \Magento\Framework\Webapi\Exception::HTTP_NOT_ACCEPTABLE
         );
     }
+
+    /**
+     * Get renderer config by accept type.
+     *
+     * @param string $acceptType
+     * @return array|null
+     */
+    private function getRendererConfig($acceptType)
+    {
+        // If Accept type = '*/*' then return default renderer.
+        if ($acceptType == '*/*' && isset($this->_renders['default'])) {
+            return $this->_renders['default'];
+        }
+        
+        foreach ($this->_renders as $rendererConfig) {
+            $rendererType = $rendererConfig['type'];
+            if ($acceptType == $rendererType
+                || $acceptType == current(explode('/', $rendererType)) . '/*'
+                || $acceptType == '*/*'
+            ) {
+                return $rendererConfig;
+            }
+        }
+
+        return null;
+    }
 }
diff --git a/lib/internal/Magento/Framework/Webapi/Test/Unit/Rest/Response/RendererFactoryTest.php b/lib/internal/Magento/Framework/Webapi/Test/Unit/Rest/Response/RendererFactoryTest.php
index ba460c5a5f6e66e7cd2d8efae56bd8ffa01d5ca4..dd7aa845f3091805a841f0324580f0d12634bc49 100644
--- a/lib/internal/Magento/Framework/Webapi/Test/Unit/Rest/Response/RendererFactoryTest.php
+++ b/lib/internal/Magento/Framework/Webapi/Test/Unit/Rest/Response/RendererFactoryTest.php
@@ -26,11 +26,18 @@ class RendererFactoryTest extends \PHPUnit\Framework\TestCase
         )->disableOriginalConstructor()->getMock();
 
         $renders = [
-            'default' => ['type' => '*/*', 'model' => \Magento\Framework\Webapi\Rest\Response\Renderer\Json::class],
+            'application_xml' => [
+                'type' => 'application/xml',
+                'model' => \Magento\Framework\Webapi\Rest\Response\Renderer\Xml::class,
+            ],
             'application_json' => [
                 'type' => 'application/json',
                 'model' => \Magento\Framework\Webapi\Rest\Response\Renderer\Json::class,
             ],
+            'default' => [
+                'type' => '*/*',
+                'model' => \Magento\Framework\Webapi\Rest\Response\Renderer\Json::class
+            ],
         ];
 
         $this->_factory = new \Magento\Framework\Webapi\Rest\Response\RendererFactory(
@@ -42,29 +49,43 @@ class RendererFactoryTest extends \PHPUnit\Framework\TestCase
 
     /**
      * Test GET method.
+     *
+     * @param array $acceptTypes
+     * @param string $model
+     * @dataProvider getTestDataProvider
      */
-    public function testGet()
+    public function testGet($acceptTypes, $model)
     {
-        $acceptTypes = ['application/json'];
-
         /** Mock request getAcceptTypes method to return specified value. */
         $this->_requestMock->expects($this->once())->method('getAcceptTypes')->will($this->returnValue($acceptTypes));
         /** Mock renderer. */
-        $rendererMock = $this->getMockBuilder(
-            \Magento\Framework\Webapi\Rest\Response\Renderer\Json::class
-        )->disableOriginalConstructor()->getMock();
+        $rendererMock = $this->getMockBuilder($model)->disableOriginalConstructor()->getMock();
         /** Mock object to return mocked renderer. */
         $this->_objectManagerMock->expects(
             $this->once()
         )->method(
             'get'
         )->with(
-            \Magento\Framework\Webapi\Rest\Response\Renderer\Json::class
+            $model
         )->will(
             $this->returnValue($rendererMock)
         );
         $this->_factory->get();
     }
+    
+    /**
+     * Data provider for method testGet
+     *
+     * @return array
+     */
+    public function getTestDataProvider()
+    {
+        return [
+            [['*/*'], \Magento\Framework\Webapi\Rest\Response\Renderer\Json::class],
+            [['application/json'], \Magento\Framework\Webapi\Rest\Response\Renderer\Json::class],
+            [['application/xml'], \Magento\Framework\Webapi\Rest\Response\Renderer\Xml::class],
+        ];
+    }
 
     /**
      * Test GET method with wrong Accept HTTP Header.