PDOException Problem nach Umstellung auf php5

sid61

Mitglied
Hallo,
ich habe nach einigen Tests eines Scriptes auf dem Testserver mit aktueller XAMP Version nunmehr meinen Webserver auf die aktuelle Debian Etch Version umgestellt. Der Grund war, das ich PHP5 auf dem Server benötige, weil einige Scripte, mit denen ich arbeite nicht mehr unter php4 laufen (leider).

Soweit die Vorgeschichte...

Nun habe ich ein Script, welches eine Cluster Routine für Google Maps vorhält und wie geasgt nach einigen Tests auf meinem Testserver klasse lief. Das gleiche Script (ohne Änderung) läuft auf meinem Webserver nicht mehr und bricht mit folgendem Fehler ab :

Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[HY000]: General error: 2014 Cannot execute queries while other unbuffered queries are active. Consider using PDOStatement::fetchAll(). Alternatively, if your code is only ever going to run against mysql, you may enable query buffering by setting the PDO::MYSQL_ATTR_USE_BUFFERED_QUERY attribute.' in /var/www/vhosts/domain.eu/httpdocs/map_data.php:65 Stack trace: #0 /var/www/vhosts/domain.eu/httpdocs/map_data.php(65): PDO->prepare('SELECT * FROM d...') #1 {main} thrown in /var/www/vhosts/domain.eu/httpdocs/map_data.php on line 65

Bei meiner Suche auf Google fand ich einiges dazu, aber nichts, was wirklich weiter hilft.
Die Lösungen, die dort aufgezeigt werden scheinen auch nicht das gelbe vom Ei zu sein, denn wenn ich PDO::MYSQL_ATTR_USE_BUFFERED_QUERY wie vorgegeben nutze, dann ist die Cluster Routine eigentlich sinnlos, da man bei vielen Markern ja wieder warten muss. Ausserdem funktioniert diese Lösung leider auch nicht (wobei ich einräume, das ich von PHP5 auch erst ein paar Stunden etwas mehr gesehen habe).

Mit der Lösung PDOStatement::fetchAll() komme ich auch nicht weiter. Bei einigen Variationen sehe ich zwar mal einige Ziffern, aber irgendwie scheint es, als wenn dir ursprünglich angedachte Funktion auf der Strecke bleibt.
Generell weiß ich also nicht, ob es global an einer Einstellung am Server liegt (Ich meine da was von Unterstützung, Transaktionen und MySQL gelesen zu haben) - oder eben durch eine Änderung am Code gelöst werden kann (So behaupten es viele andere Beiträge). Leider ist das dumme daran, das man so irre viel Zeit damit verbringt, die "Ich weiß was, verrate aber nix" Beiträge zu lesen. Deshalb muss ich leider wieder mal nerven..

Lange Rede kurzer Sinn ;-)

Ich poste hier mal das Script, damit man es besser versteht und mit dem Hintergedanken, das mir jemand hilft, daraus schlau zu werden. Zumindest würde ich mich sehr über Hilfe freuen..

PHP:
<?php

// This script serves points from MySQL based on a viewport query. The viewport takes the form
// of two parameters: sw and ne, each a comma-separated latlng pair.

$fetch_generations = 5;
$viewport_points_upper_limit = 80;

switch($_GET['data']) {
  case 'us':
    $clusters_table = "dams_us_clusters";
    break;
  default:
    $clusters_table = "dams_au_clusters";
}

require('wp-config.php');

try {
  $dbh = new PDO('mysql:host=localhost;dbname=transflug', DB_USER, DB_PASSWORD);
  $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
  print "Error: " . $e->getMessage();
  die();
}

// Firstly, we need to find the smallest cluster that fully encloses the given viewport. This
// approach won't work across the dateline, which is why we need to first yank down the viewport
// to be on one side or the other of it. A more intelligent approach might be to run two separate
// queries, one for each side of the line. That approach still excludes the possibility of any
// clusters straddling the dateline, but that's a whole different issue, since we know already
// that the data doesn't contain anything like this.

list($latitude_min, $longitude_min) = explode(',', $_GET['sw']);
list($latitude_max, $longitude_max) = explode(',', $_GET['ne']);

if ($longitude_min > $longitude_max) {
  if (abs($longitude_min) > abs($longitude_max)) {
    $longitude_min = -179.99;
  } else {
    $longitude_max = 179.99;
  }
}

$viewport_query = $dbh->prepare(
  "SELECT * FROM $clusters_table WHERE
  latitude_min <= :latitude_min AND
  latitude_max >= :latitude_max AND
  longitude_min <= :longitude_min AND
  longitude_max >= :longitude_max
  ORDER BY level DESC LIMIT 1");
$viewport_query->bindParam(':latitude_min', $latitude_min);
$viewport_query->bindParam(':latitude_max', $latitude_max);
$viewport_query->bindParam(':longitude_min', $longitude_min);
$viewport_query->bindParam(':longitude_max', $longitude_max);

$viewport_query->execute();

// If we can't find a singular cluster that encloses the whole viewport, we instead
// grab the "max" cluster and work from there.
if ($viewport_query->rowCount() > 0) {
  $parent_cluster = $viewport_query->fetch(PDO::FETCH_ASSOC);
} else {
  $viewport_query_wide = $dbh->prepare(
    "SELECT * FROM $clusters_table WHERE LEVEL=0 LIMIT 1");
  $viewport_query_wide->execute();
  $parent_cluster = $viewport_query_wide->fetch(PDO::FETCH_ASSOC);
}

// Now that we know which cluster encloses the viewport, we can fetch all children
// of that view, up to a certain depth. The ordering is important here---we sort first
// by level, and secondarily by the number of children in each node. This is providing
// the order in which the clusters will be expanded: higher-level ones first, and
// within each level, ones that are larger first.
// The exlusion by lat/lng here is a little different than the other one. In this case,
// we only want to eliminate sub-clusters that are *entirely* outside the viewport.
$root_level = $parent_cluster['level'];
$min_level = $root_level + $fetch_generations;
$children_query = $dbh->prepare(
  "SELECT * FROM $clusters_table WHERE
  left_side >= :left AND
  right_side <= :right AND
  level <= :level_min AND NOT (
    latitude_min > :latitude_max OR
    latitude_max < :latitude_min OR
    longitude_min > :longitude_max OR 
    longitude_max < :longitude_min
  )
  ORDER BY level ASC, child_count DESC");
$children_query->bindParam(':level_min', $min_level);
$children_query->bindParam(':left', $parent_cluster['left_side']);
$children_query->bindParam(':right', $parent_cluster['right_side']);
$children_query->bindParam(':latitude_min', $latitude_min);
$children_query->bindParam(':latitude_max', $latitude_max);
$children_query->bindParam(':longitude_min', $longitude_min);
$children_query->bindParam(':longitude_max', $longitude_max);

$children_query->execute();

// Now we break up the flat list of fetched ids into an array structure keyed to 
// the id, with each cluster containing an array of the ids of its children.
$clusters_by_id = array();
$root_cluster_id = 0;
while($this_cluster = $children_query->fetch(PDO::FETCH_ASSOC)) {
  $this_cluster_id = $this_cluster['id'];
  $this_cluster['children'] = array();
  $this_cluster['included'] = false;
  $clusters_by_id[$this_cluster_id] = $this_cluster;
  if ($this_cluster['level'] == $root_level) {
    $root_cluster_id = $this_cluster_id;
  } else {
    $clusters_by_id[$this_cluster['parent_id']]['children'][] = $this_cluster_id;
  }
}

//var_dump($clusters_by_id);

// Finally, we have to pick out the ones we want to actually show. The basic process here
// that we start with the base node and then iterate, each time checking if we can expand the 
// next cluster while still staying under the ceiling imposed by $viewport_points_upper_limit.

$total = 1;
$clusters_by_id[$root_cluster_id]['included'] = true;

foreach($clusters_by_id as &$this_cluster) {
  if ($this_cluster['included']) {
    if ($total + count($this_cluster['children']) - 1 <= $viewport_points_upper_limit) {
      if (count($this_cluster['children']) > 0) {
        $total += count($this_cluster['children']) - 1;
        foreach($this_cluster['children'] as $included_id) {
          $clusters_by_id[$included_id]['included'] = true;
        }
        $this_cluster['included'] = false;
      }
    } else {
      break;  // If it doesn't fit, then we're done.
    }
  }
}
unset($this_cluster);  // Required for foreach with reference.

echo "/* ".count($clusters_by_id)." clusters from SQL, chose ".$total." for display. */\n";


$items_text = array();

foreach($clusters_by_id as $this_cluster) {
  if ($this_cluster['included']) {
    $items_text[] = "[".$this_cluster['id'].",". $this_cluster['latitude'] .",". $this_cluster['longitude'] .",". $this_cluster['child_count'] ."]";  
  }
}

echo '[' . implode(", ", $items_text) . ']';

?>

Und genau diese Variante läuft auf meinem Testserver zu Hause einwanfrei.

Liebe Grüße
Sid61
 
Zuletzt bearbeitet:
Einen Schritt weiter

Hallo,

ich habe jetzt nochmals einiges probiert und bin einen kleinen Schritt weiter gekommen (glaube ich jedenfalls)..

PHP:
try {
  $dbh = new PDO('mysql:host=mysql.transflug.eu;dbname=transflug', DB_USER, DB_PASSWORD);
  $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
  $dbh->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY , true);
} catch (PDOException $e) {
  print "Error: " . $e->getMessage();
  die();
}

Ich habe nun, wie in der Fehlermeldung empfohlen :

$dbh->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY , true);

eingebaut und es werden auch Cluster angezeigt. Nun ist aber das folgende Problem, das beim rein oder rauszoomen die Cluster immer gleich bleiben.

Es ist - das gleiche Script, das ich auch mit meinem Xamp Server benutze (zuHause) - und da funktioniert es auch ohne $dbh->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY , true);

Nun scheint es, das zwas die Abfragen gepuffert werden, aber irgendwie steht sich das ganze weiterhin im Weg und reagiert nicht mit einer Aktualisierung der Zoomstufe.

Das Problem kann man hier sehen.
 
Zurück