Security update for Core, with self-updated composer
[yaffs-website] / web / core / tests / Drupal / KernelTests / Core / Database / ConnectionTest.php
1 <?php
2
3 namespace Drupal\KernelTests\Core\Database;
4
5 use Drupal\Core\Database\Database;
6 use Drupal\Core\Database\DatabaseExceptionWrapper;
7
8 /**
9  * Tests of the core database system.
10  *
11  * @group Database
12  */
13 class ConnectionTest extends DatabaseTestBase {
14
15   /**
16    * Tests that connections return appropriate connection objects.
17    */
18   public function testConnectionRouting() {
19     // Clone the primary credentials to a replica connection.
20     // Note this will result in two independent connection objects that happen
21     // to point to the same place.
22     $connection_info = Database::getConnectionInfo('default');
23     Database::addConnectionInfo('default', 'replica', $connection_info['default']);
24
25     $db1 = Database::getConnection('default', 'default');
26     $db2 = Database::getConnection('replica', 'default');
27
28     $this->assertNotNull($db1, 'default connection is a real connection object.');
29     $this->assertNotNull($db2, 'replica connection is a real connection object.');
30     $this->assertNotIdentical($db1, $db2, 'Each target refers to a different connection.');
31
32     // Try to open those targets another time, that should return the same objects.
33     $db1b = Database::getConnection('default', 'default');
34     $db2b = Database::getConnection('replica', 'default');
35     $this->assertSame($db1, $db1b, 'A second call to getConnection() returns the same object.');
36     $this->assertSame($db2, $db2b, 'A second call to getConnection() returns the same object.');
37
38     // Try to open an unknown target.
39     $unknown_target = $this->randomMachineName();
40     $db3 = Database::getConnection($unknown_target, 'default');
41     $this->assertNotNull($db3, 'Opening an unknown target returns a real connection object.');
42     $this->assertSame($db1, $db3, 'An unknown target opens the default connection.');
43
44     // Try to open that unknown target another time, that should return the same object.
45     $db3b = Database::getConnection($unknown_target, 'default');
46     $this->assertSame($db3, $db3b, 'A second call to getConnection() returns the same object.');
47   }
48
49   /**
50    * Tests that connections return appropriate connection objects.
51    */
52   public function testConnectionRoutingOverride() {
53     // Clone the primary credentials to a replica connection.
54     // Note this will result in two independent connection objects that happen
55     // to point to the same place.
56     $connection_info = Database::getConnectionInfo('default');
57     Database::addConnectionInfo('default', 'replica', $connection_info['default']);
58
59     Database::ignoreTarget('default', 'replica');
60
61     $db1 = Database::getConnection('default', 'default');
62     $db2 = Database::getConnection('replica', 'default');
63
64     $this->assertSame($db1, $db2, 'Both targets refer to the same connection.');
65   }
66
67   /**
68    * Tests the closing of a database connection.
69    */
70   public function testConnectionClosing() {
71     // Open the default target so we have an object to compare.
72     $db1 = Database::getConnection('default', 'default');
73
74     // Try to close the default connection, then open a new one.
75     Database::closeConnection('default', 'default');
76     $db2 = Database::getConnection('default', 'default');
77
78     // Opening a connection after closing it should yield an object different than the original.
79     $this->assertNotIdentical($db1, $db2, 'Opening the default connection after it is closed returns a new object.');
80   }
81
82   /**
83    * Tests the connection options of the active database.
84    */
85   public function testConnectionOptions() {
86     $connection_info = Database::getConnectionInfo('default');
87
88     // Be sure we're connected to the default database.
89     $db = Database::getConnection('default', 'default');
90     $connectionOptions = $db->getConnectionOptions();
91
92     // In the MySQL driver, the port can be different, so check individual
93     // options.
94     $this->assertEqual($connection_info['default']['driver'], $connectionOptions['driver'], 'The default connection info driver matches the current connection options driver.');
95     $this->assertEqual($connection_info['default']['database'], $connectionOptions['database'], 'The default connection info database matches the current connection options database.');
96
97     // Set up identical replica and confirm connection options are identical.
98     Database::addConnectionInfo('default', 'replica', $connection_info['default']);
99     $db2 = Database::getConnection('replica', 'default');
100     // Getting a driver class ensures the namespace option is set.
101     $this->assertEquals($db->getDriverClass('select'), $db2->getDriverClass('select'));
102     $connectionOptions2 = $db2->getConnectionOptions();
103
104     // Get a fresh copy of the default connection options.
105     $connectionOptions = $db->getConnectionOptions();
106     $this->assertIdentical($connectionOptions, $connectionOptions2, 'The default and replica connection options are identical.');
107
108     // Set up a new connection with different connection info.
109     $test = $connection_info['default'];
110     $test['database'] .= 'test';
111     Database::addConnectionInfo('test', 'default', $test);
112     $connection_info = Database::getConnectionInfo('test');
113
114     // Get a fresh copy of the default connection options.
115     $connectionOptions = $db->getConnectionOptions();
116     $this->assertNotEqual($connection_info['default']['database'], $connectionOptions['database'], 'The test connection info database does not match the current connection options database.');
117   }
118
119   /**
120    * Ensure that you cannot execute multiple statements on phpversion() > 5.5.21 or > 5.6.5.
121    */
122   public function testMultipleStatementsForNewPhp() {
123     // This just tests mysql, as other PDO integrations don't allow disabling
124     // multiple statements.
125     if (Database::getConnection()->databaseType() !== 'mysql' || !defined('\PDO::MYSQL_ATTR_MULTI_STATEMENTS')) {
126       return;
127     }
128
129     $db = Database::getConnection('default', 'default');
130     // Disable the protection at the PHP level.
131     try {
132       $db->query('SELECT * FROM {test}; SELECT * FROM {test_people}',
133         [],
134         ['allow_delimiter_in_query' => TRUE]
135       );
136       $this->fail('No PDO exception thrown for multiple statements.');
137     }
138     catch (DatabaseExceptionWrapper $e) {
139       $this->pass('PDO exception thrown for multiple statements.');
140     }
141   }
142
143   /**
144    * Ensure that you cannot execute multiple statements.
145    */
146   public function testMultipleStatements() {
147
148     $db = Database::getConnection('default', 'default');
149     try {
150       $db->query('SELECT * FROM {test}; SELECT * FROM {test_people}');
151       $this->fail('No exception thrown for multiple statements.');
152     }
153     catch (\InvalidArgumentException $e) {
154       $this->pass('Exception thrown for multiple statements.');
155     }
156   }
157
158   /**
159    * Test the escapeTable(), escapeField() and escapeAlias() methods with all possible reserved words in PostgreSQL.
160    */
161   public function testPostgresqlReservedWords() {
162     if (Database::getConnection()->databaseType() !== 'pgsql') {
163       return;
164     }
165
166     $db = Database::getConnection('default', 'default');
167     $stmt = $db->query("SELECT word FROM pg_get_keywords() WHERE catcode IN ('R', 'T')");
168     $stmt->execute();
169     foreach ($stmt->fetchAllAssoc('word') as $word => $row) {
170       $expected = '"' . $word . '"';
171       $this->assertIdentical($db->escapeTable($word), $expected, format_string('The reserved word %word was correctly escaped when used as a table name.', ['%word' => $word]));
172       $this->assertIdentical($db->escapeField($word), $expected, format_string('The reserved word %word was correctly escaped when used as a column name.', ['%word' => $word]));
173       $this->assertIdentical($db->escapeAlias($word), $expected, format_string('The reserved word %word was correctly escaped when used as an alias.', ['%word' => $word]));
174     }
175   }
176
177 }