35

I am trying to create a function in Python 2.7.3 to open a SQLite database.

This is my code at the moment:

import sqlite3 as lite
import sys

db = r'someDb.sqlite'

def opendb(db):
    try:
        conn = lite.connect(db)
    except sqlite3.Error:
        print "Error open db.\n"
        return False
    cur = conn.cursor()
    return [conn, cur]

I have tried the code above and I have observed that the sqlite3 library opens the database declared if exists, or creates a new database if this one doesn't exist.

Is there a way to check if the database exists with sqlite3 methods or I have to use file operation like os.path.isfile(path)?

6 Answers 6

49

In Python 2, you'll have to explicitly test for the existence using os.path.isfile:

if os.path.isfile(db):

There is no way to force the sqlite3.connect function to not create the file for you.


For those that are using Python 3.4 or newer, you can use the newer URI path feature to set a different mode when opening a database. The sqlite3.connect() function by default will open databases in rwc, that is Read, Write & Create mode, so connecting to a non-existing database will cause it to be created.

Using a URI, you can specify a different mode instead; if you set it to rw, so Read & Write mode, an exception is raised when trying to connect to a non-existing database. You can set different modes when you set the uri=True flag when connecting and pass in a file: URI, and add a mode=rw query parameter to the path:

from urllib.request import pathname2url

try:
    dburi = 'file:{}?mode=rw'.format(pathname2url(db))
    conn = lite.connect(dburi, uri=True)
except sqlite3.OperationalError:
    # handle missing database case

See the SQLite URI Recognized Query Parameters documentation for more details on what parameters are accepted.

Sign up to request clarification or add additional context in comments.

2 Comments

@JurkoGospodnetić: I must note that the question is tagged with python-2.7, so the URI option is not available there.
@MartijnPieters - true, I did not notice that when I originally ran into this question
28

os.path.isfile() is just telling you if a file exists, not if it exists AND is a SQLite3 database! Knowing http://www.sqlite.org/fileformat.html, you could do this :

def isSQLite3(filename):
    from os.path import isfile, getsize

    if not isfile(filename):
        return False
    if getsize(filename) < 100: # SQLite database file header is 100 bytes
        return False

    with open(filename, 'rb') as fd:
        header = fd.read(100)

    return header[:16] == 'SQLite format 3\x00'

and subsequently use it like :

for file in files:
    if isSQLite3(file):
        print "'%s' is a SQLite3 database file" % file
    else:
        print "'%s' is not a SQLite3 database file" % file

3 Comments

For Python 3, make sure you compare against bytes: Header[0:16] == b'SQLite format 3\000' (note the leading b for the format string
Not sure what's the added value here. The only case which cannot be tested against is whether the file exists prior to the connect. If the file exists and an exception is thrown from the connect, I also know if the DB is valid. The existence of the magic string still doesn't say that connect will succeed. So what's the purpose of this?
This one should be the answer, for sure. Filename or extension means nothing (specially on SQLite). Validation of database header is the most safety technique that you can apply for this case.
11

Yes, there is a way to do what you want with Python 3.4+.

Use the sqlite3.connect() function to connect, but pass it a URI instead of a file path, and add mode=rw to its query string.

Here is a complete working code example:

import sqlite3
con = sqlite3.connect('file:aaa.db?mode=rw', uri=True)

This will open an existing database from a file named aaa.db in the current folder, but will raise an error in case that file can not be opened or does not exist:

Traceback (most recent call last):
  File "aaa.py", line 2, in <module>
    con = sqlite3.connect('file:aaa.db?mode=rw', uri=True)
sqlite3.OperationalError: unable to open database file

Python sqlite.connect() docs state that:

If uri is true, database is interpreted as a URI. This allows you to specify options. For example, to open a database in read-only mode you can use:

db = sqlite3.connect('file:path/to/database?mode=ro', uri=True)

More information about this feature, including a list of recognized options, can be found in the SQLite URI documentation.

Here's an excerpt of all the relevant URI option information collected from http://www.sqlite.org/c3ref/open.html:

mode: The mode parameter may be set to either "ro", "rw", "rwc", or "memory". Attempting to set it to any other value is an error. If "ro" is specified, then the database is opened for read-only access, just as if the SQLITE_OPEN_READONLY flag had been set in the third argument to sqlite3_open_v2(). If the mode option is set to "rw", then the database is opened for read-write (but not create) access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had been set. Value "rwc" is equivalent to setting both SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. If the mode option is set to "memory" then a pure in-memory database that never reads or writes from disk is used. It is an error to specify a value for the mode parameter that is less restrictive than that specified by the flags passed in the third parameter to sqlite3_open_v2().

The sqlite3_open_v2() interface works like sqlite3_open() except that it accepts two additional parameters for additional control over the new database connection. The flags parameter to sqlite3_open_v2() can take one of the following three values, optionally combined with the SQLITE_OPEN_NOMUTEX, SQLITE_OPEN_FULLMUTEX, SQLITE_OPEN_SHAREDCACHE, SQLITE_OPEN_PRIVATECACHE, and/or SQLITE_OPEN_URI flags:

SQLITE_OPEN_READONLY The database is opened in read-only mode. If the database does not already exist, an error is returned.

SQLITE_OPEN_READWRITE The database is opened for reading and writing if possible, or reading only if the file is write protected by the operating system. In either case the database must already exist, otherwise an error is returned.

SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE The database is opened for reading and writing, and is created if it does not already exist. This is the behavior that is always used for sqlite3_open() and sqlite3_open16().

For convenience, here's also a Python 3.4+ function for converting a regular path to an URI usable by sqlite.connect():

import pathlib
import urllib.parse

def _path_to_uri(path):
    path = pathlib.Path(path)
    if path.is_absolute():
        return path.as_uri()
    return 'file:' + urllib.parse.quote(path.as_posix(), safe=':/')

2 Comments

OP: Python 2.7.3 not Python 3.x
@Nick - true, as mentioned in some earlier comments above, I did not notice that when I originally ran into this question Still, the information I posted here I did find very good use for several times since then :-)
3

This is a fork from Tom Horen's answer, with a context manager for opening/closing the resource (file), using Python 3.

Also, the answer does not evaluate any content, header, etc., in order to determine whether the file actually contains any data related to a SQLite3 database or not:

#!/usr/bin/python3

import os
import sys

if os.path.isfile('test.sqlite3'):
    if os.path.getsize('test.sqlite3') > 100:
        with open('test.sqlite3','r', encoding = "ISO-8859-1") as f:
            header = f.read(100)
            if header.startswith('SQLite format 3'):
                print("SQLite3 database has been detected.")

Comments

2

Building on a couple of other answers above. Here is a clean solution that works in Python 3.7.7:

def isSqlite3Db(db):
    if not os.path.isfile(db): return False
    sz = os.path.getsize(db)

    # file is empty, give benefit of the doubt that its sqlite
    # New sqlite3 files created in recent libraries are empty!
    if sz == 0: return True

    # SQLite database file header is 100 bytes
    if sz < 100: return False
    
    # Validate file header
    with open(db, 'rb') as fd: header = fd.read(100)    

    return (header[:16] == b'SQLite format 3\x00')

Usage:

if isSqlite3Db('<path_to_db>'):
    # ... <path_to_db> is a Sqlite 3 DB

Notes:

  • The answers checking file size is > 100 does not work as a new sqlite3 db created in recent python creates an file with length of 0.
  • Other examples reading file header returned bytes in Python 3.7.7 and not string so comparison would fail.
  • Examples that use sqlite3.connect(dburl, uri=True) did not work for me in Python 3.7.7 as it gave false positives.

Comments

-2

I am using a function like the following at the beginning of my script so that I can try and figure out why a sqlite3 db script might not be working. Like the comments say, it uses 3 phases, checks if a path exist, checks if the path is a file, checks if that file's header is a sqlite3 header.

def checkdbFileforErrors():

    #check if path exists
    try:
        with open('/path/to/your.db'): pass
    except IOError:
        return 1

    #check if path if a file
    if not isfile('/path/to/your.db'):
        return 2

    #check if first 100 bytes of path identifies itself as sqlite3 in header
    f = open('/path/to/your.db', "rx")
    ima = f.read(16).encode('hex')
    f.close()
    #see http://www.sqlite.org/fileformat.html#database_header magic header string
    if ima != "53514c69746520666f726d6174203300": 
        return 3

    return 0

2 Comments

That should read if ima == '53514c69746520666f726d6174203300': return 3
This design of returning numbers for each error or 0 for success is more C style than Python. Python is more about throwing exceptions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.