Gary
Gary

Reputation: 2859

Question concerning pointers in C API of SQLite

I am misunderstandng something likley fundamental concerning pointers in C.

In the code below, if db_open( "name.db", dbP ) is invoked from within another function, the database is opened/created but dbP is not recognized afterward in build_schema but is NULL. If db_open is changed to not have an argument sqlite3 *db and references the gloabal dbP, then dbP is recognized in build_schema and is not NULL.

The objective is to have db_open accept any database name and sqlite db handle.

Would you please explain what I am doing wrong and misunderstanding?

Thank you.


I added more code as requested. The database is created successfully and build_schema is invoked but the sqlite prepare statement returns an error code of 21 because dbP is null in that function if print it out. However, if alter db_open to not have the second argument and reference dbP in all functions, build_schema succeeds, the SQL statements are processed, the database has tables in it, and printing out dbP shows something like AL.

// function prototype
int db_open( char [], sqlite3 *db ); 

// Global variables.
sqlite3 *dbP;  // The primary database.    

int main( void )
  {
    int rc;   
    switch( rc = db_open( "path/db_name.db", dbP ) )
       {
         case 'c' :
              build_schema( &J[ i ] );  
              break;
         case 'o' :
            get_base( &J[ i ] ); 
            break;
         default: ...;
       }
    }

int db_open( char db_name[], sqlite3 *db )
  { 
    int rc; 
    // Attempt to open the database as if already existed; will fail if does not exist. 
    rc = sqlite3_open_v2( db_name, &db, SQLITE_OPEN_READWRITE, NULL );
    if ( rc == 14 )
      {
        // Error code of 14 is a generic "unable to open database." 
        // First, assume failed to open because database doesn't exist; and modify flags to attempt to create it anew. 
        rc = sqlite3_open_v2( db_name, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL );
        // If rc > 0 then failed to create a database; otherwise, return "c" indicating successful creation of database.
        return rc ? 'e' : 'c';
      } 
    else if ( rc )
      // Correction of error codes other than 14 is not attempted, and user is informed. 
      return 'e';
    else
      // Existing database opened successfully.
      return 'o';
  } // close db_open

void build_schema( char *j )
  {
    sqlite3_stmt *stmt;
    char *sql;
    const char *tail;
    int rc;

    sql = "SQL statement_1 to create a table;"
          "SQL statement_2 to create a table;"
          "SQL statement_3; to create a table";

    while ( sqlite3_complete( sql ) )
      {
        rc = sqlite3_prepare_v2( dbP, sql, -1, &stmt, &tail );
        sqlite3_step( stmt );
        sql = tail;
      }

    sqlite3_finalize( stmt );
  }

Upvotes: 0

Views: 169

Answers (1)

Dan D.
Dan D.

Reputation: 74655

The problem I see is that you are passing the value of dbP rather than the location of dbP to your helper function which then takes the location of its argument so when the sqlite3_open_v2 function writes. It is writing to the location of the argument of the db_open function db rather than the location of the global dbP.

int sqlite3_open_v2(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb,         /* OUT: SQLite db handle */
  int flags,              /* Flags */
  const char *zVfs        /* Name of VFS module to use */
);

db_open should take a sqlite3 ** and then it should just pass it along. This then puts the & in the right place. So see have a &dbP.

switch( rc = db_open( "path/db_name.db", &dbP ) )

int db_open( char db_name[], sqlite3 **db )

rc = sqlite3_open_v2( db_name, db, SQLITE_OPEN_READWRITE, NULL );

Upvotes: 1

Related Questions