30 protected $preparedStatements;
34 protected $cumulatedTime = array();
36 protected $queryCount = array();
38 private $transactionDepth = 0;
40 function __construct(Logger $logger)
42 $this->preparedStatements = array();
43 $this->logger = $logger;
49 $this->dbDriver = $dbDriver;
55 return $this->dbDriver;
58 public function begin()
60 if ($this->transactionDepth==0) {
61 $this->dbDriver->begin();
63 $this->transactionDepth++;
66 public function commit()
68 $this->transactionDepth--;
69 if ($this->transactionDepth==0) {
70 $this->dbDriver->commit();
71 }
else if ($this->transactionDepth < 0) {
72 throw new \Exception(
'too much transaction commits');
76 public function rollback()
78 if ($this->transactionDepth > 0) {
79 $this->transactionDepth--;
80 $this->dbDriver->rollback();
81 }
else if ($this->transactionDepth == 0) {
82 throw new \Exception(
'too much transaction rollbacks');
91 abstract public function prepare($statementName, $sqlStatement);
105 $sqlStatement .=
" RETURNING $returning";
106 $statementName .=
".returning:$returning";
107 $this->
prepare($statementName,$sqlStatement);
108 $res = $this->
execute($statementName,$params);
111 return $return[$returning];
120 abstract public function execute($statementName, $params = array());
129 if ($result !==
false) {
133 if ($this->dbDriver->isConnected()) {
134 $lastError = $this->dbDriver->getLastError();
135 $this->logger->addCritical($lastError);
136 if ($this->transactionDepth>0) {
137 $this->dbDriver->rollback();
140 $this->logger->addCritical(
"DB connection lost.");
143 $message =
"error executing: $sqlStatement\n\n$lastError";
153 public function getSingleRow($sqlStatement, $params = array(), $statementName =
"")
155 if (empty($statementName)) {
156 $backtrace = debug_backtrace();
157 $caller = $backtrace[1];
158 $statementName = (array_key_exists(
'class', $caller) ?
"$caller[class]::" :
'') .
"$caller[function]";
160 if (!array_key_exists($statementName, $this->preparedStatements)) {
161 $this->
prepare($statementName, $sqlStatement);
163 $res = $this->
execute($statementName, $params);
164 $row = $this->dbDriver->fetchArray($res);
165 $this->dbDriver->freeResult($res);
175 public function getRows($sqlStatement, $params = array(), $statementName =
"")
177 if (empty($statementName)) {
178 $backtrace = debug_backtrace();
179 $caller = $backtrace[1];
180 $statementName = (array_key_exists(
'class', $caller) ?
"$caller[class]::" :
'') .
"$caller[function]";
182 if (!array_key_exists($statementName, $this->preparedStatements)) {
183 $this->
prepare($statementName, $sqlStatement);
185 $res = $this->
execute($statementName, $params);
186 $rows = $this->dbDriver->fetchAll($res);
187 $this->dbDriver->freeResult($res);
198 if (empty($sqlLog)) {
199 $sqlLog = $sqlStatement;
201 $startTime = microtime($get_as_float =
true);
202 $res = $this->dbDriver->query($sqlStatement);
205 $execTime = microtime($get_as_float =
true) - $startTime;
206 $this->logger->addDebug(
"query '$sqlLog' took " . $this->
formatMilliseconds($execTime));
215 return $this->dbDriver->freeResult($res);
224 return $this->dbDriver->fetchArray($res);
233 return $this->dbDriver->fetchAll($res);
243 public function createMap($tableName,$keyColumn,$valueColumn,$sqlLog=
'')
245 if (empty($sqlLog)) {
246 $sqlLog = __METHOD__ .
".$tableName.$keyColumn,$valueColumn";
248 $this->
prepare($sqlLog,
"select $keyColumn,$valueColumn from $tableName");
249 $res = $this->
execute($sqlLog);
252 $map[$row[$keyColumn]] = $row[$valueColumn];
258 public function flushStats()
260 foreach ($this->cumulatedTime as $statementName => $seconds) {
261 $queryCount = $this->queryCount[$statementName];
262 $this->logger->addDebug(
"executing '$statementName' took " 264 .
" ($queryCount queries" . ($queryCount > 0 ?
", avg " . $this->
formatMilliseconds($seconds / $queryCount) :
"") .
")");
267 if ($this->transactionDepth != 0) {
268 throw new \Fossology\Lib\Exception(
"you have not committed enough");
278 return sprintf(
"%0.3fms", 1000 * $seconds);
287 $this->cumulatedTime[$statementName] += $execTime;
288 $this->queryCount[$statementName]++;
291 public function booleanFromDb($booleanValue)
293 return $this->dbDriver->booleanFromDb($booleanValue);
296 public function booleanToDb($booleanValue)
298 return $this->dbDriver->booleanToDb($booleanValue);
301 private function cleanupParamsArray($params)
303 $nParams =
sizeof($params);
304 for ($i = 0; $i<$nParams; $i++) {
305 if (is_bool($params[$i])) {
306 $params[$i] = $this->dbDriver->booleanToDb($params[$i]);
318 public function insertInto($tableName, $keys, $params, $sqlLog=
'', $returning=
'')
320 if (empty($sqlLog)) {
321 $sqlLog = __METHOD__ .
".$tableName.$keys" . (empty($returning) ?
"" : md5($returning));
323 $sql =
"INSERT INTO $tableName ($keys) VALUES (";
324 $nKeys = substr_count($keys,
',')+1;
325 for ($i = 1; $i < $nKeys; $i++) {
328 $sql .=
'$'.$nKeys.
')';
329 $params = $this->cleanupParamsArray($params);
330 if (!empty($returning)) {
334 $res = $this->
execute($sqlLog,$params);
346 $params = array_values($assocParams);
347 $keys = implode(
',',array_keys($assocParams));
348 if (empty($sqlLog)) {
349 $sqlLog = __METHOD__ .
".$tableName.$keys" . (empty($returning) ?
"" : md5($returning));
351 return $this->
insertInto($tableName, $keys, $params, $sqlLog, $returning);
354 public function updateTableRow($tableName, $assocParams, $idColName, $id, $sqlLog=
'')
356 $params = array_values($assocParams);
357 $keys = array_keys($assocParams);
358 $nKeys =
sizeof($keys);
360 if (empty($sqlLog)) {
361 $sqlLog = __METHOD__ .
".$tableName.$keys";
364 $sql =
"UPDATE $tableName SET";
365 for ($i = 1; $i < $nKeys; $i++) {
366 $sql .=
" ".$keys[$i - 1].
' = $'.$i.
",";
368 $sql .=
" ".$keys[$nKeys - 1].
' = $'.$nKeys;
369 $sql .=
" WHERE $idColName = \$".($nKeys + 1);
372 $params = $this->cleanupParamsArray($params);
375 $res = $this->
execute($sqlLog,$params);
386 if (! preg_match(
'/^[a-z0-9_]+$/i',$tableName)) {
387 throw new \Exception(
"invalid table name '$tableName'");
389 return $this->dbDriver->existsTable($tableName);
400 if (! preg_match(
'/^[a-z0-9_]+$/i',$columnName)) {
401 throw new \Exception(
"invalid column name '$columnName'");
403 return $this->
existsTable($tableName) && $this->dbDriver->existsColumn($tableName, $columnName);
insertPreparedAndReturn($statementName, $sqlStatement, $params, $returning)
formatMilliseconds($seconds)
createMap($tableName, $keyColumn, $valueColumn, $sqlLog='')
prepare($statementName, $sqlStatement)
setDriver(Driver &$dbDriver)
insertInto($tableName, $keys, $params, $sqlLog='', $returning='')
insertTableRow($tableName, $assocParams, $sqlLog='', $returning='')
getSingleRow($sqlStatement, $params=array(), $statementName="")
existsColumn($tableName, $columnName)
queryOnce($sqlStatement, $sqlLog= '')
execute($statementName, $params=array())
checkResult($result, $sqlStatement="")
Check the result for unexpected errors. If found, treat them as fatal.
getRows($sqlStatement, $params=array(), $statementName="")
collectStatistics($statementName, $execTime)