Prepared Statements - Wie verwenden?

Anmerkungen, Fragen und Hinweise zur Konfiguration dürfen in diesem Forum gepostet werden. // Notes, questions, and hints on the configuration can be posted here.
Benutzeravatar
ma2604121
Beiträge: 349
Registriert: 24.01.2011, 23:42:18

Re: Prepared Statements - Wie verwenden?

Beitrag von ma2604121 » 30.03.2011, 17:48:13

Kann es sein, dass wir alle etwas auf dem Holzweg sind, was die Verwendung von executeTextStatement bzw. executeTextBindStatement sind?

Folgendes funktioniert z.B. tadellos:

Code: Alles auswählen

// Verbindung zur DB herstellen
$cM = &$this->__getServiceObject('core::database', 'ConnectionManager');
$SQL = &$cM->getConnection('MySQLi');

// Eintragen der Daten
$result = $SQL->executeTextBindStatement('INSERT INTO user (nick, pwd) VALUES (?, ?)', array($nick, $password));

// Keine Daten eingefügt?
if ($data === 0){
}

// Daten abfragen
$result = $SQL->executeTextStatement('SELECT * FROM user');

// TEST *******************************************************************
echo "Anzahl der betroffenen Datensätze : " . $result->num_rows;

while ($data = $SQL->fetchData($result)){
echo "Benutzer : ".$data['nick']."<br/>";
} 
Wobei das hier immer noch nicht funktioniert (außer über die geänderte Fassung, in der ein Array erzeugt wird):

Code: Alles auswählen

$id = 2;
$result = $SQL->executeTextBindStatement('SELECT nick, regDate FROM user WHERE id=?', array($id));
echo $result->num_rows; 
Der Datensatz wird zwar ausgelesen und ist in $result verfügbar, die Anzahl der betroffenen Datensätze wird jedoch nicht ausgegeben.

Allerdings erhalte ich mittels

Code: Alles auswählen

echo "Datensätze : " . $result['numRows'] ."<br/>"; 
auch keine Anzahl...

Code: Alles auswählen

var_dump($result) 
liefert folgendes

Code: Alles auswählen

array(1) { [0]=>  array(2) { ["nick"]=>  string(11) "user2" ["regDate"]=>  string(10) "0000-00-00" } }  

Benutzeravatar
ma2604121
Beiträge: 349
Registriert: 24.01.2011, 23:42:18

Re: Prepared Statements - Wie verwenden?

Beitrag von ma2604121 » 30.03.2011, 17:55:17

Megger hat geschrieben:Aber $params ist innerhalb von executeTextBindStatement ein leeres Array wenn nichts übergeben wurde (da es ja eine Standardbelegung hat), deswegen kann es auch bei bindParams erforderlich sein und muss nicht optional sein.

Das Problem ist das call_user_func_array innerhalb des bindParams

Edit:
Ist es denn richtig, dass man bei MySQLi beim bindParam ein leeres Array übergibt, wenn man nichts zum binden hat? Habe bisher noch nicht mit PreparedStatements gearbeitet
Da könnte der Fehler sein.

Normalerweise habe ich das bislang wie folgt gehandhabt:

Code: Alles auswählen

$sql = "
    SELECT
        rank, userId, userNick
    FROM
        ranks
    ORDER BY rank
    ";
$result = $db->prepare($sql);
if(!$result){
    return $result->error;
}
if(!$result->execute()){
    return $result->error;
}
$result->store_result();
$result->bind_result($rank, $userId, $userNick) 
Da werden also keine Parameter (bindParam) übergeben, sondern direkt die Abfrage durchgeführt.

Benutzeravatar
dr.e.
Administrator
Beiträge: 4555
Registriert: 04.11.2007, 16:13:53

Re: Prepared Statements - Wie verwenden?

Beitrag von dr.e. » 30.03.2011, 18:13:36

Hallo zusammen,

ja, ich bin mit der API der mysqli-Erweiterung mehr als unglücklich, denn diese verhält sich nicht nur sehr seltsam, sondern ist auch vom Handling und der "Übersetzung" in die APF-API zickig. Das hat mich schon bei der Entwicklung massiv Nerven gekostet. :roll:

Was die letzte Insert-ID angeht, so ist dafür die Methode getLastID() gedacht. Will heißen: wenn du ein INSERT ausführst, dann rufst du danach die genannte Methode auf die Connection auf und holst dir die ID. Das sollte aber mit der aktuellen Implementierung schon funktionieren, es sei denn,

Code: Alles auswählen

$this->__dbConn->insert_id
funktioniert mit der MySQLi-Erweiterung aus welchen Gründen auch immer nicht.

Was die Bindings angeht, habe ich dort schon einie Sicherheits-Mechanismen eingebunden um die gröbsten Fehler zu verhindern, die Übergabe eines leeren Arrays sollte also valide sein.
Viele Grüße,
Christian

Megger
Beiträge: 1233
Registriert: 04.11.2008, 10:57:37

Re: Prepared Statements - Wie verwenden?

Beitrag von Megger » 30.03.2011, 18:27:04

Muss überhaupt ein bindParams ausgeführt werden wenn das Array eh leer ist? Ansonsten könnte man dort doch eine Überprüfung einbauen und das bindParams überspringen
Tutorial: Browsergame mit dem APF (Die ersten Parts handeln von Installation und Inbetriebnahme des APFs, deswegen sicherlich auch für alle Nicht-Browsergame-Programmierer interessant)

APF-Version
  • Entwicklung: 2.0
  • Produktiv: 1.15

Benutzeravatar
dr.e.
Administrator
Beiträge: 4555
Registriert: 04.11.2007, 16:13:53

Re: Prepared Statements - Wie verwenden?

Beitrag von dr.e. » 30.03.2011, 22:16:44

Das könnte man natürlich auch überspringen - klar. Nur sollte das IMHO abgefangen werden. Um auf "Nummer Sicher" zu gehen, habe ich noch einen Check eingebaut:

Code: Alles auswählen

   private function bindParams(&$query, array $params) {

      // don't bind params in case we have none!
      if (count($params) == 0) {
         return;
      }

      $binds = array();
      foreach ($params as $key => $DUMMY) {
         $binds[] = $params[$key];
      }
      call_user_func_array(
              array(&$query, 'bind_param'),
              array_merge(
                      array(str_repeat('s', count($params))),
                      $binds
              )
      );
   } 
Das sollte damit tatsächlich erledigt sein.

@ma2604121: kannst du das mal validieren?
Viele Grüße,
Christian

Benutzeravatar
ma2604121
Beiträge: 349
Registriert: 24.01.2011, 23:42:18

Re: Prepared Statements - Wie verwenden?

Beitrag von ma2604121 » 31.03.2011, 20:11:08

dr.e. hat geschrieben:Was die letzte Insert-ID angeht, so ist dafür die Methode getLastID() gedacht. Will heißen: wenn du ein INSERT ausführst, dann rufst du danach die genannte Methode auf die Connection auf und holst dir die ID. Das sollte aber mit der aktuellen Implementierung schon funktionieren, es sei denn,

Code: Alles auswählen

$this->__dbConn->insert_id
funktioniert mit der MySQLi-Erweiterung aus welchen Gründen auch immer nicht.
Das funktioniert problemlos:

Code: Alles auswählen

echo "Letzte ID : " . $SQL->getLastID() . "<br/>"; 
Damit erhalte ich die ID der zuletzt eingefügten Zeile.
dr.e. hat geschrieben:@ma2604121: kannst du das mal validieren?
Aber gerne. Folgende Zeile, die zuvor noch zu einer Fehlermeldung geführt hat, wird nun problemlos ausgeführt:

Code: Alles auswählen

$data = $SQL->executeTextBindStatement('SELECT * FROM user'); 

Benutzeravatar
dr.e.
Administrator
Beiträge: 4555
Registriert: 04.11.2007, 16:13:53

Re: Prepared Statements - Wie verwenden?

Beitrag von dr.e. » 01.04.2011, 08:48:28

Perfekt! Dann haben wir die dämliche mysqli-API wenigstens ein Stückchen durch das APF nach aussen verbessert! :) Die Sourcen habe ich so übrigens schon alle in 1.14 eingescheckt. Sobald der Branch halbwegs stable ist, kannst du darauf umsteigen.
Viele Grüße,
Christian

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast