tags:

views:

81

answers:

1

I have a function that takes 2 variables, one for the database connection and the other for a query. For some reason, the mysqli link isn't happy unless it is inside the function; It isn't enough to just pass the link.

Has anyone else had this happen and what can I do to avoid instantiating the db object inside the function.

This does not work but if I put the object inside the function, it does.


function test($db, $query)
{
  if($db->multi_query($query)){
    do{
      if($result = $db->store_result()){
        while($row = $result->fetch_row()){
          print_r($row);
        }
        $result->free_result();
        $result->close();
      }
      if($db->more_results()){
        // print something here.
      }
    }while($db->next_result());
  }
  $db->close();
}

Here is how I am calling them

$db = new mysqli('xxxx','xxxx','xxxx','xxxx');
$q1 = ("SELECT * FROM table1");
$q2 = ("SELECT * FROM table2");

test($db,$q1);
test($db,$q2);

Without using the mysqli link inside the function, I will never see query #2 come back. The only thing I get are errors on the second query. (multi_query(): Couldn't fetch mysqli)


I just ran your code and here is what I get from the error log 

[Fri Jan 08 08:12:43 2010] [error] [client 127.0.0.1] PHP Warning: mysqli::multi_query(): Couldn't fetch mysqli in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\1.php on line 24

[Fri Jan 08 08:12:43 2010] [error] [client 127.0.0.1] PHP Warning: mysqli::close(): Couldn't fetch mysqli in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\1.php on line 38 [Fri Jan 08 08:12:43 2010]

[error] [client 127.0.0.1] PHP Warning: mysqli::multi_query(): Couldn't fetch mysqli in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\1.php on line 24 [Fri Jan 08 08:12:43 2010]

[error] [client 127.0.0.1] PHP Warning: mysqli::close(): Couldn't fetch mysqli in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\1.php on line 38 [Fri Jan 08 08:12:43 2010]

[error] [client 127.0.0.1] PHP Warning: mysqli::multi_query(): Couldn't fetch mysqli in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\1.php on line 24 [Fri Jan 08 08:12:43 2010]

[error] [client 127.0.0.1] PHP Warning: mysqli::close(): Couldn't fetch mysqli in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\1.php on line 38 [Fri Jan 08 08:12:43 2010]

[error] [client 127.0.0.1] PHP Warning: mysqli::multi_query(): Couldn't fetch mysqli in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\1.php on line 24 [Fri Jan 08 08:12:43 2010]

[error] [client 127.0.0.1] PHP Warning: mysqli::close(): Couldn't fetch mysqli in C:\Program Files\Apache Software Foundation\Apache2.2\htdocs\test\1.php on line 38


Here is what I am running now but still only returns a single query which happens to be the first one listed 'Notes'

function query_db( $link, $query ) {

 /* execute multi query */
 if ( $link->multi_query( $query ) ) {
    do {
        /* store first result set */
        if ($result = $link->store_result() ) {
      while( $row =  $result->fetch_row() ) {
       print_r( $row );
      }
      echo '<br/>';
               $result->close();
        }
     if( $link->more_results() ) {
     // ...
     }
    } while ( $link->next_result() );
 }
}

$db = new mysqli( 'xxxx', 'xxxx', 'xxxx', 'xxxx' );
query_db( $db, 'CALL Notes();'
query_db( $db, 'CALL Users();'
query_db( $db, 'SELECT * FROM test';

$db = new mysqli('xxxx','xxxx','xxxx','xxxx');

$f1 = fa($db,"CALL phones();");
$f2 = fa($db,"CALL users();");

OK, very simply.. We query the database 2x. Once to get all phones then assign the return set to var $f1. We do the same thing for $f2. When I run this code, $f2 never has a result. it's always empty. However, when I do a print_r on each call independently, I get the right results. This is really weird! You should be able to replicate this very same behavior with the code we have posted below. Just try and assign the returned set to each variable, then try and echo the results.

+1  A: 

The connection is closed after the first call to this function, that's why you aren't getting the results from the second call.

Also, why are you using multi_query if you aren't passing in two or more queries in at a time? You have two options:

You can concatenate the two SQL strings and call the function ONCE with the queries concatenated together. That's why we're using multi_query here.

OR ( this is what I prefer to do ):

Get rid of the $link->close(); line and call the function as many times as you wish. ;)

This way, the function can act as a wrapper function for both query and multi_query in the sense that you can pass in as many queries as you want, but also as little as one query too.

When using stored procedures, the next_result() method returns the return value of the function, then if you call it again, it returns the actual resultset, that's why i have the optional parameter called $sp.

Here's the updated code:

$db = new mysqli( 'xxxx', 'xxxx', 'xxxx', 'xxxx' );

function query_db( $link, $query, $sp = false ) {
 $set_array = array();
 /* execute multi query */
 if ( $link->multi_query( $query ) ) {
    do {
        /* store result set */
        if ($result = $link->store_result() ) {
            $set_array[] = $result;
        }
        if( $link->more_results() ) {
            // ...
        }
    } while ( $link->next_result() && ( $sp ? $link->next_result() : true ) );
 }
 if( count( $set_array ) ) 
     return $set_array;
 return false;
}

$table_set = query_db( $db, 'show tables;');
$notes_set = query_db( $db, 'CALL Notes();', true ); // stored procedure.
$users_set = query_db( $db, 'CALL Users();', true ); // stored procedure.

Usage:

foreach( $users_set as $set ) {
    while( $row = $set->fetch_row() ) {
        print_r( $row );
        echo '<br/>';
    }
}
Jacob Relkin
jim
Yes, that's right.
Jacob Relkin
Thanks Jacob. I just tried that and it doesn't work. What happens is that I get the first query and then all the others stop and I get the following errors for every subsequent query that follows: multi_query(): Couldn't fetch mysqli
jim
If I instantiate the mysqli object inside the function, it works fine. :\
jim
Can you post some code please? And have you looked at the php docs for mysqli_multi_query?
Jacob Relkin
Thanks Jacob. I deleted it but I am still not getting all the rows back from the query. My Fatal error went away though after I removed that line. Thanks. :)
jim
Free result?? Where do I use it at?
jim
I'm trying this code out now, and it seems that calling `free`, `close` or `free_result` gives me the same results - the right ones.I'm using the same exact code as you have, and it works fine for me.
Jacob Relkin
Still the same thing.. I only get one query returned.
jim
Nah... Can't be.. Try using more than one query. You'll never get back the second one.
jim
I'll post my calls up top. Have a look at them.
jim
I ran your code, thank you by the way.. Unfortunately Jacob, I get a fatal error: PHP Fatal error: Call to undefined method mysqli::fetch_row()
jim
Updated my answer.Why are you using `multi_query` if you aren't passing two or more queries at a time?
Jacob Relkin
Also, the concat of the SQL statements would be fine but I am using these queries independent of one another. Each SQL statement will be for something else; they are not related to each other.
jim
I'm using multi_query because I have some procedures that will be running as well and multi is needed for that.
jim
Fixed it ;) I was calling `fetch_row` on the `mysqli` object, not the resultset! ;) Should work now.
Jacob Relkin
This also brings up another question that I have. If these queries are independent of one another, I don't see why I can't use query(). I tried using query and had gotten "commands out of sync". The manual says to use multi in this case.
jim
OK, I just ran your code and still the same, Jacob.. Only one result was returned along with errors that I posted up top for you to see.
jim
You got rid of the `$db->close()` line?
Jacob Relkin
Yes, I tried it with and then without. Either way proves to only return a single query out of 4 that I have.
jim
revised my code. i tried this on my local machine and it works.
Jacob Relkin
Boy Jacob, I really appreciate all your effort. :) It still isn't working though. Here is the error: [Fri Jan 08 08:33:44 2010] [error] [client 127.0.0.1] PHP Fatal error: Call to a member function multi_query() on a non-object in C:\\Program Files\\Apache Software Foundation\\Apache2.2\\htdocs\\test\\1.php on line 26
jim
Psst... I think it is looking for the link.. If I put the mysqli link inside the function it works great. If we could just find a way to pass a reference I think we would be great.
jim
You're welcome ;) Can you please post the entire bit of code that you just executed? I want to try the same exact thing on my machine, and see what happens.
Jacob Relkin
Sure. I'll post it up top.
jim
I already tried passing by reference and it won't work.. I have no idea what is happening here but if it's working on your machine then its possibly a bug. What version PHP and mysql are you runnng?
jim
php 5.2.11 mysql 5.1.37
Jacob Relkin
I'm on 5.3.0 and mysql 5.0.67.
jim
Copied this from php.net site:Ive just had exactly the same problem as below trying to execute multiple stored procedures. I thought i might as well add how to do it the object oriented way. Instead of putting the one statement: <?php $mysqli->next_result(); ?> Put two: <?php $mysqli->next_result(); $mysqli->next_result(); ?> The first statement points (possibly using the term incorrectly) you to the return value. The second one will point you to the result of the next query. I hope this makes sense.
Jacob Relkin
So you mean, stack 2 of them together? One on top of the other?
jim
updated my code again with an optional param for stored procedures.
Jacob Relkin
Thanks a heap Jacob!.. brb
jim
Broski.... :D You be da man... I think its working this time! Gimme a sec and let me try it with a few more procs.. K?
jim
I updated my code again. :)
Jacob Relkin
Dude, this is an epic win for you! Thanks!!!! I looked at the changes but I don't understand the logic. I understand the the ternary operator and that you set it to false but what switches it to true and when?
jim
The default value for `$sp` is false, so i evaluate it first, if it's true, then evaluate the execution of the `next_result()`, else just evaluate to true, which makes the whole expression evaluate to true and then continue the loop.I know, it's cool, eh?Thank you very much jim!
Jacob Relkin
lol... Yes sir, it is very cool. I cannot even tell you what a pain in the rear this has been for me. I come from the old mysql_query() world where it returns everything you throw at it. That is.. until you have to use a procedure. :( OK... so, I understand why you set $sp to false but **what** is the code looking for that will switch it from false to true? And.. when does this happen
jim
I gotta tell you Jacob, my mind kept telling me to focus on passing by reference. What was it that made you go in another direction?
jim
Jacob Relkin
Ah, ok, so $link->next_result() **knows** if there is another record and if there is, then it returns a true value?
jim
Well, going to php.net and checking the docs is something i can never do enough, when i saw in your updated code that you were using stored procedures, i went to the docs and i found that post telling me that the first result is the return value and the second is the resultset, i immediately modified the code to accomodate them.And plus, you never mentioned that you were using stored procedures in your queries, so that's why it executed on my machine.
Jacob Relkin
Exactly! -- you got it ;)
Jacob Relkin
Jacob, thanks buddy! I owe you one! Also bookmarked your site. Maybe we can stay in contact.
jim
You're very welcome, that's what StackOverflow is for!
Jacob Relkin
Great Jacob, I'm sure I'll see you around here again. Thanks again!
jim
Jacob, If you're still around, I could use a hand. This code is in fact, returning the results (echoing only) but what I want to do is assign the returned rows of each query into their respective variables. Say I have 2 variables with two different queries... The code, the way it sits now will not return the data into the second variable; it's always empty. This is making me nuts! Can you shed some light on this maybe?
jim
Sure thing, can you post the code? I need to see the code before i can really understand what you mean.
Jacob Relkin
Sure thing.. Thanks. I'm looking into PDO in case this doesn't pan out. I have to say.. I'm losing confidence in mysqli. Thanks again for the hand, Jacob.
jim
Oh i get it. You want to return the resultsets from `multi_query`!I'm gonna revise my code yet again.
Jacob Relkin
Ah... What were we missing?? Better said, What am I missing? :) You seem confident on this one..
jim
Updated the code again.
Jacob Relkin
Wow, I'm looking at the revision and I'm amazed at what needs to be done to simply get this to work. I've never seen anything like it before. Why is all this necessary in order to assign a result set to a variable?
jim
Because we're using `multi_query`, remember? we need to be dynamic. `multi_query` may return one resultset, or many. therefore we need to use a dynamic structure such as an array to return the data in.
Jacob Relkin
We couldn't just return the resultset because there may be more that weren't fetched yet.
Jacob Relkin
Ok, that makes sense. Well, it works. I've got to be honest Jacob... I'm humbled because I could not have done this without you. I'm still trying to understand how multi_query works. You certainly have it down pat.
jim
Thank you! Not a problem at all!I'll also post the usage of the returned array, just for completion.
Jacob Relkin
Your welcome. :) Now that I think about it. I'm starting to understand a little better. When I did a print_r before your revised it this last time, I noticed that everything was basically in the same array. Question.. You have: if(count($set_array)). I don't get this.. This will always evaluate to a number so what is it doing? If you would have done: if(count($set_array) == 1)... That I get.. Can you please explain this?
jim
I've noticed that you don't quite have boolean expressions in your 'i scored 100 on the test' category :< You should take a look at the PHP Boolean Cheat Sheet at http://www.blueshoes.org/en/developer/php_cheat_sheet/
Jacob Relkin
http://www.php.net/manual/en/language.types.boolean.php#language.types.boolean.casting
Jacob Relkin
Thanks Jacob... See?? There's always something new to learn. lol.. I was also going to ask you about the -1.. Now that I'm looking at the link, I just answered my own question. :)
jim
So.. (sorry to pepper you with questions) when you increment set_index, what does that evaluate to? If -1, according to the cheat sheet, is false then ++ is true?
jim
LOL :) you're right! there is infinite knowledge out there! and a place like SO harness the power of that knowledge so well.
Jacob Relkin
It looks like I have to put down my hammer, stop forcing a square peg in a round hole and start reading a little more. :) Hey Jacob, thanks again! You saved the day!
jim
No, -1++ is 0, which is false. My mistake, i revised the code yet again just to return false. I'm so used to writing functions that return -1 instead of false, for example, a classic findIndexForElement() function, which would return the index in the array if found, if not found, would return -1.
Jacob Relkin
The only reason why you were doing that was because you thought it was a square hole. :) don't worry about it, i've been there too. everyone has for that matter.
Jacob Relkin
lol.. You're right. I've only been doing this for a couple of years and have no other programming experience but I love it. I rarely shower and I've become a hermit. :) I can't wait to get really good at this, seriously. I really do enjoy this and taking a piece of code like the one you wrote today and reading it until I understand it is really how I learn more. Jacob, you really are good at this. Hats off to you man.
jim
thanks :) i appreciate it!
Jacob Relkin