upgrade script bug fix
[openemr.git] / library / sql.inc
blobf2dd581c891329897ca18816d7c713a4c0c19f2c
1 <?php
3 include_once(dirname(__FILE__) . "/sqlconf.php");
4 require_once(dirname(__FILE__) . "/adodb/adodb.inc.php");
5 include_once(dirname(__FILE__) . "/log.inc");
7 if (!defined('ADODB_FETCH_ASSOC')) define('ADODB_FETCH_ASSOC', 2);
8 $database = NewADOConnection("mysql");
9 $database->PConnect($host, $login, $pass, $dbase);
10 $GLOBALS['adodb']['db'] = $database;
11 $GLOBALS['dbh'] = $database->_connectionID;
13 // Modified 5/2009 by BM for UTF-8 project ---------
14 if (!$disable_utf8_flag) {
15  $success_flag = $database->Execute("SET NAMES 'utf8'");
16   if (!$success_flag) {
17    error_log("PHP custom error: from openemr library/sql.inc  - Unable to set up UTF8 encoding with mysql database: ".$database->ErrorMsg(), 0);
18   }
21 // set up associations in adodb calls (not sure why above define
22 //  command does not work)
23 $GLOBALS['adodb']['db']->SetFetchMode(ADODB_FETCH_ASSOC);
25 //fmg: This makes the login screen informative when no connection can be made
26 if (!$GLOBALS['dbh']) {
27   //try to be more helpful
28   if ($host == "localhost") {
29     echo "Check that mysqld is running.<p>";
30   } else {
31     echo "Check that you can ping the server '$host'.<p>";
32   }//if local
33   HelpfulDie("Could not connect to server!", mysql_error($GLOBALS['dbh']));
34   exit;
35 }//if no connection
37 // Function that will allow use of the adodb binding
38 //   feature to prevent sql-injection. Will continue to
39 //   be compatible with previous function calls that do
40 //   not use binding.
41 // If use adodb binding, then will return a recordset object.
42 // If do not use binding, then will return a resource object.
43 // The sqlFetchArray() function should be used to
44 //   utilize the return object (it will accept both recordset
45 //   and resource objects).
46 function sqlStatement($statement, $binds=NULL )
48   if (is_array($binds)) {
49     // Use adodb Execute with binding and return a recordset.
50     //   Note that the auditSQLEvent function is embedded
51     //    in the adodb Execute command.
52     $recordset = $GLOBALS['adodb']['db']->Execute( $statement, $binds );
53     if ($recordset === FALSE) {
54       HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
55     }
56     return $recordset;
57   }
58   else {
59     // Use mysql_query and return a resource.
60     $resource = mysql_query($statement, $GLOBALS['dbh']);
61     if ($resource === FALSE) {
62       auditSQLEvent($statement, FALSE);
63       HelpfulDie("query failed: $statement", mysql_error($GLOBALS['dbh']));
64     }
65     auditSQLEvent($statement, TRUE);
66     return $resource;
67   }
70 // Function that will allow use of the adodb binding
71 //   feature to prevent sql-injection.
72 // It will act upon the object returned from the 
73 //   sqlStatement() function (and sqlQ() function).
74 // It will automatically figure out if the input
75 //   object is a recordset or a resource.
76 function sqlFetchArray($r)
78   if (!is_resource($r)) {
79     //treat as an adodb recordset
80     if ($r === FALSE)
81       return false;
82     if ($r->EOF)
83       return false;
84     //ensure it's an object (ie. is set)
85     if (!is_object($r))
86       return false;
87     return $r->FetchRow();
88   }
89   else {
90     //treat as a mysql_query resource
91     if ($r == FALSE)
92       return false;
93     return mysql_fetch_array($r, MYSQL_ASSOC);
94   }
97 // Function that will allow use of the adodb binding
98 //   feature to prevent sql-injection.
99 // This function is specialized for insert functions
100 //   and will return the last id generated from the
101 //   insert.
102 function sqlInsert($statement, $binds=array())
104   //Run a adodb execute
105   // Note the auditSQLEvent function is embedded in the
106   //   adodb Execute function.
107   $recordset = $GLOBALS['adodb']['db']->Execute($statement, $binds);
108   if ($recordset === FALSE) {
109     HelpfulDie("insert failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
110   }
111   // Return the correct last id generated using function
112   //   that is safe with the audit engine.
113   return getSqlLastID();
116 // Function that will allow use of the adodb binding
117 //   feature to prevent sql-injection.
118 // This function is specialized for simply returning
119 //   the first row of a query as an associative array.
120 // The $status_or_binds parameter can do following:
121 //   FALSE or an array() - Run adodb Execute with binding,
122 //     if applicable.
123 //   TRUE - run mysql_query for a specific case in the audit engine
124 //     (library/log.inc) to skip auditing and reporting if the query
125 //     does not work.
126 function sqlQuery($statement, $status_or_binds=FALSE)
128   if ((is_array($status_or_binds)) || ($status_or_binds === FALSE)) {
129     // run the adodb Execute function
130     //   Note the auditSQLEvent function is embedded in the
131     //     adodb Execute function.
132     if (is_array($status_or_binds)) {
133       $recordset = $GLOBALS['adodb']['db']->Execute( $statement, $status_or_binds );
134     }
135     else {
136       $recordset = $GLOBALS['adodb']['db']->Execute( $statement );
137     }
138     if ($recordset === FALSE) {
139       HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
140     }
141     if ($recordset->EOF)
142      return FALSE;
143     $rez = $recordset->FetchRow();
144     if ($rez == FALSE)
145       return FALSE;
146     return $rez;
147   }
148   else {
149     // run mysql_query to bypass the audit engine if error
150     //   in query.
151     $resource = mysql_query($statement, $GLOBALS['dbh']);
152     auditSQLEvent($statement, TRUE);
153    //$rez = @mysql_fetch_array($query, MYSQL_ASSOC);
154     $rez = @mysql_fetch_array($resource, MYSQL_ASSOC); //Replace $query with $resource to calculate correct checksum
155     if ($rez == FALSE)
156       return FALSE;
157     return $rez;
158   }
161 // ViSolve: Create a seperate function for audit log calls.
162 // The audit calls are handled through separate function.
163 // Before the audit calls are executed, the mysql_insert_id() is stored in GLOBALS['lastiddao']
164 //  and used in the relevant places, i.e in the mysql adodb driver files..
165 // Note:  This GLOBAL variable gets its value only when the audit is enabled.
166 function sqlInsertClean_audit($statement)
168   // Get the mysql_insert_id() before the execution of the log statement
169  //$lastid=mysql_insert_id($GLOBALS['dbh']);
170  //$GLOBALS['lastidado']=$lastid;
171 // when audit is enabled and $GLOBALS['lastidado'] is not set, then set the GLOBALS irrespective of dbh and adodb handlers.
173 // ViCarePlus :: Fix for Audit logging Issue :: Sep 24,2010 .
174 // Issue:: The LAST_INSERT_ID of the audit log table overrides the value in the $GLOBALS['lastidado'] variable. 
175 //         In a single transaction, when more than one query is being executed, this issue happens. 
176 // Fix: This code has been taken care by the function auditSQLEvent() in log.inc file
177 //  if ($GLOBALS['lastidado'] > 0)
178 //      { /* do nothing */ }
179 //        else {
180 //                 $lastid=mysql_insert_id($GLOBALS['dbh']);
181 //                 $GLOBALS['lastidado']=$lastid;
182 //        }
184   //----------run a mysql insert, return the last id generated
185   $ret = mysql_query($statement, $GLOBALS['dbh']);
186   if ($ret === FALSE) {
187     HelpfulDie("insert failed: $statement", mysql_error($GLOBALS['dbh']));
188   }
191 // Function that will safely return the last
192 //   ID inserted, and accounts for
193 //   the audit engine.
194 function getSqlLastID() {
195   if ($GLOBALS['lastidado'] >0) {
196     return $GLOBALS['lastidado'];
197   }
198   else {
199     return $GLOBALS['adodb']['db']->Insert_ID();
200   }
203 // Function that will return an array listing
204 //   of columns that exist in a table.
205 function sqlListFields($table) {
206   $sql = "SHOW COLUMNS FROM ". mysql_real_escape_string($table);
207   $resource = sqlQ($sql);
208   $field_list = array();
209   while($row = mysql_fetch_array($resource)) {
210     $field_list[] = $row['Field'];
211   }
212   return $field_list;
215 // Function that will allow use of the adodb binding
216 //   feature to prevent sql-injection.
217 // It will act upon the object returned from the
218 //   sqlStatement() function (and sqlQ() function).
219 // It will automatically figure out if the input
220 //   object is a recordset or a resource.
221 // It will return the number of rows.
222 function sqlNumRows($r)
224   if (!is_resource($r)) {
225     //treat as an adodb recordset
226     return $r->RecordCount();
227   }
228   else {
229     //treat as a mysql_query resource
230     return mysql_num_rows($r);
231   }
234 //fmg: Much more helpful that way...
235 function HelpfulDie ($statement, $sqlerr='')
237   echo "<p><p><font color='red'>ERROR:</font> $statement<p>";
238   if ($sqlerr) {
239     echo "Error: <font color='red'>$sqlerr</font><p>";
240   }//if error
241   exit;
244 function generate_id () {
245   $database = $GLOBALS['adodb']['db'];
246   return $database->GenID("sequences");
249 // Does not fully incorporate the audit engine, so
250 //   recommend not using this function (if bind is set,
251 //   then will get logged, however if bind is not set,
252 //   then will not get logged).  
253 // Function that will allow use of the adodb binding
254 //   feature to prevent sql-injection.
255 // Function that will allow use of the adodb binding
256 //   feature to prevent sql-injection. Will continue to
257 //   be compatible with previous function calls that do
258 //   not use binding.
259 // If use adodb binding, then will return a recordset object.
260 // If do not use binding, then will return a resource object.
261 // The sqlFetchArray() function should be used to
262 //   utilize the return object (it will accept both recordset
263 //   and resource objects).
264 function sqlQ($statement, $binds=NULL )
266   if (is_array($binds)) {
267     $recordset = $GLOBALS['adodb']['db']->Execute( $statement, $binds ) or
268       HelpfulDie("query failed: $statement", $GLOBALS['adodb']['db']->ErrorMsg());
269     return $recordset;
270   }
271   else {
272     $resource = mysql_query($statement, $GLOBALS['dbh']) or
273       HelpfulDie("query failed: $statement", mysql_error($GLOBALS['dbh']));
274     return $resource;
275   }
278 // DEPRECATED FUNCTION
280 // Function that will allow use of the adodb binding
281 //   feature to prevent sql-injection.
282 // A simple wrapper for the sqlInsert() function.
283 function idSqlStatement($statement , $binds=NULL )
285   return sqlInsert($statement, $binds);
288 // DEPRECATED FUNCTION
290 // Function that will allow use of the adodb binding
291 //   feature to prevent sql-injection.
292 // A simple wrapper for the sqlInsert() function.
293 function sqlInsertClean($statement, $binds=NULL )
295   return sqlInsert($statement, $binds);
298 // DEPRECATED FUNCTION
299 function sqlConnect($login,$pass,$dbase,$host,$port = '3306')
301   $GLOBALS['dbh'] = $database->_connectionID;
302   return $GLOBALS['dbh'];
305 // DEPRECATED FUNCTION
307 // Function to close the connection. PHP does
308 //   this automatically, so not needed.
309 function sqlClose()
311   //----------Close our mysql connection
312   $closed = $GLOBALS['adodb']['db']->close or
313     HelpfulDie("could not disconnect from mysql server link", $GLOBALS['adodb']['db']->ErrorMsg());
314   return $closed;
317 // DEPRECATED FUNCTION
318 function get_db() {
319   return $GLOBALS['adodb']['db'];
322 // DEPRECATED FUNCTION
323 function sqlLastID() {
324   return mysql_insert_id($GLOBALS['dbh']);