7

I have a very simple query, not sure what I am doing wrong here.

My DB call is not receiving an insert id as I would expect it to.

Table:

enter image description here

Stored Procedure:

CREATE DEFINER=`root`@`localhost` PROCEDURE `addCustomerProduct`(IN in_customerID INT, in_productID INT)
BEGIN
    INSERT INTO order_customer_product (customerID, productID, retailAmountAtPurchase, faceValue)
    SELECT
        in_customerID,
        in_productID,
        p.retail,
        p.faceValue
    FROM
        products as p
    WHERE 
        p.productID = in_productID;
END

PHP:

   public function addProduct($data, $userID)
    {
        // Do we already have a pending order for this user?
        $orderID = $this->doesOrderExist($userID);

        // We had no order, lets create one
        if (!$orderID) {
            $orderID = $this->createOrder($userID);
        }

        /**
         * Insert the customer product.
         * This relates a denomination to a customer.
         */
        $customerProductID = $this->addCustomerProduct($data);

        // Add this customer product to the order
        $this->addProductToOrder(array("customerProductID" => $customerProductID, "orderID" => $orderID));

        // Return
        return $customerProductID;
    }

    /**
     * Description: Add a customer product / reward
     * Page: client/add_reward
     */
    public function addCustomerProduct($data){
        $procedure = "CALL addCustomerProduct(?,?)";
        $result = $this->db->query($procedure, $data);
        return $this->db->insert_id();
    }

The line with the issue is: $customerProductID = $this->addCustomerProduct($data);.

A new record is being inserted into the table and the table has a PK/AI. Data goes in fine but 0 is returned as the $customerProductID.

Will an insert from select statement not return an insert ID perhaps?

Update For @Ravi-

enter image description here

Update 2:

I created a separate method and hard coded the query and data being sent.

It adds the records fine, AI goes up, 0 is returned as the last id.

public function test(){
    $procedure = "CALL addCustomerProduct(?,?)";
    $result = $this->db->query($procedure, array("customerID" => 1, "productID" => 20));
    echo $this->db->insert_id();
}

Also restarted the MySQL server to make sure there wasn't anything weird going on there.

Also, updated the SP to just insert random data into the table without using a select.

CREATE DEFINER=`root`@`localhost` PROCEDURE `addCustomerProduct`(IN in_customerID INT, in_productID INT)
BEGIN
    INSERT INTO order_customer_product (customerID, productID, retailAmountAtPurchase, faceValue)
    VALUES(8,2,'4.55',25);
END

Update 3:

Right after the insert, I am printing out the last query that was ran as well as the result. You will notice that there is 1 affected row (the insert is happening) but the insert_id is still 0.

CALL addCustomerProduct('8','33')

CI_DB_mysqli_result Object
(
    [conn_id] => mysqli Object
        (
            [affected_rows] => 1
            [client_info] => mysqlnd 5.0.12-dev - 20150407 - $Id: b396954eeb2d1d9ed7902b8bae237b287f21ad9e $
            [client_version] => 50012
            [connect_errno] => 0
            [connect_error] => 
            [errno] => 0
            [error] => 
            [error_list] => Array
                (
                )

            [field_count] => 0
            [host_info] => Localhost via UNIX socket
            [info] => 
            [insert_id] => 0
            [server_info] => 5.6.35
            [server_version] => 50635
            [stat] => Uptime: 1637  Threads: 3  Questions: 508  Slow queries: 0  Opens: 113  Flush tables: 1  Open tables: 106  Queries per second avg: 0.310
            [sqlstate] => 00000
            [protocol_version] => 10
            [thread_id] => 25
            [warning_count] => 0
        )

    [result_id] => 1
    [result_array] => Array
        (
        )

    [result_object] => Array
        (
        )

    [custom_result_object] => Array
        (
        )

    [current_row] => 0
    [num_rows] => 
    [row_data] => 
)

Update 4:

From some of the research I have done, unless you use the mysqli method such as $this->db->insert(), it won't provide a last insert id back to you.

I am going to try and figure out Ravi's suggestion but it seems that code igniter doesn't allow the example that was shown. At least I know now that I am not crazy and its just not normal behavior unless you use the ``insert` method vs a stored procedure.

SBB
  • 8,560
  • 30
  • 108
  • 223
  • what is insert id are you expecting ? – Ravi Jan 14 '18 at 07:10
  • @Ravi - The `AI` that is created from the `addCustomerProduct()` procedure, the one on top of the page. – SBB Jan 14 '18 at 07:11
  • should it not be `$this->db->insert_id;` rather than `$this->db->insert_id();` – Professor Abronsius Jan 14 '18 at 07:12
  • @RamRaider - Don't believe so, this is a framework (CodeIgniter) and that is a method thats built in. Works everywhere else in my code :. – SBB Jan 14 '18 at 07:15
  • ok - no idea about any framework I just know the standard `mysqli` method is as above. Was worth a shot! – Professor Abronsius Jan 14 '18 at 07:17
  • @SBB are you sure data is getting inserted ? and everything is expected ? can you post the screenshot of it ? – Ravi Jan 14 '18 at 07:18
  • @Ravi - Added a screenshot of the record in the table. – SBB Jan 14 '18 at 07:23
  • @SBB Looking at your rep, you should understand how people put their effort and time to answer any post. You should always try conclude the post by accepting the answer or clarify the actual question. So, that other should get benefited. – Ravi Jan 14 '18 at 16:51
  • @Ravi - i was dealing with this for 2 hours last night and before i use your answer which I’m sure will work fine, i want to understand WHAT the problem is. The same code works perfectly all over my application so I’m trying to figure out what’s causing the problem before i apply a bandaid. – SBB Jan 14 '18 at 16:52
  • @SBB sure, just make sure we get conclusion. Thanks. – Ravi Jan 14 '18 at 16:54
  • If your abstraction layer is too abstract to understand what's going on in your database, then either use a different one or convert your procedure into a function. – symcbean Jan 15 '18 at 00:14
  • @symcbean - I just wasn't aware of how mysqli only provided an insert id when used through `$this->db->insert`. I assumed, like in MSSQL, that anything you return in the stored procedure can be obtained from the originating function call. – SBB Jan 15 '18 at 00:16
  • You are confusing procedures and functions, and your method is not applicable to mssql. It is also quite possible to achieve your desired result using out parameters (a.lthough not .as efficiently) as Ravi suggests – symcbean Jan 15 '18 at 00:37
  • 1
    Turn on the "general log" to see exactly what commands are issued. It will not include `insert_id()`, but it might include some statements that Codeigniter is inserting that get in the way. – Rick James Feb 01 '18 at 23:14
  • Why don't you just execute the query from the SP in the `addCustomerProduct()` function? – Paul Spiegel Feb 04 '18 at 17:40
  • @PaulSpiegel - I need the SP's to be re-usable so I try and only have them do one thing. I didn't want to have it do additional inserts in this SP if I was going to call it elsewhere in the app where I didn't need to do such insert. I also like to return the PK/AI to my application so I can log any errors that happen later on in the code and reference the ID/record that was involved. – SBB Feb 05 '18 at 01:24
  • Try the following in your `test()` function: `$this->db->conn_id->query("CALL addCustomerProduct(1,20)"); echo $this->db->conn_id->insert_id;` Is it still `0`? – Paul Spiegel Feb 05 '18 at 02:19

3 Answers3

5

This answer may explain why your existing code doesn't work. To quote:

CodeIgniter's insert_id() will only return an ID of an insert(). Unless you are executing something like $this->db->insert('table', $data); before calling the function it will not be able to return an ID.

MySQL's LAST_INSERT_ID(); should help you here (assuming you have permission to alter the stored procedure definition). Change it to:

CREATE DEFINER=`root`@`localhost` PROCEDURE `addCustomerProduct`(
    IN in_customerID INT, in_productID INT, OUT out_customerProductID INT)
BEGIN
    INSERT INTO order_customer_product (
        customerID, productID, retailAmountAtPurchase, faceValue)
    VALUES(8,2,'4.55',25);

    SELECT LAST_INSERT_ID() INTO out_customerProductID;
END

Then use something like the following to get the output parameter value:

public function addCustomerProduct($data) {
    $procedure = "CALL addCustomerProduct("
                   . $this->db->escape($data["customerID"]).", "
                   . $this->db->escape($data["productID"]).", "
                   . "@customerProductID);"
    $this->db->query($procedure);
    $query = $this->db->query("SELECT @customerProductID AS customerProductID");
    if($query->num_rows() > 0)
      return $query->result()->customerProductID;
    else
      return NULL;
}

If the above doesn't work, try adding a $this->db->trans_start(); and $this->db->trans_complete(); before and after the stored procedure call to ensure the transaction is committed.

Steve Chambers
  • 37,270
  • 24
  • 156
  • 208
  • I have finally got around to trying this and when I set up my SP and code like above, I get one of two errors. First, if I only provide the 2 `?,?` when it expects 3 (one for `out`), it throws an error about their being an incorrect number of arguments. If I added the 3rd `?` to the call, I receive `You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '?,?,?)' at line 1`. Tried this both with and without the transaction. – SBB Feb 10 '18 at 20:51
  • OK, am not very familiar with Codeigniter (which is why I wrote "something like...") but have now modified the code above based on [this answer](https://stackoverflow.com/questions/14561894#20727496). – Steve Chambers Feb 11 '18 at 10:25
3

Ideally, following line should work

$this->db->insert_id;

But, I'm not sure why is not working, so I would suggest a workaround as following, recompile your procedure with additional parameter out_lastId, which will return last inserted id

CREATE DEFINER=`root`@`localhost` PROCEDURE `addCustomerProduct`(IN in_customerID INT, in_productID INT, OUT out_lastId INT)

And, after insert set the value with last inserted id.

 SET out_lastId = LAST_INSERT_ID();

==Updated==

$this->db->multi_query( "CALL addCustomerProduct($data, @id);SELECT @id as id" );
$db->next_result();            // flush the null RS from the call
$rs=$this->db->store_result();       // get the RS containing the id
echo $rs->fetch_object()->id, "\n";
$rs->free();
Ravi
  • 30,829
  • 42
  • 119
  • 173
  • `$data` is an array containing the two variables I am sending. – SBB Jan 14 '18 at 07:29
  • This throws an error regarding me telling the SP theres going to be 2 params coming in but there is 3 defined in the SP. – SBB Jan 14 '18 at 07:42
  • @SBB of course, you need to add 3 parameter, I thought, you will take care from there. Should I update the php code as well ? – Ravi Jan 14 '18 at 07:43
  • Well I added `$procedure = "CALL addCustomerProduct(?,?, ?)";` but I wasn't sure what to do from there regarding getting the value. – SBB Jan 14 '18 at 07:44
  • @SBB its been long time, I haven't coded php, but I will try. – Ravi Jan 14 '18 at 07:49
  • @SBB please check, you might need to correct code here and there – Ravi Jan 14 '18 at 07:52
  • I will check this out shortly - I'm just baffled that I can't get the AI to return when hardcoding the data. – SBB Jan 14 '18 at 08:38
  • Doesn't look like this framework supports `multi_query`. – SBB Jan 14 '18 at 20:02
1

Why

insert_id() will only workes with Query Builder and Queries only. SP's are used to call with $this->db->query() but it won't retuns data insert_id().


How

Before the End of SP add SELECT MAX(id) FROM order_customer_product;. So this will return the last ID to your code.


Suggestion

As I see there is an Insert query to DB. If I use similar case will use normal Query Builder or/and will warp it with Codeigniter Transactions(My answer on another question).

Abdulla Nilam
  • 36,589
  • 17
  • 64
  • 85