From e177462c901cd29c3e423640a6f538a930c29536 Mon Sep 17 00:00:00 2001 From: Klaus Weidenbach Date: Sat, 9 Dec 2017 00:31:09 +0100 Subject: [PATCH 1/5] :white_check_mark: Unit Test for \DBA factory. --- tests/unit/includes/dba/DBATest.php | 67 +++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tests/unit/includes/dba/DBATest.php diff --git a/tests/unit/includes/dba/DBATest.php b/tests/unit/includes/dba/DBATest.php new file mode 100644 index 000000000..900d13083 --- /dev/null +++ b/tests/unit/includes/dba/DBATest.php @@ -0,0 +1,67 @@ +assertNull(\DBA::$dba); + + $ret = \DBA::dba_factory('server', 'port', 'user', 'pass', 'db', '0'); + $this->assertInstanceOf('dba_pdo', $ret); + $this->assertFalse($ret->connected); + + $this->assertSame('mysql', \DBA::$scheme); + $this->assertSame('schema_mysql.sql', \DBA::$install_script); + $this->assertSame('0001-01-01 00:00:00', \DBA::$null_date); + $this->assertSame('UTC_TIMESTAMP()', \DBA::$utc_now); + $this->assertSame('`', \DBA::$tquot); + } + + public function testDbaFactoryPostgresql() { + $this->assertNull(\DBA::$dba); + + $ret = \DBA::dba_factory('server', 'port', 'user', 'pass', 'db', '1'); + $this->assertInstanceOf('dba_pdo', $ret); + $this->assertFalse($ret->connected); + + $this->assertSame('pgsql', \DBA::$scheme); + $this->assertSame('schema_postgres.sql', \DBA::$install_script); + $this->assertSame('0001-01-01 00:00:00', \DBA::$null_date); + $this->assertSame("now() at time zone 'UTC'", \DBA::$utc_now); + $this->assertSame('"', \DBA::$tquot); + } + +} From fb111e6d958fdf56352db66e144134241abbacf8 Mon Sep 17 00:00:00 2001 From: Klaus Weidenbach Date: Sun, 10 Dec 2017 01:29:49 +0100 Subject: [PATCH 2/5] :white_check_mark: Unit Test for dba_pdo driver class. --- tests/phpunit-pgsql.xml | 10 ++ tests/phpunit.xml.dist | 10 ++ tests/travis/prepare_mysql.sh | 4 +- tests/travis/prepare_pgsql.sh | 9 +- tests/unit/DatabaseTestCase.php | 68 +++++++++ tests/unit/includes/dba/_files/account.yml | 9 ++ tests/unit/includes/dba/dba_pdoTest.php | 167 +++++++++++++++++++++ 7 files changed, 273 insertions(+), 4 deletions(-) create mode 100644 tests/unit/DatabaseTestCase.php create mode 100644 tests/unit/includes/dba/_files/account.yml create mode 100644 tests/unit/includes/dba/dba_pdoTest.php diff --git a/tests/phpunit-pgsql.xml b/tests/phpunit-pgsql.xml index ec4a6fc2d..d95c4897b 100644 --- a/tests/phpunit-pgsql.xml +++ b/tests/phpunit-pgsql.xml @@ -32,4 +32,14 @@ highLowerBound="70"/> + + + + + + + + + diff --git a/tests/phpunit.xml.dist b/tests/phpunit.xml.dist index a22317b08..7b9c1d563 100644 --- a/tests/phpunit.xml.dist +++ b/tests/phpunit.xml.dist @@ -35,4 +35,14 @@ highLowerBound="70"/> + + + + + + + + + diff --git a/tests/travis/prepare_mysql.sh b/tests/travis/prepare_mysql.sh index 095ad7e25..9fd79c1ab 100755 --- a/tests/travis/prepare_mysql.sh +++ b/tests/travis/prepare_mysql.sh @@ -42,8 +42,8 @@ mysql $PROTO -e "SELECT @@sql_mode;" # Create Hubzilla database mysql $PROTO -u root -e "CREATE DATABASE IF NOT EXISTS hubzilla;"; -mysql $PROTO -u root -e "CREATE USER 'hubzilla'@'localhost' IDENTIFIED BY 'hubzilla';" -mysql $PROTO -u root -e "GRANT ALL ON hubzilla.* TO 'hubzilla'@'localhost';" +mysql $PROTO -u root -e "CREATE USER 'hubzilla'@'%' IDENTIFIED BY 'hubzilla';" +mysql $PROTO -u root -e "GRANT ALL ON hubzilla.* TO 'hubzilla'@'%';" # Import table structure mysql $PROTO -u root hubzilla < ./install/schema_mysql.sql diff --git a/tests/travis/prepare_pgsql.sh b/tests/travis/prepare_pgsql.sh index 63c7388cb..3c38ef60c 100755 --- a/tests/travis/prepare_pgsql.sh +++ b/tests/travis/prepare_pgsql.sh @@ -34,10 +34,15 @@ psql -U postgres -c "SELECT VERSION();" # Create Hubzilla database psql -U postgres -c "DROP DATABASE IF EXISTS hubzilla;" -psql -U postgres -c "CREATE DATABASE hubzilla;" +psql -U postgres -v ON_ERROR_STOP=1 <<-EOSQL + CREATE USER hubzilla WITH PASSWORD 'hubzilla'; + CREATE DATABASE hubzilla; + ALTER DATABASE hubzilla OWNER TO hubzilla; + GRANT ALL PRIVILEGES ON DATABASE hubzilla TO hubzilla; +EOSQL # Import table structure -psql -U postgres -v ON_ERROR_STOP=1 hubzilla < ./install/schema_postgres.sql +psql -U hubzilla -v ON_ERROR_STOP=1 hubzilla < ./install/schema_postgres.sql # Show databases and tables psql -U postgres -l diff --git a/tests/unit/DatabaseTestCase.php b/tests/unit/DatabaseTestCase.php new file mode 100644 index 000000000..18c1cfb17 --- /dev/null +++ b/tests/unit/DatabaseTestCase.php @@ -0,0 +1,68 @@ +conn === null) { + if (self::$pdo === null) { + $dsn = \getenv('hz_db_scheme') . ':host=' . \getenv('hz_db_server') + . ';port=' . \getenv('hz_db_port') . ';dbname=' . \getenv('hz_db_database'); + + self::$pdo = new \PDO($dsn, \getenv('hz_db_user'), \getenv('hz_db_pass')); + } + $this->conn = $this->createDefaultDBConnection(self::$pdo, \getenv('hz_db_database')); + } + + return $this->conn; + } +} diff --git a/tests/unit/includes/dba/_files/account.yml b/tests/unit/includes/dba/_files/account.yml new file mode 100644 index 000000000..344bdb799 --- /dev/null +++ b/tests/unit/includes/dba/_files/account.yml @@ -0,0 +1,9 @@ +account: + - + account_id: 42 + account_email: "hubzilla@example.com" + account_language: "no" + - + account_id: 43 + account_email: "hubzilla@example.org" + account_language: "de" diff --git a/tests/unit/includes/dba/dba_pdoTest.php b/tests/unit/includes/dba/dba_pdoTest.php new file mode 100644 index 000000000..ce6e1ffd6 --- /dev/null +++ b/tests/unit/includes/dba/dba_pdoTest.php @@ -0,0 +1,167 @@ +dba = new \dba_pdo( + \getenv('hz_db_server'), + \getenv('hz_db_scheme'), + \getenv('hz_db_port'), + \getenv('hz_db_user'), + \getenv('hz_db_pass'), + \getenv('hz_db_database') + ); + } + protected function assertPreConditions() { + $this->assertSame('pdo', $this->dba->getdriver(), "Driver is expected to be 'pdo'."); + $this->assertInstanceOf('dba_driver', $this->dba); + $this->assertTrue($this->dba->connected, 'Pre condition failed, DB is not connected.'); + $this->assertInstanceOf('PDO', $this->dba->db); + } + protected function tearDown() { + $this->dba = null; + } + + + /** + * @group mysql + */ + public function testQuoteintervalOnMysql() { + $this->assertSame('value', $this->dba->quote_interval('value')); + } + /** + * @group postgresql + */ + public function testQuoteintervalOnPostgresql() { + $this->assertSame("'value'", $this->dba->quote_interval('value')); + } + + /** + * @group mysql + */ + public function testGenerateMysqlConcatSql() { + $this->assertSame('GROUP_CONCAT(DISTINCT field SEPARATOR \';\')', $this->dba->concat('field', ';')); + $this->assertSame('GROUP_CONCAT(DISTINCT field2 SEPARATOR \' \')', $this->dba->concat('field2', ' ')); + } + /** + * @group postgresql + */ + public function testGeneratePostgresqlConcatSql() { + $this->assertSame('string_agg(field,\';\')', $this->dba->concat('field', ';')); + $this->assertSame('string_agg(field2,\' \')', $this->dba->concat('field2', ' ')); + } + + + public function testConnectToSqlServer() { + // connect() is done in dba_pdo constructor which is called in setUp() + $this->assertTrue($this->dba->connected); + } + + /** + * @depends testConnectToSqlServer + */ + public function testCloseSqlServerConnection() { + $this->dba->close(); + + $this->assertNull($this->dba->db); + $this->assertFalse($this->dba->connected); + } + + /** + * @depends testConnectToSqlServer + */ + public function testSelectQueryShouldReturnArray() { + $ret = $this->dba->q('SELECT * FROM account'); + + $this->assertTrue(is_array($ret)); + } + + /** + * @depends testConnectToSqlServer + */ + public function testInsertQueryShouldReturnPdostatement() { + // Fixture account.yml adds two entries to account table + $this->assertEquals(2, $this->getConnection()->getRowCount('account'), 'Pre-Condition'); + + $ret = $this->dba->q('INSERT INTO account + (account_id, account_email, account_language) + VALUES (100, \'insert@example.com\', \'de\') + '); + $this->assertInstanceOf('PDOStatement', $ret); + + $this->assertEquals(3, $this->getConnection()->getRowCount('account'), 'Inserting failed'); + } + + + public function testConnectToWrongSqlServer() { + $nodba = new \dba_pdo('wrongserver', + \getenv('hz_db_scheme'), \getenv('hz_db_port'), + \getenv('hz_db_user'), \getenv('hz_db_pass'), + \getenv('hz_db_database') + ); + + $this->assertSame('pdo', $nodba->getdriver()); + $this->assertInstanceOf('dba_pdo', $nodba); + $this->assertFalse($nodba->connected); + $this->assertNull($nodba->db); + + $this->assertFalse($nodba->q('SELECT * FROM account')); + } + +} From 509844fd7e08ebccec4d924845d0f2a60f5768e5 Mon Sep 17 00:00:00 2001 From: Klaus Weidenbach Date: Fri, 8 Dec 2017 00:26:00 +0100 Subject: [PATCH 3/5] :fire: Cleanup old database related files. Remove non used database drivers, remove unused methods. Improve documentation. --- include/dba/dba_driver.php | 82 ++++++++++-------------- include/dba/dba_mysql.php | 67 -------------------- include/dba/dba_mysqli.php | 86 ------------------------- include/dba/dba_pdo.php | 40 ++++++++---- include/dba/dba_postgres.php | 117 ----------------------------------- 5 files changed, 60 insertions(+), 332 deletions(-) delete mode 100755 include/dba/dba_mysql.php delete mode 100755 include/dba/dba_mysqli.php delete mode 100644 include/dba/dba_postgres.php diff --git a/include/dba/dba_driver.php b/include/dba/dba_driver.php index deec9adfd..b3298b673 100755 --- a/include/dba/dba_driver.php +++ b/include/dba/dba_driver.php @@ -1,15 +1,20 @@ connected) { - - if(strpbrk($server,':;')) { - $dsn = $server; - } - else { - $dsn = self::$scheme . ':host=' . $server . (intval($port) ? '' : ';port=' . $port); - } - $dsn .= ';dbname=' . $db; - - - self::$dba->pdo_set(array($dsn,$user,$pass)); - } define('NULL_DATE', self::$null_date); define('ACTIVE_DBTYPE', self::$dbtype); define('TQUOT', self::$tquot); + return self::$dba; } } /** - * @brief abstract database driver class. + * @brief Abstract database driver class. * - * This class gets extended by the real database driver classes, e.g. dba_mysql, - * dba_mysqli. + * This class gets extended by the real database driver class. We used to have + * dba_mysql, dba_mysqli or dba_postgres, but we moved to PDO and the only + * implemented driver is dba_pdo. */ abstract class dba_driver { // legacy behavior public $db; - protected $pdo = array(); public $debug = 0; public $connected = false; @@ -111,6 +98,7 @@ abstract class dba_driver { * This abstract function needs to be implemented in the real driver. * * @param string $server DB server name + * @param string $scheme DB scheme * @param string $port DB port * @param string $user DB username * @param string $pass DB password @@ -166,6 +154,7 @@ abstract class dba_driver { $platform_name = \Zotlabs\Lib\System::get_platform_name(); if(file_exists('install/' . $platform_name . '/' . \DBA::$install_script)) return 'install/' . $platform_name . '/' . \DBA::$install_script; + return 'install/' . \DBA::$install_script; } @@ -173,7 +162,6 @@ abstract class dba_driver { return \DBA::$tquot; } - function utcnow() { return \DBA::$utc_now; } @@ -232,19 +220,12 @@ abstract class dba_driver { return $str; } - function pdo_set($x) { - $this->pdo = $x; - } - - function pdo_get() { - return $this->pdo; - } - } // end abstract dba_driver class - +// // Procedural functions +// function printable($s) { $s = preg_replace("~([\x01-\x08\x0E-\x0F\x10-\x1F\x7F-\xFF])~",".", $s); @@ -275,7 +256,7 @@ function dbg($state) { * wrapping with intval(). * * @param string $str A string to pass to a DB query - * @return Return an escaped string of the value to pass to a DB query. + * @return string Return an escaped string of the value to pass to a DB query. */ function dbesc($str) { @@ -298,6 +279,7 @@ function dbunescbin($str) { function dbescdate($date) { if(is_null_date($date)) return \DBA::$dba->escape(NULL_DATE); + return \DBA::$dba->escape($date); } @@ -330,17 +312,17 @@ function db_use_index($str) { * * printf style arguments %s and %d are replaced with variable arguments, which * should each be appropriately dbesc() or intval(). + * * SELECT queries return an array of results or false if SQL or DB error. Other * queries return true if the command was successful or false if it wasn't. * * Example: - * $r = q("SELECT * FROM %s WHERE `uid` = %d", - * 'user', 1); + * @code{.php}$r = q("SELECT * FROM %s WHERE `uid` = %d", + * 'user', 1);@endcode * * @param string $sql The SQL query to execute * @return bool|array */ - function q($sql) { $args = func_get_args(); @@ -359,8 +341,8 @@ function q($sql) { } /* - * This will happen occasionally trying to store the - * session data after abnormal program termination + * This will happen occasionally trying to store the + * session data after abnormal program termination */ db_logger('dba: no database: ' . print_r($args,true),LOGGER_NORMAL,LOG_CRIT); @@ -389,8 +371,8 @@ function dbq($sql) { // Caller is responsible for ensuring that any integer arguments to // dbesc_array are actually integers and not malformed strings containing -// SQL injection vectors. All integer array elements should be specifically -// cast to int to avoid trouble. +// SQL injection vectors. All integer array elements should be specifically +// cast to int to avoid trouble. function dbesc_array_cb(&$item, $key) { if(is_string($item)) { @@ -423,7 +405,7 @@ function dbesc_array(&$arr) { function db_getfunc($f) { $lookup = array( 'rand'=>array( - DBTYPE_MYSQL=>'RAND()', + DBTYPE_MYSQL=>'RAND()', DBTYPE_POSTGRES=>'RANDOM()' ), 'utc_timestamp'=>array( diff --git a/include/dba/dba_mysql.php b/include/dba/dba_mysql.php deleted file mode 100755 index 8b51cf578..000000000 --- a/include/dba/dba_mysql.php +++ /dev/null @@ -1,67 +0,0 @@ -db = mysql_connect($server.":".$port,$user,$pass); - if($this->db && mysql_select_db($db,$this->db)) { - $this->connected = true; - } - if($this->connected) { - return true; - } - return false; - } - - - function q($sql) { - if((! $this->db) || (! $this->connected)) - return false; - - $this->error = ''; - $result = @mysql_query($sql,$this->db); - - - if(mysql_errno($this->db)) - $this->error = mysql_error($this->db); - - if($result === false || $this->error) { - logger('dba_mysql: ' . printable($sql) . ' returned false.' . "\n" . $this->error); - if(file_exists('dbfail.out')) - file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . ' returned false' . "\n" . $this->error . "\n", FILE_APPEND); - } - - if(($result === true) || ($result === false)) - return $result; - - $r = array(); - if(mysql_num_rows($result)) { - while($x = mysql_fetch_array($result,MYSQL_ASSOC)) - $r[] = $x; - mysql_free_result($result); - if($this->debug) - logger('dba_mysql: ' . printable(print_r($r,true))); - } - return $r; - } - - function escape($str) { - if($this->db && $this->connected) { - return @mysql_real_escape_string($str,$this->db); - } - } - - function close() { - if($this->db) - mysql_close($this->db); - $this->connected = false; - } - - function getdriver() { - return 'mysql'; - } - -} diff --git a/include/dba/dba_mysqli.php b/include/dba/dba_mysqli.php deleted file mode 100755 index 165c8e969..000000000 --- a/include/dba/dba_mysqli.php +++ /dev/null @@ -1,86 +0,0 @@ -db = new mysqli($server,$user,$pass,$db, $port); - else - $this->db = new mysqli($server,$user,$pass,$db); - - if($this->db->connect_error) { - $this->connected = false; - $this->error = $this->db->connect_error; - - if(file_exists('dbfail.out')) { - file_put_contents('dbfail.out', datetime_convert() . "\nConnect: " . $this->error . "\n", FILE_APPEND); - } - - return false; - } - else { - $this->connected = true; - return true; - } - } - - function q($sql) { - if((! $this->db) || (! $this->connected)) - return false; - - $this->error = ''; - $result = $this->db->query($sql); - - if($this->db->errno) - $this->error = $this->db->error; - - - if($this->error) { - db_logger('dba_mysqli: ERROR: ' . printable($sql) . "\n" . $this->error, LOGGER_NORMAL, LOG_ERR); - if(file_exists('dbfail.out')) { - file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . "\n" . $this->error . "\n", FILE_APPEND); - } - } - - if(($result === true) || ($result === false)) { - if($this->debug) { - db_logger('dba_mysqli: DEBUG: ' . printable($sql) . ' returns ' . (($result) ? 'true' : 'false'), LOGGER_NORMAL,(($result) ? LOG_INFO : LOG_ERR)); - } - return $result; - } - - if($this->debug) { - db_logger('dba_mysqli: DEBUG: ' . printable($sql) . ' returned ' . $result->num_rows . ' results.', LOGGER_NORMAL, LOG_INFO); - } - - $r = array(); - if($result->num_rows) { - while($x = $result->fetch_array(MYSQLI_ASSOC)) - $r[] = $x; - $result->free_result(); - if($this->debug) { - db_logger('dba_mysqli: ' . printable(print_r($r,true)), LOGGER_NORMAL, LOG_INFO); - } - } - return $r; - } - - function escape($str) { - if($this->db && $this->connected) { - return @$this->db->real_escape_string($str); - } - } - - function close() { - if($this->db) - $this->db->close(); - $this->connected = false; - } - - function getdriver() { - return 'mysqli'; - } - -} \ No newline at end of file diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php index a9d824a50..719f23c4b 100755 --- a/include/dba/dba_pdo.php +++ b/include/dba/dba_pdo.php @@ -1,14 +1,21 @@ -driver_dbtype = $scheme; if(strpbrk($server,':;')) { @@ -17,7 +24,7 @@ class dba_pdo extends dba_driver { else { $dsn = $this->driver_dbtype . ':host=' . $server . (intval($port) ? ';port=' . $port : ''); } - + $dsn .= ';dbname=' . $db; try { @@ -36,10 +43,19 @@ class dba_pdo extends dba_driver { $this->q("SET standard_conforming_strings = 'off'; SET backslash_quote = 'on';"); $this->connected = true; - return true; + return true; } + /** + * {@inheritDoc} + * @see dba_driver::q() + * + * @return bool|array|PDOStatement + * - \b false if not connected or PDOException occured on query + * - \b array with results on a SELECT query + * - \b PDOStatement on a non SELECT SQL query + */ function q($sql) { if((! $this->db) || (! $this->connected)) return false; @@ -57,7 +73,7 @@ class dba_pdo extends dba_driver { $result = $this->db->query($sql, PDO::FETCH_ASSOC); } catch(PDOException $e) { - + $this->error = $e->getMessage(); if($this->error) { db_logger('dba_pdo: ERROR: ' . printable($sql) . "\n" . $this->error, LOGGER_NORMAL, LOG_ERR); @@ -82,11 +98,10 @@ class dba_pdo extends dba_driver { } if($this->debug) { - db_logger('dba_pdo: DEBUG: ' . printable($sql) . ' returned ' . count($r) . ' results.', LOGGER_NORMAL, LOG_INFO); + db_logger('dba_pdo: DEBUG: ' . printable($sql) . ' returned ' . count($r) . ' results.', LOGGER_NORMAL, LOG_INFO); db_logger('dba_pdo: ' . printable(print_r($r,true)), LOGGER_NORMAL, LOG_INFO); } - return (($this->error) ? false : $r); } @@ -99,9 +114,10 @@ class dba_pdo extends dba_driver { function close() { if($this->db) $this->db = null; + $this->connected = false; } - + function concat($fld,$sep) { if($this->driver_dbtype === 'pgsql') { return 'string_agg(' . $fld . ',\'' . $sep . '\')'; @@ -140,7 +156,7 @@ class dba_pdo extends dba_driver { return $this->escape($str); } } - + function unescapebin($str) { if($this->driver_dbtype === 'pgsql' && (! is_null($str))) { $x = ''; diff --git a/include/dba/dba_postgres.php b/include/dba/dba_postgres.php deleted file mode 100644 index 560d8da60..000000000 --- a/include/dba/dba_postgres.php +++ /dev/null @@ -1,117 +0,0 @@ -db = pg_connect($connstr); - if($this->db !== false) { - $this->connected = true; - } else { - $this->connected = false; - } - $this->q("SET standard_conforming_strings = 'off'; SET backslash_quote = 'on';"); // emulate mysql string escaping to prevent massive code-clobber - return $this->connected; - } - - function q($sql) { - if((! $this->db) || (! $this->connected)) - return false; - - if(!strpos($sql, ';')) - $sql .= ';'; - - if(strpos($sql, '`')) // this is a hack. quoted identifiers should be replaced everywhere in the code with dbesc_identifier(), remove this once it is - $sql = str_replace('`', '"', $sql); - - $this->error = ''; - $result = @pg_query($this->db, $sql); - if(file_exists('db-allqueries.out')) { - $bt = debug_backtrace(); - $trace = array(); - foreach($bt as $frame) { - if(!empty($frame['file']) && @strstr($frame['file'], $_SERVER['DOCUMENT_ROOT'])) - $frame['file'] = substr($frame['file'], strlen($_SERVER['DOCUMENT_ROOT'])+1); - - $trace[] = $frame['file'] . ':' . $frame['function'] . '():' . $frame['line'] ; - } - $compact = join(', ', $trace); - file_put_contents('db-allqueries.out', datetime_convert() . ": " . $sql . ' is_resource: '.var_export(is_resource($result), true).', backtrace: '.$compact."\n\n", FILE_APPEND); - } - - if($result === false) - $this->error = pg_last_error($this->db); - - if($result === false || $this->error) { - //db_logger('dba_postgres: ' . printable($sql) . ' returned false.' . "\n" . $this->error); - if(file_exists('dbfail.out')) - file_put_contents('dbfail.out', datetime_convert() . "\n" . printable($sql) . ' returned false' . "\n" . $this->error . "\n", FILE_APPEND); - } - - if(($result === true) || ($result === false)) - return $result; - - if(pg_result_status($result) == PGSQL_COMMAND_OK) - return true; - - $r = array(); - if(pg_num_rows($result)) { - while($x = pg_fetch_array($result, null, PGSQL_ASSOC)) - $r[] = $x; - pg_free_result($result); - if($this->debug) - db_logger('dba_postgres: ' . printable(print_r($r,true))); - } - return $r; - } - - function escape($str) { - if($this->db && $this->connected) { - $x = @pg_escape_string($this->db, $str); - return $x; - } - } - - function escapebin($str) { - return pg_escape_bytea($str); - } - - function unescapebin($str) { - return pg_unescape_bytea($str); - } - - function close() { - if($this->db) - pg_close($this->db); - $this->connected = false; - } - - function quote_interval($txt) { - return "'$txt'"; - } - - function escape_identifier($str) { - return pg_escape_identifier($this->db, $str); - } - - function optimize_table($table) { - // perhaps do some equivalent thing here, vacuum, etc? I think this is the DBA's domain anyway. Applications should not need to muss with this. - // for now do nothing without a compelling reason. function overrides default legacy mysql. - } - - function concat($fld, $sep) { - return 'string_agg(' . $fld . ',\'' . $sep . '\')'; - } - - function getdriver() { - return 'pgsql'; - } -} \ No newline at end of file From 4bf0c9e36a4a89d6b84c6bf8a74124603add9d9e Mon Sep 17 00:00:00 2001 From: Klaus Weidenbach Date: Mon, 22 Jan 2018 22:59:13 +0100 Subject: [PATCH 4/5] :white_check_mark: Add tests for non existent tables. Prevent PHP warnings "Undefined variable" in dba_pdo::q(); --- include/dba/dba_pdo.php | 3 ++- tests/unit/includes/dba/dba_pdoTest.php | 22 ++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/include/dba/dba_pdo.php b/include/dba/dba_pdo.php index 719f23c4b..f24c5381a 100755 --- a/include/dba/dba_pdo.php +++ b/include/dba/dba_pdo.php @@ -66,8 +66,9 @@ class dba_pdo extends dba_driver { } } + $result = null; $this->error = ''; - $select = ((stripos($sql,'select') === 0) ? true : false); + $select = ((stripos($sql, 'select') === 0) ? true : false); try { $result = $this->db->query($sql, PDO::FETCH_ASSOC); diff --git a/tests/unit/includes/dba/dba_pdoTest.php b/tests/unit/includes/dba/dba_pdoTest.php index ce6e1ffd6..12e574d42 100644 --- a/tests/unit/includes/dba/dba_pdoTest.php +++ b/tests/unit/includes/dba/dba_pdoTest.php @@ -164,4 +164,26 @@ class dba_pdoTest extends DatabaseTestCase { $this->assertFalse($nodba->q('SELECT * FROM account')); } + /** + * @depends testConnectToSqlServer + */ + public function testSelectQueryToNonExistentTableShouldReturnFalse() { + $ret = $this->dba->q('SELECT * FROM non_existent_table'); + + $this->assertFalse($ret); + } + + /** + * @depends testConnectToSqlServer + */ + public function testInsertQueryToNonExistentTableShouldReturnEmptyArray() { + $ret = $this->dba->q('INSERT INTO non_existent_table + (account_email, account_language) + VALUES (\'email@example.com\', \'en\') + '); + + $this->assertNotInstanceOf('PDOStatement', $ret); + $this->isEmpty($ret); + } + } From 210c91398da573d3c44bd1ff5bee4c65128c8686 Mon Sep 17 00:00:00 2001 From: Klaus Weidenbach Date: Mon, 29 Jan 2018 21:14:03 +0100 Subject: [PATCH 5/5] Make it little bit less likely to erase a real database. Changed the default PHPUnit database environment variables to make it little bit less likely to truncate accidently a real database. --- tests/phpunit-pgsql.xml | 9 +++++---- tests/phpunit.xml.dist | 9 +++++---- tests/travis/prepare_mysql.sh | 12 ++++++------ tests/travis/prepare_pgsql.sh | 14 +++++++------- 4 files changed, 23 insertions(+), 21 deletions(-) diff --git a/tests/phpunit-pgsql.xml b/tests/phpunit-pgsql.xml index d95c4897b..078056d56 100644 --- a/tests/phpunit-pgsql.xml +++ b/tests/phpunit-pgsql.xml @@ -33,13 +33,14 @@ - + - + - + diff --git a/tests/phpunit.xml.dist b/tests/phpunit.xml.dist index 7b9c1d563..97c84fb81 100644 --- a/tests/phpunit.xml.dist +++ b/tests/phpunit.xml.dist @@ -36,13 +36,14 @@ - + - + - + diff --git a/tests/travis/prepare_mysql.sh b/tests/travis/prepare_mysql.sh index 9fd79c1ab..5b1c96d78 100755 --- a/tests/travis/prepare_mysql.sh +++ b/tests/travis/prepare_mysql.sh @@ -25,7 +25,7 @@ # Exit if anything fails set -e -echo "Preparing for MySQL ..." +echo "Preparing for MySQL/MariaDB ..." if [[ "$MYSQL_VERSION" == "5.7" ]]; then echo "Using MySQL 5.7 in Docker container, need to use TCP" @@ -41,13 +41,13 @@ mysql $PROTO -e "SHOW VARIABLES LIKE 'character_set%';" mysql $PROTO -e "SELECT @@sql_mode;" # Create Hubzilla database -mysql $PROTO -u root -e "CREATE DATABASE IF NOT EXISTS hubzilla;"; -mysql $PROTO -u root -e "CREATE USER 'hubzilla'@'%' IDENTIFIED BY 'hubzilla';" -mysql $PROTO -u root -e "GRANT ALL ON hubzilla.* TO 'hubzilla'@'%';" +mysql $PROTO -u root -e "CREATE DATABASE IF NOT EXISTS travis_hubzilla;"; +mysql $PROTO -u root -e "CREATE USER 'travis_hz'@'%' IDENTIFIED BY 'hubzilla';" +mysql $PROTO -u root -e "GRANT ALL ON travis_hubzilla.* TO 'travis_hz'@'%';" # Import table structure -mysql $PROTO -u root hubzilla < ./install/schema_mysql.sql +mysql $PROTO -u root travis_hubzilla < ./install/schema_mysql.sql # Show databases and tables mysql $PROTO -u root -e "SHOW DATABASES;" -mysql $PROTO -u root -e "USE hubzilla; SHOW TABLES;" +mysql $PROTO -u root -e "USE travis_hubzilla; SHOW TABLES;" diff --git a/tests/travis/prepare_pgsql.sh b/tests/travis/prepare_pgsql.sh index 3c38ef60c..0175b9858 100755 --- a/tests/travis/prepare_pgsql.sh +++ b/tests/travis/prepare_pgsql.sh @@ -33,17 +33,17 @@ psql --version psql -U postgres -c "SELECT VERSION();" # Create Hubzilla database -psql -U postgres -c "DROP DATABASE IF EXISTS hubzilla;" +psql -U postgres -c "DROP DATABASE IF EXISTS travis_hubzilla;" psql -U postgres -v ON_ERROR_STOP=1 <<-EOSQL - CREATE USER hubzilla WITH PASSWORD 'hubzilla'; - CREATE DATABASE hubzilla; - ALTER DATABASE hubzilla OWNER TO hubzilla; - GRANT ALL PRIVILEGES ON DATABASE hubzilla TO hubzilla; + CREATE USER travis_hz WITH PASSWORD 'hubzilla'; + CREATE DATABASE travis_hubzilla; + ALTER DATABASE travis_hubzilla OWNER TO travis_hz; + GRANT ALL PRIVILEGES ON DATABASE travis_hubzilla TO travis_hz; EOSQL # Import table structure -psql -U hubzilla -v ON_ERROR_STOP=1 hubzilla < ./install/schema_postgres.sql +psql -U travis_hz -v ON_ERROR_STOP=1 travis_hubzilla < ./install/schema_postgres.sql # Show databases and tables psql -U postgres -l -psql -U postgres -d hubzilla -c "\dt;" +psql -U postgres -d travis_hubzilla -c "\dt;"