Patch: catalog_category_product_index

--- vendor/magento/module-catalog/Setup/UpgradeSchema.php    2019-11-12 16:43:39.884234228 +0100
+++ vendor/magento/module-catalog/Setup/UpgradeSchema.php    2019-11-12 16:00:03.338854758 +0100
@@ -37,6 +37,7 @@
             $this->addUniqueKeyToCategoryProductTable($setup);
         }
         if (version_compare($context->getVersion(), '2.1.4', '<')) {
+            $this->addCatalogCategoryProductIndex($setup);
             $this->addSourceEntityIdToProductEavIndex($setup);
         }
         if (version_compare($context->getVersion(), '2.1.5', '<')) {
@@ -841,4 +842,139 @@
             $setup->getIdxName('catalog_product_index_price_tmp', ['min_price'])
         );
     }
+
+    /**
+    * @param SchemaSetupInterface $setup
+    */
+    private function addCatalogCategoryProductIndex(SchemaSetupInterface $setup)
+    {
+        /**
+         * Create table 'catalog_category_product_index'
+         */
+        $table = $setup->getConnection()
+            ->newTable($setup->getTable('catalog_category_product_index'))
+            ->addColumn(
+                'category_id',
+                MagentoFrameworkDBDdlTable::TYPE_INTEGER,
+                null,
+                ['unsigned' => true, 'nullable' => false, 'primary' => true, 'default' => '0'],
+                'Category ID'
+            )
+            ->addColumn(
+                'product_id',
+                MagentoFrameworkDBDdlTable::TYPE_INTEGER,
+                null,
+                ['unsigned' => true, 'nullable' => false, 'primary' => true, 'default' => '0'],
+                'Product ID'
+            )
+            ->addColumn(
+                'position',
+                MagentoFrameworkDBDdlTable::TYPE_INTEGER,
+                null,
+                ['unsigned' => false, 'nullable' => true, 'default' => null],
+                'Position'
+            )
+            ->addColumn(
+                'is_parent',
+                MagentoFrameworkDBDdlTable::TYPE_SMALLINT,
+                null,
+                ['unsigned' => true, 'nullable' => false, 'default' => '0'],
+                'Is Parent'
+            )
+            ->addColumn(
+                'store_id',
+                MagentoFrameworkDBDdlTable::TYPE_SMALLINT,
+                null,
+                ['unsigned' => true, 'nullable' => false, 'primary' => true, 'default' => '0'],
+                'Store ID'
+            )
+            ->addColumn(
+                'visibility',
+                MagentoFrameworkDBDdlTable::TYPE_SMALLINT,
+                null,
+                ['unsigned' => true, 'nullable' => false],
+                'Visibility'
+            )
+            ->addIndex(
+                $setup->getIdxName(
+                    'catalog_category_product_index',
+                    ['product_id', 'store_id', 'category_id', 'visibility']
+                ),
+                ['product_id', 'store_id', 'category_id', 'visibility']
+            )
+            ->addIndex(
+                $setup->getIdxName(
+                    'catalog_category_product_index',
+                    ['store_id', 'category_id', 'visibility', 'is_parent', 'position']
+                ),
+                ['store_id', 'category_id', 'visibility', 'is_parent', 'position']
+            )
+            ->setComment('Catalog Category Product Index');
+        $setup->getConnection()->createTable($table);
+
+        /**
+         * Create table 'catalog_category_product_index_tmp'
+         */
+        $table = $setup->getConnection()
+            ->newTable(
+                $setup->getTable('catalog_category_product_index_tmp')
+            )
+            ->addColumn(
+                'category_id',
+                MagentoFrameworkDBDdlTable::TYPE_INTEGER,
+                null,
+                ['unsigned' => true, 'nullable' => false, 'default' => '0'],
+                'Category ID'
+            )
+            ->addColumn(
+                'product_id',
+                MagentoFrameworkDBDdlTable::TYPE_INTEGER,
+                null,
+                ['unsigned' => true, 'nullable' => false, 'default' => '0'],
+                'Product ID'
+            )
+            ->addColumn(
+                'position',
+                MagentoFrameworkDBDdlTable::TYPE_INTEGER,
+                null,
+                ['nullable' => false, 'default' => '0'],
+                'Position'
+            )
+            ->addColumn(
+                'is_parent',
+                MagentoFrameworkDBDdlTable::TYPE_SMALLINT,
+                null,
+                ['unsigned' => true, 'nullable' => false, 'default' => '0'],
+                'Is Parent'
+            )
+            ->addColumn(
+                'store_id',
+                MagentoFrameworkDBDdlTable::TYPE_SMALLINT,
+                null,
+                ['unsigned' => true, 'nullable' => false, 'default' => '0'],
+                'Store ID'
+            )
+            ->addColumn(
+                'visibility',
+                MagentoFrameworkDBDdlTable::TYPE_SMALLINT,
+                null,
+                ['unsigned' => true, 'nullable' => false],
+                'Visibility'
+            )
+            ->addIndex(
+                $setup->getIdxName('catalog_category_product_index_tmp', ['product_id', 'category_id', 'store_id']),
+                ['product_id', 'category_id', 'store_id']
+            )
+            ->setOption(
+                'type',
+                MagentoFrameworkDBAdapterPdoMysql::ENGINE_MEMORY
+            )
+            ->setComment(
+                'Catalog Category Product Indexer Temp Table'
+            );
+        $setup->getConnection()
+            ->createTable($table);
+
+        $setup->endSetup();
+    }
 }