Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 7725455
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 1, 20262026-06-01T04:56:28+00:00 2026-06-01T04:56:28+00:00

Two tables (Teachers and Students) are created while the Id in Students is referenced

  • 0

Two tables (Teachers and Students) are created while the Id in Students is referenced to the TeacherId in Teachers using FOREIGN KEY. If we use two different methods to insert the values into Students:
1. sqlite3_exec();
2. sqlite3_bind();
The return message from sqlite3_errmsg() is not the same using these two methods:
1. sqlite3_exec(): return “foreign key constraints failed”;
2. sqlite3_bind(): return “SQL logic error or missing database”;

The message from sqlite3_errmsg() for sqlite3_exec() is more clearer than that for sqlite3_bind();
However, sqlite3_bind() is more convenient and efficient to insert values compared to sqlite3_exec();

My question: How to get a clearer returned error message for sqlite3_bind()?

The following is the full codes:

#include <string.h>
#include <stdio.h>
#include <iostream>
#include "sqlite3.h"

using namespace std;

sqlite3* db;

int first_row;

// callback function;
int select_callback(void *p_data, int num_fields, char **p_fields, char **p_col_names)
{
    int i;
    int* nof_records = (int*) p_data;
    (*nof_records)++;

    // first_row was defined in <select_stmt> function;
    // if first_row == 1, print the first row
    // and then set first_row = 0 to avoid the subsequent execution for the following rows.
    if (first_row == 1)
    {
        first_row = 0;
        for (i=0; i < num_fields; i++)
        {   printf("%20s", p_col_names[i]);
        }
        printf("\n");
        for (i=0; i< num_fields*20; i++)
        {   printf("=");
        }
        printf("\n");
    }

    for(i=0; i < num_fields; i++)
    {   if (p_fields[i])
        {   printf("%20s", p_fields[i]);
        }
        else
        {   printf("%20s", " ");
        }
    }

    printf("\n");
    return 0;
}

// With callback function;
void select_stmt(const char* stmt)
{   char *errmsg;
    int   ret;
    int   nrecs = 0;
    first_row = 1;
    ret = sqlite3_exec(db, stmt, select_callback, &nrecs, &errmsg);

    if(ret!=SQLITE_OK)
    {   printf("Error in select statement %s [%s].\n", stmt, errmsg);
    }
    else
    {   printf("\n   %d records returned.\n", nrecs);
    }
}

// Without callback function;
void sql_stmt(const char* stmt)
{   char *errmsg;
    int   ret;
    ret = sqlite3_exec(db, stmt, 0, 0, &errmsg);

    if(ret != SQLITE_OK)
    {   printf("Error in statement: %s [%s].\n", stmt, errmsg);
    }
}

//////////////////////////////////////// Main /////////////////////////////////
int main()
{   cout << "sqlite3_open("", &db): " << sqlite3_open("./shcool.db", &db) << endl;

    if(db == 0)
    {   printf("\nCould not open database.");
        return 1;
    }
    char *errmsg;

    int result;
    result = sqlite3_exec ( db,
                            "Drop TABLE IF EXISTS Teachers",  // stmt
                            0,
                            0,
                            &errmsg
                          );
    if ( result != SQLITE_OK )
    {   cout << "\nCould not prepare statement: Drop TABLE: " << result << endl;
        cout << "errmsg: " << errmsg << endl;
        return 1;
    }

    result = sqlite3_exec ( db,
                            "Drop TABLE IF EXISTS Students",  // stmt
                            0,
                            0,
                            &errmsg
                          );
    if ( result != SQLITE_OK )
    {   cout << "\nCould not prepare statement: Drop TABLE: " << result << endl;
        cout << "errmsg: " << errmsg << endl;
        return 1;
    }


    // CREATE TABLE Teachers;
    sql_stmt("CREATE TABLE Teachers(Id integer PRIMARY KEY,Name text,Age integer NOT NULL)");



    //////////////////////////// insert values into Teachers; /////////////////////////////////
    sqlite3_stmt *stmt;
    sqlite3_prepare(db, "PRAGMA foreign_keys = ON;", -1, &stmt, 0);

    if ( sqlite3_prepare
            ( db,
              "insert into Teachers values (:Id,:Name,:Age)",  // stmt
              -1, // If than zero, then stmt is read up to the first nul terminator
              &stmt,
              0  // Pointer to unused portion of stmt
            )
            != SQLITE_OK )
    {   printf("\nCould not prepare statement.");
        return 1;
    }

    int index1, index2, index3;
    index1 =  sqlite3_bind_parameter_index(stmt, ":Id");
    index2 =  sqlite3_bind_parameter_index(stmt, ":Name");
    index3 =  sqlite3_bind_parameter_index(stmt, ":Age");

    cout << index1 << endl;
    cout << index2 << endl;
    cout << index3 << endl;

    printf("\nThe statement has %d wildcards\n", sqlite3_bind_parameter_count(stmt));

    int id[] = {1, 2, 3};
    string name[] = {"Zhang", "Hou", "Liu"};
    int age[] = {28, 29, 31};

    for ( int i = 0; i != 3; i++ )
    {   if (sqlite3_bind_int
                (stmt,
                 index1,  // Index of wildcard
                 id[i]
                )
                != SQLITE_OK)
        {   printf("\nCould not bind sqlite3_bind_int.\n");
            return 1;
        }

        if (sqlite3_bind_text
                ( stmt,
                  index2,  // Index of wildcard
                  name[i].c_str(),
                  strlen(name[i].c_str()),
                  SQLITE_STATIC
                )
                != SQLITE_OK)
        {   printf("\nCould not bind sqlite3_bind_text.\n");
            return 1;
        }

        if (sqlite3_bind_int
                ( stmt,
                  index3,  // Index of wildcard
                  age[i]
                )
                != SQLITE_OK)
        {   printf("\nCould not bind sqlite3_bind_int.\n");
            return 1;
        }
        // execute sqlite3_step(), and check the state of the statement
        if (sqlite3_step(stmt) != SQLITE_DONE)
        {   printf("\nCould not step (execute) stmt.\n");
            return 1;
        }
        // reset the statement if you want to continue the sqlite3_bind().
        cout << "sqlite3_reset(stmt): " << sqlite3_reset(stmt) << endl;
    }

//////////////////////////// insert values into Students; /////////////////////////////////

    // CREATE TABLE Students;
    sql_stmt("CREATE TABLE Students (Id integer PRIMARY KEY,  TeacherId integer,  FOREIGN KEY(TeacherId) REFERENCES Teachers(id) )" );

    //////// Method 1: use sqlite3_exec to insert values; ////////////
    sql_stmt("INSERT INTO Students Values (0,  1)" );
    sql_stmt("INSERT INTO Students Values (1,  2)" );
    sql_stmt("INSERT INTO Students Values (2,  9)" );
    cout << "sqlite3_errmsg: " << sqlite3_errmsg(db) << endl;

    //////// Method 2: use sqlite3_bind to insert values; ////////////
    result = sqlite3_exec ( db,
                            "Drop TABLE IF EXISTS Students",  // stmt
                            0,
                            0,
                            &errmsg
                          );
    if ( result != SQLITE_OK )
    {   cout << "\nCould not prepare statement: Drop TABLE: " << result << endl;
        cout << "errmsg: " << errmsg << endl;
        return 1;
    }
    // CREATE TABLE Students;
    sql_stmt("CREATE TABLE Students (Id integer PRIMARY KEY,  TeacherId integer,  FOREIGN KEY(TeacherId) REFERENCES Teachers(id) )" );


    if ( sqlite3_prepare
            ( db,
              "insert into Students values ( :Id,:TeacherId )",  // stmt
              -1, // If than zero, then stmt is read up to the first nul terminator
              &stmt,
              0  // Pointer to unused portion of stmt
            )
            != SQLITE_OK )
    {   printf("\nCould not prepare statement.");
        return 1;
    }

    index1 =  sqlite3_bind_parameter_index(stmt, ":Id");
    index2 =  sqlite3_bind_parameter_index(stmt, ":TeacherId");

    cout << index1 << endl;
    cout << index2 << endl;

    printf("\nThe statement has %d wildcards\n", sqlite3_bind_parameter_count(stmt));

    int studentId[] = {0, 1, 2};
    /// if the FOREIGN KEY works, the teacherId should not be 9;
    int teacherId[] = {1, 2, 9};

    for ( int i = 0; i != 3; i++ )
    {   if (sqlite3_bind_int
                (stmt,
                 index1,  // Index of wildcard
                 studentId[i]
                )
                != SQLITE_OK)
        {   printf("\nCould not bind sqlite3_bind_int.\n");
            return 1;
        }

        if (sqlite3_bind_int
                ( stmt,
                  index2,  // Index of wildcard
                  teacherId[i]
                )
                != SQLITE_OK)
        {   printf("\nCould not bind sqlite3_bind_int.\n");
            cout << "sqlite3_errmsg: " << sqlite3_errmsg(db) << endl;
            return 1;
        }
        // execute sqlite3_step(), and check the state of the statement

//        cout << "sqlite3_errmsg: " << sqlite3_errmsg(db) << endl;
        if (  result = sqlite3_step(stmt)  != SQLITE_DONE )
        {   printf("\nCould not step (execute) stmt.\n");
            cout << "sqlite3_errmsg: " << sqlite3_errmsg(db) << endl;
            cout << "result: " << result << endl;
            return 1;
        }


        cout << "result: " << result << endl;
        // reset the statement if you want to continue the sqlite3_bind().
        cout << "sqlite3_reset(stmt): " << sqlite3_reset(stmt) << endl;
    }

    printf("\n");

    // Print all;
    select_stmt("select * from Teachers");
    select_stmt("select * from Students");

    sqlite3_close(db);
    return 0;
}
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-01T04:56:29+00:00Added an answer on June 1, 2026 at 4:56 am

    It’s recommended to use sqlite3_prepare_v2 instead of sqlite3_prepare. Excerpt:

    The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are recommended for all new programs. The two older interfaces are retained for backwards compatibility, but their use is discouraged. In the “v2” interfaces, the prepared statement that is returned (the sqlite3_stmt object) contains a copy of the original SQL text. This causes the sqlite3_step() interface to behave differently in three ways:

    [Point 1 omitted]

    2. When an error occurs, sqlite3_step() will return one of the detailed error codes or extended error codes. The legacy behavior was that sqlite3_step() would only return a generic SQLITE_ERROR result code and the application would have to make a second call to sqlite3_reset() in order to find the underlying cause of the problem. With the “v2” prepare interfaces, the underlying reason for the error is returned immediately.

    [Point 3 omitted]

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

For exmple i have two tables A create table teachers( id number(4) primary key,
Two tables: COURSE_ROSTER - contains COURSE_ID as foreign key to COURSES USER_ID as field
Let us say I have two different entities on a site. Teachers and Students
If two tables have foreign keys to the same primary key of another table,
I have two tables : teachers (teacher_id,teacher_name) courses (teacher_id,course_id) And I need to display
Consider two tables: Transactions , with amounts in a foreign currency: Date Amount =========
I have tables: Teachers and Students. We have a SpecialProjects Table where Teachers and
I two tables within a MySql 5.1.34 database. When using SubSonic to generate the
Two tables in my database are as follows: [Employee] Table: Id (Primary Key, Autoincrement)
Two tables: table_a ------- table_a_id: (primary, int) table_b ------- table_a_id: (index, int, from table_a)

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.