From e5f2ddf77a413dd0c38549cb649605eb131b01d0 Mon Sep 17 00:00:00 2001 From: techno-express Date: Mon, 3 Jun 2019 00:14:36 -0400 Subject: [PATCH 01/17] initial setup for native async mysql queries, to be used with https://github.com/symplely/coroutine Todo: - setup native async postgresql queries - setup pdo, sqlite3, and sqlsrv to to use parallel sub processes. --- lib/Database/async_mysqli.php | 127 ++++++++++++++++++++++++++++++++++ lib/Database/ez_mysqli.php | 16 ++--- 2 files changed, 135 insertions(+), 8 deletions(-) create mode 100644 lib/Database/async_mysqli.php diff --git a/lib/Database/async_mysqli.php b/lib/Database/async_mysqli.php new file mode 100644 index 00000000..2163345e --- /dev/null +++ b/lib/Database/async_mysqli.php @@ -0,0 +1,127 @@ +database = $settings; + + if (empty($GLOBALS['async'.\MYSQLI])) + $GLOBALS['async'.\MYSQLI] = $this; + \setInstance($this); + + // Prepare statement usage not possible with async queries. + $this->prepareOff(); + } // __construct + + public function query_prepared(string $query, array $param = null) { + return false; + } + + /** + * Perform mySQL query and try to determine result value + * + * @param string $query + * @param bool $use_prepare + * @return bool|mixed + */ + public function query(string $query, bool $use_prepare = false) + { + // Initialize return + $this->return_val = 0; + + // Flush cached values.. + $this->flush(); + + // For reg expressions + $query = \trim($query); + + // Log how the function was called + $this->log_query("\$db->query(\"$query\")"); + + // Keep track of the last query for debug.. + $this->last_query = $query; + + // Count how many queries there have been + $this->num_queries++; + + // Use core file cache function + if ( $cache = $this->get_cache($query) ) { + return $cache; + } + + // If there is no existing database connection then try to connect + if ( ! isset($this->dbh) || ! $this->dbh ) { + $this->connect($this->database->getUser(), $this->database->getPassword(), $this->database->getHost()); + $this->select($this->database->getName()); + } + + \mysqli_query($this->dbh, $query, \MYSQLI_ASYNC); + $connection = $this->dbh; + + do { + yield; + $links = $errors = $reject = array($this->dbh); + \mysqli_poll($links, $errors, $reject, 0, 1); + } while (!\in_array($connection, $links, true) && !\in_array($connection, $errors, true) && !\in_array($connection, $reject, true)); + + $result = \mysqli_reap_async_query($connection); + // If there is an error then take note of it.. + if ( $str = \mysqli_error($this->dbh) ) { + $this->register_error($str); + + // If debug ALL queries + $this->trace || $this->debug_all ? $this->debug() : null ; + return false; + } + + if ($this->processQueryResult($query, $result) === false) + return false; + + // disk caching of queries + $this->store_cache($query, $this->is_insert); + + // If debug ALL queries + $this->trace || $this->debug_all ? $this->debug() : null ; + + return $this->return_val; + } // query + + /** + * Begin Mysql Transaction + */ + public function beginTransaction() + { + /* turn autocommit off */ + $this->dbh->autocommit(false); + $this->dbh->begin_transaction(MYSQLI_TRANS_START_READ_WRITE); + $this->isTransactional = true; + } + + public function commit() + { + $this->dbh->commit(); + $this->dbh->autocommit(true); + $this->isTransactional = false; + } + + public function rollback() + { + $this->dbh->rollBack(); + $this->dbh->autocommit(true); + $this->isTransactional = false; + } +} // ez_mysqli \ No newline at end of file diff --git a/lib/Database/ez_mysqli.php b/lib/Database/ez_mysqli.php index 8015c283..fc3d1fef 100644 --- a/lib/Database/ez_mysqli.php +++ b/lib/Database/ez_mysqli.php @@ -10,28 +10,28 @@ class ez_mysqli extends ezsqlModel implements DatabaseInterface { - private $return_val = 0; - private $is_insert = false; - private $shortcutUsed = false; - private $isTransactional = false; + protected $return_val = 0; + protected $is_insert = false; + protected $shortcutUsed = false; + protected $isTransactional = false; /** * Database connection handle * @var resource */ - private $dbh; + protected $dbh; /** * Query result * @var mixed */ - private $result; + protected $result; /** * Database configuration setting * @var ConfigInterface */ - private $database; + protected $database; public function __construct(ConfigInterface $settings = null) { @@ -310,7 +310,7 @@ function ($string, &$arg) use (&$params) { * @param mixed $result * @return bool|void */ - private function processQueryResult(string $query, $result = null) + protected function processQueryResult(string $query, $result = null) { $this->shortcutUsed = false; From e2ede34a79a82ab998c9e7fea558f747441dc88a Mon Sep 17 00:00:00 2001 From: techno-express Date: Mon, 3 Jun 2019 00:25:45 -0400 Subject: [PATCH 02/17] Update README.md --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index ca338a80..571d4376 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,4 @@ -# **ezsql** - -[![Build Status](https://travis-ci.org/ezSQL/ezsql.svg?branch=master)](https://travis-ci.org/ezSQL/ezsql)[![Build status](https://ci.appveyor.com/api/projects/status/6s8oqnoxa2i5k04f?svg=true)](https://ci.appveyor.com/project/jv2222/ezsql)[![codecov](https://codecov.io/gh/ezSQL/ezSQL/branch/master/graph/badge.svg)](https://codecov.io/gh/ezSQL/ezSQL)[![Codacy Badge](https://api.codacy.com/project/badge/Grade/aad1f6aaaaa14f60933e75615da900b8)](https://www.codacy.com/app/techno-express/ezsql?utm_source=github.com&utm_medium=referral&utm_content=ezSQL/ezsql&utm_campaign=Badge_Grade)[![Maintainability](https://api.codeclimate.com/v1/badges/6f6107f25e9de7bf4272/maintainability)](https://codeclimate.com/github/ezSQL/ezsql/maintainability) +# **sql** ***A class to make it very easy to deal with database connections.*** From 38a529d71244df488e5b1ac8f765e49f455b39fc Mon Sep 17 00:00:00 2001 From: techno-express Date: Mon, 3 Jun 2019 00:31:35 -0400 Subject: [PATCH 03/17] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 571d4376..ca338a80 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# **sql** +# **ezsql** + +[![Build Status](https://travis-ci.org/ezSQL/ezsql.svg?branch=master)](https://travis-ci.org/ezSQL/ezsql)[![Build status](https://ci.appveyor.com/api/projects/status/6s8oqnoxa2i5k04f?svg=true)](https://ci.appveyor.com/project/jv2222/ezsql)[![codecov](https://codecov.io/gh/ezSQL/ezSQL/branch/master/graph/badge.svg)](https://codecov.io/gh/ezSQL/ezSQL)[![Codacy Badge](https://api.codacy.com/project/badge/Grade/aad1f6aaaaa14f60933e75615da900b8)](https://www.codacy.com/app/techno-express/ezsql?utm_source=github.com&utm_medium=referral&utm_content=ezSQL/ezsql&utm_campaign=Badge_Grade)[![Maintainability](https://api.codeclimate.com/v1/badges/6f6107f25e9de7bf4272/maintainability)](https://codeclimate.com/github/ezSQL/ezsql/maintainability) ***A class to make it very easy to deal with database connections.*** From 66e42d9f16b088237df2584f13a8022880fe0776 Mon Sep 17 00:00:00 2001 From: techno-express Date: Mon, 3 Jun 2019 10:56:30 -0400 Subject: [PATCH 04/17] Create index.md --- docs/index.md | 840 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 840 insertions(+) create mode 100644 docs/index.md diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..347c6b96 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,840 @@ +Overview +=== + +__ezsql__ +----- + +Is a library/widget that makes it very fast and easy for you to use database(s) within your **PHP** scripts, supporting ( **_MySQL_** / **_PostgreSQL_** / **_Microsoft SQL Server_** / **_SQLite3_**), and the **_PDO_** equivalents. + +- It is one php file that you include at the top of your script. Then, instead of using standard php database functions listed in the php manual, you use a much smaller (and easier) set of **ezsql** functions and methods. +- It automatically caches query results and allows you to use easy to understand functions to manipulate and extract them without causing extra server overhead. +- It has excellent debug functions making it lightning-fast to see what’s going on in your SQL code. +- Most **ezsql** functions can return results as *Objects*, *Associative Arrays*, *Numerical Arrays* or *Json Encoded*. +- It can dramatically decrease development time and in most cases will streamline your code and make things run faster as well as making it very easy to debug and optimise your database queries. +- It is a small class and will not add very much overhead to your website. + +**_Note:_** _It is assumed that you are familiar with PHP, basic Database concepts and basic SQL constructs._ + +Quick Examples +--- + +Note: In all these examples no other code is required other than including: + +either + + require 'ez_sql_loader.php'; + +or + + // composer is required for version 4 + require 'vendor/autoload.php'; + +___Example 1___ + +```php +// Select multiple records from the database and print them out.. +$users = $db->get_results("SELECT name, email FROM users"); +foreach ( $users as $user ) +{ + // Access data using object syntax + echo $user->name; + echo $user->email; +} +``` + +___Example 2___ + +```php +// Get one row from the database and print it out.. +$user = $db->get_row("SELECT name,email FROM users WHERE id = 2"); + +echo $user->name; +echo $user->email; +``` + +___Example 3___ + +```php +// Get one variable from the database and print it out.. +$var = $db->get_var("SELECT count(\*) FROM users"); + +echo $var; +``` + +___Example 4___ + +```php +// Insert into the database +$db->query("INSERT INTO users (id, name, email) VALUES (NULL,'justin','jv@foo.com')"); +``` + +___Example 5___ + +```php +// Update the database +$db->query("UPDATE users SET name = 'Justin' WHERE id = 2)"); +``` + +___Example 6___ + +```php +// Display last query and all associated results +$db->debug(); +``` + +___Example 7___ + +```php +// Display the structure and contents of any result(s) .. or any variable +$results = $db->get_results("SELECT name, email FROM users"); + +$db->varDump($results); +``` + +___Example 8___ + +```php +// Get 'one column' (based on column index) and print it out.. +$names = $db->get_col("SELECT name,email FROM users", 0) + +foreach ( $names as $name ) +{ + echo $name; +} +``` + +___Example 9___ + +```php +// Same as above ‘but quicker’ +foreach ( $db->get_col("SELECT name,email FROM users", 0) as $name ) +{ + echo $name; +} +``` + +___Example 10___ + +```php +// Map out the full schema of any given database and print it out.. +$db->select("my_database"); + +foreach ( $db->get_col("SHOW TABLES",0) as $table-name ) +{ + $db->debug(); + $db->get_results("DESC $table-name"); +} + +$db->debug(); +``` + +Introduction +--- + +When working with databases most of the time you will want to do one of four types of basic operations. + +1. _Perform a query such as Insert or Update (without results)_ +2. _Get a single variable from the database_ +3. _Get a single row from the database_ +4. _Get a list of results from the database_ + +**ezsql** wraps up these four basic actions into four very easy to use functions. + +- bool: **`$db->query`**(query) +- var: **`$db->get_var`**(query) +- mixed: **`$db->get_row`**(query) +- mixed: **`$db->get_results`**(query) + +With **ezsql** these four functions are all you will need 99.9% of the time. Of course there are also some other useful functions but we will get into those later. + +**_Important Note:_** _If you use **ezsql** inside a function you write, you will need to put **global $db;** at the top._ +>In version 3 and higher there are global functions available to retrieve the object. **`getInstance()`**, **`tagInstance`**(getTagCreated) + +Need more help, try reading these articles: https://wpshout.com/introduction-to-wpdb-why-not/, https://wpreset.com/customize-wpdb-class/, and https://codex.wordpress.org/Class_Reference/wpdb. + +Any articles referencing WordPress database engine is an good source of what kind of ecosystem can be built with the flexible of what this library provides. However, the ease of use and process this library initially fostered, spread to other areas, leading to hard to follow, and bad coding habits by today's standards. + +Version 4 of this library attempts to, beside all the additional features, _remove some bad coding styles_, _bring the library to modern coding practices of which_, _follow proper __OOP__ and be __PSR__ compliant_. + +This version further break things introduced in version 3 that broke version 2.1.7. See [CHANGE LOG](https://github.com/ezSQL/ezSQL/blob/master/CHANGELOG.md) + +____Installation and Usage____ +--- + + +Either: ***for version 3.x*** + + composer require ezsql/ezsql=^3.1.2 + +```php +require 'vendor/autoload.php'; +``` +```php +// Manually download https://github.com/ezSQL/ezSQL/archive/v3.zip and extract. +require 'ez_sql_loader.php'; +``` +```php +$db = new ezSQL_****(user, password, database, or, other settings); +``` + +Or: ***for version 4.x*** + + // composer is required for version 4 + composer require ezsql/ezsql + +```php +require 'vendor/autoload.php'; + +$db = Database::initialize('****', [user, password, database, other settings], **optional tag); + +// Is same as: +$setting = new Config('****', [user, password, database, other settings]); +$db = new ez_****($settings); +``` + +>Note: __****__ is one of **mysqli**, **pgsql**, **sqlsrv**, **sqlite3**, or **Pdo**. + +**ezsql** functions +--- + +**$db->get_results** -- get multiple row result set from the database (or previously cached results) + +**$db->get_row** -- get one row from the database (or previously cached results) + +**$db->get_col** -- get one column from query (or previously cached results) based on column offset + +**$db->get_var** -- get one variable, from one row, from the database (or previously cached results) + +**$db->query** -- send a query to the database (and if any results, cache them) + +**$db->debug** -- print last sql query and returned results (if any) + +**$db->vardump** -- print the contents and structure of any variable + +**$db->select** -- select a new database to work with + +**$db->get_col-info** -- get information about one or all columns such as column name or type + +**$db->hide-errors** -- turn **ezsql** error output to browser off + +**$db->show-errors** -- turn **ezsql** error output to browser on + +**$db->escape** -- Format a string correctly to stop accidental mal formed queries under all PHP conditions + +**$db = new db** -- Initiate new db object. + +**ezsql** variables +--- + +**$db->num-rows** – Number of rows that were returned (by the database) for the last query (if any) + +**$db->insert-id** -- ID generated from the AUTO-INCRIMENT of the previous INSERT operation (if any) + +**$db->rows-affected** -- Number of rows affected (in the database) by the last INSERT, UPDATE or DELETE (if any) + +**$db->num-queries** -- Keeps track of exactly how many 'real' (not cached) queries were executed during the lifetime of the current script + +**$db->debug-all** – If set to true (i.e. $db->debug-all = true;) Then it will print out ALL queries and ALL results of your script. + +**$db->cache-dir –** Path to mySQL caching dir. + +**$db->cache-queries –** Boolean flag (see mysql/disk-cache-example.php) + +**$db->cache-inserts –** Boolean flag (see mysql/disk-cache-example.php) + +**$db->use-disk-cache –** Boolean flag (see mysql/disk-cache-example.php) + +**$db->cache-timeout –** Number in hours (see mysql/disk-cache-example.php) + +____db = new db____ + +__$db = new db__ -- Initiate new db object. Connect to a database server. Select a database. + +____Description____ + +**$db = new db**(string username, string password, string database name, string database host) + +Does three things. (1) Initiates a new db object. (2) Connects to a database server. (3) Selects a database. You can also re-submit this command if you would like to initiate a second db object. This is interesting because you can run two concurrent database connections at the same time. You can even connect to two different servers at the same time if you want to. + +_Note: For the sake of efficiency it is recommended that you only run one instance of the **db** object and use **$db->select** to switch between different databases on the same server connection._ + +Example + +```php + // Initiate new database object.. +$db2 = new db(”user-name”, ”user-password”, ”database-name”, “database-host”); // version 2 and 3 + + // Perform some kind of query.. + $other_db_tables = $db2->get_results(“SHOW TABLES”); + + // You can still query the database you were already connected to.. + $existing_connection_tables = $db->get_results(“SHOW TABLES”); + + // Print the results from both of these queries.. + $db->debug(); + $db2->debug(); + ``` + +__$db->select__ - for **mysql** only. + +___$db->select___ -- select a new database to work with + +____Description____ + +bool **$db->select**(string database name) + +**$db->select**() selects a new database to work with using the current database connection as created with **$db = new db**. + +Example + +```php + // Get a users name from the user’s database (as initiated with $db = new db).. +$user-name = $db->get_var(“SELECT name FROM users WHERE id = 22”) ; + + // Select the database stats.. +$db->select(“stats”); + + // Get a users name from the user’s database.. +$total-hours = $db->get_var(“SELECT sum(time-logged-in) FROM user-stats WHERE user = ‘$user-name’”) ; + + // Re-select the ‘users’ database to continue working as normal.. +$db->select(“users”); +``` + +____$db->query____ + +__$db->query__ -- send a query to the database (and if any results, cache them) + +____Description____ + +bool **$db->query**(string query) + +**$db->query**() sends a query to the currently selected database. It should be noted that you can send any type of query to the database using this command. If there are any results generated they will be stored and can be accessed by any **ezsql** function as long as you use a null query. If there are results returned the function will return **true** if no results the return will be **false** + +Example 1 + +```php + // Insert a new user into the database.. +$db->query(“INSERT INTO users (id,name) VALUES (1, ’Amy’)”); +``` + +Example 2 + +```php + // Update user into the database.. +$db->query(“UPDATE users SET name = ‘Tyson’ WHERE id = 1”); +``` + +Example 3 + +```php + // Query to get full user list.. +$db->query(“SELECT name,email FROM users”) ; + + // Get the second row from the cached results by using a **null** query.. +$user->details = $db->get->row(null, OBJECT, 1); + + // Display the contents and structure of the variable $user-details.. +$db->varDump($user->details); +``` + +**$db->get_var** + +$db->get_var -- get one variable, from one row, from the database (or previously cached results) + +**Description** + +var **$db->get_var**(string query / null [,int column offset[, int row offset]) + +**$db->get_var**() gets one single variable from the database or previously cached results. This function is very useful for evaluating query results within logic statements such as **if** or **switch**. If the query generates more than one row the first row will always be used by default. If the query generates more than one column the leftmost column will always be used by default. Even so, the full results set will be available within the array $db->last-results should you wish to use them. + +Example 1 + +```php + // Get total number of users from the database.. +$num-users = $db->get_var(“SELECT count(\*) FROM users”) ; +``` + +Example 2 + +```php + // Get a users email from the second row of results (note: col 1, row 1 [starts at 0]).. +$user-email = $db->get_var(“SELECT name, email FROM users”,1,1) ; + + // Get the full second row from the cached results (row = 1 [starts at 0]).. +$user = $db->get_row(null,OBJECT,1); + + // Both are the same value.. + echo $user-email; + echo $user->email; +``` + +Example 3 + +```php + // Find out how many users there are called Amy.. +if ( $n = $db->get_var(“SELECT count(\*) FROM users WHERE name = ‘Amy’”) ) +{ + // If there are users then the if clause will evaluate to true. This is useful because +// we can extract a value from the DB and test it at the same time. +echo “There are $n users called Amy!”; +} else { +// If there are no users then the if will evaluate to false.. +echo “There are no users called Amy.”; +} +``` + +Example 4 + +```php + // Match a password from a submitted from a form with a password stored in the DB +if ( $pwd-from-form == $db->get_var(“SELECT pwd FROM users WHERE name = ‘$name-from-form’”) ) +{ + // Once again we have extracted and evaluated a result at the same time.. +echo “Congratulations you have logged in.”; +} else { + // If has evaluated to false.. +echo “Bad password or Bad user ID”; +} +``` + +**$db->get_row** + +$db->get_row -- get one row from the database (or previously cached results) + +**Description** + +object **$db->get_row**(string query / null [, OBJECT / ARRAY-A / ARRAY-N [, int row offset]]) + +**$db->get_row**() gets a single row from the database or cached results. If the query returns more than one row and no row offset is supplied the first row within the results set will be returned by default. Even so, the full results will be cached should you wish to use them with another **ezsql** query. + +Example 1 + +```php + // Get a users name and email from the database and extract it into an object called user.. +$user = $db->get_row(“SELECT name,email FROM users WHERE id = 22”) ; + + // Output the values.. + echo “$user->name has the email of $user->email”; + + Output: + Amy has the email of amy@foo.com +``` + +Example 2 + +```php +// Get users name and date joined as associative array +// (Note: we must specify the row offset index in order to use the third argument) + $user = $db->get_row(“SELECT name, UNIX-TIMESTAMP(my-date-joined) as date-joined FROM users WHERE id = 22”,ARRAY-A) ; + +// Note how the unix-timestamp command is used with **as** this will ensure that the resulting data will be easily +// accessible via the created object or associative array. In this case $user[‘date-joined’] (object would be $user->date-joined) + echo $user[‘name’] . “ joined us on ” . date(“m/d/y”,$user[‘date-joined’]); + + Output: + Amy joined us on 05/02/01 +``` + +Example 3 + +```php + // Get second row of cached results. + $user = $db->get_row(null,OBJECT,1); + + // Note: Row offset starts at 0 + echo “$user->name joined us on ” . date(“m/d/y”,$user->date-joined); + + Output: + Tyson joined us on 05/02/02 +``` + +Example 4 + +```php + // Get one row as a numerical array.. + $user = $db->get_row(“SELECT name,email,address FROM users WHERE id = 1”,ARRAY-N); + + // Output the results as a table.. + echo “”; + + for ( $i=1; $i <= count($user); $i++ ) + { + echo “”; + } + + echo “
$i$user[$I]
”; + + Output: + 1 amy + 2 amy@foo.com + 3 123 Foo Road +``` + +**$db->get_results** +$db->get_results – get multiple row result set from the database (or previously cached results) + +**Description** +array **$db->get_results**(string query / null [, OBJECT / ARRAY-A / ARRAY-N ] ) + +**$db->get_row**() gets multiple rows of results from the database based on _query_ and returns them as a multi dimensional array. Each element of the array contains one row of results and can be specified to be either an object, associative array or numerical array. If no results are found then the function returns false enabling you to use the function within logic statements such as **if.** + +Example 1 – Return results as objects (default) + +Returning results as an object is the quickest way to get and display results. It is also useful that you are able to put $object->var syntax directly inside print statements without having to worry about causing php parsing errors. + +```php + // Extract results into the array $users (and evaluate if there are any results at the same time).. +if ( $users = $db->get_results(“SELECT name, email FROM users”) ) +{ + // Loop through the resulting array on the index $users[n] + foreach ( $users as $user ) + { + // Access data using column names as associative array keys + echo “$user->name - $user->email”; + } +} else { + // If no users were found then **if** evaluates to false.. +echo “No users found.”; +} + + Output: + Amy - amy@hotmail.com + Tyson - tyson@hotmail.com + ``` + +Example 2 – Return results as associative array +Returning results as an associative array is useful if you would like dynamic access to column names. Here is an example. + +```php + // Extract results into the array $dogs (and evaluate if there are any results at the same time).. +if ( $dogs = $db->get_results(“SELECT breed, owner, name FROM dogs”, ARRAY-A) ) +{ + // Loop through the resulting array on the index $dogs[n] + foreach ( $dogs as $dog-detail ) + { + // Loop through the resulting array + foreach ( $dogs->detail as $key => $val ) + { + // Access and format data using $key and $val pairs.. + echo “” . ucfirst($key) . “: $val
”; + } + // Do a P between dogs.. + echo “

”; + } +} else { + // If no users were found then **if** evaluates to false.. +echo “No dogs found.”; +} + +Output: + Breed: Boxer + Owner: Amy + Name: Tyson + Breed: Labrador + Owner: Lee + Name: Henry + Breed: Dachshund + Owner: Mary + Name: Jasmine +``` + +Example 3 – Return results as numerical array +Returning results as a numerical array is useful if you are using completely dynamic queries with varying column names but still need a way to get a handle on the results. Here is an example of this concept in use. Imagine that this script was responding to a form with $type being submitted as either ‘fish’ or ‘dog’. + +```php + // Create an associative array for animal types.. + $animal = array ( “fish” => “num-fins”, “dog” => “num-legs” ); + + // Create a dynamic query on the fly.. + if ( $results = $db->(“SELECT $animal[$type] FROM $type”, ARRAY-N)) + { + foreach ( $results as $result ) + { + echo “$result[0]
”; + } + } else { + echo “No $animal\\s!”; + } + +Output: + 4 + 4 + 4 +Note: The dynamic query would be look like one of the following... +· SELECT num-fins FROM fish +· SELECT num-legs FROM dogs + +It would be easy to see which it was by using $db->debug(); after the dynamic query call. +``` + +**$db->debug** + +$db->debug – print last sql query and returned results (if any) + +**Description** + +**$db->debug**(void) + +**$db->debug**() prints last sql query and its results (if any) + +Example 1 +If you need to know what your last query was and what the returned results are here is how you do it. + +```php + // Extract results into the array $users.. +$users = $db->get_results(“SELECT name, email FROM users”); + +// See what just happened! +$db->debug(); +``` + +**$db->vardump** + +$db->vardump – print the contents and structure of any variable + +**Description** + +**$db->vardump**(void) + +**$db->vardump**() prints the contents and structure of any variable. It does not matter what the structure is be it an object, associative array or numerical array. + +Example 1 +If you need to know what value and structure any of your results variables are here is how you do it. + +```php + // Extract results into the array $users.. +$users = $db->get_results(“SELECT name, email FROM users”); + +// View the contents and structure of $users +$db->vardump($users); +``` + +**$db->get_col** + +$db->get_col – get one column from query (or previously cached results) based on column offset + +**Description** + +**$db->get_col**( string query / null [, int column offset] ) + +**$db->get_col**() extracts one column as one dimensional array based on a column offset. If no offset is supplied the offset will defualt to column 0. I.E the first column. If a null query is supplied the previous query results are used. + +Example 1 + +```php + // Extract list of products and print them out at the same time.. +foreach ( $db->get_col(“SELECT product FROM product-list”) as $product +{ + echo $product; +} +``` + +Example 2 – Working with cached results + +```php + // Extract results into the array $users.. +$users = $db->get_results(“SELECT \* FROM users”); + +// Work out how many columns have been selected.. +$last-col-num = $db->num-cols - 1; + +// Print the last column of the query using cached results.. +foreach ( $db->get_col(null, $last-col-num) as $last-col ) +{ + echo $last-col; +} +``` + +**$db->get_col-info** + +$db->get_col-info - get information about one or all columns such as column name or type + +**Description** + +**$db->get_col-info**(string info-type[, int column offset]) + +**$db->get_col-info**()returns meta information about one or all columns such as column name or type. If no information type is supplied then the default information type of **name** is used. If no column offset is supplied then a one dimensional array is returned with the information type for ‘all columns’. For access to the full meta information for all columns you can use the cached variable $db->col-info + +Available Info-Types + +**mySQL** + +· name - column name + +· table - name of the table the column belongs to + +· max-length - maximum length of the column + +· not-null - 1 if the column cannot be NULL + +· primary-key - 1 if the column is a primary key + +· unique-key - 1 if the column is a unique key + +· multiple-key - 1 if the column is a non-unique key + +· numeric - 1 if the column is numeric + +· blob - 1 if the column is a BLOB + +· type - the type of the column + +· unsigned - 1 if the column is unsigned + +· zerofill - 1 if the column is zero-filled + +**ibase** + +· name - column name + +· type - the type of the column + +· length - size of column + +· alias - undocumented + +· relation - undocumented + +**MS-SQL / Oracle / Postgress** + +· name - column name + +· type - the type of the column + +· length - size of column + +**SQLite** + +· name - column name +Example 1 + +```php + // Extract results into the array $users.. +$users = $db->get_results(“SELECT id, name, email FROM users”); + +// Output the name for each column type +foreach ( $db->get_col-info(“name”) as $name ) +{ + echo “$name
”; +} + + Output: + id + name + email +``` + +Example 2 + +```php + // Extract results into the array $users.. +$users = $db->get_results(“SELECT id, name, email FROM users”); + + // View all meta information for all columns.. + $db->vardump($db->col-info); +``` + +**$db->hide-errors** + +$db->hide-errors – turn **ezsql** error output to browser off + +**Description** + +**$db->hide-errors**( void ) + +**$db->hide-errors**() stops error output from being printed to the web client. If you would like to stop error output but still be able to trap errors for debugging or for your own error output function you can make use of the global error array $EZSQL-ERROR. + +**_Note:_** _If there were no errors then the global error array $EZSQL-ERROR will evaluate to false. If there were one or more errors then it will have the following structure. Errors are added to the array in order of being called._ + +$EZSQL-ERROR[0] = Array +( + [query] => SOME BAD QUERY + [error-str] => You have an error in your SQL syntax near ‘SOME BAD QUERY' at line 1 +) + +$EZSQL-ERROR[1] = Array +( + [query] => ANOTHER BAD QUERY + [error-str] => You have an error in your SQL syntax near ‘ANOTHER BAD QUERY' at line 1 +) + +$EZSQL-ERROR[2] = Array +( + [query] => THIRD BAD QUERY + [error-str] => You have an error in your SQL syntax near ‘THIRD BAD QUERY' at line 1 +) + +Example 1 + +```php + // Using a custom error function +$db->hide-errors(); + +// Make a silly query that will produce an error +$db->query(“INSERT INTO my-table A BAD QUERY THAT GENERATES AN ERROR”); + +// And another one, for good measure +$db->query(“ANOTHER BAD QUERY THAT GENERATES AN ERROR”); + +// If the global error array exists at all then we know there was 1 or more **ezsql** errors.. +if ( $EZSQL-ERROR ) +{ + // View the errors + $db->vardump($EZSQL-ERROR); +} else { + echo “No Errors”; +} +``` + +**$db->show_errors** + +$db->show_errors – turn **ezsql** error output to browser on + +**Description** + +**$db->show_errors**( void ) + +**$db->show_errors**() turns **ezsql** error output to the browser on. If you have not used the function $db->hide-errors this function (show-errors) will have no effect. + +**$db->escape** + +$db->escape – Format a string correctly in order to stop accidental mal formed queries under all PHP conditions. + +**Description** + +**$db->escape**( string ) + +**$db->escape**() makes any string safe to use as a value in a query under all PHP conditions. I.E. if magic quotes are turned on or off. Note: Should not be used by itself to guard against SQL injection attacks. The purpose of this function is to stop accidental mal formed queries. + +Example 1 + +```php + // Escape and assign the value.. + $title = $db->escape(“Justin’s and Amy’s Home Page”); + + // Insert in to the DB.. +$db->query(“INSERT INTO pages (title) VALUES (’$title’)”) ; +``` + +Example 2 + +```php + // Assign the value.. + $title = “Justin’s and Amy’s Home Page”; + + // Insert in to the DB and escape at the same time.. +$db->query(“INSERT INTO pages (title) VALUES (’”. $db->escape($title).”’)”) ; +``` + +Disk Caching + +**ezsql** has the ability to cache your queries which can make dynamic sites run much faster. + +If you want to cache EVERYTHING just do.. + +**$db->setUse_Disk_Cache(true);** + +**$db->setCache_Queries(true);** + +**$db->setCache_Timeout(24);** From 39caec0ad1b9ad62be2217649341afb13b2efd80 Mon Sep 17 00:00:00 2001 From: techno-express Date: Mon, 3 Jun 2019 12:34:35 -0400 Subject: [PATCH 05/17] Update .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b90a936d..8dde154a 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ test.php *.crt *.cache tmp +.vscode/sftp.json From 81be0d9d9965403cd054b18bc576d79a5c3c513d Mon Sep 17 00:00:00 2001 From: techno-express Date: Mon, 3 Jun 2019 13:07:04 -0400 Subject: [PATCH 06/17] Update async_mysqli.php --- lib/Database/async_mysqli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Database/async_mysqli.php b/lib/Database/async_mysqli.php index 2163345e..5f2c8516 100644 --- a/lib/Database/async_mysqli.php +++ b/lib/Database/async_mysqli.php @@ -4,6 +4,7 @@ namespace ezsql\Database; use Exception; +use ezsql\ConfigInterface; use ezsql\Database\ez_mysqli; class async_mysqli extends ez_mysqli From b33d603bb1adba0ce3e87dd3b63a1e970986bd03 Mon Sep 17 00:00:00 2001 From: techno-express Date: Mon, 3 Jun 2019 13:07:43 -0400 Subject: [PATCH 07/17] Update async_mysqli.php --- lib/Database/async_mysqli.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Database/async_mysqli.php b/lib/Database/async_mysqli.php index 2163345e..5f2c8516 100644 --- a/lib/Database/async_mysqli.php +++ b/lib/Database/async_mysqli.php @@ -4,6 +4,7 @@ namespace ezsql\Database; use Exception; +use ezsql\ConfigInterface; use ezsql\Database\ez_mysqli; class async_mysqli extends ez_mysqli From 3d98cb92b55d465a3c56ae119127cde6d18045ba Mon Sep 17 00:00:00 2001 From: techno-express Date: Mon, 3 Jun 2019 15:11:25 -0400 Subject: [PATCH 08/17] update/initial setup for native async mysql/pgsql queries, to be used with https://github.com/symplely/coroutine Todo: - setup pdo, sqlite3, and sqlsrv to to use parallel sub processes. --- lib/Database/async_interface.php | 7 ++ lib/Database/async_mysqli.php | 29 +++-- lib/Database/async_pgsql.php | 204 +++++++++++++++++++++++++++++++ lib/Database/ez_pgsql.php | 14 +-- 4 files changed, 237 insertions(+), 17 deletions(-) create mode 100644 lib/Database/async_interface.php create mode 100644 lib/Database/async_pgsql.php diff --git a/lib/Database/async_interface.php b/lib/Database/async_interface.php new file mode 100644 index 00000000..be03c03f --- /dev/null +++ b/lib/Database/async_interface.php @@ -0,0 +1,7 @@ +dbh; + do { + yield; + $links = $errors = $reject = array($this->dbh); + \mysqli_poll($links, $errors, $reject, 0, 1); + } while (!\in_array($connection, $links, true) + && !\in_array($connection, $errors, true) + && !\in_array($connection, $reject, true) + ); + + return $connection; + } + /** * Perform mySQL query and try to determine result value * @@ -71,13 +85,8 @@ public function query(string $query, bool $use_prepare = false) } \mysqli_query($this->dbh, $query, \MYSQLI_ASYNC); - $connection = $this->dbh; - - do { - yield; - $links = $errors = $reject = array($this->dbh); - \mysqli_poll($links, $errors, $reject, 0, 1); - } while (!\in_array($connection, $links, true) && !\in_array($connection, $errors, true) && !\in_array($connection, $reject, true)); + // Do things while the connection is getting ready + $connection = yield $this->query_wait(); $result = \mysqli_reap_async_query($connection); // If there is an error then take note of it.. diff --git a/lib/Database/async_pgsql.php b/lib/Database/async_pgsql.php new file mode 100644 index 00000000..bc9e4376 --- /dev/null +++ b/lib/Database/async_pgsql.php @@ -0,0 +1,204 @@ +database = $settings; + + if (empty($GLOBALS['async'.\PGSQL])) + $GLOBALS['async'.\PGSQL] = $this; + \setInstance($this); + + // Prepare statement usage not possible with async queries. + $this->prepareOff(); + } // __construct + + /** + * Creates a prepared query, binds the given parameters and returns the result of the executed + * + * @param string $query + * @param array $param + * @return bool|mixed + */ + public function query_prepared(string $query, array $param = null) + { + return false; + } + + /** + * Try to connect to PostgreSQL database server + * + * @param string $user The database user name + * @param string $password The database users password + * @param string $name The name of the database + * @param string $host The host name or IP address of the database server. + * Default is localhost + * @param string $port The database TCP/IP port + * Default is PostgreSQL default port 5432 + * @return boolean + */ + public function connect( + string $user = '', + string $password = '', + string $name = '', + string $host = 'localhost', + string $port = '5432') + { + $this->_connected = false; + + $user = empty($user) ? $this->database->getUser() : $user; + $password = empty($password) ? $this->database->getPassword() : $password; + $name = empty($name) ? $this->database->getName() : $name; + $host = ($host != 'localhost') ? $host : $this->database->getHost(); + $port = ($port != '5432') ? $port : $this->database->getPort(); + + $connect_string = "host=".$host." port=".$port." dbname=".$name." user=".$user." password=".$password; + + // Try to establish the server database handle + if (!$this->dbh = \pg_connect($connect_string, \PGSQL_CONNECT_ASYNC | \PGSQL_CONNECT_FORCE_NEW)) { + $this->register_error(\FAILED_CONNECTION . ' in ' . __FILE__ . ' on line ' . __LINE__); + } else { + $this->_connected = true; + } + + return $this->_connected; + } // connect + + /** + * The documentation on this function is pretty barebones (as is the case for a lot of thin PHP wrappers around C functions), + * but from what I've gathered by reading the libpq doc and trying various things, you should probably know the following : + + * Polling the connection while the underlying socket is busy will cause the connection (or at least the polling, + * I'm not sure) to fail. + * + * As stated by the libpq documentation, "do not assume that the socket remains the same across PQconnectPoll calls" + * The socket will become ready after every change in connection status, + * so the connection must be polled multiple times until the function returns "polling_ok" or "polling_failed". + * "polling_active" can never be returned by libpq and has literally never been used anywhere ever, it has been an unused constant since day 1. + * What you need to do is use pg_socket get a PHP stream object corresponding to the current socket and wait after it before polling, like so: + */ + public function query_wait() { + $conn = $this->dbh; + assert(\is_resource($conn)); + assert(\get_resource_type($conn) === "pgsql link" || \get_resource_type($conn) === "pgsql link persistent"); + + // "On the first iteration, i.e. if you have yet to call PQconnectPoll, behave as if it last returned PGRES_POLLING_WRITING." + $poll_outcome = \PGSQL_POLLING_WRITING; + + while (true) { + $socket = [\pg_socket($conn)]; // "Caution: do not assume that the socket remains the same across PQconnectPoll calls." + + if (!$socket) { + $this->register_error(\FAILED_CONNECTION . ' in ' . __FILE__ . ' on line ' . __LINE__); + } + + $null = []; + + if ($poll_outcome === \PGSQL_POLLING_READING) { + \stream_select($socket, $null, $null, 5); + $poll_outcome = \pg_connect_poll($conn); + } elseif ($poll_outcome === \PGSQL_POLLING_WRITING) { + \stream_select($null, $socket, $null, 5); + $poll_outcome = \pg_connect_poll($conn); + } elseif ($poll_outcome === \PGSQL_POLLING_FAILED) { + $this->register_error(\FAILED_CONNECTION . ' in ' . __FILE__ . ' on line ' . __LINE__); + } else { + break; + } + yield; + } + } + + /** + * Perform PostgreSQL query and try to determine result value + * + * @param string + * @param bool + * @return bool|mixed + */ + public function query(string $query, bool $use_prepare = false) + { + // Initialize return + $this->return_val = 0; + + // Flush cached values.. + $this->flush(); + + // For reg expressions + $query = \trim($query); + + // Log how the function was called + $this->log_query("\$db->query(\"$query\")"); + + // Keep track of the last query for debug.. + $this->last_query = $query; + + // Count how many queries there have been + $this->count(true, true); + + // Use core file cache function + if ($cache = $this->get_cache($query)) { + return $cache; + } + + // If there is no existing database connection then try to connect + if (!isset($this->dbh) || !$this->dbh) { + $this->connect($this->database->getUser(), + $this->database->getPassword(), + $this->database->getName(), + $this->database->getHost(), + $this->database->getPort()); + } + + // Do things while the connection is getting ready + yield $this->query_wait(); + @\pg_send_query($this->dbh, $query); + $result = \pg_get_result($this->dbh); + + if ($this->processQueryResult($query, $result) === false) + return false; + + // disk caching of queries + $this->store_cache($query, $this->is_insert); + + // If debug ALL queries + $this->trace || $this->debug_all ? $this->debug() : null; + + return $this->return_val; + } // query + + /** + * Begin Postgresql Transaction + */ + public function beginTransaction() + { + @\pg_query($this->dbh, "BEGIN"); + $this->isTransactional = true; + } + + public function commit() + { + @\pg_query($this->dbh, "COMMIT"); + $this->isTransactional = false; + } + + public function rollback() + { + @\pg_query($this->dbh, "ROLLBACK"); + $this->isTransactional = false; + } +} // ez_pgsql \ No newline at end of file diff --git a/lib/Database/ez_pgsql.php b/lib/Database/ez_pgsql.php index 1241d507..feef289e 100644 --- a/lib/Database/ez_pgsql.php +++ b/lib/Database/ez_pgsql.php @@ -10,28 +10,28 @@ class ez_pgsql extends ezsqlModel implements DatabaseInterface { - private $return_val = 0; - private $is_insert = false; - private $shortcutUsed = false; - private $isTransactional = false; + protected $return_val = 0; + protected $is_insert = false; + protected $shortcutUsed = false; + protected $isTransactional = false; /** * Database connection handle * @var resource */ - private $dbh; + protected $dbh; /** * Query result * @var mixed */ - private $result; + protected $result; /** * Database configuration setting * @var ConfigInterface */ - private $database; + protected $database; public function __construct(ConfigInterface $settings = null) { From 959fd80a620973624a4d44c9fd281244a9877c40 Mon Sep 17 00:00:00 2001 From: techno-express Date: Mon, 3 Jun 2019 15:49:42 -0400 Subject: [PATCH 09/17] Update async_pgsql.php --- lib/Database/async_pgsql.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Database/async_pgsql.php b/lib/Database/async_pgsql.php index bc9e4376..fda22ab5 100644 --- a/lib/Database/async_pgsql.php +++ b/lib/Database/async_pgsql.php @@ -100,7 +100,8 @@ public function query_wait() { $poll_outcome = \PGSQL_POLLING_WRITING; while (true) { - $socket = [\pg_socket($conn)]; // "Caution: do not assume that the socket remains the same across PQconnectPoll calls." + $socket = [\pg_socket($conn)]; // "Caution: do not assume that the socket remains the same across `pg_connect_poll` calls." + \stream_set_blocking($socket, false); if (!$socket) { $this->register_error(\FAILED_CONNECTION . ' in ' . __FILE__ . ' on line ' . __LINE__); From d4de91b81dcb482464d1d0c47c6ed29d390d2552 Mon Sep 17 00:00:00 2001 From: techno-express Date: Tue, 4 Jun 2019 05:27:33 -0400 Subject: [PATCH 10/17] Update ezResultset.php --- lib/ezResultset.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ezResultset.php b/lib/ezResultset.php index 92a7b1a2..ab1a44c8 100644 --- a/lib/ezResultset.php +++ b/lib/ezResultset.php @@ -97,10 +97,10 @@ public function current($mode=self::RESULT_AS_OBJECT) $return_val = \json_encode($this->_resultset[$this->_position]); break; default: - throw new \Error("Invalid result fetch type"); + throw new \Exception("Invalid result fetch type"); } } else { - $result = false; + $return_val = false; } return $return_val; } // current @@ -109,7 +109,7 @@ public function current($mode=self::RESULT_AS_OBJECT) * Returns the current position in the resultset * @return int */ - public function key() + public function key(): int { return $this->_position; } // key @@ -139,7 +139,7 @@ public function previous() * Whether the current position contains a row, or not * @return boolean */ - public function valid() + public function valid(): bool { return isset($this->_resultset[$this->_position]); } // valid From 22f8c79683e4f31a36327036dc387406e2f07818 Mon Sep 17 00:00:00 2001 From: techno-express Date: Tue, 4 Jun 2019 05:49:57 -0400 Subject: [PATCH 11/17] Update ezFunctions.php --- lib/ezFunctions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ezFunctions.php b/lib/ezFunctions.php index 45175fd2..0f431289 100644 --- a/lib/ezFunctions.php +++ b/lib/ezFunctions.php @@ -450,7 +450,7 @@ function update($table = '', $keyValue, ...$args) { : false; } - function delete($table = '', ...$args) { + function deleting($table = '', ...$args) { $ezQuery = \getInstance(); return ($ezQuery instanceOf DatabaseInterface) ? $ezQuery->delete($table, ...$args) From 19ca2c852e00f56d0043ae4d97c4c31dd1da08af Mon Sep 17 00:00:00 2001 From: techno-express Date: Wed, 5 Jun 2019 10:38:57 -0400 Subject: [PATCH 12/17] revert additions, using async branch instead --- docs/index.md | 840 ---------------------------------- lib/Database/async_mysqli.php | 128 ------ 2 files changed, 968 deletions(-) delete mode 100644 docs/index.md delete mode 100644 lib/Database/async_mysqli.php diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index 347c6b96..00000000 --- a/docs/index.md +++ /dev/null @@ -1,840 +0,0 @@ -Overview -=== - -__ezsql__ ------ - -Is a library/widget that makes it very fast and easy for you to use database(s) within your **PHP** scripts, supporting ( **_MySQL_** / **_PostgreSQL_** / **_Microsoft SQL Server_** / **_SQLite3_**), and the **_PDO_** equivalents. - -- It is one php file that you include at the top of your script. Then, instead of using standard php database functions listed in the php manual, you use a much smaller (and easier) set of **ezsql** functions and methods. -- It automatically caches query results and allows you to use easy to understand functions to manipulate and extract them without causing extra server overhead. -- It has excellent debug functions making it lightning-fast to see what’s going on in your SQL code. -- Most **ezsql** functions can return results as *Objects*, *Associative Arrays*, *Numerical Arrays* or *Json Encoded*. -- It can dramatically decrease development time and in most cases will streamline your code and make things run faster as well as making it very easy to debug and optimise your database queries. -- It is a small class and will not add very much overhead to your website. - -**_Note:_** _It is assumed that you are familiar with PHP, basic Database concepts and basic SQL constructs._ - -Quick Examples ---- - -Note: In all these examples no other code is required other than including: - -either - - require 'ez_sql_loader.php'; - -or - - // composer is required for version 4 - require 'vendor/autoload.php'; - -___Example 1___ - -```php -// Select multiple records from the database and print them out.. -$users = $db->get_results("SELECT name, email FROM users"); -foreach ( $users as $user ) -{ - // Access data using object syntax - echo $user->name; - echo $user->email; -} -``` - -___Example 2___ - -```php -// Get one row from the database and print it out.. -$user = $db->get_row("SELECT name,email FROM users WHERE id = 2"); - -echo $user->name; -echo $user->email; -``` - -___Example 3___ - -```php -// Get one variable from the database and print it out.. -$var = $db->get_var("SELECT count(\*) FROM users"); - -echo $var; -``` - -___Example 4___ - -```php -// Insert into the database -$db->query("INSERT INTO users (id, name, email) VALUES (NULL,'justin','jv@foo.com')"); -``` - -___Example 5___ - -```php -// Update the database -$db->query("UPDATE users SET name = 'Justin' WHERE id = 2)"); -``` - -___Example 6___ - -```php -// Display last query and all associated results -$db->debug(); -``` - -___Example 7___ - -```php -// Display the structure and contents of any result(s) .. or any variable -$results = $db->get_results("SELECT name, email FROM users"); - -$db->varDump($results); -``` - -___Example 8___ - -```php -// Get 'one column' (based on column index) and print it out.. -$names = $db->get_col("SELECT name,email FROM users", 0) - -foreach ( $names as $name ) -{ - echo $name; -} -``` - -___Example 9___ - -```php -// Same as above ‘but quicker’ -foreach ( $db->get_col("SELECT name,email FROM users", 0) as $name ) -{ - echo $name; -} -``` - -___Example 10___ - -```php -// Map out the full schema of any given database and print it out.. -$db->select("my_database"); - -foreach ( $db->get_col("SHOW TABLES",0) as $table-name ) -{ - $db->debug(); - $db->get_results("DESC $table-name"); -} - -$db->debug(); -``` - -Introduction ---- - -When working with databases most of the time you will want to do one of four types of basic operations. - -1. _Perform a query such as Insert or Update (without results)_ -2. _Get a single variable from the database_ -3. _Get a single row from the database_ -4. _Get a list of results from the database_ - -**ezsql** wraps up these four basic actions into four very easy to use functions. - -- bool: **`$db->query`**(query) -- var: **`$db->get_var`**(query) -- mixed: **`$db->get_row`**(query) -- mixed: **`$db->get_results`**(query) - -With **ezsql** these four functions are all you will need 99.9% of the time. Of course there are also some other useful functions but we will get into those later. - -**_Important Note:_** _If you use **ezsql** inside a function you write, you will need to put **global $db;** at the top._ ->In version 3 and higher there are global functions available to retrieve the object. **`getInstance()`**, **`tagInstance`**(getTagCreated) - -Need more help, try reading these articles: https://wpshout.com/introduction-to-wpdb-why-not/, https://wpreset.com/customize-wpdb-class/, and https://codex.wordpress.org/Class_Reference/wpdb. - -Any articles referencing WordPress database engine is an good source of what kind of ecosystem can be built with the flexible of what this library provides. However, the ease of use and process this library initially fostered, spread to other areas, leading to hard to follow, and bad coding habits by today's standards. - -Version 4 of this library attempts to, beside all the additional features, _remove some bad coding styles_, _bring the library to modern coding practices of which_, _follow proper __OOP__ and be __PSR__ compliant_. - -This version further break things introduced in version 3 that broke version 2.1.7. See [CHANGE LOG](https://github.com/ezSQL/ezSQL/blob/master/CHANGELOG.md) - -____Installation and Usage____ ---- - - -Either: ***for version 3.x*** - - composer require ezsql/ezsql=^3.1.2 - -```php -require 'vendor/autoload.php'; -``` -```php -// Manually download https://github.com/ezSQL/ezSQL/archive/v3.zip and extract. -require 'ez_sql_loader.php'; -``` -```php -$db = new ezSQL_****(user, password, database, or, other settings); -``` - -Or: ***for version 4.x*** - - // composer is required for version 4 - composer require ezsql/ezsql - -```php -require 'vendor/autoload.php'; - -$db = Database::initialize('****', [user, password, database, other settings], **optional tag); - -// Is same as: -$setting = new Config('****', [user, password, database, other settings]); -$db = new ez_****($settings); -``` - ->Note: __****__ is one of **mysqli**, **pgsql**, **sqlsrv**, **sqlite3**, or **Pdo**. - -**ezsql** functions ---- - -**$db->get_results** -- get multiple row result set from the database (or previously cached results) - -**$db->get_row** -- get one row from the database (or previously cached results) - -**$db->get_col** -- get one column from query (or previously cached results) based on column offset - -**$db->get_var** -- get one variable, from one row, from the database (or previously cached results) - -**$db->query** -- send a query to the database (and if any results, cache them) - -**$db->debug** -- print last sql query and returned results (if any) - -**$db->vardump** -- print the contents and structure of any variable - -**$db->select** -- select a new database to work with - -**$db->get_col-info** -- get information about one or all columns such as column name or type - -**$db->hide-errors** -- turn **ezsql** error output to browser off - -**$db->show-errors** -- turn **ezsql** error output to browser on - -**$db->escape** -- Format a string correctly to stop accidental mal formed queries under all PHP conditions - -**$db = new db** -- Initiate new db object. - -**ezsql** variables ---- - -**$db->num-rows** – Number of rows that were returned (by the database) for the last query (if any) - -**$db->insert-id** -- ID generated from the AUTO-INCRIMENT of the previous INSERT operation (if any) - -**$db->rows-affected** -- Number of rows affected (in the database) by the last INSERT, UPDATE or DELETE (if any) - -**$db->num-queries** -- Keeps track of exactly how many 'real' (not cached) queries were executed during the lifetime of the current script - -**$db->debug-all** – If set to true (i.e. $db->debug-all = true;) Then it will print out ALL queries and ALL results of your script. - -**$db->cache-dir –** Path to mySQL caching dir. - -**$db->cache-queries –** Boolean flag (see mysql/disk-cache-example.php) - -**$db->cache-inserts –** Boolean flag (see mysql/disk-cache-example.php) - -**$db->use-disk-cache –** Boolean flag (see mysql/disk-cache-example.php) - -**$db->cache-timeout –** Number in hours (see mysql/disk-cache-example.php) - -____db = new db____ - -__$db = new db__ -- Initiate new db object. Connect to a database server. Select a database. - -____Description____ - -**$db = new db**(string username, string password, string database name, string database host) - -Does three things. (1) Initiates a new db object. (2) Connects to a database server. (3) Selects a database. You can also re-submit this command if you would like to initiate a second db object. This is interesting because you can run two concurrent database connections at the same time. You can even connect to two different servers at the same time if you want to. - -_Note: For the sake of efficiency it is recommended that you only run one instance of the **db** object and use **$db->select** to switch between different databases on the same server connection._ - -Example - -```php - // Initiate new database object.. -$db2 = new db(”user-name”, ”user-password”, ”database-name”, “database-host”); // version 2 and 3 - - // Perform some kind of query.. - $other_db_tables = $db2->get_results(“SHOW TABLES”); - - // You can still query the database you were already connected to.. - $existing_connection_tables = $db->get_results(“SHOW TABLES”); - - // Print the results from both of these queries.. - $db->debug(); - $db2->debug(); - ``` - -__$db->select__ - for **mysql** only. - -___$db->select___ -- select a new database to work with - -____Description____ - -bool **$db->select**(string database name) - -**$db->select**() selects a new database to work with using the current database connection as created with **$db = new db**. - -Example - -```php - // Get a users name from the user’s database (as initiated with $db = new db).. -$user-name = $db->get_var(“SELECT name FROM users WHERE id = 22”) ; - - // Select the database stats.. -$db->select(“stats”); - - // Get a users name from the user’s database.. -$total-hours = $db->get_var(“SELECT sum(time-logged-in) FROM user-stats WHERE user = ‘$user-name’”) ; - - // Re-select the ‘users’ database to continue working as normal.. -$db->select(“users”); -``` - -____$db->query____ - -__$db->query__ -- send a query to the database (and if any results, cache them) - -____Description____ - -bool **$db->query**(string query) - -**$db->query**() sends a query to the currently selected database. It should be noted that you can send any type of query to the database using this command. If there are any results generated they will be stored and can be accessed by any **ezsql** function as long as you use a null query. If there are results returned the function will return **true** if no results the return will be **false** - -Example 1 - -```php - // Insert a new user into the database.. -$db->query(“INSERT INTO users (id,name) VALUES (1, ’Amy’)”); -``` - -Example 2 - -```php - // Update user into the database.. -$db->query(“UPDATE users SET name = ‘Tyson’ WHERE id = 1”); -``` - -Example 3 - -```php - // Query to get full user list.. -$db->query(“SELECT name,email FROM users”) ; - - // Get the second row from the cached results by using a **null** query.. -$user->details = $db->get->row(null, OBJECT, 1); - - // Display the contents and structure of the variable $user-details.. -$db->varDump($user->details); -``` - -**$db->get_var** - -$db->get_var -- get one variable, from one row, from the database (or previously cached results) - -**Description** - -var **$db->get_var**(string query / null [,int column offset[, int row offset]) - -**$db->get_var**() gets one single variable from the database or previously cached results. This function is very useful for evaluating query results within logic statements such as **if** or **switch**. If the query generates more than one row the first row will always be used by default. If the query generates more than one column the leftmost column will always be used by default. Even so, the full results set will be available within the array $db->last-results should you wish to use them. - -Example 1 - -```php - // Get total number of users from the database.. -$num-users = $db->get_var(“SELECT count(\*) FROM users”) ; -``` - -Example 2 - -```php - // Get a users email from the second row of results (note: col 1, row 1 [starts at 0]).. -$user-email = $db->get_var(“SELECT name, email FROM users”,1,1) ; - - // Get the full second row from the cached results (row = 1 [starts at 0]).. -$user = $db->get_row(null,OBJECT,1); - - // Both are the same value.. - echo $user-email; - echo $user->email; -``` - -Example 3 - -```php - // Find out how many users there are called Amy.. -if ( $n = $db->get_var(“SELECT count(\*) FROM users WHERE name = ‘Amy’”) ) -{ - // If there are users then the if clause will evaluate to true. This is useful because -// we can extract a value from the DB and test it at the same time. -echo “There are $n users called Amy!”; -} else { -// If there are no users then the if will evaluate to false.. -echo “There are no users called Amy.”; -} -``` - -Example 4 - -```php - // Match a password from a submitted from a form with a password stored in the DB -if ( $pwd-from-form == $db->get_var(“SELECT pwd FROM users WHERE name = ‘$name-from-form’”) ) -{ - // Once again we have extracted and evaluated a result at the same time.. -echo “Congratulations you have logged in.”; -} else { - // If has evaluated to false.. -echo “Bad password or Bad user ID”; -} -``` - -**$db->get_row** - -$db->get_row -- get one row from the database (or previously cached results) - -**Description** - -object **$db->get_row**(string query / null [, OBJECT / ARRAY-A / ARRAY-N [, int row offset]]) - -**$db->get_row**() gets a single row from the database or cached results. If the query returns more than one row and no row offset is supplied the first row within the results set will be returned by default. Even so, the full results will be cached should you wish to use them with another **ezsql** query. - -Example 1 - -```php - // Get a users name and email from the database and extract it into an object called user.. -$user = $db->get_row(“SELECT name,email FROM users WHERE id = 22”) ; - - // Output the values.. - echo “$user->name has the email of $user->email”; - - Output: - Amy has the email of amy@foo.com -``` - -Example 2 - -```php -// Get users name and date joined as associative array -// (Note: we must specify the row offset index in order to use the third argument) - $user = $db->get_row(“SELECT name, UNIX-TIMESTAMP(my-date-joined) as date-joined FROM users WHERE id = 22”,ARRAY-A) ; - -// Note how the unix-timestamp command is used with **as** this will ensure that the resulting data will be easily -// accessible via the created object or associative array. In this case $user[‘date-joined’] (object would be $user->date-joined) - echo $user[‘name’] . “ joined us on ” . date(“m/d/y”,$user[‘date-joined’]); - - Output: - Amy joined us on 05/02/01 -``` - -Example 3 - -```php - // Get second row of cached results. - $user = $db->get_row(null,OBJECT,1); - - // Note: Row offset starts at 0 - echo “$user->name joined us on ” . date(“m/d/y”,$user->date-joined); - - Output: - Tyson joined us on 05/02/02 -``` - -Example 4 - -```php - // Get one row as a numerical array.. - $user = $db->get_row(“SELECT name,email,address FROM users WHERE id = 1”,ARRAY-N); - - // Output the results as a table.. - echo “”; - - for ( $i=1; $i <= count($user); $i++ ) - { - echo “”; - } - - echo “
$i$user[$I]
”; - - Output: - 1 amy - 2 amy@foo.com - 3 123 Foo Road -``` - -**$db->get_results** -$db->get_results – get multiple row result set from the database (or previously cached results) - -**Description** -array **$db->get_results**(string query / null [, OBJECT / ARRAY-A / ARRAY-N ] ) - -**$db->get_row**() gets multiple rows of results from the database based on _query_ and returns them as a multi dimensional array. Each element of the array contains one row of results and can be specified to be either an object, associative array or numerical array. If no results are found then the function returns false enabling you to use the function within logic statements such as **if.** - -Example 1 – Return results as objects (default) - -Returning results as an object is the quickest way to get and display results. It is also useful that you are able to put $object->var syntax directly inside print statements without having to worry about causing php parsing errors. - -```php - // Extract results into the array $users (and evaluate if there are any results at the same time).. -if ( $users = $db->get_results(“SELECT name, email FROM users”) ) -{ - // Loop through the resulting array on the index $users[n] - foreach ( $users as $user ) - { - // Access data using column names as associative array keys - echo “$user->name - $user->email”; - } -} else { - // If no users were found then **if** evaluates to false.. -echo “No users found.”; -} - - Output: - Amy - amy@hotmail.com - Tyson - tyson@hotmail.com - ``` - -Example 2 – Return results as associative array -Returning results as an associative array is useful if you would like dynamic access to column names. Here is an example. - -```php - // Extract results into the array $dogs (and evaluate if there are any results at the same time).. -if ( $dogs = $db->get_results(“SELECT breed, owner, name FROM dogs”, ARRAY-A) ) -{ - // Loop through the resulting array on the index $dogs[n] - foreach ( $dogs as $dog-detail ) - { - // Loop through the resulting array - foreach ( $dogs->detail as $key => $val ) - { - // Access and format data using $key and $val pairs.. - echo “” . ucfirst($key) . “: $val
”; - } - // Do a P between dogs.. - echo “

”; - } -} else { - // If no users were found then **if** evaluates to false.. -echo “No dogs found.”; -} - -Output: - Breed: Boxer - Owner: Amy - Name: Tyson - Breed: Labrador - Owner: Lee - Name: Henry - Breed: Dachshund - Owner: Mary - Name: Jasmine -``` - -Example 3 – Return results as numerical array -Returning results as a numerical array is useful if you are using completely dynamic queries with varying column names but still need a way to get a handle on the results. Here is an example of this concept in use. Imagine that this script was responding to a form with $type being submitted as either ‘fish’ or ‘dog’. - -```php - // Create an associative array for animal types.. - $animal = array ( “fish” => “num-fins”, “dog” => “num-legs” ); - - // Create a dynamic query on the fly.. - if ( $results = $db->(“SELECT $animal[$type] FROM $type”, ARRAY-N)) - { - foreach ( $results as $result ) - { - echo “$result[0]
”; - } - } else { - echo “No $animal\\s!”; - } - -Output: - 4 - 4 - 4 -Note: The dynamic query would be look like one of the following... -· SELECT num-fins FROM fish -· SELECT num-legs FROM dogs - -It would be easy to see which it was by using $db->debug(); after the dynamic query call. -``` - -**$db->debug** - -$db->debug – print last sql query and returned results (if any) - -**Description** - -**$db->debug**(void) - -**$db->debug**() prints last sql query and its results (if any) - -Example 1 -If you need to know what your last query was and what the returned results are here is how you do it. - -```php - // Extract results into the array $users.. -$users = $db->get_results(“SELECT name, email FROM users”); - -// See what just happened! -$db->debug(); -``` - -**$db->vardump** - -$db->vardump – print the contents and structure of any variable - -**Description** - -**$db->vardump**(void) - -**$db->vardump**() prints the contents and structure of any variable. It does not matter what the structure is be it an object, associative array or numerical array. - -Example 1 -If you need to know what value and structure any of your results variables are here is how you do it. - -```php - // Extract results into the array $users.. -$users = $db->get_results(“SELECT name, email FROM users”); - -// View the contents and structure of $users -$db->vardump($users); -``` - -**$db->get_col** - -$db->get_col – get one column from query (or previously cached results) based on column offset - -**Description** - -**$db->get_col**( string query / null [, int column offset] ) - -**$db->get_col**() extracts one column as one dimensional array based on a column offset. If no offset is supplied the offset will defualt to column 0. I.E the first column. If a null query is supplied the previous query results are used. - -Example 1 - -```php - // Extract list of products and print them out at the same time.. -foreach ( $db->get_col(“SELECT product FROM product-list”) as $product -{ - echo $product; -} -``` - -Example 2 – Working with cached results - -```php - // Extract results into the array $users.. -$users = $db->get_results(“SELECT \* FROM users”); - -// Work out how many columns have been selected.. -$last-col-num = $db->num-cols - 1; - -// Print the last column of the query using cached results.. -foreach ( $db->get_col(null, $last-col-num) as $last-col ) -{ - echo $last-col; -} -``` - -**$db->get_col-info** - -$db->get_col-info - get information about one or all columns such as column name or type - -**Description** - -**$db->get_col-info**(string info-type[, int column offset]) - -**$db->get_col-info**()returns meta information about one or all columns such as column name or type. If no information type is supplied then the default information type of **name** is used. If no column offset is supplied then a one dimensional array is returned with the information type for ‘all columns’. For access to the full meta information for all columns you can use the cached variable $db->col-info - -Available Info-Types - -**mySQL** - -· name - column name - -· table - name of the table the column belongs to - -· max-length - maximum length of the column - -· not-null - 1 if the column cannot be NULL - -· primary-key - 1 if the column is a primary key - -· unique-key - 1 if the column is a unique key - -· multiple-key - 1 if the column is a non-unique key - -· numeric - 1 if the column is numeric - -· blob - 1 if the column is a BLOB - -· type - the type of the column - -· unsigned - 1 if the column is unsigned - -· zerofill - 1 if the column is zero-filled - -**ibase** - -· name - column name - -· type - the type of the column - -· length - size of column - -· alias - undocumented - -· relation - undocumented - -**MS-SQL / Oracle / Postgress** - -· name - column name - -· type - the type of the column - -· length - size of column - -**SQLite** - -· name - column name -Example 1 - -```php - // Extract results into the array $users.. -$users = $db->get_results(“SELECT id, name, email FROM users”); - -// Output the name for each column type -foreach ( $db->get_col-info(“name”) as $name ) -{ - echo “$name
”; -} - - Output: - id - name - email -``` - -Example 2 - -```php - // Extract results into the array $users.. -$users = $db->get_results(“SELECT id, name, email FROM users”); - - // View all meta information for all columns.. - $db->vardump($db->col-info); -``` - -**$db->hide-errors** - -$db->hide-errors – turn **ezsql** error output to browser off - -**Description** - -**$db->hide-errors**( void ) - -**$db->hide-errors**() stops error output from being printed to the web client. If you would like to stop error output but still be able to trap errors for debugging or for your own error output function you can make use of the global error array $EZSQL-ERROR. - -**_Note:_** _If there were no errors then the global error array $EZSQL-ERROR will evaluate to false. If there were one or more errors then it will have the following structure. Errors are added to the array in order of being called._ - -$EZSQL-ERROR[0] = Array -( - [query] => SOME BAD QUERY - [error-str] => You have an error in your SQL syntax near ‘SOME BAD QUERY' at line 1 -) - -$EZSQL-ERROR[1] = Array -( - [query] => ANOTHER BAD QUERY - [error-str] => You have an error in your SQL syntax near ‘ANOTHER BAD QUERY' at line 1 -) - -$EZSQL-ERROR[2] = Array -( - [query] => THIRD BAD QUERY - [error-str] => You have an error in your SQL syntax near ‘THIRD BAD QUERY' at line 1 -) - -Example 1 - -```php - // Using a custom error function -$db->hide-errors(); - -// Make a silly query that will produce an error -$db->query(“INSERT INTO my-table A BAD QUERY THAT GENERATES AN ERROR”); - -// And another one, for good measure -$db->query(“ANOTHER BAD QUERY THAT GENERATES AN ERROR”); - -// If the global error array exists at all then we know there was 1 or more **ezsql** errors.. -if ( $EZSQL-ERROR ) -{ - // View the errors - $db->vardump($EZSQL-ERROR); -} else { - echo “No Errors”; -} -``` - -**$db->show_errors** - -$db->show_errors – turn **ezsql** error output to browser on - -**Description** - -**$db->show_errors**( void ) - -**$db->show_errors**() turns **ezsql** error output to the browser on. If you have not used the function $db->hide-errors this function (show-errors) will have no effect. - -**$db->escape** - -$db->escape – Format a string correctly in order to stop accidental mal formed queries under all PHP conditions. - -**Description** - -**$db->escape**( string ) - -**$db->escape**() makes any string safe to use as a value in a query under all PHP conditions. I.E. if magic quotes are turned on or off. Note: Should not be used by itself to guard against SQL injection attacks. The purpose of this function is to stop accidental mal formed queries. - -Example 1 - -```php - // Escape and assign the value.. - $title = $db->escape(“Justin’s and Amy’s Home Page”); - - // Insert in to the DB.. -$db->query(“INSERT INTO pages (title) VALUES (’$title’)”) ; -``` - -Example 2 - -```php - // Assign the value.. - $title = “Justin’s and Amy’s Home Page”; - - // Insert in to the DB and escape at the same time.. -$db->query(“INSERT INTO pages (title) VALUES (’”. $db->escape($title).”’)”) ; -``` - -Disk Caching - -**ezsql** has the ability to cache your queries which can make dynamic sites run much faster. - -If you want to cache EVERYTHING just do.. - -**$db->setUse_Disk_Cache(true);** - -**$db->setCache_Queries(true);** - -**$db->setCache_Timeout(24);** diff --git a/lib/Database/async_mysqli.php b/lib/Database/async_mysqli.php deleted file mode 100644 index 5f2c8516..00000000 --- a/lib/Database/async_mysqli.php +++ /dev/null @@ -1,128 +0,0 @@ -database = $settings; - - if (empty($GLOBALS['async'.\MYSQLI])) - $GLOBALS['async'.\MYSQLI] = $this; - \setInstance($this); - - // Prepare statement usage not possible with async queries. - $this->prepareOff(); - } // __construct - - public function query_prepared(string $query, array $param = null) { - return false; - } - - /** - * Perform mySQL query and try to determine result value - * - * @param string $query - * @param bool $use_prepare - * @return bool|mixed - */ - public function query(string $query, bool $use_prepare = false) - { - // Initialize return - $this->return_val = 0; - - // Flush cached values.. - $this->flush(); - - // For reg expressions - $query = \trim($query); - - // Log how the function was called - $this->log_query("\$db->query(\"$query\")"); - - // Keep track of the last query for debug.. - $this->last_query = $query; - - // Count how many queries there have been - $this->num_queries++; - - // Use core file cache function - if ( $cache = $this->get_cache($query) ) { - return $cache; - } - - // If there is no existing database connection then try to connect - if ( ! isset($this->dbh) || ! $this->dbh ) { - $this->connect($this->database->getUser(), $this->database->getPassword(), $this->database->getHost()); - $this->select($this->database->getName()); - } - - \mysqli_query($this->dbh, $query, \MYSQLI_ASYNC); - $connection = $this->dbh; - - do { - yield; - $links = $errors = $reject = array($this->dbh); - \mysqli_poll($links, $errors, $reject, 0, 1); - } while (!\in_array($connection, $links, true) && !\in_array($connection, $errors, true) && !\in_array($connection, $reject, true)); - - $result = \mysqli_reap_async_query($connection); - // If there is an error then take note of it.. - if ( $str = \mysqli_error($this->dbh) ) { - $this->register_error($str); - - // If debug ALL queries - $this->trace || $this->debug_all ? $this->debug() : null ; - return false; - } - - if ($this->processQueryResult($query, $result) === false) - return false; - - // disk caching of queries - $this->store_cache($query, $this->is_insert); - - // If debug ALL queries - $this->trace || $this->debug_all ? $this->debug() : null ; - - return $this->return_val; - } // query - - /** - * Begin Mysql Transaction - */ - public function beginTransaction() - { - /* turn autocommit off */ - $this->dbh->autocommit(false); - $this->dbh->begin_transaction(MYSQLI_TRANS_START_READ_WRITE); - $this->isTransactional = true; - } - - public function commit() - { - $this->dbh->commit(); - $this->dbh->autocommit(true); - $this->isTransactional = false; - } - - public function rollback() - { - $this->dbh->rollBack(); - $this->dbh->autocommit(true); - $this->isTransactional = false; - } -} // ez_mysqli \ No newline at end of file From c2137ff9a6361a54cfe81ce290d717bcfa355d68 Mon Sep 17 00:00:00 2001 From: techno-express Date: Wed, 5 Jun 2019 10:42:13 -0400 Subject: [PATCH 13/17] Update ezFunctionsTest.php --- tests/ezFunctionsTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ezFunctionsTest.php b/tests/ezFunctionsTest.php index 846b3d10..cec4580a 100644 --- a/tests/ezFunctionsTest.php +++ b/tests/ezFunctionsTest.php @@ -301,8 +301,8 @@ public function testUpdate() { /** * @test delete */ - public function testDelete() { - $this->assertFalse(delete('field', 'data', 'data2')); + public function testDeleting() { + $this->assertFalse(deleting('field', 'data', 'data2')); } /** From b98d463be067a555b31ca36aefdbb274283f8423 Mon Sep 17 00:00:00 2001 From: techno-express Date: Wed, 5 Jun 2019 10:46:14 -0400 Subject: [PATCH 14/17] Revert "Merge branch 'masters' into v4" This reverts commit 2900eafb968d6497e73272659d20bccd91c136c4, reversing changes made to 19ca2c852e00f56d0043ae4d97c4c31dd1da08af. --- lib/Database/async_interface.php | 7 -- lib/Database/async_pgsql.php | 205 ------------------------------- lib/Database/ez_pgsql.php | 14 +-- lib/ezFunctions.php | 2 +- lib/ezResultset.php | 8 +- 5 files changed, 12 insertions(+), 224 deletions(-) delete mode 100644 lib/Database/async_interface.php delete mode 100644 lib/Database/async_pgsql.php diff --git a/lib/Database/async_interface.php b/lib/Database/async_interface.php deleted file mode 100644 index be03c03f..00000000 --- a/lib/Database/async_interface.php +++ /dev/null @@ -1,7 +0,0 @@ -database = $settings; - - if (empty($GLOBALS['async'.\PGSQL])) - $GLOBALS['async'.\PGSQL] = $this; - \setInstance($this); - - // Prepare statement usage not possible with async queries. - $this->prepareOff(); - } // __construct - - /** - * Creates a prepared query, binds the given parameters and returns the result of the executed - * - * @param string $query - * @param array $param - * @return bool|mixed - */ - public function query_prepared(string $query, array $param = null) - { - return false; - } - - /** - * Try to connect to PostgreSQL database server - * - * @param string $user The database user name - * @param string $password The database users password - * @param string $name The name of the database - * @param string $host The host name or IP address of the database server. - * Default is localhost - * @param string $port The database TCP/IP port - * Default is PostgreSQL default port 5432 - * @return boolean - */ - public function connect( - string $user = '', - string $password = '', - string $name = '', - string $host = 'localhost', - string $port = '5432') - { - $this->_connected = false; - - $user = empty($user) ? $this->database->getUser() : $user; - $password = empty($password) ? $this->database->getPassword() : $password; - $name = empty($name) ? $this->database->getName() : $name; - $host = ($host != 'localhost') ? $host : $this->database->getHost(); - $port = ($port != '5432') ? $port : $this->database->getPort(); - - $connect_string = "host=".$host." port=".$port." dbname=".$name." user=".$user." password=".$password; - - // Try to establish the server database handle - if (!$this->dbh = \pg_connect($connect_string, \PGSQL_CONNECT_ASYNC | \PGSQL_CONNECT_FORCE_NEW)) { - $this->register_error(\FAILED_CONNECTION . ' in ' . __FILE__ . ' on line ' . __LINE__); - } else { - $this->_connected = true; - } - - return $this->_connected; - } // connect - - /** - * The documentation on this function is pretty barebones (as is the case for a lot of thin PHP wrappers around C functions), - * but from what I've gathered by reading the libpq doc and trying various things, you should probably know the following : - - * Polling the connection while the underlying socket is busy will cause the connection (or at least the polling, - * I'm not sure) to fail. - * - * As stated by the libpq documentation, "do not assume that the socket remains the same across PQconnectPoll calls" - * The socket will become ready after every change in connection status, - * so the connection must be polled multiple times until the function returns "polling_ok" or "polling_failed". - * "polling_active" can never be returned by libpq and has literally never been used anywhere ever, it has been an unused constant since day 1. - * What you need to do is use pg_socket get a PHP stream object corresponding to the current socket and wait after it before polling, like so: - */ - public function query_wait() { - $conn = $this->dbh; - assert(\is_resource($conn)); - assert(\get_resource_type($conn) === "pgsql link" || \get_resource_type($conn) === "pgsql link persistent"); - - // "On the first iteration, i.e. if you have yet to call PQconnectPoll, behave as if it last returned PGRES_POLLING_WRITING." - $poll_outcome = \PGSQL_POLLING_WRITING; - - while (true) { - $socket = [\pg_socket($conn)]; // "Caution: do not assume that the socket remains the same across `pg_connect_poll` calls." - \stream_set_blocking($socket, false); - - if (!$socket) { - $this->register_error(\FAILED_CONNECTION . ' in ' . __FILE__ . ' on line ' . __LINE__); - } - - $null = []; - - if ($poll_outcome === \PGSQL_POLLING_READING) { - \stream_select($socket, $null, $null, 5); - $poll_outcome = \pg_connect_poll($conn); - } elseif ($poll_outcome === \PGSQL_POLLING_WRITING) { - \stream_select($null, $socket, $null, 5); - $poll_outcome = \pg_connect_poll($conn); - } elseif ($poll_outcome === \PGSQL_POLLING_FAILED) { - $this->register_error(\FAILED_CONNECTION . ' in ' . __FILE__ . ' on line ' . __LINE__); - } else { - break; - } - yield; - } - } - - /** - * Perform PostgreSQL query and try to determine result value - * - * @param string - * @param bool - * @return bool|mixed - */ - public function query(string $query, bool $use_prepare = false) - { - // Initialize return - $this->return_val = 0; - - // Flush cached values.. - $this->flush(); - - // For reg expressions - $query = \trim($query); - - // Log how the function was called - $this->log_query("\$db->query(\"$query\")"); - - // Keep track of the last query for debug.. - $this->last_query = $query; - - // Count how many queries there have been - $this->count(true, true); - - // Use core file cache function - if ($cache = $this->get_cache($query)) { - return $cache; - } - - // If there is no existing database connection then try to connect - if (!isset($this->dbh) || !$this->dbh) { - $this->connect($this->database->getUser(), - $this->database->getPassword(), - $this->database->getName(), - $this->database->getHost(), - $this->database->getPort()); - } - - // Do things while the connection is getting ready - yield $this->query_wait(); - @\pg_send_query($this->dbh, $query); - $result = \pg_get_result($this->dbh); - - if ($this->processQueryResult($query, $result) === false) - return false; - - // disk caching of queries - $this->store_cache($query, $this->is_insert); - - // If debug ALL queries - $this->trace || $this->debug_all ? $this->debug() : null; - - return $this->return_val; - } // query - - /** - * Begin Postgresql Transaction - */ - public function beginTransaction() - { - @\pg_query($this->dbh, "BEGIN"); - $this->isTransactional = true; - } - - public function commit() - { - @\pg_query($this->dbh, "COMMIT"); - $this->isTransactional = false; - } - - public function rollback() - { - @\pg_query($this->dbh, "ROLLBACK"); - $this->isTransactional = false; - } -} // ez_pgsql \ No newline at end of file diff --git a/lib/Database/ez_pgsql.php b/lib/Database/ez_pgsql.php index feef289e..1241d507 100644 --- a/lib/Database/ez_pgsql.php +++ b/lib/Database/ez_pgsql.php @@ -10,28 +10,28 @@ class ez_pgsql extends ezsqlModel implements DatabaseInterface { - protected $return_val = 0; - protected $is_insert = false; - protected $shortcutUsed = false; - protected $isTransactional = false; + private $return_val = 0; + private $is_insert = false; + private $shortcutUsed = false; + private $isTransactional = false; /** * Database connection handle * @var resource */ - protected $dbh; + private $dbh; /** * Query result * @var mixed */ - protected $result; + private $result; /** * Database configuration setting * @var ConfigInterface */ - protected $database; + private $database; public function __construct(ConfigInterface $settings = null) { diff --git a/lib/ezFunctions.php b/lib/ezFunctions.php index 0f431289..45175fd2 100644 --- a/lib/ezFunctions.php +++ b/lib/ezFunctions.php @@ -450,7 +450,7 @@ function update($table = '', $keyValue, ...$args) { : false; } - function deleting($table = '', ...$args) { + function delete($table = '', ...$args) { $ezQuery = \getInstance(); return ($ezQuery instanceOf DatabaseInterface) ? $ezQuery->delete($table, ...$args) diff --git a/lib/ezResultset.php b/lib/ezResultset.php index ab1a44c8..92a7b1a2 100644 --- a/lib/ezResultset.php +++ b/lib/ezResultset.php @@ -97,10 +97,10 @@ public function current($mode=self::RESULT_AS_OBJECT) $return_val = \json_encode($this->_resultset[$this->_position]); break; default: - throw new \Exception("Invalid result fetch type"); + throw new \Error("Invalid result fetch type"); } } else { - $return_val = false; + $result = false; } return $return_val; } // current @@ -109,7 +109,7 @@ public function current($mode=self::RESULT_AS_OBJECT) * Returns the current position in the resultset * @return int */ - public function key(): int + public function key() { return $this->_position; } // key @@ -139,7 +139,7 @@ public function previous() * Whether the current position contains a row, or not * @return boolean */ - public function valid(): bool + public function valid() { return isset($this->_resultset[$this->_position]); } // valid From 45417916fb04d25576c28e1f1eb7243577a41755 Mon Sep 17 00:00:00 2001 From: techno-express Date: Wed, 5 Jun 2019 10:49:23 -0400 Subject: [PATCH 15/17] resync with master --- .gitignore | 1 - lib/Database/ez_mysqli.php | 16 ++++++++-------- tests/ezFunctionsTest.php | 4 ++-- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 8dde154a..b90a936d 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,3 @@ test.php *.crt *.cache tmp -.vscode/sftp.json diff --git a/lib/Database/ez_mysqli.php b/lib/Database/ez_mysqli.php index fc3d1fef..8015c283 100644 --- a/lib/Database/ez_mysqli.php +++ b/lib/Database/ez_mysqli.php @@ -10,28 +10,28 @@ class ez_mysqli extends ezsqlModel implements DatabaseInterface { - protected $return_val = 0; - protected $is_insert = false; - protected $shortcutUsed = false; - protected $isTransactional = false; + private $return_val = 0; + private $is_insert = false; + private $shortcutUsed = false; + private $isTransactional = false; /** * Database connection handle * @var resource */ - protected $dbh; + private $dbh; /** * Query result * @var mixed */ - protected $result; + private $result; /** * Database configuration setting * @var ConfigInterface */ - protected $database; + private $database; public function __construct(ConfigInterface $settings = null) { @@ -310,7 +310,7 @@ function ($string, &$arg) use (&$params) { * @param mixed $result * @return bool|void */ - protected function processQueryResult(string $query, $result = null) + private function processQueryResult(string $query, $result = null) { $this->shortcutUsed = false; diff --git a/tests/ezFunctionsTest.php b/tests/ezFunctionsTest.php index cec4580a..846b3d10 100644 --- a/tests/ezFunctionsTest.php +++ b/tests/ezFunctionsTest.php @@ -301,8 +301,8 @@ public function testUpdate() { /** * @test delete */ - public function testDeleting() { - $this->assertFalse(deleting('field', 'data', 'data2')); + public function testDelete() { + $this->assertFalse(delete('field', 'data', 'data2')); } /** From 8d37ca7f07dd0358fff4145d4669f83aaa2d45cc Mon Sep 17 00:00:00 2001 From: techno-express Date: Sun, 2 Feb 2020 10:35:45 -0500 Subject: [PATCH 16/17] Update Constants.php --- lib/Constants.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Constants.php b/lib/Constants.php index 1b10d719..83c50a28 100644 --- a/lib/Constants.php +++ b/lib/Constants.php @@ -5,7 +5,7 @@ /** * ezsqlModel Constants */ - \defined('EZSQL_VERSION') or \define('EZSQL_VERSION', '4.0.10'); + \defined('EZSQL_VERSION') or \define('EZSQL_VERSION', '4.0.9'); \defined('OBJECT') or \define('OBJECT', 'OBJECT'); \defined('ARRAY_A') or \define('ARRAY_A', 'ARRAY_A'); \defined('ARRAY_N') or \define('ARRAY_N', 'ARRAY_N'); From a02853f3d9825edb999e16697df9c45968e2a0fc Mon Sep 17 00:00:00 2001 From: techno-express Date: Sat, 13 Feb 2021 22:17:59 -0500 Subject: [PATCH 17/17] Merge branch 'master' into v4 --- .github/install_mssql.sh | 72 ++++ .github/workflows/ezsql-linux.yml | 56 +++ .github/workflows/ezsql-macos.yml | 66 +++ .github/workflows/ezsql-windows.yml | 65 +++ .travis.yml | 34 -- README.md | 9 +- appveyor.yml | 114 ------ composer.json | 23 +- lib/ConfigAbstract.php | 28 ++ lib/Constants.php | 2 +- lib/DInjector.php | 4 +- lib/Database.php | 12 +- lib/Database/ez_mysqli.php | 35 +- lib/Database/ez_pdo.php | 65 ++- lib/Database/ez_pgsql.php | 18 +- lib/Database/ez_sqlite3.php | 2 +- lib/Database/ez_sqlsrv.php | 100 ++--- lib/DatabaseInterface.php | 4 +- lib/ezFunctions.php | 607 ++++++++++++++++++++++++++-- lib/ezQuery.php | 18 +- lib/ezQueryInterface.php | 20 +- lib/ezSchema.php | 5 + lib/ezsqlModel.php | 87 +++- lib/ezsqlModelInterface.php | 65 --- tests/EZTestCase.php | 2 +- tests/ezFunctionsTest.php | 1 - tests/mysqli/mysqliTest.php | 2 +- tests/pdo/pdo_mysqlTest.php | 19 +- tests/pdo/pdo_pgsqlTest.php | 34 +- tests/pdo/pdo_sqliteTest.php | 10 +- tests/pdo/pdo_sqlsrvTest.php | 31 +- tests/sqlsrv/sqlsrvTest.php | 8 +- unsupported/install_sql.sh | 122 ------ 33 files changed, 1216 insertions(+), 524 deletions(-) create mode 100644 .github/install_mssql.sh create mode 100644 .github/workflows/ezsql-linux.yml create mode 100644 .github/workflows/ezsql-macos.yml create mode 100644 .github/workflows/ezsql-windows.yml delete mode 100644 .travis.yml delete mode 100644 appveyor.yml delete mode 100644 unsupported/install_sql.sh diff --git a/.github/install_mssql.sh b/.github/install_mssql.sh new file mode 100644 index 00000000..64b19baa --- /dev/null +++ b/.github/install_mssql.sh @@ -0,0 +1,72 @@ +#!/bin/bash -e + +# Use the following variables to control your install: + +# Password for the SA user (required) +MSSQL_SA_PASSWORD='!Passw0rd' + +# Product ID of the version of SQL server you're installing +# Must be evaluation, developer, express, web, standard, enterprise, or your 25 digit product key +# Defaults to developer +MSSQL_PID='evaluation' + +# Install SQL Server Agent (recommended) +SQL_INSTALL_AGENT='y' + +# Install SQL Server Full Text Search (optional) +# SQL_INSTALL_FULLTEXT='y' + +# Create an additional user with sysadmin privileges (optional) +SQL_INSTALL_USER='ez_test' +SQL_INSTALL_USER_PASSWORD='ezTest' +SQL_INSTALL_DATABASE='ez_test' + +if [ -z $MSSQL_SA_PASSWORD ] +then + echo Environment variable MSSQL_SA_PASSWORD must be set for unattended install + exit 1 +fi + +echo Adding Microsoft repositories... +sudo curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - +sudo curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - +repoargs="$(curl https://packages.microsoft.com/config/ubuntu/18.04/mssql-server-2019.list)" +sudo add-apt-repository "${repoargs}" + +echo Running apt-get update -y... +sudo apt-get update -y + +echo Installing SQL Server... +sudo apt-get install -y mssql-server + +echo Running mssql-conf setup... +sudo MSSQL_SA_PASSWORD=$MSSQL_SA_PASSWORD \ + MSSQL_PID=$MSSQL_PID \ + /opt/mssql/bin/mssql-conf -n setup accept-eula + +# Configure firewall to allow TCP port 1433: +echo Configuring UFW to allow traffic on port 1433... +sudo ufw allow 1433/tcp +sudo ufw reload + +# Restart SQL Server after installing: +echo Restarting SQL Server... +sudo systemctl restart mssql-server + +# Optional new user creation: +if [ ! -z $SQL_INSTALL_USER ] && [ ! -z $SQL_INSTALL_USER_PASSWORD ] +then + echo Creating user $SQL_INSTALL_USER + sqlcmd \ + -S localhost \ + -U SA \ + -P $MSSQL_SA_PASSWORD \ + -Q "CREATE DATABASE ez_test" + sqlcmd \ + -S localhost \ + -U SA \ + -P $MSSQL_SA_PASSWORD \ + -Q "CREATE LOGIN [$SQL_INSTALL_USER] WITH PASSWORD=N'$SQL_INSTALL_USER_PASSWORD', DEFAULT_DATABASE=[$SQL_INSTALL_DATABASE], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF; ALTER SERVER ROLE [sysadmin] ADD MEMBER [$SQL_INSTALL_USER]" +fi + +echo Done! diff --git a/.github/workflows/ezsql-linux.yml b/.github/workflows/ezsql-linux.yml new file mode 100644 index 00000000..0bec9206 --- /dev/null +++ b/.github/workflows/ezsql-linux.yml @@ -0,0 +1,56 @@ +# GitHub Action for PHP with extensions +name: Linux + +on: + push: + branches: + - v4 + pull_request: + branches: + - v4 + +jobs: + linux: + name: Linux (PHP ${{ matrix.php-versions }} CI) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + operating-system: [ubuntu-latest] + php-versions: ['7.4', '8.0'] + + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, fileinfo, mysqli, pdo_mysql, pgsql, pdo_pgsql, sqlite3, pdo_sqlite, sqlsrv, pdo_sqlsrv, xdebug + coverage: xdebug + - name: Start MySQL + run: sudo systemctl start mysql.service + - name: Setup MySQL Database + run: | + mysql -uroot -h127.0.0.1 -proot -e "CREATE DATABASE IF NOT EXISTS ez_test;" + mysql -uroot -h127.0.0.1 -proot -e "CREATE USER ez_test@localhost IDENTIFIED BY 'ezTest'; GRANT ALL ON ez_test.* TO ez_test@localhost; FLUSH PRIVILEGES;" + - name: Start PostgreSql + run: | + sudo systemctl start postgresql.service + pg_isready + - name: Create additional user + run: | + sudo -u postgres psql --command="CREATE USER ez_test PASSWORD 'ezTest'" --command="\du" + - name: Setup PostgreSql Database + run: | + sudo -u postgres createdb --owner=ez_test ez_test + - name: Setup SQLServer Database + run: | + chmod +x "${GITHUB_WORKSPACE}/.github/install_mssql.sh" + "${GITHUB_WORKSPACE}/.github/install_mssql.sh" + - name: Install dependencies + run: composer update + - name: Test with phpunit + run: vendor/bin/phpunit --coverage-clover=coverage.xml + - name: Submit code coverage + run: bash <(curl -s https://codecov.io/bash) diff --git a/.github/workflows/ezsql-macos.yml b/.github/workflows/ezsql-macos.yml new file mode 100644 index 00000000..382486d3 --- /dev/null +++ b/.github/workflows/ezsql-macos.yml @@ -0,0 +1,66 @@ +# GitHub Action for PHP with extensions +name: macOS + +on: + push: + branches: + - v4 + pull_request: + branches: + - v4 + +jobs: + windows: + name: macOS (PHP ${{ matrix.php-versions }} CI) + runs-on: macos-latest + continue-on-error: true + strategy: + fail-fast: false + matrix: + operating-system: [macos-latest] + php-versions: ['7.3'] + + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, fileinfo, mysqli, pdo_mysql, pgsql, pdo_pgsql, sqlite3, pdo_sqlite, xdebug + coverage: xdebug + - name: Brew Install MySQL + run: | + brew install mysql@5.7 + - name: Brew Start MySQL + run: | + brew services start mysql@5.7 + brew link mysql@5.7 --force + mysqld --initialize-insecure + mysql.server start + - name: Setup MySQL Database + run: | + mysql -u root -e "CREATE DATABASE IF NOT EXISTS ez_test;" + mysql -u root -e "CREATE USER ez_test@localhost IDENTIFIED BY 'ezTest'; GRANT ALL ON ez_test.* TO ez_test@localhost; FLUSH PRIVILEGES;" + - name: Brew Start PostgreSql + run: | + sudo mkdir /var/pgsql_socket/ + sudo ln -s /private/tmp/.s.PGSQL.5432 /var/pgsql_socket/ + pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start + brew services restart postgresql + - name: Setup PostgreSql Database + run: | + createuser -s postgres + psql -U postgres --command="CREATE USER ez_test PASSWORD 'ezTest'" --command="\du" + createdb --owner=ez_test ez_test + - name: Install dependencies + run: | + composer self-update + composer update + - name: Test with phpunit + run: ./vendor/bin/phpunit --coverage-clover=coverage.xml + - name: Submit code coverage + if: ${{ success() }} || ${{ failure() }} + uses: codecov/codecov-action@v1 + with: + file: ./coverage.xml # optional diff --git a/.github/workflows/ezsql-windows.yml b/.github/workflows/ezsql-windows.yml new file mode 100644 index 00000000..0af684d1 --- /dev/null +++ b/.github/workflows/ezsql-windows.yml @@ -0,0 +1,65 @@ +# GitHub Action for PHP with extensions +name: Windows + +on: + push: + branches: + - v4 + pull_request: + branches: + - v4 + +jobs: + windows: + name: Windows (PHP ${{ matrix.php-versions }} CI) + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + operating-system: [windows-latest] + php-versions: ['7.1', '7.2'] + + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, fileinfo, mysqli, pdo_mysql, pgsql, pdo_pgsql, sqlite3, pdo_sqlite, sqlsrv, pdo_sqlsrv, xdebug + coverage: xdebug + - name: Chocolatey Install MySQL + run: choco install mysql --version=5.7.18 -y -f + - name: Setup MySQL Database + run: | + mysql -u root -e "CREATE DATABASE IF NOT EXISTS ez_test;" + mysql -u root -e "CREATE USER ez_test@localhost IDENTIFIED BY 'ezTest'; GRANT ALL ON ez_test.* TO ez_test@localhost; FLUSH PRIVILEGES;" + - name: Chocolatey Uninstall PostgreSql 13 + run: choco uninstall postgresql13 -y -f + - name: Chocolatey Install PostgreSql 9 + run: choco install postgresql9 --params '/Password:root' -y -f + - name: Setup PostgreSql Database + run: | + $env:Path += ";C:\Program Files\PostgreSQL\9.6\bin" + $env:PGPASSWORD = "root" + psql -U postgres --command="\conninfo" + psql -U postgres -c "CREATE USER ez_test WITH PASSWORD 'ezTest';" --command="\du" + createdb --owner=ez_test ez_test + [Environment]::SetEnvironmentVariable("Path", $env:Path, [EnvironmentVariableTarget]::Machine) + - name: Chocolatey Install SQLServer + run: choco install sql-server-express -ia "/IACCEPTSQLSERVERLICENSETERMS /Q /ACTION=install /INSTANCEID=MSSQLSERVER /INSTANCENAME=MSSQLSERVER /UPDATEENABLED=FALSE /TCPENABLED=1 /SECURITYMODE=SQL /SAPWD=Password12!" -o -y -f + - name: Setup SQLServer Database + run: | + sqlcmd -L + New-NetFirewallRule -DisplayName "SQLServer default instance" -Direction Inbound -LocalPort 1433 -Protocol TCP -Action Allow + New-NetFirewallRule -DisplayName "SQLServer Browser service" -Direction Inbound -LocalPort 1434 -Protocol UDP -Action Allow + sqlcmd -S localhost,1433 -U sa -P Password12! -Q "CREATE DATABASE ez_test" + sqlcmd -S localhost,1433 -U sa -P Password12! -d ez_test -Q "CREATE LOGIN ez_test WITH PASSWORD=N'ezTest', DEFAULT_DATABASE=ez_test, CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF; ALTER SERVER ROLE [sysadmin] ADD MEMBER ez_test" + - name: Install dependencies + run: composer update + - name: Test with phpunit + run: vendor\bin\phpunit --coverage-clover=coverage.xml + - name: Submit code coverage + uses: codecov/codecov-action@v1 + with: + file: ./coverage.xml # optional diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 7bb41573..00000000 --- a/.travis.yml +++ /dev/null @@ -1,34 +0,0 @@ -language: php - -# Versions of PHP you want your project run with. -php: - - 7.1 - - 7.2 - - 7.4 - -env: - - MYSQL_HOST=127.0.0.1 MYSQL_USER=root - -services: - - mysql - - postgresql - -# Commands to be run before your environment runs. -before_script: - - composer self-update - - composer require phpstan/phpstan "0.11.3" - - mysql -e 'CREATE DATABASE IF NOT EXISTS ez_test;' - - mysql -e "CREATE USER ez_test@localhost IDENTIFIED BY 'ezTest'; GRANT ALL ON ez_test.* TO ez_test@localhost; FLUSH PRIVILEGES;" - - psql -c 'CREATE DATABASE ez_test;' -U postgres - - psql -c "CREATE USER ez_test WITH PASSWORD 'ezTest';" -U postgres -# - mysql -e 'GRANT ALL PRIVILEGES ON ez_test.* TO ez_test@localhost;' -# - mysql -e "SET PASSWORD FOR 'ez_test'@'localhost' = PASSWORD('ezTest')" - -after_success: - - bash <(curl -s https://codecov.io/bash) - - travis_retry php vendor/bin/php-coveralls - -# Commands you want to run that will verify your build. -script: - - vendor/bin/phpunit --coverage-clover=coverage.xml - - vendor/bin/phpstan analyse lib tests --level=1 diff --git a/README.md b/README.md index 526839bf..cb1b811b 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,12 @@ # **ezsql** -[![Build Status](https://travis-ci.org/ezSQL/ezsql.svg?branch=master)](https://travis-ci.org/ezSQL/ezsql) -[![Build status](https://ci.appveyor.com/api/projects/status/6s8oqnoxa2i5k04f?svg=true)](https://ci.appveyor.com/project/jv2222/ezsql) -[![codecov](https://codecov.io/gh/ezSQL/ezSQL/branch/master/graph/badge.svg)](https://codecov.io/gh/ezSQL/ezSQL) +[![Windows](https://github.com/ezSQL/ezsql/workflows/Windows/badge.svg?branch=v4)](https://github.com/ezSQL/ezsql/actions?query=workflow%3AWindows) +[![Linux](https://github.com/ezSQL/ezsql/workflows/Linux/badge.svg?branch=v4)](https://github.com/ezSQL/ezsql/actions?query=workflow%3ALinux) +[![macOS](https://github.com/ezSQL/ezsql/workflows/macOS/badge.svg?branch=v4)](https://github.com/ezSQL/ezsql/actions?query=workflow%3AmacOS) +[![codecov](https://codecov.io/gh/ezSQL/ezSQL/branch/v4/graph/badge.svg)](https://codecov.io/gh/ezSQL/ezSQL) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/aad1f6aaaaa14f60933e75615da900b8)](https://www.codacy.com/app/techno-express/ezsql?utm_source=github.com&utm_medium=referral&utm_content=ezSQL/ezsql&utm_campaign=Badge_Grade) [![Maintainability](https://api.codeclimate.com/v1/badges/6f6107f25e9de7bf4272/maintainability)](https://codeclimate.com/github/ezSQL/ezsql/maintainability) -[![Total Downloads](https://poser.pugx.org/jv2222/ezsql/downloads)](https://packagist.org/packages/jv2222/ezsql) +[![Total Downloads](https://poser.pugx.org/ezSQL/ezsql/downloads)](https://packagist.org/packages/ezSQL/ezsql) ***A class to make it very easy to deal with database connections.*** diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 67245644..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,114 +0,0 @@ -build: false -platform: - - x64 -clone_folder: c:\projects\php-project-workspace - -## Build matrix for lowest and highest possible targets -environment: - matrix: - - php_ver_target: 7.3.11 - MYSQL_DATABASE: ez_test - MYSQL_HOST: localhost - MYSQL_USER: root - MYSQL_PASSWORD: Password12! - MYSQL_PATH: C:\Program Files\MySQL\MySQL Server 5.7 - -services: - - mssql2014 - - mysql - - postgresql - -## Set up environment variables -init: - - SET COMPOSER_NO_INTERACTION=1 - - SET PHP=1 # This var is connected to PHP install cache - - SET ANSICON=121x90 (121x90) - -## Install PHP and composer, and run the appropriate composer command Get the MSSQL DLL's and XDEBUG -install: - # Enable Windows Update service, needed to install vcredist2015 (dependency of php) - - IF EXIST c:\tools\php73 (SET PHP=0) - - ps: Set-Service wuauserv -StartupType Manual - - choco config set cacheLocation %LOCALAPPDATA%\Temp\Chocolatey - - choco install -y php --version %php_ver_target% - - choco install -y sqlite - - choco install -y composer - - refreshenv - - composer install --no-interaction --no-progress --prefer-dist - - cd C:\tools\php73 - # Get the MSSQL DLL's - - ps: >- - If ($env:PHP -eq "1") { - $DLLVersion = "5.6.1" - cd C:\tools\php73\ext - $source = "http://windows.php.net/downloads/pecl/releases/sqlsrv/$($DLLVersion)/php_sqlsrv-$($DLLVersion)-7.3-nts-vc15-x64.zip" - $destination = "C:\tools\php73\ext\php_sqlsrv-$($DLLVersion)-7.3-nts-vc15-x64.zip" - Invoke-WebRequest $source -OutFile $destination - 7z x -y php_sqlsrv-$($DLLVersion)-7.3-nts-vc15-x64.zip > $null - $source = "http://windows.php.net/downloads/pecl/releases/pdo_sqlsrv/$($DLLVersion)/php_pdo_sqlsrv-$($DLLVersion)-7.3-nts-vc15-x64.zip" - $destination = "C:\tools\php73\ext\php_pdo_sqlsrv-$($DLLVersion)-7.3-nts-vc15-x64.zip" - Invoke-WebRequest $source -OutFile $destination - 7z x -y php_pdo_sqlsrv-$($DLLVersion)-7.3-nts-vc15-x64.zip > $null - Remove-Item C:\tools\php73\ext* -include .zip - Invoke-WebRequest "https://xdebug.org/files/php_xdebug-2.7.2-7.3-vc15-nts-x86_64.dll" -OutFile "C:\tools\php73\ext\php_xdebug-2.7.2-7.3-vc15-nts-x86_64.dll" - cd C:\tools\php73 - } - - IF %PHP%==1 echo date.timezone="UTC" >> php.ini - - IF %PHP%==1 echo extension_dir=ext >> php.ini - - IF %PHP%==1 echo extension=php_fileinfo.dll >> php.ini - - ps: >- - If ($env:php_ver_target -eq "5.6") { - Add-Content php.ini "`nextension=php_sqlsrv_nts.dll" - Add-Content php.ini "`nextension=php_pdo_sqlsrv_nts.dll" - Add-Content php.ini "`n" - } Else { - Add-Content php.ini "`nextension=php_sqlsrv.dll" - Add-Content php.ini "`nextension=php_pdo_sqlsrv.dll" - Add-Content php.ini "`n" - } - - IF %PHP%==1 echo extension=php_pgsql.dll >> php.ini - - IF %PHP%==1 echo extension=php_pdo_pgsql.dll >> php.ini - - IF %PHP%==1 echo extension=php_sqlite3.dll >> php.ini - - IF %PHP%==1 echo extension=php_pdo_sqlite.dll >> php.ini - - IF %PHP%==1 echo extension=php_mysqli.dll >> php.ini - - IF %PHP%==1 echo extension=php_pdo_mysql.dll >> php.ini - - IF %PHP%==1 echo [xdebug] >> php.ini - - IF %PHP%==1 echo zend_extension=php_xdebug-2.7.2-7.3-vc15-nts-x86_64.dll >> php.ini - - IF %PHP%==1 echo zend.assertions=1 >> php.ini - - IF %PHP%==1 echo assert.exception=On >> php.ini - - IF %PHP%==1 echo xdebug.remote_enable=1 >> php.ini - - IF %PHP%==1 echo xdebug.remote_autostart=1 >> php.ini - - IF %PHP%==1 echo xdebug.profiler_enable=off >> php.ini - - cd c:\projects\php-project-workspace - - composer self-update - - composer require phpstan/phpstan "0.11.3" - -build_script: - # postgres - - SET PGUSER=postgres - - SET PGPASSWORD=Password12! - - PATH=C:\Program Files\PostgreSQL\9.6\bin\;%PATH% - - createdb ez_test - - psql -c "CREATE USER ez_test WITH PASSWORD 'ezTest';" - # sqlserver - - sqlcmd -S localhost,1433 -U sa -P Password12! -Q "CREATE DATABASE ez_test" - - sqlcmd -S localhost,1433 -U sa -P Password12! -d ez_test -Q "CREATE LOGIN ez_test WITH PASSWORD=N'ezTest', DEFAULT_DATABASE=ez_test, CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF; ALTER SERVER ROLE [sysadmin] ADD MEMBER ez_test" - -before_test: - - SET PATH=%MYSQL_PATH%\bin;%PATH% - - mysqladmin --host=%MYSQL_HOST% --user=%MYSQL_USER% --password=%MYSQL_PASSWORD% create %MYSQL_DATABASE% - # mysql - - mysql -u root -p"Password12!" -e "CREATE DATABASE IF NOT EXISTS ez_test;" - - mysql -u root -p"Password12!" -e "GRANT ALL PRIVILEGES ON ez_test.* TO ez_test@localhost IDENTIFIED BY 'ezTest'"; - - mysql -u root -p"Password12!" -e "FLUSH PRIVILEGES;" - -on_success: - - ps: | - $env:PATH = 'C:\msys64\usr\bin;' + $env:PATH - Invoke-WebRequest -Uri 'https://codecov.io/bash' -OutFile codecov.sh - bash codecov.sh -f "coverage.xml" - -## Run the actual test -test_script: - - cd c:\projects\php-project-workspace - - vendor\bin\phpunit --coverage-clover=coverage.xml diff --git a/composer.json b/composer.json index 97cd7f08..29f7ef48 100644 --- a/composer.json +++ b/composer.json @@ -1,8 +1,25 @@ { "name": "ezsql/ezsql", "description": "Advance database access library. Make interacting with a database ridiculously easy.", - "keywords": ["mysql", "mysqli", "postgresql", "mssql", "sqlsrv", "sqlserver", "pdo", "sqlite", "sqlite3", "database", "abstraction", "sql", "dba"], - "license": ["LGPL-3.0-or-later", "MIT"], + "keywords": [ + "mysql", + "mysqli", + "postgresql", + "mssql", + "sqlsrv", + "sqlserver", + "pdo", + "sqlite", + "sqlite3", + "database", + "abstraction", + "sql", + "dba" + ], + "license": [ + "LGPL-3.0-or-later", + "MIT" + ], "authors": [ { "name": "Justin Vincent", @@ -21,7 +38,7 @@ "issues": "https://github.com/ezSQL/ezSQL/issues" }, "require": { - "php": "^7.1", + "php": "^7.1 || ^8", "psr/container": "^1.0" }, "provide": { diff --git a/lib/ConfigAbstract.php b/lib/ConfigAbstract.php index ef660a40..0d93f6eb 100644 --- a/lib/ConfigAbstract.php +++ b/lib/ConfigAbstract.php @@ -25,6 +25,34 @@ /** * @method set/get{property} - a property that needs to be accessed + * + * @method void setDriver($args); + * @method void setDsn($args); + * @method void setUser($args); + * @method void setPassword($args); + * @method void setName($args); + * @method void setHost($args); + * @method void setPort($args); + * @method void setCharset($args); + * @method void setOptions($args); + * @method void setIsFile($args); + * @method void setToMssql($args); + * @method void setToMysql($args); + * @method void setPath($args); + * + * @method string getDriver(); + * @method string getDsn(); + * @method string getUser(); + * @method string getPassword() + * @method string getName(); + * @method string getHost(); + * @method string getPort(); + * @method string getCharset(); + * @method string getOptions(); + * @method string getToMysql(); + * @method bool getIsFile(); + * @method bool getToMssql(); + * @method string getPath(); */ abstract class ConfigAbstract { diff --git a/lib/Constants.php b/lib/Constants.php index 83c50a28..f485dc2c 100644 --- a/lib/Constants.php +++ b/lib/Constants.php @@ -5,7 +5,7 @@ /** * ezsqlModel Constants */ - \defined('EZSQL_VERSION') or \define('EZSQL_VERSION', '4.0.9'); + \defined('EZSQL_VERSION') or \define('EZSQL_VERSION', '4.1.0'); \defined('OBJECT') or \define('OBJECT', 'OBJECT'); \defined('ARRAY_A') or \define('ARRAY_A', 'ARRAY_A'); \defined('ARRAY_N') or \define('ARRAY_N', 'ARRAY_N'); diff --git a/lib/DInjector.php b/lib/DInjector.php index f24e8c13..b34bbb64 100644 --- a/lib/DInjector.php +++ b/lib/DInjector.php @@ -129,7 +129,9 @@ protected function getDependencies($parameters, $values = null) if (\is_array($parameters)) { foreach ($parameters as $parameter) { // get the type hinted class - $dependency = $parameter->getClass(); + $dependency = $parameter->getType() && !$parameter->getType()->isBuiltin() + ? new \ReflectionClass($parameter->getType()->getName()) + : NULL; if ($dependency === NULL) { // check if the constructor parameter name exists as a key in the values array if (\array_key_exists($parameter->getName(), $values)) { diff --git a/lib/Database.php b/lib/Database.php index b5126084..914d0687 100644 --- a/lib/Database.php +++ b/lib/Database.php @@ -18,11 +18,14 @@ class Database private static $instances = []; private function __construct() - { } + { + } private function __clone() - { } - private function __wakeup() - { } + { + } + public function __wakeup() + { + } /** * Initialize and connect a vendor database. @@ -30,6 +33,7 @@ private function __wakeup() * @param mixed $vendor - SQL driver * @param mixed $setting - SQL connection parameters * @param mixed $tag - Store the instance for later use + * @return Database\ez_pdo|Database\ez_pgsql|Database\ez_sqlsrv|Database\ez_sqlite3|Database\ez_mysqli */ public static function initialize(?string $vendor = null, ?array $setting = null, ?string $tag = null) { diff --git a/lib/Database/ez_mysqli.php b/lib/Database/ez_mysqli.php index 16b9326b..2ec89afb 100644 --- a/lib/Database/ez_mysqli.php +++ b/lib/Database/ez_mysqli.php @@ -18,7 +18,7 @@ class ez_mysqli extends ezsqlModel implements DatabaseInterface /** * Database connection handle - * @var resource + * @var \mysqli */ private $dbh; @@ -132,19 +132,13 @@ public function connect( */ public function select($name = '', $charset = '') { - $this->_connected = false; $name = empty($name) ? $this->database->getName() : $name; - if (!$this->dbh) { - // Must have an active database connection - $this->register_error(\FAILED_CONNECTION . ' in ' . __FILE__ . ' on line ' . __LINE__); - } elseif (!\mysqli_select_db($this->dbh, $name)) { + try { // Try to connect to the database - // Try to get error supplied by mysql if not use our own - if (!$str = \mysqli_error($this->dbh)) { - $str = 'Unexpected error while trying to select database'; + if (($this->dbh === null) || ($this->_connected === false) || !\mysqli_select_db($this->dbh, $name)) { + throw new Exception("Error Processing Request", 1); } - $this->register_error($str . ' in ' . __FILE__ . ' on line ' . __LINE__); - } else { + $this->database->setName($name); if ($charset == '') { $charset = $this->database->getCharset(); @@ -162,10 +156,21 @@ public function select($name = '', $charset = '') \mysqli_query($this->dbh, 'SET NAMES \'' . $encoding . '\''); } } - $this->_connected = true; - } - return $this->_connected; + return true; + } catch (\Throwable $e) { + $str = \FAILED_CONNECTION; + // Must have an active database connection + if ($this->dbh && $this->_connected) { + // Try to get error supplied by mysql if not use our own + if (!$str = \mysqli_error($this->dbh)) { + $str = 'Unexpected error while trying to select database'; + } + } + + $this->register_error($str . ' in ' . __FILE__ . ' on line ' . __LINE__); + return false; + } } // select /** @@ -225,7 +230,7 @@ private function fetch_prepared_result(&$stmt, $query) } // Binds variables to a prepared statement for result storage - \call_user_func_array([$stmt, 'bind_result'], $variables); + \call_user_func_array([$stmt, 'bind_result'], \array_values($variables)); $i = 0; // Store Query Results diff --git a/lib/Database/ez_pdo.php b/lib/Database/ez_pdo.php index 8b80dbb4..f736d691 100644 --- a/lib/Database/ez_pdo.php +++ b/lib/Database/ez_pdo.php @@ -19,22 +19,22 @@ class ez_pdo extends ezsqlModel implements DatabaseInterface /** * Database connection handle - * @var resource + * @var \PDO */ private $dbh; - /** - * Query result - * @var mixed - */ - private $result; - /** * Database configuration setting * @var ConfigInterface */ private $database; + /** + * Query result + * @var mixed + */ + protected $result; + public function __construct(ConfigInterface $settings = null) { if (empty($settings)) { @@ -239,14 +239,18 @@ public function query_prepared(string $query, array $param = null, $isSelect = f { $stmt = $this->dbh->prepare($query); $result = false; - if ($stmt && $stmt->execute($param)) { + if ($stmt && $stmt->execute(\array_values($param))) { $result = $stmt->rowCount(); // Store Query Results $num_rows = 0; - while ($row = @$stmt->fetch(\PDO::FETCH_ASSOC)) { - // Store results as an objects within main array - $this->last_result[$num_rows] = (object) $row; - $num_rows++; + try { + while ($row = @$stmt->fetch(\PDO::FETCH_ASSOC)) { + // Store results as an objects within main array + $this->last_result[$num_rows] = (object) $row; + $num_rows++; + } + } catch (\Throwable $ex) { + // } $this->num_rows = $num_rows; @@ -300,10 +304,14 @@ private function processResult(string $query, $result = null, bool $isSelect = f // Store Query Results $num_rows = 0; - while ($row = @$result->fetch(\PDO::FETCH_ASSOC)) { - // Store results as an objects within main array - $this->last_result[$num_rows] = (object) $row; - $num_rows++; + try { + while ($row = @$result->fetch(\PDO::FETCH_ASSOC)) { + // Store results as an objects within main array + $this->last_result[$num_rows] = (object) $row; + $num_rows++; + } + } catch (\Throwable $ex) { + // } // Log number of rows the query returned @@ -318,9 +326,13 @@ private function processResult(string $query, $result = null, bool $isSelect = f if (!empty($result)) $this->_affectedRows = $result; - // Take note of the insert_id - if (\preg_match("/^(insert|replace)\s+/i", $query)) { - $this->insert_id = @$this->dbh->lastInsertId(); + try { + // Take note of the insert_id + if (\preg_match("/^(insert|replace)\s+/i", $query)) { + $this->insert_id = @$this->dbh->lastInsertId(); + } + } catch (\Throwable $ex) { + // } // Return number of rows affected @@ -346,8 +358,13 @@ private function processQuery(string $query, array $param = null) if (!empty($param) && \is_array($param) && $this->isPrepareOn()) { $this->shortcutUsed = true; $this->_affectedRows = $this->query_prepared($query, $param, false); - } else - $this->_affectedRows = $this->dbh->exec($query); + } else { + try { + $this->_affectedRows = $this->dbh->exec($query); + } catch (\Throwable $ex) { + // + } + } if ($this->processResult($query) === false) return false; @@ -360,7 +377,11 @@ private function processQuery(string $query, array $param = null) $this->shortcutUsed = true; $sth = $this->query_prepared($query, $param, true); } else - $sth = $this->dbh->query($query); + try { + $sth = $this->dbh->query($query); + } catch (\Throwable $ex) { + // + } if ($this->processResult($query, $sth, true) === false) return false; diff --git a/lib/Database/ez_pgsql.php b/lib/Database/ez_pgsql.php index 34da6eb0..3d5eed8c 100644 --- a/lib/Database/ez_pgsql.php +++ b/lib/Database/ez_pgsql.php @@ -103,7 +103,7 @@ public function connect( $connect_string = "host=" . $host . " port=" . $port . " dbname=" . $name . " user=" . $user . " password=" . $password; // Try to establish the server database handle - if (!$this->dbh = \pg_connect($connect_string, true)) { + if (!$this->dbh = \pg_connect($connect_string, PGSQL_CONNECT_FORCE_NEW)) { $this->register_error(\FAILED_CONNECTION . ' in ' . __FILE__ . ' on line ' . __LINE__); } else { $this->_connected = true; @@ -162,9 +162,13 @@ private function processQueryResult(string $query, $result = null) if (!empty($result)) $this->result = $result; - // If there is an error then take note of it.. - if ($str = @\pg_last_error($this->dbh)) { - return $this->register_error($str); + try { + // If there is an error then take note of it.. + if ($str = @\pg_last_error($this->dbh)) { + return $this->register_error($str); + } + } catch (\Throwable $ex) { + return $this->register_error($ex->getMessage()); } // Query was an insert, delete, update, replace @@ -298,7 +302,11 @@ public function query(string $query, bool $use_prepare = false) $this->shortcutUsed = true; $this->result = $this->query_prepared($query, $param); } else { - $this->result = @\pg_query($this->dbh, $query); + try { + $this->result = @\pg_query($this->dbh, $query); + } catch (\Throwable $ex) { + // + } } if ($this->processQueryResult($query) === false) { diff --git a/lib/Database/ez_sqlite3.php b/lib/Database/ez_sqlite3.php index 8c9a7f37..b7dead0e 100644 --- a/lib/Database/ez_sqlite3.php +++ b/lib/Database/ez_sqlite3.php @@ -18,7 +18,7 @@ class ez_sqlite3 extends ezsqlModel implements DatabaseInterface /** * Database connection handle - * @var resource + * @var \SQLite3 */ private $dbh; diff --git a/lib/Database/ez_sqlsrv.php b/lib/Database/ez_sqlsrv.php index ccfe5806..154f260f 100644 --- a/lib/Database/ez_sqlsrv.php +++ b/lib/Database/ez_sqlsrv.php @@ -179,61 +179,65 @@ private function processQueryResult(string $query, $result = null) // Query was an insert, delete, update, replace $this->is_insert = false; - if (\preg_match("/^(insert|delete|update|replace)\s+/i", $query)) { - $this->is_insert = true; - $this->_affectedRows = @\sqlsrv_rows_affected($this->result); - - // Take note of the insert_id - if (\preg_match("/^(insert|replace)\s+/i", $query)) { - $identityResultset = @\sqlsrv_query($this->dbh, "select SCOPE_IDENTITY()"); - - if ($identityResultset != false) { - $identityRow = @\sqlsrv_fetch($identityResultset); - $this->insert_id = $identityRow[0]; + try { + if (\preg_match("/^(insert|delete|update|replace)\s+/i", $query)) { + $this->is_insert = true; + $this->_affectedRows = @\sqlsrv_rows_affected($this->result); + + // Take note of the insert_id + if (\preg_match("/^(insert|replace)\s+/i", $query)) { + $identityResultset = @\sqlsrv_query($this->dbh, "select SCOPE_IDENTITY()"); + + if ($identityResultset != false) { + $identityRow = @\sqlsrv_fetch($identityResultset); + $this->insert_id = $identityRow[0]; + } } - } - // Return number of rows affected - $this->return_val = $this->_affectedRows; - } else { // Query was a select - // Take note of column info - $i = 0; - foreach (@\sqlsrv_field_metadata($this->result) as $field) { - $col = []; - foreach ($field as $name => $value) { - $name = \strtolower($name); - if ($name == "size") { - $name = "max_length"; - } elseif ($name == "type") { - $name = "typeid"; + // Return number of rows affected + $this->return_val = $this->_affectedRows; + } else { // Query was a select + // Take note of column info + $i = 0; + foreach (@\sqlsrv_field_metadata($this->result) as $field) { + $col = []; + foreach ($field as $name => $value) { + $name = \strtolower($name); + if ($name == "size") { + $name = "max_length"; + } elseif ($name == "type") { + $name = "typeid"; + } + + //DEFINED FOR E_STRICT + $col = new \stdClass(); + $col->{$name} = $value; } - //DEFINED FOR E_STRICT - $col = new \stdClass(); - $col->{$name} = $value; + $col->type = $this->get_datatype($col); + $this->col_info[$i++] = $col; + unset($col); } - $col->type = $this->get_datatype($col); - $this->col_info[$i++] = $col; - unset($col); - } - - // Store Query Results - $num_rows = 0; + // Store Query Results + $num_rows = 0; - while ($row = @\sqlsrv_fetch_object($this->result)) { + while ($row = @\sqlsrv_fetch_object($this->result)) { - // Store results as an objects within main array - $this->last_result[$num_rows] = $row; - $num_rows++; - } + // Store results as an objects within main array + $this->last_result[$num_rows] = $row; + $num_rows++; + } - @\sqlsrv_free_stmt($this->result); + @\sqlsrv_free_stmt($this->result); - // Log number of rows the query returned - $this->num_rows = $num_rows; + // Log number of rows the query returned + $this->num_rows = $num_rows; - // Return number of rows selected - $this->return_val = $this->num_rows; + // Return number of rows selected + $this->return_val = $this->num_rows; + } + } catch (\Throwable $ex) { + return false; } return $this->return_val; @@ -300,7 +304,11 @@ public function query(string $query, bool $use_prepare = false) $this->shortcutUsed = true; $this->result = $this->query_prepared($query, $param); } else { - $this->result = @\sqlsrv_query($this->dbh, $query); + try { + $this->result = @\sqlsrv_query($this->dbh, $query); + } catch (\Throwable $ex) { + // + } } if ($this->processQueryResult($query) === false) { diff --git a/lib/DatabaseInterface.php b/lib/DatabaseInterface.php index 8e9040d8..ca5ae9d5 100644 --- a/lib/DatabaseInterface.php +++ b/lib/DatabaseInterface.php @@ -18,6 +18,7 @@ interface DatabaseInterface * - getOptions(); * - getIsFile(); * - getToMssql(); + * - getToMysql(); * - getPath(); *--- * - setDriver($args); @@ -31,9 +32,10 @@ interface DatabaseInterface * - setOptions($args); * - setIsFile($args); * - setToMssql($args); + * - setToMysql($args); * - setPath($args); * - * @return string|array|bool|void + * @return string|array|bool|object */ public function settings(); diff --git a/lib/ezFunctions.php b/lib/ezFunctions.php index b99fc9a7..6b420bd8 100644 --- a/lib/ezFunctions.php +++ b/lib/ezFunctions.php @@ -3,57 +3,135 @@ use ezsql\ezQuery; use ezsql\ezSchema; use ezsql\Database; +use ezsql\ezQueryInterface; use ezsql\DatabaseInterface; -use ezsql\Database\ez_pdo; -// Global class instances, will be used to call methods directly here. - -if (!function_exists('ezFunctions')) { +if (!\function_exists('ezFunctions')) { + /** + * Initialize and connect a vendor database. + * + * @param mixed $sqlDriver - SQL driver + * @param mixed $connectionSetting - SQL connection parameters + * @param mixed $instanceTag - Store the instance for later use + * @return ezsql\Database\ez_pdo|ezsql\Database\ez_pgsql|ezsql\Database\ez_sqlsrv|Database\ez_sqlite3|ezsql\Database\ez_mysqli + */ function database(string $sqlDriver = null, array $connectionSetting = null, string $instanceTag = null) { return Database::initialize($sqlDriver, $connectionSetting, $instanceTag); } + /** + * Returns an already initialized database instance that was created an tag. + * + * @param string $getTag - An stored tag instance + * @return ezsql\Database\ez_pdo|ezsql\Database\ez_pgsql|ezsql\Database\ez_sqlsrv|Database\ez_sqlite3|ezsql\Database\ez_mysqli + */ function tagInstance(string $getTag = null) { return \database($getTag); } + /** + * Initialize an mysqli database. + * + * @param array $databaseSetting - SQL connection parameters + * @param mixed $instanceTag - Store the instance for later use + * + * @return ezsql\Database\ez_mysqli + */ function mysqlInstance(array $databaseSetting = null, string $instanceTag = null) { return \database(\MYSQLI, $databaseSetting, $instanceTag); } + /** + * Initialize an pgsql database. + * + * @param mixed $databaseSetting - SQL connection parameters + * @param mixed $instanceTag - Store the instance for later use + * + * @return ezsql\Database\ez_pgsql + */ function pgsqlInstance(array $databaseSetting = null, string $instanceTag = null) { return \database(\PGSQL, $databaseSetting, $instanceTag); } + /** + * Initialize an mssql database. + * + * @param mixed $databaseSetting - SQL connection parameters + * @param mixed $instanceTag - Store the instance for later use + * + * @return ezsql\Database\ez_sqlsrv + */ function mssqlInstance(array $databaseSetting = null, string $instanceTag = null) { return \database(\MSSQL, $databaseSetting, $instanceTag); } + /** + * Initialize an pdo database. + * + * @param mixed $databaseSetting - SQL connection parameters + * @param mixed $instanceTag - Store the instance for later use + * + * @return ezsql\Database\ez_pdo + */ function pdoInstance(array $databaseSetting = null, string $instanceTag = null) { return \database(\Pdo, $databaseSetting, $instanceTag); } + /** + * Initialize an sqlite3 database. + * + * @param mixed $databaseSetting - SQL connection parameters + * @param mixed $instanceTag - Store the instance for later use + * + * @return ezsql\Database\ez_sqlite3 + */ function sqliteInstance(array $databaseSetting = null, string $instanceTag = null) { return \database(\SQLITE3, $databaseSetting, $instanceTag); } + /** + * Returns the current global database vendor being used. + * + * @return string|null `mysqli`|`pgsql`|`sqlite3`|`sqlsrv` + */ function getVendor() { return ezSchema::vendor(); } + /** + * Convert array to string, and attach '`, `' for separation, if none is provided. + * + * @return string + */ function to_string($arrays, $separation = ',') { return ezQuery::to_string($arrays, $separation); } + /** + * Creates an database column, + * - column, datatype, value/options with the given arguments. + * + * // datatype are global CONSTANTS and can be written out like: + * - VARCHAR, 32, notNULL, PRIMARY, SEQUENCE|AUTO, .... + * // SEQUENCE|AUTO constants will replaced with the proper auto sequence for the SQL driver + * + * @param string $column|CONSTRAINT, - column name/CONSTRAINT usage for PRIMARY|FOREIGN KEY + * @param string $type|$constraintName, - data type for column/primary|foreign constraint name + * @param mixed $size|...$primaryForeignKeys, + * @param mixed $value, - column should be NULL or NOT NULL. If omitted, assumes NULL + * @param mixed $default - Optional. It is the value to assign to the column + * + * @return string|bool - SQL schema string, or false for error + */ function column(string $column = null, string $type = null, ...$args) { return ezSchema::column($column, $type, ...$args); @@ -92,6 +170,29 @@ function dropColumn(string $columnName, ...$data) return \column(\DROP, $columnName, ...$data); } + /** + * Creates self signed certificate + * + * @param string $privatekeyFile + * @param string $certificateFile + * @param string $signingFile + * // param string $caCertificate + * @param string $ssl_path + * @param array $details - certificate details + * + * Example: + * array $details = [ + * "countryName" => '', + * "stateOrProvinceName" => '', + * "localityName" => '', + * "organizationName" => '', + * "organizationalUnitName" => '', + * "commonName" => '', + * "emailAddress" => '' + * ]; + * + * @return string certificate path + */ function createCertificate( string $privatekeyFile = 'certificate.key', string $certificateFile = 'certificate.crt', @@ -104,28 +205,15 @@ function createCertificate( } /** - * Creates an array from expressions in the following format + * Creates an equality comparison expression with the given arguments. * * @param strings $x, - The left expression. - * @param strings $operator, - One of - * '<', '>', '=', '!=', '>=', '<=', '<>', 'IN',, 'NOT IN', 'LIKE', - * 'NOT LIKE', 'BETWEEN', 'NOT BETWEEN', 'IS', 'IS NOT', or the constants above. - * * @param strings $y, - The right expression. * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. * @param strings $args - for any extras * - * function comparison($x, $operator, $y, $and=null, ...$args) - * { - * return array($x, $operator, $y, $and, ...$args); - * } - * * @return array */ - - /** - * Creates an equality comparison expression with the given arguments. - */ function eq($x, $y, $and = null, ...$args) { $expression = array(); @@ -135,6 +223,22 @@ function eq($x, $y, $and = null, ...$args) /** * Creates a non equality comparison expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $operator, - One of + * '<', '>', '=', '!=', '>=', '<=', '<>', 'IN',, 'NOT IN', 'LIKE', + * 'NOT LIKE', 'BETWEEN', 'NOT BETWEEN', 'IS', 'IS NOT', or the constants above. + * + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * function comparison($x, $operator, $y, $and=null, ...$args) + * { + * return array($x, $operator, $y, $and, ...$args); + * } + * + * @return array */ function neq($x, $y, $and = null, ...$args) { @@ -145,6 +249,13 @@ function neq($x, $y, $and = null, ...$args) /** * Creates the other non equality comparison expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function ne($x, $y, $and = null, ...$args) { @@ -155,6 +266,13 @@ function ne($x, $y, $and = null, ...$args) /** * Creates a lower-than comparison expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function lt($x, $y, $and = null, ...$args) { @@ -165,6 +283,13 @@ function lt($x, $y, $and = null, ...$args) /** * Creates a lower-than-equal comparison expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function lte($x, $y, $and = null, ...$args) { @@ -175,6 +300,13 @@ function lte($x, $y, $and = null, ...$args) /** * Creates a greater-than comparison expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function gt($x, $y, $and = null, ...$args) { @@ -185,6 +317,13 @@ function gt($x, $y, $and = null, ...$args) /** * Creates a greater-than-equal comparison expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function gte($x, $y, $and = null, ...$args) { @@ -195,6 +334,13 @@ function gte($x, $y, $and = null, ...$args) /** * Creates an IS NULL expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function isNull($x, $y = 'null', $and = null, ...$args) { @@ -205,6 +351,13 @@ function isNull($x, $y = 'null', $and = null, ...$args) /** * Creates an IS NOT NULL expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function isNotNull($x, $y = 'null', $and = null, ...$args) { @@ -215,6 +368,13 @@ function isNotNull($x, $y = 'null', $and = null, ...$args) /** * Creates a LIKE() comparison expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function like($x, $y, $and = null, ...$args) { @@ -225,6 +385,13 @@ function like($x, $y, $and = null, ...$args) /** * Creates a NOT LIKE() comparison expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function notLike($x, $y, $and = null, ...$args) { @@ -235,6 +402,13 @@ function notLike($x, $y, $and = null, ...$args) /** * Creates a IN () comparison expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function in($x, $y, ...$args) { @@ -245,6 +419,13 @@ function in($x, $y, ...$args) /** * Creates a NOT IN () comparison expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function notIn($x, $y, ...$args) { @@ -255,6 +436,13 @@ function notIn($x, $y, ...$args) /** * Creates a BETWEEN () comparison expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function between($x, $y, $y2, ...$args) { @@ -265,6 +453,13 @@ function between($x, $y, $y2, ...$args) /** * Creates a NOT BETWEEN () comparison expression with the given arguments. + * + * @param strings $x, - The left expression. + * @param strings $y, - The right expression. + * @param strings $and, - combine additional expressions with, 'AND','OR', 'NOT', 'AND NOT'. + * @param strings $args - for any extras + * + * @return array */ function notBetween($x, $y, $y2, ...$args) { @@ -274,16 +469,18 @@ function notBetween($x, $y, $y2, ...$args) } /** - * Using global class instances, setup functions to call class methods directly. + * Sets the global class instance for functions to call class methods directly. + * + * @param ezQueryInterface|null $ezSQL * - * @return boolean - true, or false for error + * @return boolean - `true`, or `false` for error */ - function setInstance($ezSQL = '') + function setInstance(ezQueryInterface $ezSQL = null) { global $ezInstance; $status = false; - if ($ezSQL instanceof DatabaseInterface) { + if ($ezSQL instanceof ezQueryInterface) { $ezInstance = $ezSQL; $status = true; } @@ -291,24 +488,73 @@ function setInstance($ezSQL = '') return $status; } + /** + * Returns the global database class, last created instance or the one set with `setInstance()`. + * + * @return ezQueryInterface|null + */ function getInstance() { global $ezInstance; - return ($ezInstance instanceof DatabaseInterface) ? $ezInstance : null; + return ($ezInstance instanceof ezQueryInterface) ? $ezInstance : null; } + /** + * Clear/unset the global database class instance. + */ function clearInstance() { + global $ezInstance; $GLOBALS['ezInstance'] = null; + $ezInstance = null; unset($GLOBALS['ezInstance']); } + /** + * Clean input of XSS, html, javascript, etc... + * @param string $string + * + * @return string cleaned string + */ function cleanInput($string) { return ezQuery::clean($string); } + /** + * Returns an SQL string or result set, given the + * - table, column fields, conditions or conditional array. + * + * In the following format: + * ```js + * select( + * table, + * columns, + * (innerJoin(), leftJoin(), rightJoin(), fullJoin()), // alias of joining(inner|left|right|full, leftTable, rightTable, leftColumn, rightColumn, equal condition), + * where( eq( columns, values, _AND ), like( columns, _d ) ), + * groupBy( columns ), + * having( between( columns, values1, values2 ) ), + * orderBy( columns, desc ), + * limit( numberOfRecords, offset ), + * union(table, columnFields, conditions), // Returns an select SQL string with `UNION` + * unionAll(table, columnFields, conditions) // Returns an select SQL string with `UNION ALL` + *); + * ``` + * @param $table, - database table to access + * @param $columnFields, - table columns, string or array + * @param mixed ...$conditions - of the following parameters: + * + * @param $joins, - join clause (type, left table, right table, left column, right column, condition = EQ) + * @param $whereKey, - where clause ( comparison(x, y, and) ) + * @param $groupBy, - grouping over clause the results + * @param $having, - having clause ( comparison(x, y, and) ) + * @param $orderby, - ordering by clause for the query + * @param $limit, - limit clause the number of records + * @param $union/$unionAll - union clause combine the result sets and removes duplicate rows/does not remove + * + * @return mixed result set - see docs for more details, or false for error + */ function select($table = '', $columns = '*', ...$args) { $ezQuery = \getInstance(); @@ -317,6 +563,15 @@ function select($table = '', $columns = '*', ...$args) : false; } + /** + * Does an select into statement by calling selecting method + * @param $newTable, - new database table to be created + * @param $fromColumns - the columns from old database table + * @param $oldTable - old database table + * @param $fromWhere, - where clause ( array(x, =, y, and, extra) ) or ( "x = y and extra" ) + * + * @return mixed bool/result - false for error + */ function select_into($table, $columns = '*', $old = null, ...$args) { $ezQuery = \getInstance(); @@ -325,7 +580,15 @@ function select_into($table, $columns = '*', $old = null, ...$args) : false; } - function insert_select($totable = '', $columns = '*', $fromTable, $from = '*', ...$args) + /** + * Does an insert into select statement by calling insert method helper then selecting method + * @param $toTable, - database table to insert table into + * @param $toColumns - the receiving columns from other table columns, leave blank for all or array of column fields + * @param $WhereKey, - where clause ( array(x, =, y, and, extra) ) or ( "x = y and extra" ) + * + * @return mixed bool/id of inserted record, or false for error + */ + function insert_select($totable = '', $columns = '*', $fromTable = null, $from = '*', ...$args) { $ezQuery = \getInstance(); return ($ezQuery instanceof DatabaseInterface) @@ -333,6 +596,16 @@ function insert_select($totable = '', $columns = '*', $fromTable, $from = '*', . : false; } + /** + * Does an create select statement by calling selecting method + * + * @param $newTable, - new database table to be created + * @param $fromColumns - the columns from old database table + * @param $oldTable - old database table + * @param $fromWhere, - where clause ( array(x, =, y, and, extra) ) or ( "x = y and extra" ) + * + * @return mixed bool/result - false for error + */ function create_select($table, $from, $old = null, ...$args) { $ezQuery = \getInstance(); @@ -341,14 +614,68 @@ function create_select($table, $from, $old = null, ...$args) : false; } - function where(...$args) + /** + * Returns an `WHERE` **sql clause** string. + * + * format: + * `where( comparison(x, y, and) )` + * + * example: + * `where( eq(key, value ), like('key', '_%?');` + * + * @param array $whereConditions - In the following format: + *```js + * eq('key/Field/Column', $value, _AND), // combine next expression + * neq('key/Field/Column', $value, _OR), // will combine next expression if + * ne('key/Field/Column', $value), // the default is _AND so will combine next expression + * lt('key/Field/Column', $value) + * lte('key/Field/Column', $value) + * gt('key/Field/Column', $value) + * gte('key/Field/Column', $value) + * isNull('key/Field/Column') + * isNotNull('key/Field/Column') + * like('key/Field/Column', '_%') + * notLike('key/Field/Column', '_%') + * in('key/Field/Column', $values) + * notIn('key/Field/Column', $values) + * between('key/Field/Column', $value, $value2) + * notBetween('key/Field/Column', $value, $value2) + *``` + * @return mixed bool/string - WHERE sql statement, or false on error + */ + function where(...$whereConditions) { $ezQuery = \getInstance(); return ($ezQuery instanceof DatabaseInterface) - ? $ezQuery->where(...$args) + ? $ezQuery->where(...$whereConditions) : false; } + /** + * Adds WHERE grouping to the conditions + * + * format: + * `grouping( comparison(x, y, and) )` + * + * example: + * `grouping( eq(key, value, combiner ), eq(key, value, combiner ) );` + * + * @param array $whereConditions - In the following format: + *```js + * eq('key/Field/Column', $value, _AND), // combine next expression + * neq('key/Field/Column', $value, _OR), // will combine next expression again + * ne('key/Field/Column', $value), // the default is _AND so will combine next expression + * lt('key/Field/Column', $value) + * lte('key/Field/Column', $value) + * gt('key/Field/Column', $value) + * gte('key/Field/Column', $value) + * isNull('key/Field/Column') + * isNotNull('key/Field/Column') + * like('key/Field/Column', '_%') + * notLike('key/Field/Column', '_%') + *``` + * @return array modified conditions + */ function grouping(...$args) { $ezQuery = \getInstance(); @@ -357,6 +684,20 @@ function grouping(...$args) : false; } + /** + * Specifies a grouping over the results of the query. + * + * selecting('table', + * 'columns', + * where( eq( 'columns', values, _AND ), like( 'columns', _d ) ), + * groupBy( 'columns' ), + * having( between( 'columns', values1, values2 ) ), + * orderBy( 'columns', 'desc' ); + * + * @param mixed $groupBy The grouping expression. + * + * @return string - GROUP BY SQL statement, or false on error + */ function groupBy($groupBy) { $ezQuery = \getInstance(); @@ -365,6 +706,29 @@ function groupBy($groupBy) : false; } + /** + * Specifies a restriction over the groups of the query. + * + * format + * `having( array(x, =, y, and, extra) );` or + * `having( "x = y and extra" );` + * + * example: + * `having( array(key, operator, value, combine, extra) );`or + * `having( "key operator value combine extra" );` + * + * @param array $having + * @param string $key, - table column + * @param string $operator, - set the operator condition, + * either '<','>', '=', '!=', '>=', '<=', '<>', 'in', + * 'like', 'between', 'not between', 'is null', 'is not null' + * @param mixed $value, - will be escaped + * @param string $combine, - combine additional where clauses with, + * either 'AND','OR', 'NOT', 'AND NOT' + * or carry over of @value in the case the @operator is 'between' or 'not between' + * @param string $extra - carry over of @combine in the case the operator is 'between' or 'not between' + * @return bool/string - HAVING SQL statement, or false on error + */ function having(...$args) { $ezQuery = \getInstance(); @@ -373,6 +737,29 @@ function having(...$args) : false; } + /** + * Return all rows from multiple tables where the join condition is met. + * + * - Will perform an equal on tables by left column key, + * left column key and left table, left column key and right table, + * if `rightColumn` is null. + * + * - Will perform an equal on tables by, + * left column key and left table, right column key and right table, + * if `rightColumn` not null, and `$condition` not changed. + * + * - Will perform the `condition` on passed in arguments, for left column, and right column. + * if `$condition`, is in the array + * + * @param string $leftTable - + * @param string $rightTable - + * @param string $leftColumn - + * @param string $rightColumn - + * @param string $tableAs - + * @param string $condition - + * + * @return bool|string JOIN sql statement, false for error + */ function innerJoin( $leftTable = '', $rightTable = '', @@ -387,6 +774,31 @@ function innerJoin( : false; } + /** + * This type of join returns all rows from the LEFT-hand table + * specified in the ON condition and only those rows from the other table + * where the joined fields are equal (join condition is met). + * + * - Will perform an equal on tables by left column key, + * left column key and left table, left column key and right table, + * if `rightColumn` is null. + * + * - Will perform an equal on tables by, + * left column key and left table, right column key and right table, + * if `rightColumn` not null, and `$condition` not changed. + * + * - Will perform the `condition` on passed in arguments, for left column, and right column. + * if `$condition`, is in the array + * + * @param string $leftTable - + * @param string $rightTable - + * @param string $leftColumn - + * @param string $rightColumn - + * @param string $tableAs - + * @param string $condition - + * + * @return bool|string JOIN sql statement, false for error + */ function leftJoin( $leftTable = '', $rightTable = '', @@ -401,6 +813,31 @@ function leftJoin( : false; } + /** + * This type of join returns all rows from the RIGHT-hand table + * specified in the ON condition and only those rows from the other table + * where the joined fields are equal (join condition is met). + * + * - Will perform an equal on tables by left column key, + * left column key and left table, left column key and right table, + * if `rightColumn` is null. + * + * - Will perform an equal on tables by, + * left column key and left table, right column key and right table, + * if `rightColumn` not null, and `$condition` not changed. + * + * - Will perform the `condition` on passed in arguments, for left column, and right column. + * if `$condition`, is in the array + * + * @param string $leftTable - + * @param string $rightTable - + * @param string $leftColumn - + * @param string $rightColumn - + * @param string $tableAs - + * @param string $condition - + * + * @return bool|string JOIN sql statement, false for error + */ function rightJoin( $leftTable = '', $rightTable = '', @@ -415,6 +852,30 @@ function rightJoin( : false; } + /** + * This type of join returns all rows from the LEFT-hand table and RIGHT-hand table + * with NULL values in place where the join condition is not met. + * + * - Will perform an equal on tables by left column key, + * left column key and left table, left column key and right table, + * if `rightColumn` is null. + * + * - Will perform an equal on tables by, + * left column key and left table, right column key and right table, + * if `rightColumn` not null, and `$condition` not changed. + * + * - Will perform the `condition` on passed in arguments, for left column, and right column. + * if `$condition`, is in the array + * + * @param string $leftTable - + * @param string $rightTable - + * @param string $leftColumn - + * @param string $rightColumn - + * @param string $tableAs - + * @param string $condition - + * + * @return bool|string JOIN sql statement, false for error + */ function fullJoin( $leftTable = '', $rightTable = '', @@ -429,6 +890,30 @@ function fullJoin( : false; } + /** + * Returns an `UNION` SELECT SQL string, given the + * - table, column fields, conditions or conditional array. + * + * In the following format: + * ``` + * union( + * table, + * columns, + * // innerJoin(), leftJoin(), rightJoin(), fullJoin() alias of + * joining(inner|left|right|full, leftTable, rightTable, leftColumn, rightColumn, equal condition), + * where( eq( columns, values, _AND ), like( columns, _d ) ), + * groupBy( columns ), + * having( between( columns, values1, values2 ) ), + * orderBy( columns, desc ), + * limit( numberOfRecords, offset ) + *); + * ``` + * @param $table, - database table to access + * @param $columnFields, - table columns, string or array + * @param mixed $conditions - same as selecting method. + * + * @return bool|string - false for error + */ function union($table = '', $columnFields = '*', ...$conditions) { $ezQuery = \getInstance(); @@ -437,6 +922,30 @@ function union($table = '', $columnFields = '*', ...$conditions) : false; } + /** + * Returns an `UNION ALL` SELECT SQL string, given the + * - table, column fields, conditions or conditional array. + * + * In the following format: + * ``` + * unionAll( + * table, + * columns, + * // innerJoin(), leftJoin(), rightJoin(), fullJoin() alias of + * joining(inner|left|right|full, leftTable, rightTable, leftColumn, rightColumn, equal condition), + * where( eq( columns, values, _AND ), like( columns, _d ) ), + * groupBy( columns ), + * having( between( columns, values1, values2 ) ), + * orderBy( columns, desc ), + * limit( numberOfRecords, offset ) + *); + * ``` + * @param $table, - database table to access + * @param $columnFields, - table columns, string or array + * @param mixed $conditions - same as selecting method. + * + * @return bool|string - false for error + */ function unionAll($table = '', $columnFields = '*', ...$conditions) { $ezQuery = \getInstance(); @@ -445,6 +954,13 @@ function unionAll($table = '', $columnFields = '*', ...$conditions) : false; } + /** + * Specifies an ordering for the query results. + * @param string $orderBy - The column. + * @param string $order - The ordering direction. + * + * @return string - ORDER BY SQL statement, or false on error + */ function orderBy($orderBy, $order) { $ezQuery = \getInstance(); @@ -453,6 +969,15 @@ function orderBy($orderBy, $order) : false; } + /** + * Specifies records from one or more tables in a database and + * limit the number of records returned. + * + * @param int $numberOf - set limit number of records to be returned. + * @param int $offset - Optional. The first row returned by LIMIT will be determined by offset value. + * + * @return string - LIMIT and/or OFFSET SQL statement, or false on error + */ function limit($numberOf, $offset = null) { $ezQuery = \getInstance(); @@ -461,7 +986,13 @@ function limit($numberOf, $offset = null) : false; } - function insert($table = '', $keyValue) + /** + * Does an insert query with an array + * @param $table, - database table to access + * @param $keyAndValue - table fields, assoc array with key = value (doesn't need escaped) + * @return mixed bool/id of inserted record, or false for error + */ + function insert($table = '', $keyValue = null) { $ezQuery = \getInstance(); return ($ezQuery instanceof DatabaseInterface) @@ -469,7 +1000,15 @@ function insert($table = '', $keyValue) : false; } - function update($table = '', $keyValue, ...$args) + /** + * Does an update query with an array, by conditional operator array + * @param $table, - database table to access + * @param $keyAndValue, - table fields, assoc array with key = value (doesn't need escaped) + * @param $WhereKey, - where clause ( array(x, =, y, and, extra) ) or ( "x = y and extra" ) + * + * @return mixed bool/results - false for error + */ + function update($table = '', $keyValue = null, ...$args) { $ezQuery = \getInstance(); return ($ezQuery instanceof DatabaseInterface) @@ -477,6 +1016,10 @@ function update($table = '', $keyValue, ...$args) : false; } + /** + * Does the delete query with an array + * @return mixed bool/results - false for error + */ function deleting($table = '', ...$args) { $ezQuery = \getInstance(); @@ -485,7 +1028,13 @@ function deleting($table = '', ...$args) : false; } - function replace($table = '', $keyValue) + /** + * Does an replace query with an array + * @param $table, - database table to access + * @param $keyAndValue - table fields, assoc array with key = value (doesn't need escaped) + * @return mixed bool/id of replaced record, or false for error + */ + function replace($table = '', $keyValue = null) { $ezQuery = \getInstance(); return ($ezQuery instanceof DatabaseInterface) diff --git a/lib/ezQuery.php b/lib/ezQuery.php index 7c02ac73..88a76f5d 100644 --- a/lib/ezQuery.php +++ b/lib/ezQuery.php @@ -723,7 +723,7 @@ public function delete(string $table = null, ...$whereConditions) * Helper does the actual insert or replace query with an array * @return mixed bool/results - false for error */ - private function _query_insert_replace($table = '', $keyAndValue, $type = '', $execute = true) + private function _query_insert_replace($table = '', $keyAndValue = null, $type = '', $execute = true) { if ((!\is_array($keyAndValue) && ($execute)) || empty($table)) { return $this->clearPrepare(); @@ -812,7 +812,15 @@ public function get_results( return array(); } - // query call template + // + + /** + * query call template + * + * @param string $query + * @param bool $use_prepare + * @return bool|mixed + */ public function query(string $query, bool $use_prepare = false) { return false; @@ -965,6 +973,12 @@ public function alter(string $table = null, ...$schemas) return false; } + /** + * Does an drop table query if table exists. + * @param $table - database table to erase + * + * @return bool + */ public function drop(string $table = null) { if (empty($table)) diff --git a/lib/ezQueryInterface.php b/lib/ezQueryInterface.php index 5007d1d2..6ce44b58 100644 --- a/lib/ezQueryInterface.php +++ b/lib/ezQueryInterface.php @@ -304,7 +304,7 @@ public function limit($numberOf, $offset = null); * `grouping( eq(key, value, combiner ), eq(key, value, combiner ) );` * * @param array $whereConditions - In the following format: - * + *```js * eq('key/Field/Column', $value, _AND), // combine next expression * neq('key/Field/Column', $value, _OR), // will combine next expression again * ne('key/Field/Column', $value), // the default is _AND so will combine next expression @@ -316,7 +316,7 @@ public function limit($numberOf, $offset = null); * isNotNull('key/Field/Column') * like('key/Field/Column', '_%') * notLike('key/Field/Column', '_%') - * + *``` * @return array modified conditions */ public function grouping(...$whereConditions); @@ -331,9 +331,9 @@ public function grouping(...$whereConditions); * `where( eq(key, value ), like('key', '_%?');` * * @param array $whereConditions - In the following format: - * + *```js * eq('key/Field/Column', $value, _AND), // combine next expression - * neq('key/Field/Column', $value, _OR), // will combine next expression again + * neq('key/Field/Column', $value, _OR), // will combine next expression if * ne('key/Field/Column', $value), // the default is _AND so will combine next expression * lt('key/Field/Column', $value) * lte('key/Field/Column', $value) @@ -347,22 +347,22 @@ public function grouping(...$whereConditions); * notIn('key/Field/Column', $values) * between('key/Field/Column', $value, $value2) * notBetween('key/Field/Column', $value, $value2) - * + *``` * @return mixed bool/string - WHERE SQL statement, or false on error */ public function where(...$whereConditions); + /** * Returns an SQL string or result set, given the * - table, column fields, conditions or conditional array. * * In the following format: - * ``` - * selecting( + * ```js + * select( * table, * columns, - * // innerJoin(), leftJoin(), rightJoin(), fullJoin() alias of - * joining(inner|left|right|full, leftTable, rightTable, leftColumn, rightColumn, equal condition), + * (innerJoin(), leftJoin(), rightJoin(), fullJoin()), // alias of joining(inner|left|right|full, leftTable, rightTable, leftColumn, rightColumn, equal condition), * where( eq( columns, values, _AND ), like( columns, _d ) ), * groupBy( columns ), * having( between( columns, values1, values2 ) ), @@ -374,7 +374,7 @@ public function where(...$whereConditions); * ``` * @param $table, - database table to access * @param $columnFields, - table columns, string or array - * @param mixed $conditions - of the following parameters: + * @param mixed ...$conditions - of the following parameters: * * @param $joins, - join clause (type, left table, right table, left column, right column, condition = EQ) * @param $whereKey, - where clause ( comparison(x, y, and) ) diff --git a/lib/ezSchema.php b/lib/ezSchema.php index 8c0c75a0..e73f7d73 100644 --- a/lib/ezSchema.php +++ b/lib/ezSchema.php @@ -153,6 +153,11 @@ public function __call($type, $args) return $data; } + /** + * Returns the current global database vendor being used. + * + * @return string|null `mysqli`|`pgsql`|`sqlite3`|`sqlsrv` + */ public static function vendor() { $type = null; diff --git a/lib/ezsqlModel.php b/lib/ezsqlModel.php index 93710198..6de9efc3 100644 --- a/lib/ezsqlModel.php +++ b/lib/ezsqlModel.php @@ -174,9 +174,73 @@ public function __construct() } /** - * Use for Calling Non-Existent Functions, handling Getters and Setters + * Magic methods for Calling Non-Existent Functions, handling Getters and Setters. * @method set/get{property} - a property that needs to be accessed * + * @method void setDebug_All($args); + * @method void setTrace($args); + * @method void setDebug_Called($args); + * @method void setVarDump_Called($args); + * @method void setShow_Errors($args); + * @method void setNum_Queries($args); + * @method void setConn_Queries($args); + * @method void setCaptured_Errors($args); + * @method void setCache_Dir($args); + * @method void setUse_Disk_Cache($args); + * @method void setCache_Timeout($args); + * @method void setCache_Queries($args); + * @method void setCache_Inserts($args); + * @method void setNum_Rows($args); + * @method void setDb_Connect_Time($args); + * @method void setSql_Log_File($args); + * @method void setProfile_Times($args); + * @method void setInsert_Id($args); + * @method void setLast_Query($args); + * @method void setLast_Error($args); + * @method void setCol_Info($args); + * @method void setTimers($args); + * @method void setTotal_Query_Time($args); + * @method void setTrace_Log($args); + * @method void setUse_Trace_Log($args); + * @method void setDo_Profile($args); + * @method void setLast_Result($args); + * @method void setFrom_Disk_Cache($args); + * @method void setDebug_Echo_Is_On($args); + * @method void setFunc_Call($args); + * @method void setAll_Func_Calls($args); + * + * @method string getDebug_All(); + * @method string getTrace(); + * @method string getDebug_Called(); + * @method string getVarDump_Called(); + * @method string getShow_Errors(); + * @method string getNum_Queries(); + * @method string getConn_Queries(); + * @method string getCaptured_Errors(); + * @method string getCache_Dir(); + * @method string getUse_Disk_Cache(); + * @method string getCache_Timeout(); + * @method string getCache_Queries(); + * @method string getCache_Inserts(); + * @method string getNum_Rows(); + * @method string getDb_Connect_Time(); + * @method string getSql_Log_File(); + * @method string getProfile_Times(); + * @method string getInsert_Id(); + * @method string getLast_Query(); + * @method string getLast_Error(); + * @method string getCol_Info(); + * @method string getTimers(); + * @method string getTotal_Query_Time(); + * @method string getTrace_Log(); + * @method string getUse_Trace_Log(); + * @method string getDo_Profile(); + * @method string getLast_Result(); + * @method string getFrom_Disk_Cache(); + * @method string getDebug_Echo_Is_On(); + * @method string getFunc_Call(); + * @method string getAll_Func_Calls(); + * * @property-read function * @property-write args * @@ -258,8 +322,8 @@ public function flush() // Get rid of these $this->last_result = null; $this->col_info = array(); - $this->last_query = null; - $this->all_func_calls = array(); + $this->last_query = null; + $this->all_func_calls = array(); $this->from_disk_cache = false; $this->clearPrepare(); } @@ -337,7 +401,7 @@ public function get_col(string $query = null, int $x = 0, bool $use_prepare = fa return $new_array; } - public function get_results(string $query = null, $output = \OBJECT, bool $use_prepare = false) + public function get_results(string $query = null, $output = \OBJECT, bool $use_prepare = false) { // Log how the function was called $this->log_query("\$db->get_results(\"$query\", $output, $use_prepare)"); @@ -664,16 +728,31 @@ public function secureReset() $this->secureOptions = null; } + /** + * Returns `true` if the database connection is established. + * + * @return bool + */ public function isConnected() { return $this->_connected; } // isConnected + /** + * Returns the `number` of affected rows of a query. + * + * @return int + */ public function affectedRows() { return $this->_affectedRows; } // affectedRows + /** + * Returns the last query `result`. + * + * @return object + */ public function queryResult() { return $this->last_result; diff --git a/lib/ezsqlModelInterface.php b/lib/ezsqlModelInterface.php index 74b8be79..171e5f26 100644 --- a/lib/ezsqlModelInterface.php +++ b/lib/ezsqlModelInterface.php @@ -2,71 +2,6 @@ namespace ezsql; -/** - * @method void setDebug_All($args); - * @method void setTrace($args); - * @method void setDebug_Called($args); - * @method void setVarDump_Called($args); - * @method void setShow_Errors($args); - * @method void setNum_Queries($args); - * @method void setConn_Queries($args); - * @method void setCaptured_Errors($args); - * @method void setCache_Dir($args); - * @method void setUse_Disk_Cache($args); - * @method void setCache_Timeout($args); - * @method void setCache_Queries($args); - * @method void setCache_Inserts($args); - * @method void setNum_Rows($args); - * @method void setDb_Connect_Time($args); - * @method void setSql_Log_File($args); - * @method void setProfile_Times($args); - * @method void setInsert_Id($args); - * @method void setLast_Query($args); - * @method void setLast_Error($args); - * @method void setCol_Info($args); - * @method void setTimers($args); - * @method void setTotal_Query_Time($args); - * @method void setTrace_Log($args); - * @method void setUse_Trace_Log($args); - * @method void setDo_Profile($args); - * @method void setLast_Result($args); - * @method void setFrom_Disk_Cache($args); - * @method void setDebug_Echo_Is_On($args); - * @method void setFunc_Call($args); - * @method void setAll_Func_Calls($args); - * - * @method string getDebug_All(); - * @method string getTrace(); - * @method string getDebug_Called(); - * @method string getVarDump_Called(); - * @method string getShow_Errors(); - * @method string getNum_Queries(); - * @method string getConn_Queries(); - * @method string getCaptured_Errors(); - * @method string getCache_Dir(); - * @method string getUse_Disk_Cache(); - * @method string getCache_Timeout(); - * @method string getCache_Queries(); - * @method string getCache_Inserts(); - * @method string getNum_Rows(); - * @method string getDb_Connect_Time(); - * @method string getSql_Log_File(); - * @method string getProfile_Times(); - * @method string getInsert_Id(); - * @method string getLast_Query(); - * @method string getLast_Error(); - * @method string getCol_Info(); - * @method string getTimers(); - * @method string getTotal_Query_Time(); - * @method string getTrace_Log(); - * @method string getUse_Trace_Log(); - * @method string getDo_Profile(); - * @method string getLast_Result(); - * @method string getFrom_Disk_Cache(); - * @method string getDebug_Echo_Is_On(); - * @method string getFunc_Call(); - * @method string getAll_Func_Calls(); - */ interface ezsqlModelInterface { /** diff --git a/tests/EZTestCase.php b/tests/EZTestCase.php index d0e81728..3600f46c 100644 --- a/tests/EZTestCase.php +++ b/tests/EZTestCase.php @@ -42,7 +42,7 @@ abstract class EZTestCase extends \PHPUnit\Framework\TestCase protected $errors; - public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext) + public function errorHandler($errno, $errstr, $errfile, $errline, $errcontext = null) { $this->errors[] = compact("errno", "errstr", "errfile", "errline", "errcontext"); } diff --git a/tests/ezFunctionsTest.php b/tests/ezFunctionsTest.php index e080bb21..197acba9 100644 --- a/tests/ezFunctionsTest.php +++ b/tests/ezFunctionsTest.php @@ -149,7 +149,6 @@ public function testNotBetween() public function testSetInstance() { $this->assertFalse(\setInstance()); - $this->assertFalse(\setInstance($this)); } public function testSelect() diff --git a/tests/mysqli/mysqliTest.php b/tests/mysqli/mysqliTest.php index 87618173..40d2f367 100644 --- a/tests/mysqli/mysqliTest.php +++ b/tests/mysqli/mysqliTest.php @@ -90,7 +90,7 @@ public function testSelect() $this->assertTrue($result); $this->errors = array(); - set_error_handler(array($this, 'errorHandler')); + //set_error_handler(array($this, 'errorHandler')); $this->assertTrue($this->object->select('')); $this->object->disconnect(); $this->assertFalse($this->object->select('notest')); diff --git a/tests/pdo/pdo_mysqlTest.php b/tests/pdo/pdo_mysqlTest.php index a46f2a2a..a6c1c7d5 100644 --- a/tests/pdo/pdo_mysqlTest.php +++ b/tests/pdo/pdo_mysqlTest.php @@ -16,7 +16,7 @@ class pdo_mysqlTest extends EZTestCase const TEST_DB_PORT = '3306'; /** - * @var resource + * @var \ezsql\Database\ez_pdo */ protected $object; @@ -288,23 +288,24 @@ public function testWhereGrouping() public function testJoins() { $this->assertTrue($this->object->connect('mysql:host=' . self::TEST_DB_HOST . ';dbname=' . self::TEST_DB_NAME . ';port=' . self::TEST_DB_PORT, self::TEST_DB_USER, self::TEST_DB_PASSWORD)); + $this->object->query('DROP TABLE unit_test'); $this->object->query('CREATE TABLE unit_test(id integer, test_key varchar(50), PRIMARY KEY (ID))'); $this->object->insert('unit_test', array('id' => '1', 'test_key' => 'testing 1')); $this->object->insert('unit_test', array('id' => '2', 'test_key' => 'testing 2')); $this->object->insert('unit_test', array('id' => '3', 'test_key' => 'testing 3')); $this->object->query('CREATE TABLE unit_test_child(child_id integer, child_test_key varchar(50), parent_id integer, PRIMARY KEY (child_id))'); - $this->object->insert('unit_test', array('child_id' => '1', 'child_test_key' => 'testing child 1', 'parent_id' => '3')); - $this->object->insert('unit_test', array('child_id' => '2', 'child_test_key' => 'testing child 2', 'parent_id' => '2')); - $this->object->insert('unit_test', array('child_id' => '3', 'child_test_key' => 'testing child 3', 'parent_id' => '1')); + $this->object->insert('unit_test_child', array('child_id' => '1', 'child_test_key' => 'testing child 1', 'parent_id' => '3')); + $this->object->insert('unit_test_child', array('child_id' => '2', 'child_test_key' => 'testing child 2', 'parent_id' => '2')); + $this->object->insert('unit_test_child', array('child_id' => '3', 'child_test_key' => 'testing child 3', 'parent_id' => '1')); $result = $this->object->selecting('unit_test_child', '*', leftJoin('unit_test_child', 'unit_test', 'parent_id', 'id')); $i = 1; $o = 3; foreach ($result as $row) { - $this->assertEquals($i, $row->child_id); - $this->assertEquals('testing child ' . $i, $row->child_test_key); - $this->assertEquals($o, $row->id); - $this->assertEquals('testing ' . $o, $row->test_key); + $this->assertEquals($o, $row->child_id); + $this->assertEquals('testing child ' . $o, $row->child_test_key); + $this->assertEquals($i, $row->id); + $this->assertEquals('testing ' . $i, $row->test_key); ++$i; --$o; } @@ -323,6 +324,7 @@ public function testJoins() public function testBeginTransactionCommit() { $this->object->connect(); + $this->object->query('DROP TABLE unit_test'); $this->object->query('CREATE TABLE unit_test(id integer, test_key varchar(50), PRIMARY KEY (ID))'); $commit = null; @@ -355,6 +357,7 @@ public function testBeginTransactionCommit() public function testBeginTransactionRollback() { $this->object->connect(); + $this->object->query('DROP TABLE unit_test'); $this->object->query('CREATE TABLE unit_test(id integer, test_key varchar(50), PRIMARY KEY (ID))'); $commit = null; diff --git a/tests/pdo/pdo_pgsqlTest.php b/tests/pdo/pdo_pgsqlTest.php index 58a91eb1..ea6f314c 100644 --- a/tests/pdo/pdo_pgsqlTest.php +++ b/tests/pdo/pdo_pgsqlTest.php @@ -18,7 +18,7 @@ class pdo_pgsqlTest extends EZTestCase const TEST_SQLITE_DB = 'ez_test.sqlite'; /** - * @var resource + * @var \ezsql\Database\ez_pdo */ protected $object; @@ -102,6 +102,7 @@ public function testInsert() public function testUpdate() { $this->assertTrue($this->object->connect('pgsql:host=' . self::TEST_DB_HOST . ';dbname=' . self::TEST_DB_NAME . ';port=' . self::TEST_DB_PORT, self::TEST_DB_USER, self::TEST_DB_PASSWORD)); + $this->object->drop('unit_test'); $this->object->query('CREATE TABLE unit_test(id serial, test_key varchar(50), test_value varchar(50), PRIMARY KEY (ID))'); $this->object->insert('unit_test', array('test_key' => 'test 1', 'test_value' => 'testing string 1')); @@ -134,6 +135,7 @@ public function testUpdate() public function testDelete() { $this->assertTrue($this->object->connect('pgsql:host=' . self::TEST_DB_HOST . ';dbname=' . self::TEST_DB_NAME . ';port=' . self::TEST_DB_PORT, self::TEST_DB_USER, self::TEST_DB_PASSWORD)); + $this->object->drop('unit_test'); $this->object->query('CREATE TABLE unit_test(id serial, test_key varchar(50), test_value varchar(50), PRIMARY KEY (ID))'); $this->object->insert('unit_test', array('test_key' => 'test 1', 'test_value' => 'testing string 1')); $this->object->insert('unit_test', array('test_key' => 'test 2', 'test_value' => 'testing string 2')); @@ -157,6 +159,7 @@ public function testDelete() public function testSelecting() { $this->assertTrue($this->object->connect('pgsql:host=' . self::TEST_DB_HOST . ';dbname=' . self::TEST_DB_NAME . ';port=' . self::TEST_DB_PORT, self::TEST_DB_USER, self::TEST_DB_PASSWORD)); + $this->object->drop('unit_test'); $this->object->query('CREATE TABLE unit_test(id serial, test_key varchar(50), test_value varchar(50), PRIMARY KEY (ID))'); $this->object->insert('unit_test', array('test_key' => 'test 1', 'test_value' => 'testing string 1')); $this->object->insert('unit_test', array('test_key' => 'test 2', 'test_value' => 'testing string 2')); @@ -187,37 +190,43 @@ public function testSelecting() foreach ($result as $row) { $this->assertEquals('testing string 1', $row->test_value); } + + $this->object->drop('unit_test'); } public function testWhereGrouping() { $this->assertTrue($this->object->connect('pgsql:host=' . self::TEST_DB_HOST . ';dbname=' . self::TEST_DB_NAME . ';port=' . self::TEST_DB_PORT, self::TEST_DB_USER, self::TEST_DB_PASSWORD)); - $this->object->query('CREATE TABLE unit_test(id integer, test_key varchar(50), active tinyint(1), PRIMARY KEY (ID))'); - $this->object->insert('unit_test', array('id' => '1', 'test_key' => 'testing 1', 'active' => 1)); - $this->object->insert('unit_test', array('id' => '2', 'test_key' => 'testing 2', 'active' => 0)); - $this->object->insert('unit_test', array('id' => '3', 'test_key' => 'testing 3', 'active' => 1)); - $this->object->insert('unit_test', array('id' => '4', 'test_key' => 'testing 4', 'active' => 1)); - - $result = $this->object->selecting('unit_test', '*', where(eq('active', '1'), grouping(like('test_key', '%1%', _OR), like('test_key', '%3%')))); + $this->object->drop('unit_test_more'); + $this->object->query('CREATE TABLE unit_test_more(id serial, test_key varchar(50), active_data integer, PRIMARY KEY (ID))'); + $this->object->insert('unit_test_more', array('test_key' => 'testing 1', 'active_data' => 1)); + $this->object->insert('unit_test_more', array('test_key' => 'testing 2', 'active_data' => 0)); + $this->object->insert('unit_test_more', array('test_key' => 'testing 3', 'active_data' => 1)); + $this->object->insert('unit_test_more', array('test_key' => 'testing 4', 'active_data' => 1)); + + $result = $this->object->selecting('unit_test_more', '*', where(eq('active_data', 1), grouping(like('test_key', '%1%', _OR), like('test_key', '%3%')))); $i = 1; foreach ($result as $row) { $this->assertEquals($i, $row->id); $this->assertEquals('testing ' . $i, $row->test_key); $i = $i + 2; } + + $this->object->drop('unit_test_more'); } public function testJoins() { $this->assertTrue($this->object->connect('pgsql:host=' . self::TEST_DB_HOST . ';dbname=' . self::TEST_DB_NAME . ';port=' . self::TEST_DB_PORT, self::TEST_DB_USER, self::TEST_DB_PASSWORD)); + $this->object->drop('unit_test'); $this->object->query('CREATE TABLE unit_test(id integer, test_key varchar(50), PRIMARY KEY (ID))'); $this->object->insert('unit_test', array('id' => '1', 'test_key' => 'testing 1')); $this->object->insert('unit_test', array('id' => '2', 'test_key' => 'testing 2')); $this->object->insert('unit_test', array('id' => '3', 'test_key' => 'testing 3')); $this->object->query('CREATE TABLE unit_test_child(child_id integer, child_test_key varchar(50), parent_id integer, PRIMARY KEY (child_id))'); - $this->object->insert('unit_test', array('child_id' => '1', 'child_test_key' => 'testing child 1', 'parent_id' => '3')); - $this->object->insert('unit_test', array('child_id' => '2', 'child_test_key' => 'testing child 2', 'parent_id' => '2')); - $this->object->insert('unit_test', array('child_id' => '3', 'child_test_key' => 'testing child 3', 'parent_id' => '1')); + $this->object->insert('unit_test_child', array('child_id' => '1', 'child_test_key' => 'testing child 1', 'parent_id' => '3')); + $this->object->insert('unit_test_child', array('child_id' => '2', 'child_test_key' => 'testing child 2', 'parent_id' => '2')); + $this->object->insert('unit_test_child', array('child_id' => '3', 'child_test_key' => 'testing child 3', 'parent_id' => '1')); $result = $this->object->selecting('unit_test_child', '*', leftJoin('unit_test_child', 'unit_test', 'parent_id', 'id')); $i = 1; @@ -237,6 +246,9 @@ public function testJoins() $this->assertEquals($o, $row->parent_id); --$o; } + + $this->object->drop('unit_test'); + $this->object->drop('unit_test_child'); } public function testPosgreSQLDisconnect() diff --git a/tests/pdo/pdo_sqliteTest.php b/tests/pdo/pdo_sqliteTest.php index 2cc13485..d9644c73 100644 --- a/tests/pdo/pdo_sqliteTest.php +++ b/tests/pdo/pdo_sqliteTest.php @@ -17,7 +17,7 @@ class pdo_sqliteTest extends EZTestCase const TEST_SQLITE_DB = './tests/pdo/ez_test.sqlite'; /** - * @var resource + * @var \ezsql\Database\ez_pdo */ protected $object; @@ -219,6 +219,7 @@ public function testSelecting() public function testWhereGrouping() { $this->assertTrue($this->object->connect('sqlite:' . self::TEST_SQLITE_DB, '', '', array(), true)); + $this->object->drop('unit_test'); $this->object->query('CREATE TABLE unit_test(id integer, test_key varchar(50), active tinyint(1), PRIMARY KEY (ID))'); $this->object->insert('unit_test', array('id' => '1', 'test_key' => 'testing 1', 'active' => 1)); $this->object->insert('unit_test', array('id' => '2', 'test_key' => 'testing 2', 'active' => 0)); @@ -239,14 +240,15 @@ public function testWhereGrouping() public function testJoins() { $this->assertTrue($this->object->connect('sqlite:' . self::TEST_SQLITE_DB, '', '', array(), true)); + $this->object->drop('unit_test'); $this->object->query('CREATE TABLE unit_test(id integer, test_key varchar(50), PRIMARY KEY (ID))'); $this->object->insert('unit_test', array('id' => '1', 'test_key' => 'testing 1')); $this->object->insert('unit_test', array('id' => '2', 'test_key' => 'testing 2')); $this->object->insert('unit_test', array('id' => '3', 'test_key' => 'testing 3')); $this->object->query('CREATE TABLE unit_test_child(child_id integer, child_test_key varchar(50), parent_id integer, PRIMARY KEY (child_id))'); - $this->object->insert('unit_test', array('child_id' => '1', 'child_test_key' => 'testing child 1', 'parent_id' => '3')); - $this->object->insert('unit_test', array('child_id' => '2', 'child_test_key' => 'testing child 2', 'parent_id' => '2')); - $this->object->insert('unit_test', array('child_id' => '3', 'child_test_key' => 'testing child 3', 'parent_id' => '1')); + $this->object->insert('unit_test_child', array('child_id' => '1', 'child_test_key' => 'testing child 1', 'parent_id' => '3')); + $this->object->insert('unit_test_child', array('child_id' => '2', 'child_test_key' => 'testing child 2', 'parent_id' => '2')); + $this->object->insert('unit_test_child', array('child_id' => '3', 'child_test_key' => 'testing child 3', 'parent_id' => '1')); $result = $this->object->selecting('unit_test_child', '*', leftJoin('unit_test_child', 'unit_test', 'parent_id', 'id')); $i = 1; diff --git a/tests/pdo/pdo_sqlsrvTest.php b/tests/pdo/pdo_sqlsrvTest.php index de8e82bd..58619195 100644 --- a/tests/pdo/pdo_sqlsrvTest.php +++ b/tests/pdo/pdo_sqlsrvTest.php @@ -8,7 +8,7 @@ class pdo_sqlsrvTest extends EZTestCase { /** - * @var resource + * @var \ezsql\Database\ez_pdo */ protected $object; @@ -89,8 +89,8 @@ public function testInsert() public function testUpdate() { $this->assertTrue($this->object->connect('sqlsrv:Server=' . self::TEST_DB_HOST . ';Database=' . self::TEST_DB_NAME, self::TEST_DB_USER, self::TEST_DB_PASSWORD)); + $this->object->drop('unit_test'); $this->object->query('CREATE TABLE unit_test(id integer, test_key varchar(50), PRIMARY KEY (ID))'); - $this->assertNotFalse($this->object->insert('unit_test', array('id' => 1, 'test_key' => 'testUpdate() 1'))); $this->object->insert('unit_test', array('id' => 2, 'test_key' => 'testUpdate() 2')); $this->object->insert('unit_test', array('id' => 3, 'test_key' => 'testUpdate() 3')); @@ -163,6 +163,7 @@ public function testDelete() public function testSelecting() { $this->assertTrue($this->object->connect('sqlsrv:Server=' . self::TEST_DB_HOST . ';Database=' . self::TEST_DB_NAME, self::TEST_DB_USER, self::TEST_DB_PASSWORD)); + $this->object->drop('unit_test'); $this->object->query('CREATE TABLE unit_test(id integer, test_key varchar(50), PRIMARY KEY (ID))'); $this->object->insert('unit_test', array('id' => 8, 'test_key' => 'testing 8')); $this->object->insert('unit_test', array('id' => 9, 'test_key' => 'testing 9')); @@ -191,37 +192,42 @@ public function testSelecting() foreach ($result as $row) { $this->assertEquals('testing 8', $row->test_key); } + + $this->object->drop('unit_test'); } public function testWhereGrouping() { $this->assertTrue($this->object->connect('sqlsrv:Server=' . self::TEST_DB_HOST . ';Database=' . self::TEST_DB_NAME, self::TEST_DB_USER, self::TEST_DB_PASSWORD)); - $this->object->query('CREATE TABLE unit_test(id integer, test_key varchar(50), active tinyint(1), PRIMARY KEY (ID))'); - $this->object->insert('unit_test', array('id' => '1', 'test_key' => 'testing 1', 'active' => 1)); - $this->object->insert('unit_test', array('id' => '2', 'test_key' => 'testing 2', 'active' => 0)); - $this->object->insert('unit_test', array('id' => '3', 'test_key' => 'testing 3', 'active' => 1)); - $this->object->insert('unit_test', array('id' => '4', 'test_key' => 'testing 4', 'active' => 1)); + $this->object->query('CREATE TABLE unit_test_other(id integer, test_key varchar(50), active_data integer, PRIMARY KEY (ID))'); + $this->object->insert('unit_test_other', array('id' => 1, 'test_key' => 'testing 1', 'active_data' => 1)); + $this->object->insert('unit_test_other', array('id' => 2, 'test_key' => 'testing 2', 'active_data' => 0)); + $this->object->insert('unit_test_other', array('id' => 3, 'test_key' => 'testing 3', 'active_data' => 1)); + $this->object->insert('unit_test_other', array('id' => 4, 'test_key' => 'testing 4', 'active_data' => 1)); - $result = $this->object->selecting('unit_test', '*', where(eq('active', '1'), grouping(like('test_key', '%1%', _OR), like('test_key', '%3%')))); + $result = $this->object->selecting('unit_test_other', '*', where(eq('active_data', '1'), grouping(like('test_key', '%1%', _OR), like('test_key', '%3%')))); $i = 1; foreach ($result as $row) { $this->assertEquals($i, $row->id); $this->assertEquals('testing ' . $i, $row->test_key); $i = $i + 2; } + + $this->object->drop('unit_test_other'); } public function testJoins() { $this->assertTrue($this->object->connect('sqlsrv:Server=' . self::TEST_DB_HOST . ';Database=' . self::TEST_DB_NAME, self::TEST_DB_USER, self::TEST_DB_PASSWORD)); + $this->object->drop('unit_test'); $this->object->query('CREATE TABLE unit_test(id integer, test_key varchar(50), PRIMARY KEY (ID))'); $this->object->insert('unit_test', array('id' => '1', 'test_key' => 'testing 1')); $this->object->insert('unit_test', array('id' => '2', 'test_key' => 'testing 2')); $this->object->insert('unit_test', array('id' => '3', 'test_key' => 'testing 3')); $this->object->query('CREATE TABLE unit_test_child(child_id integer, child_test_key varchar(50), parent_id integer, PRIMARY KEY (child_id))'); - $this->object->insert('unit_test', array('child_id' => '1', 'child_test_key' => 'testing child 1', 'parent_id' => '3')); - $this->object->insert('unit_test', array('child_id' => '2', 'child_test_key' => 'testing child 2', 'parent_id' => '2')); - $this->object->insert('unit_test', array('child_id' => '3', 'child_test_key' => 'testing child 3', 'parent_id' => '1')); + $this->object->insert('unit_test_child', array('child_id' => '1', 'child_test_key' => 'testing child 1', 'parent_id' => '3')); + $this->object->insert('unit_test_child', array('child_id' => '2', 'child_test_key' => 'testing child 2', 'parent_id' => '2')); + $this->object->insert('unit_test_child', array('child_id' => '3', 'child_test_key' => 'testing child 3', 'parent_id' => '1')); $result = $this->object->selecting('unit_test_child', '*', leftJoin('unit_test_child', 'unit_test', 'parent_id', 'id')); $i = 1; @@ -241,6 +247,9 @@ public function testJoins() $this->assertEquals($o, $row->parent_id); --$o; } + + $this->object->drop('unit_test'); + $this->object->drop('unit_test_child'); } public function testSQLsrvDisconnect() diff --git a/tests/sqlsrv/sqlsrvTest.php b/tests/sqlsrv/sqlsrvTest.php index 21d1f682..04df061f 100644 --- a/tests/sqlsrv/sqlsrvTest.php +++ b/tests/sqlsrv/sqlsrvTest.php @@ -37,7 +37,7 @@ protected function setUp(): void */ protected function tearDown(): void { - $this->object->query('DROP TABLE unit_test'); + $this->object->drop('unit_test'); $this->object = null; } @@ -363,9 +363,9 @@ public function testQuery_prepared() column('prepare_key', VARCHAR, 50) ); - $this->object->insert('prepare_test', ['id' => 1, 'prepare_key' => 'test 2']); - $this->object->query_prepared('INSERT INTO prepare_test( id, prepare_key ) VALUES( ?, ? )', [4, 'test 10']); - $this->object->query_prepared('INSERT INTO prepare_test( id, prepare_key ) VALUES( ?, ? )', [9, 'test 3']); + $this->object->query_prepared('INSERT INTO prepare_test(id, prepare_key ) VALUES( ?, ? )', [1, 'test 2']); + $this->object->query_prepared('INSERT INTO prepare_test(id, prepare_key ) VALUES( ?, ? )', [4, 'test 10']); + $this->object->query_prepared('INSERT INTO prepare_test(id, prepare_key ) VALUES( ?, ? )', [9, 'test 3']); $this->object->query_prepared('SELECT id, prepare_key FROM prepare_test WHERE id = ?', [9]); $query = $this->object->queryResult(); diff --git a/unsupported/install_sql.sh b/unsupported/install_sql.sh deleted file mode 100644 index e2ad2acb..00000000 --- a/unsupported/install_sql.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/bin/bash -e - -# Use the following variables to control your install: - -# Password for the SA user (required) -MSSQL_SA_PASSWORD='MasterTest' - -# Product ID of the version of SQL server you're installing -# Must be evaluation, developer, express, web, standard, enterprise, or your 25 digit product key -# Defaults to developer -MSSQL_PID='evaluation' - -# Install SQL Server Agent (recommended) -SQL_INSTALL_AGENT='y' - -# Install SQL Server Full Text Search (optional) -# SQL_INSTALL_FULLTEXT='y' - -# Create an additional user with sysadmin privileges (optional) -SQL_INSTALL_USER='ez_test' -SQL_INSTALL_USER_PASSWORD='ezTest' - -if [ -z $MSSQL_SA_PASSWORD ] -then - echo Environment variable MSSQL_SA_PASSWORD must be set for unattended install - exit 1 -fi - -echo Adding Microsoft repositories... -sudo curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add - -repoargs="$(curl https://packages.microsoft.com/config/ubuntu/16.04/mssql-server-2017.list)" -sudo add-apt-repository "${repoargs}" -repoargs="$(curl https://packages.microsoft.com/config/ubuntu/16.04/prod.list)" -sudo add-apt-repository "${repoargs}" - -echo Running apt-get update -y... -sudo apt-get update -y - -echo Installing SQL Server... -sudo apt-get install -y mssql-server - -echo Running mssql-conf setup... -sudo MSSQL_SA_PASSWORD=$MSSQL_SA_PASSWORD \ - MSSQL_PID=$MSSQL_PID \ - /opt/mssql/bin/mssql-conf -n setup accept-eula - -echo Installing mssql-tools and unixODBC developer... -sudo ACCEPT_EULA=Y apt-get install -y mssql-tools unixodbc-dev - -# Add SQL Server tools to the path by default: -echo Adding SQL Server tools to your path... -echo PATH="$PATH:/opt/mssql-tools/bin" >> ~/.bash_profile -echo 'export PATH="$PATH:/opt/mssql-tools/bin"' >> ~/.bashrc - -# Optional SQL Server Agent installation: -if [ ! -z $SQL_INSTALL_AGENT ] -then - echo Installing SQL Server Agent... - sudo apt-get install -y mssql-server-agent -fi - -# Optional SQL Server Full Text Search installation: -if [ ! -z $SQL_INSTALL_FULLTEXT ] -then - echo Installing SQL Server Full-Text Search... - sudo apt-get install -y mssql-server-fts -fi - -# Configure firewall to allow TCP port 1433: -echo Configuring UFW to allow traffic on port 1433... -sudo ufw allow 1433/tcp -sudo ufw reload - -# Optional example of post-installation configuration. -# Trace flags 1204 and 1222 are for deadlock tracing. -# echo Setting trace flags... -# sudo /opt/mssql/bin/mssql-conf traceflag 1204 1222 on - -# Restart SQL Server after installing: -echo Restarting SQL Server... -sudo systemctl restart mssql-server - -# Connect to server and get the version: -counter=1 -errstatus=1 -while [ $counter -le 5 ] && [ $errstatus = 1 ] -do - echo Waiting for SQL Server to start... - sleep 3s - /opt/mssql-tools/bin/sqlcmd \ - -S localhost \ - -U SA \ - -P $MSSQL_SA_PASSWORD \ - -Q "SELECT @@VERSION" 2>/dev/null - errstatus=$? - ((counter++)) -done - -# Display error if connection failed: -if [ $errstatus = 1 ] -then - echo Cannot connect to SQL Server, installation aborted - exit $errstatus -fi - -# Optional new user creation: -if [ ! -z $SQL_INSTALL_USER ] && [ ! -z $SQL_INSTALL_USER_PASSWORD ] -then - echo Creating user $SQL_INSTALL_USER - /opt/mssql-tools/bin/sqlcmd \ - -S localhost \ - -U SA \ - -P $MSSQL_SA_PASSWORD \ - -Q "CREATE LOGIN [$SQL_INSTALL_USER] WITH PASSWORD=N'$SQL_INSTALL_USER_PASSWORD', DEFAULT_DATABASE=[master], CHECK_EXPIRATION=ON, CHECK_POLICY=ON; ALTER SERVER ROLE [sysadmin] ADD MEMBER [$SQL_INSTALL_USER]" - /opt/mssql-tools/bin/sqlcmd \ - -S localhost \ - -U SA \ - -P $MSSQL_SA_PASSWORD \ - -Q "CREATE DATABASE ez_test" -fi - -echo Done!