Download Python: Strings - CS-People by full name

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Serializability wikipedia , lookup

Database wikipedia , lookup

Relational algebra wikipedia , lookup

Concurrency control wikipedia , lookup

Open Database Connectivity wikipedia , lookup

Microsoft SQL Server wikipedia , lookup

Microsoft Jet Database Engine wikipedia , lookup

SQL wikipedia , lookup

Extensible Storage Engine wikipedia , lookup

Clusterpoint wikipedia , lookup

Versant Object Database wikipedia , lookup

PostgreSQL wikipedia , lookup

Database model wikipedia , lookup

PL/SQL wikipedia , lookup

Relational model wikipedia , lookup

Transcript
Programming in Python V:
Accessing a Database
Computer Science 105
Boston University
Fall 2007
David G. Sullivan, Ph.D.
Accessing PostgreSQL from Python
• Preparing PostgreSQL:
• start up psql on csa3.bu.edu
• enter the following command:
ALTER USER <username> PASSWORD '<password>';
• Accessing PostgreSQL:
• start the python interpreter on csa3.bu.edu
• import the pgdb module
>>> import pgdb
• connect to PostgreSQL and create a database handle
>>> db = pgdb.connect('localhost::<username>',
'<username>', '<password>')
Performing a Query
• Given a database handle, we can perform a query by:
• using the database handle to create a cursor:
>>> cursor = db.cursor()
• using the cursor to execute the query:
>>> cursor.execute("<SELECT command>")
• Once the query has been executed, we use the cursor to
access the results.
• to get one tuple from the result:
>>> row = cursor.fetchone()
• to get all remaining tuples from the result:
>>> result = cursor.fetchall()
• if there's nothing to get, these functions return None
• the number of tuples in the result is stored in the variable
cursor.rowcount
Performing a Query (cont.)
• Example for our movie database:
>>> cursor = db.cursor()
>>> cursor.execute("SELECT name, year FROM Movie")
>>> cursor.fetchone()
['Titanic', 1997]
>>> cursor.execute('''SELECT name, rating
FROM Movie
WHERE year = 1976;''')
>>> cursor.fetchall()
[['Rocky', 'PG'], ['Network', 'R'],
["All the President's Men", 'R']]
• Each tuple is represented in Python as a list of values.
• The full result of a query (a relation) is represented as
a list of lists.
Using a for Loop to Display Query Results
• Because cursor.fetchall() produces a list of tuples,
we can use a for loop to process one tuple at a time.
• Example:
cursor = db.cursor()
cursor.execute('''SELECT name, rating
FROM Movie
WHERE year = 1976;''')
for tuple in cursor.fetchall():
print "
", tuple[0], tuple[1]
• The above code would give the following output:
Rocky PG
Network R
All the President's Men R
Executing a Query Based on User Input
• How can we execute a query that's based on user inputs?
• example interaction:
Year to search for? 1976
Rocky PG
Network R
All the President's Men R
• In theory, we could construct the query using
string concatenation:
searchYear = raw_input("Year to search for? ")
command = '''SELECT name, rating FROM Movie
WHERE year = '''
command = command + searchYear + ";"
cursor.execute(command)
for tuple in cursor.fetchall():
print "
", tuple[0], tuple[1]
SQL Injection Vulnerability
• Problem: constructing a query using string concatenation
can lead to a serious security breaches.
• known as a SQL injection.
• Example: let's say that in addition to the movie tables,
there's a table called Secret containing sensitive data.
• The user of the program shown on the previous slide can
see data from Secret by entering something like this:
Year to search for? 1976; SELECT * FROM Secret
• The string concatenation will produce the following:
SELECT name, rating FROM Movie WHERE year = 1976;
SELECT * FROM Secret;
• The program will display the entire first two columns of Secret!
SQL Injection Vulnerability (cont.)
• Here's another problematic input!
Year to search for? 1976; DROP TABLE Secret
• It might seem like adding quotes to the query would help:
searchYear = raw_input("Year to search for? ")
command = '''SELECT name, rating FROM Movie
WHERE year = ''''
command = command + searchYear + "';"
The string concatenation would then produce the following:
SELECT name, rating FROM Movie WHERE year = '1976;
SELECT * FROM Secret';
• However, it's still possible to outwit this:
Year to search for? 1976'; SELECT * FROM Secret
WHERE 'a' = 'a
Parameterized Queries
• To avoid SQL injections, we use a parameterized query.
• This involves using a command string with a placeholders
for the values to be supplied by the user.
• example:
command = '''SELECT name, rating FROM Movie
WHERE year = %s;'''
• %s is a placeholder for a string
• it's the correct placeholder for any value read using
a raw_input command
• We execute the parameterized query as follows:
cursor.execute(command, [searchYear])
command string
with placeholders
a list containing the values
that should replace the
placeholders (the parameters)
Parameterized Queries (cont.)
• Python replaces the placeholders with the specified values,
and it performs whatever steps are needed to treat each
parameter as a string literal.
• Consider our last problematic input:
Year to search for? 1976'; SELECT * FROM Secret
WHERE 'a' = 'a
• After replacing the placeholder with the input, the command
becomes:
SELECT name, rating FROM Movie WHERE year = '1976'';
SELECT * FROM Secret WHERE ''a'' = ''a';
• the single-quote characters inside the string are turned
into '' – which is how single quotes are represented
inside a SQL string
• thus, year is compared to one big string, which fails
Parameterized Queries (cont.)
• Here's a query that takes three parameters:
command = '''SELECT M.name, M.year
FROM Movie M, Person P, Director D
WHERE M.id = D.movie_id
AND P.id = D.director_id
AND P.name = %s
AND M.year BETWEEN %s AND %s;'''
• Here's an example of using it:
dirName = raw_input("director's name: ")
start = raw_input("start of year range: ")
end = raw_input("end of year range: ")
cursor.execute(command, [dirName, start, end])
for tuple in cursor.fetchall():
print "
", tuple[0], tuple[1]
Cursors and Transactions
• cursor.execute() can also be used to execute other types
of SQL commands (INSERT, UPDATE, etc.).
• Creating a cursor begins a new transaction.
• transaction = ?
• to undo all changes made during a transaction:
>>> db.rollback()
• to make permanent all changes made during a transaction:
>>> db.commit()
• committing or rolling back a transaction begins a new one
• If an error occurs when executing a command, you need to
rollback the current transaction before issuing other commands.
A Front-End for Our Movie Database
• Let's write a Python program that serves as a front-end to
our movie database.
• For now, it will do the following:
• get the name of a person from the user
• use a parameterized SELECT command to retrieve
the appropriate record from the Person table
• if the specified person is in the database, print his/her
information in the following format:
<name> was born on <dob> in <pob>.
• otherwise, print an appropriate error message
• Extension: change the format of the dob from
yyyy-mm-dd to mm/dd/yyyy
A Front-End for Our Movie Database
Converting the Date Format
• To change the format of the dob from
yyyy-mm-dd to mm/dd/yyyy, what should we do?