Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Serializability 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
Extensible Storage Engine wikipedia , lookup
Clusterpoint wikipedia , lookup
Versant Object Database wikipedia , lookup
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?