- GUI
- Windows API tutorial
- Introduction to Windows API
- Windows API main functions
- System functions in Windows API
- Strings in Windows API
- Date & time in Windows API
- A window in Windows API
- First steps in UI
- Windows API menus
- Windows API dialogs
- Windows API controls I
- Windows API controls II
- Windows API controls III
- Advanced controls in Windows API
- Custom controls in Windows API
- The GDI in Windows API
- PyQt4 tutorial
- PyQt5 tutorial
- Qt4 tutorial
- Introduction to Qt4 toolkit
- Qt4 utility classes
- Strings in Qt4
- Date and time in Qt4
- Working with files and directories in Qt4
- First programs in Qt4
- Menus and toolbars in Qt4
- Layout management in Qt4
- Events and signals in Qt4
- Qt4 Widgets
- Qt4 Widgets II
- Painting in Qt4
- Custom widget in Qt4
- The Breakout game in Qt4
- Qt5 tutorial
- Introduction to Qt5 toolkit
- Strings in Qt5
- Date and time in Qt5
- Containers in Qt5
- Working with files and directories in Qt5
- First programs in Qt5
- Menus and toolbars in Qt5
- Layout management in Qt5
- Events and signals in Qt5
- Qt5 Widgets
- Qt5 Widgets II
- Painting in Qt5
- Custom widget in Qt5
- Snake in Qt5
- The Breakout game in Qt5
- PySide tutorial
- Tkinter tutorial
- Tcl/Tk tutorial
- Qt Quick tutorial
- Java Swing tutorial
- JavaFX tutorial
- Java SWT tutorial
- wxWidgets tutorial
- Introduction to wxWidgets
- wxWidgets helper classes
- First programs in wxWidgets
- Menus and toolbars in wxWidgets
- Layout management in wxWidgets
- Events in wxWidgets
- Dialogs in wxWidgets
- wxWidgets widgets
- wxWidgets widgets II
- Drag and Drop in wxWidgets
- Device Contexts in wxWidgets
- Custom widgets in wxWidgets
- The Tetris game in wxWidgets
- wxPython tutorial
- Introduction to wxPython
- First Steps
- Menus and toolbars
- Layout management in wxPython
- Events in wxPython
- wxPython dialogs
- Widgets
- Advanced widgets in wxPython
- Drag and drop in wxPython
- Internationalisation
- Application skeletons in wxPython
- The GDI
- Mapping modes
- Creating custom widgets
- Tips and Tricks
- wxPython Gripts
- The Tetris game in wxPython
- C# Winforms Mono tutorial
- Java Gnome tutorial
- Introduction to Java Gnome
- First steps in Java Gnome
- Layout management in Java Gnome
- Layout management II in Java Gnome
- Menus in Java Gnome
- Toolbars in Java Gnome
- Events in Java Gnome
- Widgets in Java Gnome
- Widgets II in Java Gnome
- Advanced widgets in Java Gnome
- Dialogs in Java Gnome
- Pango in Java Gnome
- Drawing with Cairo in Java Gnome
- Drawing with Cairo II
- Nibbles in Java Gnome
- QtJambi tutorial
- GTK+ tutorial
- Ruby GTK tutorial
- GTK# tutorial
- Visual Basic GTK# tutorial
- PyGTK tutorial
- Introduction to PyGTK
- First steps in PyGTK
- Layout management in PyGTK
- Menus in PyGTK
- Toolbars in PyGTK
- Signals & events in PyGTK
- Widgets in PyGTK
- Widgets II in PyGTK
- Advanced widgets in PyGTK
- Dialogs in PyGTK
- Pango
- Pango II
- Drawing with Cairo in PyGTK
- Drawing with Cairo II
- Snake game in PyGTK
- Custom widget in PyGTK
- PHP GTK tutorial
- C# Qyoto tutorial
- Ruby Qt tutorial
- Visual Basic Qyoto tutorial
- Mono IronPython Winforms tutorial
- Introduction
- First steps in IronPython Mono Winforms
- Layout management
- Menus and toolbars
- Basic Controls in Mono Winforms
- Basic Controls II in Mono Winforms
- Advanced Controls in Mono Winforms
- Dialogs
- Drag & drop in Mono Winforms
- Painting
- Painting II in IronPython Mono Winforms
- Snake in IronPython Mono Winforms
- The Tetris game in IronPython Mono Winforms
- FreeBASIC GTK tutorial
- Jython Swing tutorial
- JRuby Swing tutorial
- Visual Basic Winforms tutorial
- JavaScript GTK tutorial
- Ruby HTTPClient tutorial
- Ruby Faraday tutorial
- Ruby Net::HTTP tutorial
- Java 2D games tutorial
- Java 2D tutorial
- Cairo graphics tutorial
- PyCairo tutorial
- HTML5 canvas tutorial
- Python tutorial
- Python language
- Interactive Python
- Python lexical structure
- Python data types
- Strings in Python
- Python lists
- Python dictionaries
- Python operators
- Keywords in Python
- Functions in Python
- Files in Python
- Object-oriented programming in Python
- Modules
- Packages in Python
- Exceptions in Python
- Iterators and Generators
- Introspection in Python
- Ruby tutorial
- PHP tutorial
- Visual Basic tutorial
- Visual Basic
- Visual Basic lexical structure
- Basics
- Visual Basic data types
- Strings in Visual Basic
- Operators
- Flow control
- Visual Basic arrays
- Procedures & functions in Visual Basic
- Organizing code in Visual Basic
- Object-oriented programming
- Object-oriented programming II in Visual Basic
- Collections in Visual Basic
- Input & output
- Tcl tutorial
- C# tutorial
- Java tutorial
- AWK tutorial
- Jetty tutorial
- Tomcat Derby tutorial
- Jtwig tutorial
- Android tutorial
- Introduction to Android development
- First Android application
- Android Button widgets
- Android Intents
- Layout management in Android
- Android Spinner widget
- SeekBar widget
- Android ProgressBar widget
- Android ListView widget
- Android Pickers
- Android menus
- Dialogs
- Drawing in Android
- Java EE 5 tutorials
- Introduction
- Installing Java
- Installing NetBeans 6
- Java Application Servers
- Resin CGIServlet
- JavaServer Pages, (JSPs)
- Implicit objects in JSPs
- Shopping cart
- JSP & MySQL Database
- Java Servlets
- Sending email in a Servlet
- Creating a captcha in a Servlet
- DataSource & DriverManager
- Java Beans
- Custom JSP tags
- Object relational mapping with iBATIS
- Jsoup tutorial
- MySQL tutorial
- MySQL quick tutorial
- MySQL storage engines
- MySQL data types
- Creating, altering and dropping tables in MySQL
- MySQL expressions
- Inserting, updating, and deleting data in MySQL
- The SELECT statement in MySQL
- MySQL subqueries
- MySQL constraints
- Exporting and importing data in MySQL
- Joining tables in MySQL
- MySQL functions
- Views in MySQL
- Transactions in MySQL
- MySQL stored routines
- MySQL Python tutorial
- MySQL Perl tutorial
- MySQL C API programming tutorial
- MySQL Visual Basic tutorial
- MySQL PHP tutorial
- MySQL Java tutorial
- MySQL Ruby tutorial
- MySQL C# tutorial
- SQLite tutorial
- SQLite C tutorial
- SQLite PHP tutorial
- SQLite Python tutorial
- SQLite Perl tutorial
- SQLite Ruby tutorial
- SQLite C# tutorial
- SQLite Visual Basic tutorial
- PostgreSQL C tutorial
- PostgreSQL Python tutorial
- PostgreSQL Ruby tutorial
- PostgreSQL PHP tutorial
- PostgreSQL Java tutorial
- Apache Derby tutorial
- SQLAlchemy tutorial
- MongoDB PHP tutorial
- MongoDB Java tutorial
- MongoDB JavaScript tutorial
- MongoDB Ruby tutorial
- Spring JdbcTemplate tutorial
- JDBI tutorial
PostgreSQL C tutorial
This is a C programming tutorial for the PostgreSQL database. It covers the basics of PostgreSQL programming with the C API.
About PostgreSQL database
PostgreSQL is a powerful, open source, object-relational database system. It is a multi-user database management system. It runs on multiple platforms, including Linux, FreeBSD, Solaris, Microsoft Windows, and Mac OS X. PostgreSQL is developed by the PostgreSQL Global Development Group.
PostgreSQL has sophisticated features such as Multi-Version Concurrency Control (MVCC), point in time recovery, tablespaces, asynchronous replication, nested transactions (savepoints), online/hot backups, a sophisticated query planner/optimizer, and write ahead logging for fault tolerance. It supports international character sets, multibyte character encodings, Unicode, and it is locale-aware for sorting, case-sensitivity, and formatting.
Installation
We are going to install PostgreSQL database and the C development library.
$ sudo apt-get install postgresql
On a Debian-based system, we can install the PostgreSQL database from the packages using the above command.
$ sudo update-rc.d -f postgresql remove Removing any system startup links for /etc/init.d/postgresql ... /etc/rc0.d/K21postgresql /etc/rc1.d/K21postgresql /etc/rc2.d/S19postgresql /etc/rc3.d/S19postgresql /etc/rc4.d/S19postgresql /etc/rc5.d/S19postgresql /etc/rc6.d/K21postgresql
If we install the PostgreSQL database from packages, it is automatically added to the startup scripts of the operating system. If we are only learning to work with the database, it is unnecessary to start the database each time we boot the system. The above command removes any system startup links for the PostgreSQL database.
$ sudo apt-get install libpq-dev
To be able to compile C examples, we need to install the PostgreSQL C development libraries. The above line shows how we can do it on Debian-based Linux.
$ sudo -u postgres psql postgres psql (9.3.9) Type "help" for help. postgres=# \password postgres
We set a password for the postgres
user.
Starting and stopping PostgreSQL
In the next section, we are going to show how to start the PostgreSQL database, stop it, and query its status.
$ sudo service postgresql start * Starting PostgreSQL 9.3 database server [ OK ]
On Debian-based Linux, we can start the server with the service postgresql start
command.
$ sudo service postgresql status 9.3/main (port 5432): online
We use the service postgresql status
command to check if PostgreSQL is running.
$ sudo service postgresql stop * Stopping PostgreSQL 9.3 database server [ OK ]
We use the service postgresql stop
command to stop PostgreSQL.
$ service postgresql status 9.3/main (port 5432): down
At this moment, the service postgresql status
command reports that the PostgreSQL database is down.
Creating a user and a database
In the following steps, we create a new database user and database.
$ sudo -u postgres createuser janbodnar
We create a new role in the PostgreSQL system. We allow it to have ability to create new databases. A role is a user in a database world. Roles are separate from operating system users.
$ sudo -u postgres psql postgres psql (9.3.9) Type "help" for help. postgres=# ALTER USER janbodnar WITH password 'pswd37'; ALTER ROLE postgres=# \q
With the psql
command, we add a password for the new user.
PostgreSQL often uses trust or peer authentication policies on local connections. In case of the trust authentication policy, PostgreSQL assumes that anyone who can connect to the server is authorized to access the database with whatever database user name they specify (even superuser names). When making connections to the database, no password is required. (The restrictions made in the database and user columns still apply.) The trust authentication is appropriate and very convenient for local connections on a single-user workstation. It is usually not appropriate on a multiuser machine. In case of the peer authentication policy, the database username must match the operating system username.
$ sudo -u postgres createdb testdb --owner janbodnar
With the createdb
command, we create a new database called testdb
. Its owner is the new database user.
C99
This tutorial uses C99. For GNU C compiler, we need to add the -std=c99 option. For Windows users, the Pelles C IDE is highly recommended. (MSVC does not support C99.)
PGconn *conn = PQconnectdb("user=janbodnar dbname=testdb");
In C99, we can mix declarations with code. In older C programs, we would need to separate this line into two lines.
for(int i=0; i<rows; i++) {
We can also use initial for loop declarations.
The libpq library
The libpq
library is the C interface to PostgreSQL. It is a set of library functions that allow client programs to interact with PostgreSQL. It is also the underlying engine for several other PostgreSQL application interfaces, including those written for C++, Perl, PHP, Ruby, Python, and Tcl.
lib_version.c
#include <stdio.h> #include <libpq-fe.h> int main() { int lib_ver = PQlibVersion(); printf("Version of libpq: %d\n", lib_ver); return 0; }
The program prints the version of the libpq
library.
#include <libpq-fe.h>
The libpq-fe.h
file contains definitions of enumerations, structures, constants, and functions of the C programming interface.
int lib_ver = PQlibVersion();
The PQlibVersion()
function returns the version of the libpq
being used.
$ pg_config --includedir /usr/include/postgresql $ pg_config --libdir /usr/lib
The pg_config
tool is used to find out the location of the C header files and object code libraries.
$ gcc -o lib_version lib_version.c -I/usr/include/postgresql -lpq -std=c99
With the above command, we compile the program.
$ ./lib_version Version of libpq: 90309
The version of the library is 9.3.9.
Server version
In the following example, we find out the version of the PostgreSQL database.
server_version.c
#include <stdio.h> #include <stdlib.h> #include <libpq-fe.h> void do_exit(PGconn *conn) { PQfinish(conn); exit(1); } int main() { PGconn *conn = PQconnectdb("user=janbodnar dbname=testdb"); if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); do_exit(conn); } int ver = PQserverVersion(conn); printf("Server version: %d\n", ver); PQfinish(conn); return 0; }
The example connects to the PostgreSQL database, executes a PQserverVersion()
function, prints the version, closes the connection, and cleans up.
... # TYPE DATABASE USER ADDRESS METHOD # "local" is for Unix domain socket connections only local all all peer ...
In the pg_hba.conf
, we have the peer
default authentication method. In this method, the database user name must match the operating system user name. No password is required to make a connection.
PGconn *conn = PQconnectdb("user=janbodnar dbname=testdb");
With the PQconnectdb()
function, we make a connection to the database. In the connection string, we provide the user name and the database name.
if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn)); do_exit(conn); }
The PQstatus()
function returns the status of the connection. In case of a successfull connection, CONNECTION_OK
is returned; for unsuccessfull connection, CONNECTION_BAD
is returned. The PQerrorMessage()
returns the most recently generated error message.
int ver = PQserverVersion(conn);
The PQserverVersion()
function returns an integer representing the PostgreSQL database version. It takes the connection object as a parameter.
PQfinish(conn);
The PQfinish()
function closes the connection to the server and frees the memory used by the PGconn
object.
$ ./server_version Server version: 90309
Running the program, we get the database server version.
Authentication with a password
Next, we are going to authenticate to the database server with a password. In all other examples in this tutorial, we assume the peer
or trust
authentication mode. We change the authentication type for the local connection inside the pg_hba.conf
file to md5
.
$ sudo service postgresql restart
To apply the changes, the database server must be restarted.
password_authentication.c
#include <stdio.h> #include <stdlib.h> #include <libpq-fe.h> void do_exit(PGconn *conn) { PQfinish(conn); exit(1); } int main() { PGconn *conn = PQconnectdb("user=janbodnar password=pswd37 dbname=testdb"); if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); do_exit(conn); } char *user = PQuser(conn); char *db_name = PQdb(conn); char *pswd = PQpass(conn); printf("User: %s\n", user); printf("Database name: %s\n", db_name); printf("Password: %s\n", pswd); PQfinish(conn); return 0; }
In the example, we connect to the database with a password. We print the username, database name, and the password of the current database connection.
PGconn *conn = PQconnectdb("user=janbodnar password=pswd37 dbname=testdb");
In the connection string, we add the password option.
char *user = PQuser(conn);
The PQuser()
function returns the user name of the connection.
char *db_name = PQdb(conn);
The PQdb()
function returns the database name of the connection.
char *pswd = PQpass(conn);
The PQpass()
function returns the password of the connection.
$ ./password_authentication User: janbodnar Database name: testdb Password: pswd37
The program prints the database user, the database name, and the password used.
Creating a database table
In this section, we create a database table and fill it with data.
create_table.c
#include <stdio.h> #include <stdlib.h> #include <libpq-fe.h> void do_exit(PGconn *conn, PGresult *res) { fprintf(stderr, "%s\n", PQerrorMessage(conn)); PQclear(res); PQfinish(conn); exit(1); } int main() { PGconn *conn = PQconnectdb("user=janbodnar dbname=testdb"); if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); PQfinish(conn); exit(1); } PGresult *res = PQexec(conn, "DROP TABLE IF EXISTS Cars"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { do_exit(conn, res); } PQclear(res); res = PQexec(conn, "CREATE TABLE Cars(Id INTEGER PRIMARY KEY," \ "Name VARCHAR(20), Price INT)"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { do_exit(conn, res); } PQclear(res); res = PQexec(conn, "INSERT INTO Cars VALUES(1,'Audi',52642)"); if (PQresultStatus(res) != PGRES_COMMAND_OK) do_exit(conn, res); PQclear(res); res = PQexec(conn, "INSERT INTO Cars VALUES(2,'Mercedes',57127)"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { do_exit(conn, res); } PQclear(res); res = PQexec(conn, "INSERT INTO Cars VALUES(3,'Skoda',9000)"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { do_exit(conn, res); } PQclear(res); res = PQexec(conn, "INSERT INTO Cars VALUES(4,'Volvo',29000)"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { do_exit(conn, res); } PQclear(res); res = PQexec(conn, "INSERT INTO Cars VALUES(5,'Bentley',350000)"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { do_exit(conn, res); } PQclear(res); res = PQexec(conn, "INSERT INTO Cars VALUES(6,'Citroen',21000)"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { do_exit(conn, res); } PQclear(res); res = PQexec(conn, "INSERT INTO Cars VALUES(7,'Hummer',41400)"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { do_exit(conn, res); } PQclear(res); res = PQexec(conn, "INSERT INTO Cars VALUES(8,'Volkswagen',21600)"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { do_exit(conn, res); } PQclear(res); PQfinish(conn); return 0; }
The created table is called Cars
and it has three columns: the Id, the name of the car, and its price.
PGresult *res = PQexec(conn, "DROP TABLE IF EXISTS Cars");
The PQexec()
function submits an SQL command to the server and waits for the result. The PGresult
encapsulates the result of a query. Our SQL command drops a table if it already exists.
if (PQresultStatus(res) != PGRES_COMMAND_OK) { do_exit(conn, res); }
The PQresultStatus()
function should be called to check the return value for any errors. The PGRES_COMMAND_OK
is returned if the command was properly executed and it does not return data.
PQclear(res);
Every command result should be freed with the PQclear()
function when it is no longer needed.
$ ./create_table $ psql testdb psql (9.3.9) Type "help" for help. testdb=> SELECT * FROM Cars; id | name | price ----+------------+-------- 1 | Audi | 52642 2 | Mercedes | 57127 3 | Skoda | 9000 4 | Volvo | 29000 5 | Bentley | 350000 6 | Citroen | 21000 7 | Hummer | 41400 8 | Volkswagen | 21600 (8 rows)
We execute the program and verify the created table with the psql
tool.
Simple query
In this section, we execute a simple query command.
query_version.c
#include <stdio.h> #include <stdlib.h> #include <libpq-fe.h> void do_exit(PGconn *conn) { PQfinish(conn); exit(1); } int main() { PGconn *conn = PQconnectdb("user=janbodnar dbname=testdb"); if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); do_exit(conn); } PGresult *res = PQexec(conn, "SELECT VERSION()"); if (PQresultStatus(res) != PGRES_TUPLES_OK) { printf("No data retrieved\n"); PQclear(res); do_exit(conn); } printf("%s\n", PQgetvalue(res, 0, 0)); PQclear(res); PQfinish(conn); return 0; }
The example gets the version of the database server.
PGresult *res = PQexec(conn, "SELECT VERSION()");
The SELECT VERSION()
SQL statement retrieves the version of the database.
if (PQresultStatus(res) != PGRES_TUPLES_OK) { printf("No data retrieved\n"); PQclear(res); do_exit(conn); }
The PGRES_TUPLES_OK
is returned for a query that returns data by the PQresultStatus()
function.
printf("%s\n", PQgetvalue(res, 0, 0));
The PQgetvalue()
function returns a single field value of one row of a PGresult
.
$ ./query_version PostgreSQL 9.3.9 on x86_64-unknown-linux-gnu, compiled by gcc (Ubuntu 4.8.4-2ubuntu1~14.04) 4.8.4, 64-bit
The program prints this output.
Retrieving multiple rows of data
The following example executes a query that returns multiple rows of data.
multiple_rows.c
#include <stdio.h> #include <stdlib.h> #include <libpq-fe.h> void do_exit(PGconn *conn) { PQfinish(conn); exit(1); } int main() { PGconn *conn = PQconnectdb("user=janbodnar dbname=testdb"); if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); do_exit(conn); } PGresult *res = PQexec(conn, "SELECT * FROM Cars LIMIT 5"); if (PQresultStatus(res) != PGRES_TUPLES_OK) { printf("No data retrieved\n"); PQclear(res); do_exit(conn); } int rows = PQntuples(res); for(int i=0; i<rows; i++) { printf("%s %s %s\n", PQgetvalue(res, i, 0), PQgetvalue(res, i, 1), PQgetvalue(res, i, 2)); } PQclear(res); PQfinish(conn); return 0; }
The program prints the data of the first five rows of the Cars
table.
PGresult *res = PQexec(conn, "SELECT * FROM Cars LIMIT 5");
This SQL query returns five rows of data.
int rows = PQntuples(res);
The PQntuples()
returns the number of rows in the query result.
for(int i=0; i<rows; i++) { printf("%s %s %s\n", PQgetvalue(res, i, 0), PQgetvalue(res, i, 1), PQgetvalue(res, i, 2)); }
In the for loop, we get all three fields of a row with the PQgetvalue()
function.
$ ./multiple_rows 1 Audi 52642 2 Mercedes 57127 3 Skoda 9000 4 Volvo 29000 5 Bentley 350000
This is the output of the multiple_rows
program.
Prepared statements
Prepared statements guard against SQL injections and increase performance. When using prepared statements, we use placeholders instead of directly writing the values into the statements.
prepared_statement.c
#include <stdio.h> #include <stdlib.h> #include <libpq-fe.h> void do_exit(PGconn *conn) { PQfinish(conn); exit(1); } int main(int argc, char *argv[]) { const int LEN = 10; const char *paramValues[1]; if (argc != 2) { fprintf(stderr, "Usage: prepared_statement rowId\n"); exit(1); } int rowId; int ret = sscanf(argv[1], "%d", &rowId); if (ret != 1) { fprintf(stderr, "The argument must be an integer\n"); exit(1); } if (rowId < 0) { fprintf(stderr, "Error passing a negative rowId\n"); exit(1); } char str[LEN]; snprintf(str, LEN, "%d", rowId); paramValues[0] = str; PGconn *conn = PQconnectdb("user=janbodnar dbname=testdb"); if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); do_exit(conn); } char *stm = "SELECT * FROM Cars WHERE Id=$1"; PGresult *res = PQexecParams(conn, stm, 1, NULL, paramValues, NULL, NULL, 0); if (PQresultStatus(res) != PGRES_TUPLES_OK) { printf("No data retrieved\n"); PQclear(res); do_exit(conn); } printf("%s %s %s\n", PQgetvalue(res, 0, 0), PQgetvalue(res, 0, 1), PQgetvalue(res, 0, 2)); PQclear(res); PQfinish(conn); return 0; }
The program takes a row Id as its argument. It fetches the data of the specified row and prints it. Since the program takes a value from a user, which cannot be trusted, we must sanitize the input data. A prepared statement is created with a PQexecParams()
function.
int rowId; int ret = sscanf(argv[1], "%d", &rowId);
The command line argument is stored in the rowId
variable. We expect an integer value.
char str[LEN]; snprintf(str, LEN, "%d", rowId); paramValues[0] = str;
The value is transformed into a string and passed to an array of characters. The paramValues
is a parameter of the PQexecParams()
function.
char *stm = "SELECT * FROM Cars WHERE Id=$1";
This is our SQL statement, which returns one row of the Cars table. The $1
is a placeholder, which is later filled with an actual value.
PGresult *res = PQexecParams(conn, stm, 1, NULL, paramValues, NULL, NULL, 0);
The PQexecParams()
function creates a prepared statement and executes it. The second parameter is the SQL statement. The third parameter is the number of parameters passed. Passing NULL to the fourth parameter means that the server should figure out the parameter types. The fifth parameter is a pointer to an array of strings containing parameters. The next two parameters are only relevant with binary parameters. Passing 0 to the final parameter we obtain result in text format, 1 in binary format.
printf("%s %s %s\n", PQgetvalue(res, 0, 0), PQgetvalue(res, 0, 1), PQgetvalue(res, 0, 2));
We print the three fields of the specified row.
$ ./prepared_statement 4 4 Volvo 29000
This is the output of the example.
Metadata
Metadata is information about the data in the database. The following belongs to metadata: information about the tables and columns in which we store data, the number of rows affected by an SQL statement, or the number of rows and columns returned in a result set.
Column headers
In the first example, we print column headers.
column_headers.c
#include <stdio.h> #include <stdlib.h> #include <libpq-fe.h> void do_exit(PGconn *conn) { PQfinish(conn); exit(1); } int main() { PGconn *conn = PQconnectdb("user=janbodnar dbname=testdb"); if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); do_exit(conn); } PGresult *res = PQexec(conn, "SELECT * FROM Cars WHERE Id=0"); if (PQresultStatus(res) != PGRES_TUPLES_OK) { printf("No data retrieved\n"); PQclear(res); do_exit(conn); } int ncols = PQnfields(res); printf("There are %d columns\n", ncols); printf("The column names are:\n"); for (int i=0; i<ncols; i++) { char *name = PQfname(res, i); printf("%s\n", name); } PQclear(res); PQfinish(conn); return 0; }
The example prints the number of available columns and their names to the console.
PGresult *res = PQexec(conn, "SELECT * FROM Cars WHERE Id=0");
In the SQL statement, we select all columns of a row.
int ncols = PQnfields(res);
The PQnfields
function returns the number of columns in the row of the query result.
char *name = PQfname(res, i);
The PQfname()
function returns the column name associated with the given column number.
$ ./column_headers There are 3 columns The column names are: id name price
This is the output of the example.
Listing tables
The PostgreSQL's information schema consists of a set of views that contain information about the objects defined in the current database. The tables
view contains all tables and views defined in the current database.
list_tables.c
#include <stdio.h> #include <stdlib.h> #include <libpq-fe.h> void do_exit(PGconn *conn) { PQfinish(conn); exit(1); } int main() { PGconn *conn = PQconnectdb("user=janbodnar dbname=testdb"); if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); do_exit(conn); } PGresult *res = PQexec(conn, "SELECT table_name FROM information_schema.tables " "WHERE table_schema = 'public'"); if (PQresultStatus(res) != PGRES_TUPLES_OK) { printf("No data retrieved\n"); PQclear(res); do_exit(conn); } int rows = PQntuples(res); for(int i=0; i<rows; i++) { printf("%s\n", PQgetvalue(res, i, 0)); } PQclear(res); PQfinish(conn); return 0; }
The example prints all the tables in the testdb
database.
PGresult *res = PQexec(conn, "SELECT table_name FROM information_schema.tables " "WHERE table_schema = 'public'");
This SQL statement selects all tables from the current database.
int rows = PQntuples(res); for(int i=0; i<rows; i++) { printf("%s\n", PQgetvalue(res, i, 0)); }
The tables are printed to the console.
$ ./list_tables cars authors books
The list_tables
program prints available tables in the testdb
database.
Transactions
A transaction is an atomic unit of database operations against the data in one or more databases. SQL statements in a transaction can be either all committed to the database or all rolled back. SQL statements are put into transactions for data safety and integrity.
PostgreSQL operates in the autocommit mode. Every SQL statement is executed within a transaction: each individual statement has an implicit BEGIN
and (if successful) COMMIT
wrapped around it.
An explicit transaction is started with the BEGIN
command and ended with the COMMIT
command.
transaction.c
#include <stdio.h> #include <stdlib.h> #include <libpq-fe.h> void do_exit(PGconn *conn) { PQfinish(conn); exit(1); } int main() { PGconn *conn = PQconnectdb("user=janbodnar dbname=testdb"); if (PQstatus(conn) == CONNECTION_BAD) { fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn)); do_exit(conn); } PGresult *res = PQexec(conn, "BEGIN"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { printf("BEGIN command failed\n"); PQclear(res); do_exit(conn); } PQclear(res); res = PQexec(conn, "UPDATE Cars SET Price=23700 WHERE Id=8"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { printf("UPDATE command failed\n"); PQclear(res); do_exit(conn); } res = PQexec(conn, "INSERT INTO Cars VALUES(9,'Mazda',27770)"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { printf("INSERT command failed\n"); PQclear(res); do_exit(conn); } res = PQexec(conn, "COMMIT"); if (PQresultStatus(res) != PGRES_COMMAND_OK) { printf("COMMIT command failed\n"); PQclear(res); do_exit(conn); } PQclear(res); PQfinish(conn); return 0; }
In the example, we update the price of a car and insert a new car. The two operations are included in a single transaction. This means that either both operations are executed or none.
PGresult *res = PQexec(conn, "BEGIN");
A transaction is started with the BEGIN
command.
res = PQexec(conn, "UPDATE Cars SET Price=23700 WHERE Id=8");
We update the price of a car with Id 8.
res = PQexec(conn, "INSERT INTO Cars VALUES(9,'Mazda',27770)");
A new car is inserted into the Cars
table.
res = PQexec(conn, "COMMIT");
The transaction is committed with the COMMIT
command.
This was PostgreSQL C API tutorial. You may be also interested in PostgreSQL Python tutorial , PostgreSQL PHP tutorial , SQLite C tutorial , or MySQL C tutorial on ZetCode.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论