Using the Python Library PyGreSQL to Connect to a DWS Cluster
You can use the Python library PyGreSQL to connect to a DWS cluster you have created, access DWS using Python, and perform operations on data tables, such as creating tables, inserting data, querying data, updating data, and deleting data.
Application Scenarios
PyGreSQL applies to the following scenarios:
-
You want to use the data analysis or processing scripts developed using Python to operate data in DWS.
- You want to connect existing Python applications to DWS and reuse the mature capabilities of the PyGreSQL ecosystem.
- You want to use Python to create data tables or add, delete, modify, or query data.
Example: Data engineers can use Python scripts to query and process service data in batches from DWS or write analysis results to DWS in batches through PyGreSQL.
Preparations Before Connecting to a Cluster
Before connecting to a cluster, ensure that you have completed the following preparations:
- You have created a DWS cluster and bound an EIP to the cluster.
- You have obtained the administrator username and password for logging in to the database in the DWS cluster.
- The MD5 algorithm has collision risks. By default, MD5 password verification is not allowed by DWS. If an authentication failure is displayed when you use an open-source client to connect to the cluster, the most likely cause is that the client uses MD5 authentication. In this case, perform the following steps:
- Contact technical support to check whether the value of the database parameter password_encryption_type is 1. If the value is not 1, change it to 1.
- Change the password of the database user to be used or create another database user.
- The database stores the hash digest of passwords instead of password text. During password verification, the system compares the hash digest with the password digest sent from the client (salt operations are involved). If the cryptographic algorithm policy changes, the database cannot automatically generate a digest of the password based on the new algorithm. In this case, you must change the password or create another user. A digest will then be generated for the new password based on the new algorithm for the next connection authentication.
- The MD5 algorithm has collision risks. By default, MD5 password verification is not allowed by DWS. If an authentication failure is displayed when you use an open-source client to connect to the cluster, the most likely cause is that the client uses MD5 authentication. In this case, perform the following steps:
- You have obtained the public IP address and port number of the DWS cluster. For details, see Obtaining the Connection Address of a DWS Cluster.
Installing PyGreSQL
Download PyGreSQL from https://pygresql.org/download/index.html and install it by referring to https://pygresql.org/contents/install.html. The installation methods for different OSs are as follows:
- In CentOS and Red Hat OS, run the following yum command:
1yum install PyGreSQL
- PyGreSQL depends on the libpq dynamic library of PostgreSQL (32-bit or 64-bit version, whichever matches the PyGreSQL bit version). In Linux, you can run the yum command and do not need to install the library. In Windows, you can install libpq using either of the following methods:
- Install PostgreSQL and add the directories of the libpq, SSL, and crypto dynamic libraries to the environment variable PATH.
- Install psqlodbc and use the libpq, SSL, and crypto dynamic libraries provided by the PostgreSQL ODBC driver.
Constraints
PyGreSQL is a PostgreSQL-based client interface, and its functions are not fully supported by DWS. For details, see Table 1. The following APIs are supported based on Python 3.8.5 and PyGreSQL 5.2.4.
| PyGreSQL | Yes | Remarks | |
|---|---|---|---|
| Module functions and constants | connect – Open a PostgreSQL connection | Y | - |
| get_pqlib_version – get the version of pqlib | Y | - | |
| get/set_defhost – default server host [DV] | Y | - | |
| get/set_defport – default server port [DV] | Y | - | |
| get/set_defopt – default connection options [DV] | Y | - | |
| get/set_defbase – default database name [DV] | Y | - | |
| get/set_defuser – default database user [DV] | Y | - | |
| get/set_defpasswd – default database password [DV] | Y | - | |
| escape_string – escape a string for use within SQL | Y | - | |
| escape_bytea – escape binary data for use within SQL | Y | - | |
| unescape_bytea – unescape data that has been retrieved as text | Y | - | |
| get/set_namedresult – conversion to named tuples | Y | - | |
| get/set_decimal – decimal type to be used for numeric values | Y | - | |
| get/set_decimal_point – decimal mark used for monetary values | Y | - | |
| get/set_bool – whether boolean values are returned as bool objects | Y | - | |
| get/set_array – whether arrays are returned as list objects | Y | - | |
| get/set_bytea_escaped – whether bytea data is returned escaped | Y | - | |
| get/set_jsondecode – decoding JSON format | Y | - | |
| get/set_cast_hook – fallback typecast function | Y | - | |
| get/set_datestyle – assume a fixed date style | Y | - | |
| get/set_typecast – custom typecasting | Y | - | |
| cast_array/record – fast parsers for arrays and records | Y | - | |
| Type helpers | Y | - | |
| Module constants | Y | - | |
| Connection – The connection object | query – execute a SQL command string | Y | - |
| send_query - executes a SQL command string asynchronously | Y | - | |
| query_prepared – execute a prepared statement | Y | - | |
| prepare – create a prepared statement | Y | - | |
| describe_prepared – describe a prepared statement | Y | - | |
| reset – reset the connection | Y | - | |
| poll - completes an asynchronous connection | Y | - | |
| cancel – abandon processing of current SQL command | Y | - | |
| close – close the database connection | Y | - | |
| transaction – get the current transaction state | Y | - | |
| parameter – get a current server parameter setting | Y | - | |
| date_format – get the currently used date format | Y | - | |
| fileno – get the socket used to connect to the database | Y | - | |
| set_non_blocking - set the non-blocking status of the connection | Y | - | |
| is_non_blocking - report the blocking status of the connection | Y | - | |
| getnotify – get the last notify from the server | N | The database does not support listen/notify. | |
| inserttable – insert a list into a table | Y | Use double quotation marks ("") to quote \n in the copy command. | |
| get/set_notice_receiver – custom notice receiver | Y | - | |
| putline – write a line to the server socket [DA] | Y | - | |
| getline – get a line from server socket [DA] | Y | - | |
| endcopy – synchronize client and server [DA] | Y | - | |
| locreate – create a large object in the database [LO] | N | Operations related to large objects | |
| getlo – build a large object from given oid [LO] | N | Operations related to large objects | |
| loimport – import a file to a large object [LO] | N | Operations related to large objects | |
| Object attributes | Y | - | |
| The DB wrapper class | Initialization | Y | - |
| pkey – return the primary key of a table | Y | - | |
| get_databases – get list of databases in the system | Y | - | |
| get_relations – get list of relations in connected database | Y | - | |
| get_tables – get list of tables in connected database | Y | - | |
| get_attnames – get the attribute names of a table | Y | - | |
| has_table_privilege – check table privilege | Y | - | |
| get/set_parameter – get or set run-time parameters | Y | - | |
| begin/commit/rollback/savepoint/release – transaction handling | Y | - | |
| get – get a row from a database table or view | Y | - | |
| insert – insert a row into a database table | Y | - | |
| update – update a row in a database table | Y | - | |
| upsert – insert a row with conflict resolution | Y | - | |
| query – execute a SQL command string | Y | - | |
| query_formatted – execute a formatted SQL command string | Y | - | |
| query_prepared – execute a prepared statement | Y | - | |
| prepare – create a prepared statement | Y | - | |
| describe_prepared – describe a prepared statement | Y | - | |
| delete_prepared – delete a prepared statement | Y | - | |
| clear – clear row values in memory | Y | - | |
| delete – delete a row from a database table | Y | A tuple must have unique key or primary key. | |
| truncate – quickly empty database tables | Y | - | |
| get_as_list/dict – read a table as a list or dictionary | Y | - | |
| escape_literal/identifier/string/bytea – escape for SQL | Y | - | |
| unescape_bytea – unescape data retrieved from the database | Y | - | |
| encode/decode_json – encode and decode JSON data | Y | - | |
| use_regtypes – determine use of regular type names | Y | - | |
| notification_handler – create a notification handler | N | The database does not support listen/notify. | |
| Attributes of the DB wrapper class | Y | - | |
| Query methods | getresult – get query values as list of tuples | Y | - |
| dictresult/dictiter – get query values as dictionaries | Y | - | |
| namedresult/namediter – get query values as named tuples | Y | - | |
| scalarresult/scalariter – get query values as scalars | Y | - | |
| one/onedict/onenamed/onescalar – get one result of a query | Y | - | |
| single/singledict/singlenamed/singlescalar – get single result of a query | Y | - | |
| listfields – list fields names of previous query result | Y | - | |
| fieldname, fieldnum – field name/number conversion | Y | - | |
| fieldinfo – detailed info about query result fields | Y | - | |
| ntuples – return number of tuples in query object | Y | - | |
| memsize – return number of bytes allocated by query result | Y | - | |
| LargeObject – Large Objects | open – open a large object | N | Operations related to large objects |
| close – close a large object | N | Operations related to large objects | |
| read, write, tell, seek, unlink – file-like large object handling | N | Operations related to large objects | |
| size – get the large object size | N | Operations related to large objects | |
| export – save a large object to a file | N | Operations related to large objects | |
| Object attributes | N | Operations related to large objects | |
| The Notification Handler | Instantiating the notification handler | N | The database does not support listen/notify. |
| Invoking the notification handler | N | The database does not support listen/notify. | |
| Sending notifications | N | The database does not support listen/notify. | |
| Auxiliary methods | N | The database does not support listen/notify. | |
| pgdb | |||
| Module functions and constants | connect – Open a PostgreSQL connection | Y | - |
| get/set/reset_typecast – Control the global typecast functions | Y | - | |
| Module constants | Y | - | |
| Errors raised by this module | Y | - | |
| Connection – The connection object | close – close the connection | Y | - |
| commit – commit the connection | Y | - | |
| rollback – roll back the connection | Y | - | |
| cursor – return a new cursor object | Y | - | |
| Attributes that are not part of the standard | Y | - | |
| Cursor – The cursor object | description – details regarding the result columns | Y | - |
| rowcount – number of rows of the result | Y | - | |
| close – close the cursor | Y | - | |
| execute – execute a database operation | Y | - | |
| executemany – execute many similar database operations | Y | - | |
| callproc – Call a stored procedure | Y | - | |
| fetchone – fetch next row of the query result | Y | - | |
| fetchmany – fetch next set of rows of the query result | Y | - | |
| fetchall – fetch all rows of the query result | Y | - | |
| arraysize - the number of rows to fetch at a time | Y | - | |
| Methods and attributes that are not part of the standard | Y | - | |
| Type – Type objects and constructors | Type constructors | Y | - |
| Type objects | Y | - | |
Using the Third-Party Function Library PyGreSQL to Connect to a Cluster (Linux)
- Log in to the Linux environment as user root.
- Run the following command to create the python_dws.py file:
1vi python_dws.py
Copy and paste the following content to the python_dws.py file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
#!/usr/bin/env python3 # _*_ encoding:utf-8 _*_ from __future__ import print_function import pg def create_table(connection): print("Begin to create table") try: connection.query("drop table if exists test;" "create table test(id int, name text);") except pg.InternalError as e: print(e) else: print("Table created successfully") def insert_data(connection): print("Begin to insert data") try: connection.query("insert into test values(1,'number1');") connection.query("insert into test values(2,'number2');") connection.query("insert into test values(3,'number3');") except pg.InternalError as e: print(e) else: print("Insert data successfully") def update_data(connection): print("Begin to update data") try: result = connection.query("update test set name = 'numberupdated' where id=1;") print("Total number of rows updated:", result) result = connection.query("select * from test order by 1;") rows = result.getresult() for row in rows: print("id = ", row[0]) print("name = ", row[1], "\n") except pg.InternalError as e: print(e) else: print("After Update, Operation done successfully") def delete_data(connection): print("Begin to delete data") try: result = connection.query("delete from test where id=3;") print("Total number of rows deleted:", result) result = connection.query("select * from test order by 1;") rows = result.getresult() for row in rows: print("id = ", row[0]) print("name = ", row[1], "\n") except pg.InternalError as e: print(e) else: print("After Delete,Operation done successfully") def select_data(connection): print("Begin to select data") try: result = connection.query("select * from test order by 1;") rows = result.getresult() for row in rows: print("id = ", row[0]) print("name = ", row[1]) except pg.InternalError as e: print(e) print("select failed") else: print("Operation done successfully") if __name__ == '__main__': try: conn = pg.DB(host='10.154.70.231', port=8000, dbname='gaussdb', # Database to be connected user='dbadmin', passwd='password') # Database user password except pg.InternalError as ex: print(ex) print("Connect database failed") else: print("Opened database successfully") create_table(conn) insert_data(conn) select_data(conn) update_data(conn) delete_data(conn) conn.close()
Alternatively, use the dbapi interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
#!/usr/bin/python # -*- coding: UTF-8 -*- from __future__ import print_function import pg import pgdb def create_table(connection): print("Begin to create table") try: cursor = connection.cursor() cursor.execute("drop table if exists test;" "create table test(id int, name text);") connection.commit() except pg.InternalError as e: print(e) else: print("Table created successfully") cursor.close() def insert_data(connection): print("Begin to insert data") try: cursor = connection.cursor() cursor.execute("insert into test values(1,'number1');") cursor.execute("insert into test values(2,'number2');") cursor.execute("insert into test values(3,'number3');") connection.commit() except pg.InternalError as e: print(e) else: print("Insert data successfully") cursor.close() def update_data(connection): print("Begin to update data") try: cursor = connection.cursor() cursor.execute("update test set name = 'numberupdated' where id=1;") connection.commit() print("Total number of rows updated :", cursor.rowcount) cursor.execute("select * from test;") rows = cursor.fetchall() for row in rows: print("id = ", row[0]) print("name = ", row[1], "\n") except pg.InternalError as e: print(e) else: print("After Update, Operation done successfully") def delete_data(connection): print("Begin to delete data") try: cursor = connection.cursor() cursor.execute("delete from test where id=3;") connection.commit() print("Total number of rows deleted :", cursor.rowcount) cursor.execute("select * from test;") rows = cursor.fetchall() for row in rows: print("id = ", row[0]) print("name = ", row[1], "\n") except pg.InternalError as e: print(e) else: print("After Delete,Operation done successfully") def select_data(connection): print("Begin to select data") try: cursor = connection.cursor() cursor.execute("select * from test;") rows = cursor.fetchall() for row in rows: print("id = ", row[0]) print("name = ", row[1], "\n") except pg.InternalError as e: print(e) print("select failed") else: print("Operation done successfully") cursor.close() if __name__ == '__main__': try: conn = pgdb.connect(host='10.154.70.231', port='8000', database='gaussdb', # Database to be connected user='dbadmin', password='password') # Database user password except pg.InternalError as ex: print(ex) print("Connect database failed") else: print("Opened database successfully") create_table(conn) insert_data(conn) select_data(conn) update_data(conn) delete_data(conn) conn.close()
- Change the public IP address, port number, database name, database username, and database password of the cluster in the python_dws.py file based on the actual cluster information. The PyGreSQL API does not provide the connection retry capability. You need to implement the retry processing in the service code.
1 2 3 4 5
conn = pgdb.connect(host='10.154.70.231', port='8000', database='gaussdb', # Database to be connected user='dbadmin', password='password') # Database user password
Table 2 Parameters for connecting to a cluster Parameter
Description
host
Public IP address (EIP) for accessing the DWS cluster. Replace it with the actual address. For how to obtain the address, see Table 4.
port
Database port number of the DWS cluster. The default port number is 8000.
database
Name of the database to connect to. The default database is gaussdb.
user
Database username. The default database administrator is dbadmin.
password
Password of the database user. Replace it with the actual password.
- Run the following command to connect to the cluster using the third-party function library PyGreSQL:
1python python_dws.py
- If the command output indicates that the database is successfully connected and messages indicating successful table creation, data insertion, query, update, and deletion are displayed in sequence, the database connection is normal and the operations on data tables have been successfully executed.
Using the Third-Party Function Library PyGreSQL to Connect to a Cluster (Windows)
- In the Windows operating system, click Start, enter cmd in the search box, and click cmd.exe in the result list to open the command-line interface (CLI).
- In the CLI, run the following command to create the python_dws.py file:
1type nul> python_dws.py
Copy and paste the following content to the python_dws.py file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
#!/usr/bin/env python3 # _*_ encoding:utf-8 _*_ from __future__ import print_function import pg def create_table(connection): print("Begin to create table") try: connection.query("drop table if exists test;" "create table test(id int, name text);") except pg.InternalError as e: print(e) else: print("Table created successfully") def insert_data(connection): print("Begin to insert data") try: connection.query("insert into test values(1,'number1');") connection.query("insert into test values(2,'number2');") connection.query("insert into test values(3,'number3');") except pg.InternalError as e: print(e) else: print("Insert data successfully") def update_data(connection): print("Begin to update data") try: result = connection.query("update test set name = 'numberupdated' where id=1;") print("Total number of rows updated:", result) result = connection.query("select * from test order by 1;") rows = result.getresult() for row in rows: print("id = ", row[0]) print("name = ", row[1], "\n") except pg.InternalError as e: print(e) else: print("After Update, Operation done successfully") def delete_data(connection): print("Begin to delete data") try: result = connection.query("delete from test where id=3;") print("Total number of rows deleted:", result) result = connection.query("select * from test order by 1;") rows = result.getresult() for row in rows: print("id = ", row[0]) print("name = ", row[1], "\n") except pg.InternalError as e: print(e) else: print("After Delete,Operation done successfully") def select_data(connection): print("Begin to select data") try: result = connection.query("select * from test order by 1;") rows = result.getresult() for row in rows: print("id = ", row[0]) print("name = ", row[1]) except pg.InternalError as e: print(e) print("select failed") else: print("Operation done successfully") if __name__ == '__main__': try: conn = pg.DB(host='10.154.70.231', port=8000, dbname='gaussdb', # Database to be connected user='dbadmin', passwd='password') # Database user password except pg.InternalError as ex: print(ex) print("Connect database failed") else: print("Opened database successfully") create_table(conn) insert_data(conn) select_data(conn) update_data(conn) delete_data(conn) conn.close()
Alternatively, use the dbapi interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
#!/usr/bin/python # -*- coding: UTF-8 -*- from __future__ import print_function import pg import pgdb def create_table(connection): print("Begin to create table") try: cursor = connection.cursor() cursor.execute("drop table if exists test;" "create table test(id int, name text);") connection.commit() except pg.InternalError as e: print(e) else: print("Table created successfully") cursor.close() def insert_data(connection): print("Begin to insert data") try: cursor = connection.cursor() cursor.execute("insert into test values(1,'number1');") cursor.execute("insert into test values(2,'number2');") cursor.execute("insert into test values(3,'number3');") connection.commit() except pg.InternalError as e: print(e) else: print("Insert data successfully") cursor.close() def update_data(connection): print("Begin to update data") try: cursor = connection.cursor() cursor.execute("update test set name = 'numberupdated' where id=1;") connection.commit() print("Total number of rows updated :", cursor.rowcount) cursor.execute("select * from test;") rows = cursor.fetchall() for row in rows: print("id = ", row[0]) print("name = ", row[1], "\n") except pg.InternalError as e: print(e) else: print("After Update, Operation done successfully") def delete_data(connection): print("Begin to delete data") try: cursor = connection.cursor() cursor.execute("delete from test where id=3;") connection.commit() print("Total number of rows deleted :", cursor.rowcount) cursor.execute("select * from test;") rows = cursor.fetchall() for row in rows: print("id = ", row[0]) print("name = ", row[1], "\n") except pg.InternalError as e: print(e) else: print("After Delete,Operation done successfully") def select_data(connection): print("Begin to select data") try: cursor = connection.cursor() cursor.execute("select * from test;") rows = cursor.fetchall() for row in rows: print("id = ", row[0]) print("name = ", row[1], "\n") except pg.InternalError as e: print(e) print("select failed") else: print("Operation done successfully") cursor.close() if __name__ == '__main__': try: conn = pgdb.connect(host='10.154.70.231', port='8000', database='gaussdb', # Database to be connected user='dbadmin', password='password') # Database user password except pg.InternalError as ex: print(ex) print("Connect database failed") else: print("Opened database successfully") create_table(conn) insert_data(conn) select_data(conn) update_data(conn) delete_data(conn) conn.close()
- Change the public IP address, port number, database name, database username, and database password of the cluster in the python_dws.py file based on the actual cluster information. For details about the parameters, see Table 2.
The PyGreSQL API does not provide the connection retry capability. You need to implement the retry processing in the service code.
1 2 3 4 5
conn = pgdb.connect(host='10.154.70.231', port='8000', database='gaussdb', # Database to be connected user='dbadmin', password='password') # Database user password
- Run the following command to connect to the cluster using the third-party function library PyGreSQL:
1python python_dws.py
- If the command output indicates that the database is successfully connected and messages indicating successful table creation, data insertion, query, update, and deletion are displayed in sequence, the database connection is normal and the operations on data tables have been successfully executed.
What is your overall rating for this page?
Thank you very much for your feedback. We will continue working to improve the documentation.See the reply and handling status in My Cloud VOC.
For any further questions, feel free to contact us through the chatbot.
Chatbot