COMP102: Introduction to Databases, 23 Dr Muhammad Sulaiman Khan Department of Computer Science University of Liverpool U.K. 04 April, 2011
Programming with SQL
Specific topics for today: Client/Server Architecture Applications CGI Scripts Interaction with RDBMS SQL Injection Attacks JDBC Connections Queries Results
Client/Server Remember that the RDBMS is a server which accepts connections from multiple client applications:
Client/Server This architecture imposes some requirements, regardless of programming language. Need to know where the server is. Need standards for interaction. Need to connect before use. Need to transfer authentication information. Need to transfer information across network. Need to disconnect after use.
Client/Server Need to know where the server is: Hostname for the machine and port to connect to. Named pipe to talk across. File write and read to. Shared memory location. Need standards for interaction: All clients need to use the same protocol for communication so that the server doesn t have to implement methods for individual clients. Same protocol for different transports (above).
Client/Server Need to connect before use: Need to have some sort of connection object to represent the connection to the database to give commands to. Need to make sure the scope of the connection is appropriate eg everything that needs to talk to the database can see the connection. Need to handle errors due to lack of network. Need to transfer authentication information: To match database user to human, need to send user, password (etc) at connection time.
Client/Server Need to transfer information across network Results must be represented in a way to transfer across a network (e.g., strings, not references). Possibility for network interruptions in the middle of a session. Need to disconnect after use: We should sign off explicitly even if the client application doesn t finish so that the resources of the server aren t used unnecessarily.
Applications There are many possible applications for databases: Maintain a web site: client generates html for display. Maintain business information: client creates and updates information in database based on business activities (e.g., sales, staff, etc). Maintain a collection of objects: some clients create (admin interface), other clients search (display interface), e.g.: library database needs book entry forms for library staff, and OPAC (Online Public Access Catalogue) terminals for the rest of us. (etc., etc.)
Web Applications Web sites very commonly now use databases, and for many purposes: Users, for personalisation and authentication. Comments and Forum systems, for interaction between users, rather than static content. Content Management, e.g., to enable many people to administrate what content is available. Search, to enable users to find content of interest. Business Functions, e.g., shopping online.
Web Applications Some common methods of generating web pages that interact with a database: A constantly running application that generates all of the HTML for a site. (e.g., mod python, mod perl, apache tomcat) A CGI script that generates all of the HTML for a page. (e.g., python, perl, ruby) Code embedded into HTML pages that is executed before being returned to the web browser. (e.g., php, asp, jsp, psp)
CGI Scripts CGI: Common Gateway Interface Accepts the values in an HTML form in a standard way for processing. Runs the program from scratch: Initialise java, python, perl (etc.) virtual machine. Execute code to generate HTML. Shutdown program Sufficient for most uses (but the initialisation and shutdown for every page can cause scalability problems).
CGI Scripts Architecture Diagram:
CGI Scripts Two methods for sending data from browser to web server: GET: Put the form values into the URL after a? e.g.: http://foo.com?name=value&name2=value2 POST: Put the form values into an encoded section which is sent to the server after the URL. Can be used to send a lot of data (eg entire files) and to keep URLs short. However, almost identical processing in the CGI script.
Interaction with RDBMS In a CGI script, because the program is executed from beginning to end, it must connect to the RDBMS, perform its SQL commands and then close the connection, each time the web page is requested. For example, a CGI script that updates the database might do: Parse form information. Check form information is valid. Connect to database. Issue SQL commands. Close connection. Return HTML to display results of the commands.
Interaction with RDBMS A CGI script that simply displays content stored in a database may do these: Parse form information for content to select. Connect to database. Issue SELECT(s) and get results. Close connection. Turn results into HTML. Return results.
SQL Injection A very common problem with web based interfaces to databases is known as SQL Injection. The idea is that a malicious user can get your code to send SQL commands that the user supplies in the form. If those SQL commands can call operating system functions, alter user tables, or even just delete a bunch of your data, then the attacker has just caused you a pretty big headache. This is why ALL content accepted from the web should be checked before sending it to the database!!! Some examples to demonstrate...
Example: SQL Injection Naive CGI pseudo-code: email = form.getvalue( email ) query = "SELECT * FROM users WHERE email = " + email + " ;" results = sql.docommand(query) Find details in the users table for the given email address... (Note: + is string concatenation) What could go wrong? What about if the user puts in the form: email: foo Then the query will be invalid: SELECT * FROM users WHERE email = foo ;
Example: SQL Injection, contd Making the query fail is relatively harmless but what about setting the email value in the form to: ; DELETE FROM users; SELECT * FROM users WHERE email = foo Then the CGI script will execute: sql.docommand("select * FROM users WHERE email = ; DELETE FROM users; SELECT * FROM users WHERE email = foo ;") Erk! Goodbye user data :(
SQL Injection Rule Number 1: Never Trust Unknown Data! Rule Number 2: Never Put Passwords In Accessible Files! E.g., if you have a password to access the data, have it read it from a file outside of the web directories so that crackers can t find some way to read the file remotely.
JDBC Stands for: Java Database Connectivity Produced by Sun Microsystems Home page: http://java.sun.com/products/jdbc/ Not going to go into that much detail today. Goals: Provide programmatic access to relational data from the Java programming language. Fit into the J2EE and J2SE platforms. Be consistent with SQL99. Offer vendor-neutral access to common features. Keep it simple
Libraries Step 1: Import libraries. Import the base JDBC libraries: import java.sql.*; And there s some other utility functions that may prove useful: import java.util.*;
Drivers Step 2: Configure RDBMS Implementation. Because there are many different implementations of SQL, and JDBC aims to provide vendor-neutral access, we need to have a specific driver loaded to access our database. This is done by: Class.forName(driverName) Example: Class.forName("com.mysql.jdbc.Driver") Class.forName("org.postgresql.Driver") Class.forName("oracle.jdbc.driver.OracleDriver")
Connection Step 3: Create Connection. We create a Connection object that acts as our gateway over to the database. We do this through a DriverManager that does the actual work. Connection cxn = DriverManager.getConnection(url, username, password); The url parameter is implementation specific. For PostgreSQL: String url = "jdbc:postgresql://host/database"; For MySQL: String url = "jdbc:mysql://host/database";
Connection Step 3: Create Connection. So to connect to the videos database on the local machine, with user piotr and password mysqql : String url = "jdbc:mysql://localhost/videos"; String username = "piotr"; String password = "mysqql"; Connection cxn = DriverManager.getConnection(url, username, password);
Connection Step 3: Create Connection (alternative 1). We can also use a Properties object to carry the information, and configure other things like encryption of the communication: Properties props = new Properties(); props.setproperty("user", "piotr"); props.setproperty("password", "mysqql"); props.setproperty("ssl", "true"); Connection cxn = DriverManager.getConnection(url, props);
Connection Step 3: Create Connection (alternative 2). Or we can just throw everything into the URL given. The options are put after the database name as a query. String url = "jdbc:mysql://localhost/videos?user=piotr&password=mysqql &ssl=true"; Connection cxn =DriverManager.getConnection(url); So now we have our connection (called cxn) established to the database, and can start to interact with it.
Query Step 4: Create SQL Statement. Because java has this whole class obsession thing, we need to create an object to hold our query. This is what will send the SQL over to the DBMS. Statement stmt = cxn.createstatement(); Where s the SQL? We give the actual SQL commands when we execute the statement...
Query Step 5: Execute SQL Statement. Say we want to retrieve all of the fields in the VideoTitle table where the name is Lord of the Rings. String query = "SELECT * FROM VideoTitle WHERE name = Lord of the Rings "; ResultSet rs = stmt.executequery(query); So we ve built our query, and sent it over the connection (as represented by the statement) and gotten back something called a ResultSet.
ResultSet Step 6: Process ResultSet. The ResultSet is an object that represents the full set of results from the SQL query. The result set object has a function called next() which steps to the next row in the result. It starts off uninitialised, so first of all we need to call: rs.next() to get the cursor to step to the first row. Now we need to fetch the data off the result set object for the row the cursor is pointing at...
ResultSet Step 6: Process ResultSet. We can use a series of methods to fetch the data from specific columns in the row. The data can be retrieved with: ResultSet.getType(columnName); where type is String, Float, Date, Time, Int, etc. Example: String name = rs.getstring( name ); would retrieve the value of the name column as a string.
ResultSet Step 6: Process ResultSet. The data can also be retrieved by column number: ResultSet.getType(columnNumber); where type is String, Float, Date, Time, Int, etc. Example: String name = rs.getstring(1); would retrieve the value of the first column as a string. (Remember what we said about implicit ordering in tables?)
ResultSet Step 6: Process ResultSet. We can wrap the next() call in a while loop (it returns false if there is no more data) to step through all of the returned values: while (rs.next()) { Int i = rs.getint( identifier ); String n = rs.getstring( name ); System.out.println(n + " (" + i + ")"); }
ResultSet Step 6: Process ResultSet. Other movement functions on the result set object: previous() Step backwards one row first() Jump to being on the first row last() Jump to being on the last row beforefirst() Jump to before the first row afterlast() Jump to after the last row relative(i) Step a number of rows, + i or - i absolute(i) Jump to row number i
Close Step 7: Close Statement, ResultSet. Once we ve finished using a resultset and statement, we close it: rs.close(); stmt.close(); Ta-dah! Our first jdbc application : ) But we might also want to perform updates...
Update To modify our database (INSERT, UPDATE or DELETE) we use the executeupdate() method rather than executequery() So: Statement stmt = cxn.createstatement() stmt.executeupdate("insert INTO Users (id, password) VALUES ( az, bar );"); stmt.executeupdate("update Users SET password = foo WHERE id = az ;");