How do I print all the queries in Magento? - php

Is it possible to display all the query strings in Magento? I really like to see what queries are executed.
Thanks

In Varien_Db_Adapter_Pdo_Mysql
Magento 1.4 : lib/varien/Db/Adapter/Pdo/Mysql.php
set
protected $_debug = true;
protected $_logAllQueries = true;
and (if nor already there) create the folder defined in
protected $_debugFile = 'var/debug/sql.txt';
Give read / write permission

I'm not 100% sure this will catch every query, but most run through the query method Zend_Db_Adapter_Abstract query method in
lib/Zend/Db/Adapter/Abstract.php
With that in mind, you could temporarily add some debugging statements (to a copy you make in app/code/local/Mage to be safe)
public function query($sql, $bind = array())
{
// connect to the database if needed
$this->_connect();
// is the $sql a Zend_Db_Select object?
if ($sql instanceof Zend_Db_Select) {
if (empty($bind)) {
$bind = $sql->getBind();
}
$sql = $sql->assemble();
}
echo "{$sql}\n<br />\n";
var_dump($bind);
If you need to catch them all, you'd be better off doing this at the MySQL level (which isn't always possible depending on your host/IT situation)

Activate the Zend SQL Profiler with the following node in your local.xml
<resources>
<default_setup>
<connection>
<profiler>1</profiler>
Then you can access the profiler somewhere in your code and retrieve a lot of informations about all executed queries:
$profiler = Mage::getSingleton('core/resource')->getConnection('core_write')->getProfiler();
To simply output all queries:
print_r($profiler->getQueryProfiles());
You can add these two lines at the end of index.php to see all queries at the bottom of each page. Be aware that this will break AJAX requests that return a JSON response, so you might consider logging the queries instead of printing them, with this code (again, add it at the end of index.php):
$profiler = Mage::getSingleton('core/resource')->getConnection('core_write')->getProfiler();
Mage::log(print_r($profiler->getQueryProfiles(), true), null, 'queries.log', true);
Then you will find all queries in var/log/queries.log
Don't forget to remove the lines again after you finished debugging!

The queries will vary significantly depending on your activities. If you have some control over your MySQL server, try turning on query logging:
set global general_log = on
Then you can get the SQL log to see queries. As a word or warning, Magento tends to execute dozens of queries on every page load, and hundreds to save an object.
Thanks,
Joe

$collection->printLogQuery(true);

Turn on the MySQL logging will sure log all queries transactions. Here is how you can turn on the logging on.To turn on the logging to log to a file. Place the following in the my.cnf file or my.ini file if on windows, and restart MySQL.
log = /path/to/your/logfile.log
Then if you want to log to the table mysql.general_log, run these queries:
SET GLOBAL log_output = 'TABLE';
SET GLOBAL general_log = 'ON';
Run these if you want to log to the file:
SET GLOBAL log_output = "FILE";
SET GLOBAL general_log = 'ON';

Related

Yii2/PHP: Check connection to MySQL and PostgreSQL

When starting my Yii2/PHP application, how can I check if / wait until the database is up?
Currently with MySQL I use:
$time = time();
$ok = false;
do {
try {
$pdo = new PDO($dsn,$username,$password);
if ($pdo->query("SELECT 1 FROM INFORMATION_SCHEMA.SCHEMATA"))
$ok=true;
} catch (\Exception $e) {
sleep(1);
}
} while (!$ok && time()<$time+30);
Now I want make my application running with MySQL and PostgreSQL.
But SELECT 1 FROM INFORMATION_SCHEMA.SCHEMATA does not work in PostgreSQL.
Is there a SQL-statement (using PDO database connectivity) that works on both database systems to check if the database is up and running?
Yii2 has a property to verify if a connection exists or not, it is really not necessary to create a script for this, since this framework has an abstraction implemented for the databases it supports ($isActive property).
$isActive public read-only property Whether the DB connection is
established
public boolean getIsActive ( )
You can do the check in your default controller in the following way:
<?php
class DefaultController extends Controller
{
public function init()
{
if (!Yii::$app->db->isActive) {
// The connection does not exist.
}
parent::init();
}
}
It is not good practice to force waiting for a connection to a database unless there are very specific requirements. The availability of a connection to the database must be a mandatory requirement for an application to start and the application should not "wait" for the database to be available.
There are ways to run containers in docker in an orderly manner or with a specific requirement, this link could give you a better option instead of delegating this to the application.
You could use SELECT 1 which is standard SQL.
You can use dbfiddle to test against various servers.
The server could go away an any time so checking the error response with every query is a much better approach.

Internal Server Error with linking database in PHP

I have a database that I want to use to make an array for an app I'm working on in Xcode. I'm following a tutorial I found on the internet here, and I followed the instructions, but my page is displaying an Internal Server Error. I am assuming that I didn't correctly change the info in the following code. Also, my web host uses MYSQL not MYSQLite, so I'm not sure what to change the "new mysqli" to in the code. For obvious reasons I omitted the database info. The database has one table named "descriptions" and the columns are labeled 1-50 with different values assigned.
<?php
class RedeemAPI {
private $db;
// Constructor - open DB connection
function __construct() {
$this->db = new mysqli('hostname', 'Username', 'Pass', 'Database Name');
$this->db->autocommit(FALSE);
}
// Destructor - close DB connection
function __destruct() {
$this->db->close();
}
// Main method to redeem a code
function redeem() {
// Print all codes in database
$stmt = $this->db->prepare('SELECT 1 FROM descriptions');
$stmt->execute();
$stmt->bind_result($1);
while ($stmt->fetch()) {
echo "$1";
}
$stmt->close();
}
}
// This is the first thing that gets called when this page is loaded
// Creates a new instance of the RedeemAPI class and calls the redeem method
$api = new RedeemAPI;
$api->redeem();
?>
PHP variables must start with a letter or _, so your error stems from this statement:
$stmt->bind_result($1);
Change the variable name to something like $col1, or whatever is meaningful.
Also, your select statement will return a single value: 1. You probably mean to do this:
SELECT * FROM descriptions
Two other points:
You shouldn't disable autocommit unless you intend to use transactions.
There's no need to prepare statements with simple queries that don't include untrusted input. You can just use $this->db->query("...")'. You'd need to tweak the other statements to match if you change this.
That internal server error 500 is probably masking some lovely error messages that may help. Switch your debugging on in your php.ini / php5.ini
Add this to your php.ini / php5.ini or just add one of these files to the root of your website should do the trick
display_errors = On
display_startup_errors = On
error_reporting = -1
Second, if your host is not running MYSQLi, then they are running REALLY old php as MYSQLi is standard in php4.1.3 and above
Third, that SQL statement.. its it just some kind of rough example or is that your actual statement? If you are trying to pull off one record it should be
SELECT * FROM tablename.description LIMIT 1
Always best to make your statements very thorough

How to route every mysql query through a function?

I have developed a project under which several sql query have been used. Now I want to monitor some query in order increase security. So I want every query to be passed through a function first. As there are too many queries so I can not go back and edit every file and query. Is there a way that I can trap into queries before they are sent to mysql server?
There are four ways to accomplish this depending on what you are using, the last being the much more reliable.
The General Query Log
MySQL provides a mechanism to log just about everything that the mysqld process is doing, via the general query log. As you described in your question you probably do not have persistent connections, so you will need to either:
Enable the MySQL general query log when the mysqld process is started, with the --log[=file_name]
Set a global/session variable with SET GLOBAL general_log = 'ON'.
Fore more information about the general query log, see the MySQL 5.1 reference manual.
Using sed (or manually!)
This technique involves creating a a new function, and renaming all of the mysqli_* function calls to call another function.
Presuming your newly created function is named proxy_query(), you can use sed to traverse through all files and change them automatically:
sed i '.bck' 's/mysqli_query/proxy_query/'
The -i paramater specifies that the file should be edited in place, and that a copy should be made of the original file and have a .bck extension appended.
The runkit extension
I must admit that I'm being naive here, and that I haven't used this particular extension before - but it is possible to rename functions with this PECL extension.
The requirements for this extension can be found here, and note that it is not bundled with PHP.
As with above, you can create a proxy function where all calls will go through. Let's assume it's also called proxy_query. Usage would go something like this:
// rename the function (a very bad idea, really!)
runkit_function_renam('mysqli_connect', 'proxy_super');
function mysqli_query($query, $resultmode = MYSQLI_STORE_RESULT)
{
// do something with the SQL in $query
// .. and call mysqli_query, now proxy_super
return proxy_super($query, $resultmode);
}
I have to note here that this method is highly discouraged. You shouldn't ever need to set default PHP functions.
Using Pdo/OO-mysqli
This is the simplest technique, and probably the most reliable as well. If you're using Pdo already, you can simply extend the \Pdo class. A similar approach could be used with MySQL Improved(mysqli):
class MyPdo extends \Pdo
{
public function query($query [, ... ])
{
// do something with $query
return parent::query($query [, ... ]);
}
}
Also note here, that this will only work if you are using Pdo, and if you are able to change the instantiation of the Pdo object, to overwrite it to your own class: MyPdo.
For more information about the \Pdo class, and it's children, see the manual.
If you want to monitor incoming queries using SQL profiler can be an excellent way to gather information on what's going on inside SQL without passing it all through a single function or procedure.

Result_array sqlsrv very slow in codeigniter [duplicate]

I have installed the latest version of CI 2.1.3
Now after running a query, I am getting a very slow response time for something very simple such as:
function Bash(){
$sql = “SELECT * FROM Contacts”;
$stmt = sqlsrv_query( $conn, $sql );
if( $stmt === false) {
die( print_r( sqlsrv_errors(), true) );
}
after querying a remote database. (Sql server 2008)
When I run this same query in a simple PHP script against the same remote database. I get results instantly.
a) Has anyone else experienced this problem with the sqlsrv drivers in codeigniter?
If so, how did you solve it?
Here is my connection string:
$db['default']['hostname'] = "xxxxx,1433";
$db['default']['username'] = "xx";
$db['default']['password'] = "xxxxxx-xx";
$db['default']['database'] = "xxxxxxxxx";
$db['default']['dbdriver'] = "sqlsrv";
$db['default']['dbprefix'] = '';
$db['default']['pconnect'] = TRUE;
$db['default']['db_debug'] = TRUE;
$db['default']['cache_on'] = TRUE;
$db['default']['cachedir'] = '';
$db['default']['char_set'] = 'utf8';
$db['default']['dbcollat'] = 'utf8_general_ci';
$db['default']['swap_pre'] = '';
$db['default']['autoinit'] = TRUE;
$db['default']['stricton'] = FALSE;
UPDATE:
I have found the following from running the profiler.
DATABASE: database QUERIES: 1 (Hide)
0.0659 select * from Contacts
Loading Time: Base Classes 0.0428
Controller Execution Time ( Welcome / AzureBash ) 58.2173
Total Execution Time 58.2602
It seems as though the query is executing in 0.06 secs but the controller is taking a minute to load.
No idea why this is happening.
Solution
The active records interface for the latest SQLSRV drivers are buggy.
So, download and overwrite the existing interface with these (overwrite your sqlsrv folder in the database folder in CI):
http://www.kaweb.co.uk/blog/mssql-server-2005-and-codeigniter/
Note: These have been tested with SQL Azure and works.
$query->num_rows(); does not work with these drivers, so I suggest you use count instead. Or create your own wrapper.
In addition date is now a date object type in your result set.
I hope this helps.
Solution 2
If for whatever reason you find a bug that makes this completely unusable. Revert back to the sqlsrv interface originally provided. You will find what is causing the problem is the way the original interface are executing the query, thus, create a database helper class; use $sql = $this->db->last_query(); to get the query you was about to execute and then within the database_helper class execute it yourself:
function MakeDbCall ($sql)
{
$serverName = "xxxxx-xxxx-xxx,1433"; //serverName\instanceName
$connectionInfo = array( "Database"=>"xxx", "UID"=>"xx", "PWD"=>"xxxxx","ConnectionPooling" => "1");
$conn = sqlsrv_connect($serverName,$connectionInfo);
$stmt = sqlsrv_query($conn, $sql);
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) ) {
$result_array[] = $row;
}
return $result_array;
}
Create one for row_array.
You should be able to call this function directly, from anywhere in your app. Whilst taking advantage of the way active_records constructs your query.
Not an ideal solution, but until codeigniter sort their SQLSRV class, there is not a lot we can do.
Adding an answer to this after the answer has already been accepted because I found a different solution. I was having the same problem ... looping through the result set was very very slow. i opened system/database/drivers/sqlsrv/sqlsrv_driver.php and found the connection function. i noticed that is was using the SQLSRV_CURSOR_STATIC option. i changed this to SQLSRV_CURSOR_CLIENT_BUFFERED and my slowness problems went away. See documentation for this here:
http://msdn.microsoft.com/en-us/library/hh487160(v=sql.105).aspx
I honestly have no idea what the sql server driver for php is doing, however, given the speed up, etc i can guess that the driver might be using a cursor by default. this seems like an awful idea. i also am assuming that by choosing client_buffered the data for the query would b e read without a cursor and accessed in memory on the client as if it were a cursor. If this is the case, bad things might happen if you try to execute a query that has many many rows to read. Perhaps another option (SQLSRV_CURSOR_FORWARD?) can be used to read data without a cursor - but i'm sure the methods used to access the query will be more limited (e.g. not using result_array())
-Don
Solution
The active records interface for the latest SQLSRV drivers are buggy.
So, download and overwrite the existing interface with these (overwrite your sqlsrv folder in the database folder in CI):
http://www.kaweb.co.uk/blog/mssql-server-2005-and-codeigniter/
Note: These have been tested with SQL Azure and works.
$query->num_rows(); does not work with these drivers, so I suggest you use count instead. Or create your own wrapper.
In addition date is now a date object type in your result set.
Solution 2
If for whatever reason you find a bug that makes this completely unusable. Revert back to the sqlsrv interface originally provided. You will find what is causing the problem is the way the original interface are executing the query, thus, create a database helper class; use $sql = $this->db->last_query(); to get the query you was about to execute and then within the database_helper class execute it yourself:
function MakeDbCall ($sql)
{
$serverName = "xxxxx-xxxx-xxx,1433"; //serverName\instanceName
$connectionInfo = array( "Database"=>"xxx", "UID"=>"xx", "PWD"=>"xxxxx","ConnectionPooling" => "1");
$conn = sqlsrv_connect($serverName,$connectionInfo);
$stmt = sqlsrv_query($conn, $sql);
while( $row = sqlsrv_fetch_array( $stmt, SQLSRV_FETCH_ASSOC) ) {
$result_array[] = $row;
}
return $result_array;
}
Create one for row_array.
You should be able to call this function directly, from anywhere in your app. Whilst taking advantage of the way active_records constructs your query.
Not an ideal solution, but until codeigniter sort their SQLSRV class, there is not a lot we can do.
What is your connection string? You can specify the "network protocol" explicitly, which somtimes can affect speed.
http://www.connectionstrings.com/articles/show/define-sql-server-network-protocol
"Provider=sqloledb;Data Source=190.190.200.100,1433;Network Library=DBMSSOCN;Initial Catalog=pubs;User ID=myUsername;Password=myPassword;"
By specifying the IP address, the port number (1433) and the Network Library, you are providing a very granular connection string.
Your details may vary of course.
Alot of times, you don't need this. But I've been on a few client trips where this was the magic dust.
You might want to turn db_debug to FALSE which should save time debugging the database.
Also, would suggest to turn cache_on to FALSE and specify cachedir and use $this->db->cache_on(); for queries that are less dynamic, i.e. does not change frequently.
For speed up fetch up to 3 times please use "MultipleActiveResultSets"=>'0' in your sqlsrv_connect connection options.
Ex:
$db = sqlsrv_connect('127.0.0.1', array('Database'=>'dbname','UID'=> 'sa','PWD'=> 'pass',"CharacterSet" =>"UTF-8","ConnectionPooling" => "1"
,"MultipleActiveResultSets"=>'0'
));

Get actual opened db connection

How can I check if a db-connection is open in PHP?
How can I get a reference to this connection?
How can I determine if it is MySQL, Postgres or something else?
Ideally you would know the variable the connection is saved into. Without this it becomes a hassle to find it. It means you would have to loop through every variable and test each one, but doing this for any reason can be a pain because it wont find variables outside of the current scope. You can loop the current variables using:
foreach(get_defined_vars() as $x){
// Code
}
To check if a variable is a valid connection you can use the below code, it should return an integer:
if(mysql_thread_id($connection){
// Connection exists
}
Once you know its a connection you can use the following to return the type of connection, eg, mysql.
echo get_resource_type($connection);
You'd have to iterate over every defined variable and figure out if it's a resource handle or not. Try get_defined_vars().
Probably the best solution to the problem is to not lose track of the DB connection in the first place.
Consider integrating an ORM into your project such as Doctrine or Propel, or if you want something a little more lightweight, consider a DBAL such as Zend_Db. All of these solutions encapsulate the database connections in class instances, ensuring that they are always available to your code if necessary.
In general terms, I don't think it's really possible, not at least with some sort of complicate workaround. You can, for instance, loop through all defined variables:
foreach(get_defined_vars() as $variable){
if( is_resource($variable) && get_resource_type($variable)=='mysql link' ){
// Found a connection!
var_dump($variable);
}
}
Though, in fact, a connection remains available even if assigned to a local variable out of current scope:
function foo(){
$conn = mysql_connect('localhost', 'test', 'test');
}
foo();
$res = mysql_query('SELECT NOW() AS what_is_the_time');
if( $row = mysql_fetch_assoc($res) ){
var_dump($row);
}
The problem is that PHP doesn't really care about variables when talking about connections:
// One connection and zero variables!
mysql_connect('localhost', 'test', 'test');
$res = mysql_query('SELECT NOW() AS what_is_the_time');
if( $row = mysql_fetch_assoc($res) ){
var_dump($row);
}
You can try and find information about current connection:
var_dump(mysql_thread_id());
// int(2696)
... though many of the functions will just attempt to stablish a new connection if there isn't one so must take care of warnings...:
Warning: mysql_thread_id(): Access denied for user ''#'localhost' (using password: NO)
bool(false)
... unless your configuration actually allows a succesful credential-less connnection attempt.
I'm pretty sure that, whatever you want to do, can be done in an entirely different way :)

Categories