7
7
namespace Magento \Framework \Setup \Declaration \Schema \Db \MySQL ;
8
8
9
9
use Magento \Framework \App \ResourceConnection ;
10
+ use Magento \Framework \DB \Adapter \ConnectionException ;
11
+ use Magento \Framework \DB \Adapter \SqlVersionProvider ;
12
+ use Magento \Framework \DB \Adapter \AdapterInterface ;
10
13
use Magento \Framework \Setup \Declaration \Schema \Db \DbSchemaWriterInterface ;
11
14
use Magento \Framework \Setup \Declaration \Schema \Db \Statement ;
12
15
use Magento \Framework \Setup \Declaration \Schema \Db \StatementAggregator ;
@@ -59,22 +62,30 @@ class DbSchemaWriter implements DbSchemaWriterInterface
59
62
*/
60
63
private $ dryRunLogger ;
61
64
65
+ /**
66
+ * @var SqlVersionProvider
67
+ */
68
+ private $ sqlVersionProvider ;
69
+
62
70
/**
63
71
* @param ResourceConnection $resourceConnection
64
- * @param StatementFactory $statementFactory
65
- * @param DryRunLogger $dryRunLogger
66
- * @param array $tableOptions
72
+ * @param StatementFactory $statementFactory
73
+ * @param DryRunLogger $dryRunLogger
74
+ * @param SqlVersionProvider $sqlVersionProvider
75
+ * @param array $tableOptions
67
76
*/
68
77
public function __construct (
69
78
ResourceConnection $ resourceConnection ,
70
79
StatementFactory $ statementFactory ,
71
80
DryRunLogger $ dryRunLogger ,
81
+ SqlVersionProvider $ sqlVersionProvider ,
72
82
array $ tableOptions = []
73
83
) {
74
84
$ this ->resourceConnection = $ resourceConnection ;
75
85
$ this ->statementFactory = $ statementFactory ;
76
86
$ this ->dryRunLogger = $ dryRunLogger ;
77
87
$ this ->tableOptions = array_replace ($ this ->tableOptions , $ tableOptions );
88
+ $ this ->sqlVersionProvider = $ sqlVersionProvider ;
78
89
}
79
90
80
91
/**
@@ -271,15 +282,14 @@ public function compile(StatementAggregator $statementAggregator, $dryRun)
271
282
$ statementsSql = [];
272
283
$ statement = null ;
273
284
274
- /**
275
- * @var Statement $statement
276
- */
277
- foreach ($ statementBank as $ statement ) {
278
- $ statementsSql [] = $ statement ->getStatement ();
279
- }
280
- $ adapter = $ this ->resourceConnection ->getConnection ($ statement ->getResource ());
281
-
282
285
if ($ dryRun ) {
286
+ /**
287
+ * @var Statement $statement
288
+ */
289
+ foreach ($ statementBank as $ statement ) {
290
+ $ statementsSql [] = $ statement ->getStatement ();
291
+ }
292
+ $ adapter = $ this ->resourceConnection ->getConnection ($ statement ->getResource ());
283
293
$ this ->dryRunLogger ->log (
284
294
sprintf (
285
295
$ this ->statementDirectives [$ statement ->getType ()],
@@ -288,18 +298,81 @@ public function compile(StatementAggregator $statementAggregator, $dryRun)
288
298
)
289
299
);
290
300
} else {
301
+ $ this ->doQuery ($ statementBank );
302
+ $ statement = end ($ statementBank );
303
+ //Do post update, like SQL DML operations or etc...
304
+ foreach ($ statement ->getTriggers () as $ trigger ) {
305
+ call_user_func ($ trigger );
306
+ }
307
+ }
308
+ }
309
+ }
310
+
311
+ /**
312
+ * Check if we can concatenate sql into one statement
313
+ *
314
+ * Due to issues with some versions of MariaBD such statements
315
+ * may produce errors, e.g. with foreign key definition with column modification
316
+ *
317
+ * @return bool
318
+ * @throws ConnectionException
319
+ */
320
+ private function isNeedToSplitSql () : bool
321
+ {
322
+ return str_contains ($ this ->sqlVersionProvider ->getSqlVersion (), SqlVersionProvider::MARIA_DB_10_4_VERSION ) ||
323
+ str_contains ($ this ->sqlVersionProvider ->getSqlVersion (), SqlVersionProvider::MARIA_DB_10_6_VERSION );
324
+ }
325
+
326
+ /**
327
+ * Perform queries based on statements
328
+ *
329
+ * @param Statement[] $statementBank
330
+ * @return void
331
+ * @throws ConnectionException
332
+ */
333
+ private function doQuery (
334
+ array $ statementBank
335
+ ) : void {
336
+ if (empty ($ statementBank )) {
337
+ return ;
338
+ }
339
+
340
+ $ statement = null ;
341
+ $ statementsSql = [];
342
+ foreach ($ statementBank as $ statement ) {
343
+ $ statementsSql [] = $ statement ->getStatement ();
344
+ }
345
+ $ adapter = $ this ->resourceConnection ->getConnection ($ statement ->getResource ());
346
+
347
+ if ($ this ->isNeedToSplitSql ()) {
348
+ $ preparedStatements = $ this ->getPreparedStatements ($ statementBank );
349
+
350
+ if (!empty ($ preparedStatements ['canBeCombinedStatements ' ])) {
291
351
$ adapter ->query (
292
352
sprintf (
293
353
$ this ->statementDirectives [$ statement ->getType ()],
294
354
$ adapter ->quoteIdentifier ($ statement ->getTableName ()),
295
- implode (", " , $ statementsSql )
355
+ implode (", " , $ preparedStatements ['canBeCombinedStatements ' ])
356
+ )
357
+ );
358
+ }
359
+ foreach ($ preparedStatements ['separatedStatements ' ] as $ separatedStatement ) {
360
+ $ adapter ->query (
361
+ sprintf (
362
+ $ this ->statementDirectives [$ statement ->getType ()],
363
+ $ adapter ->quoteIdentifier ($ statement ->getTableName ()),
364
+ $ separatedStatement
296
365
)
297
366
);
298
- //Do post update, like SQL DML operations or etc...
299
- foreach ($ statement ->getTriggers () as $ trigger ) {
300
- call_user_func ($ trigger );
301
- }
302
367
}
368
+ } else {
369
+ $ adapter ->query (
370
+ sprintf (
371
+ $ this ->statementDirectives [$ statement ->getType ()],
372
+ $ adapter ->quoteIdentifier ($ statement ->getTableName ()),
373
+ implode (", " , $ statementsSql )
374
+ )
375
+ );
303
376
}
304
377
}
305
378
@@ -309,6 +382,7 @@ public function compile(StatementAggregator $statementAggregator, $dryRun)
309
382
* @param string $tableName
310
383
* @param string $resource
311
384
* @return int
385
+ * @throws \Zend_Db_Statement_Exception
312
386
*/
313
387
private function getNextAutoIncrementValue (string $ tableName , string $ resource ): int
314
388
{
@@ -323,6 +397,59 @@ private function getNextAutoIncrementValue(string $tableName, string $resource):
323
397
} else {
324
398
return 1 ;
325
399
}
400
+ }
326
401
402
+ /**
403
+ * Prepare list of modified columns from statement
404
+ *
405
+ * @param array $statementBank
406
+ * @return array
407
+ */
408
+ private function getModifiedColumns (array $ statementBank ) : array
409
+ {
410
+ $ columns = [];
411
+ foreach ($ statementBank as $ statement ) {
412
+ if ($ statement ->getType () === 'alter '
413
+ && str_contains ($ statement ->getStatement (), 'MODIFY COLUMN ' )) {
414
+ $ columns [] = $ statement ->getName ();
415
+ }
416
+ }
417
+ return $ columns ;
418
+ }
419
+
420
+ /**
421
+ * Separate statements that can't be executed as one statement
422
+ *
423
+ * @param array $statementBank
424
+ * @return array
425
+ */
426
+ private function getPreparedStatements (array $ statementBank ) : array
427
+ {
428
+ $ statementsSql = [];
429
+ foreach ($ statementBank as $ statement ) {
430
+ $ statementsSql [] = $ statement ->getStatement ();
431
+ }
432
+ $ result = ['separatedStatements ' => [], 'canBeCombinedStatements ' => []];
433
+ $ modifiedColumns = $ this ->getModifiedColumns ($ statementBank );
434
+
435
+ foreach ($ statementsSql as $ statementSql ) {
436
+ if (str_contains ($ statementSql , 'FOREIGN KEY ' )) {
437
+ $ isThisColumnModified = false ;
438
+ foreach ($ modifiedColumns as $ modifiedColumn ) {
439
+ if (str_contains ($ statementSql , '` ' . $ modifiedColumn . '` ' )) {
440
+ $ isThisColumnModified = true ;
441
+ break ;
442
+ }
443
+ }
444
+ if ($ isThisColumnModified ) {
445
+ $ result ['separatedStatements ' ][] = $ statementSql ;
446
+ } else {
447
+ $ result ['canBeCombinedStatements ' ][] = $ statementSql ;
448
+ }
449
+ } else {
450
+ $ result ['canBeCombinedStatements ' ][] = $ statementSql ;
451
+ }
452
+ }
453
+ return $ result ;
327
454
}
328
455
}
0 commit comments