Skip to content

17. استخدام نظام إدارة قواعد البيانات PostgreSQL

نظام إدارة قواعد البيانات PostgreSQL متاح مجانًا. وهو بديل عن الإصدار "المجتمعي" من MySQL.

نستخدمه هنا لإثبات أنه من السهل جدًا ترحيل نصوص Python/MySQL إلى نصوص Python/PostgreSQL.

مع نظام إدارة قواعد البيانات MySQL، كانت بنية نصوصنا البرمجية كما يلي:

Image

مع نظام إدارة قواعد البيانات PostgreSQL، ستكون كما يلي:

Image

17.1. تثبيت نظام إدارة قواعد البيانات PostgreSQL

تتوفر توزيعات نظام إدارة قواعد البيانات PostgreSQL على الرابط [https://www.postgresql.org/download/] (مايو 2019). نعرض هنا تثبيت إصدار Windows 64 بت:

Image

Image

  • في [1-4]، قم بتنزيل أداة تثبيت نظام إدارة قواعد البيانات؛

قم بتشغيل برنامج التثبيت الذي تم تنزيله:

Image

  • في [6]، حدد دليل التثبيت؛

Image

  • في [8]، لا حاجة إلى خيار [Stack Builder] لما نقوم به هنا؛
  • في [10]، اترك القيمة الافتراضية؛

Image

  • في [12-13]، أدخلنا كلمة المرور [root] هنا. ستكون هذه كلمة المرور لمسؤول نظام إدارة قواعد البيانات (DBMS)، الذي يُسمى [postgres]. يُشير PostgreSQL إلى هذا أيضًا باسم المستخدم المتميز (superuser
  • في [15]، اترك القيمة الافتراضية: هذا هو منفذ الاستماع لنظام إدارة قواعد البيانات (DBMS

Image

  • في [17]، اترك القيمة الافتراضية؛
  • في [19]، ملخص تكوين التثبيت؛

Image

Image

في نظام Windows، يتم تثبيت نظام إدارة قواعد البيانات PostgreSQL كخدمة Windows تبدأ تلقائيًا. في معظم الأحيان، هذا غير مرغوب فيه. سنقوم بتعديل هذا التكوين. اكتب [services] في شريط البحث في Windows [24-26]:

Image

  • في [29]، يمكنك أن ترى أن خدمة نظام إدارة قواعد البيانات PostgreSQL مضبوطة على الوضع التلقائي. قم بتغيير هذا عن طريق الوصول إلى خصائص الخدمة [30]:

Image

  • في [31-32]، اضبط نوع بدء التشغيل على يدوي؛
  • في [33]، أوقف الخدمة؛

عندما ترغب في تشغيل نظام إدارة قواعد البيانات يدويًّا، عد إلى تطبيق [services]، وانقر بزر الماوس الأيمن على خدمة [postgresql] (34)، ثم قم بتشغيلها (35).

17.2. إدارة PostgreSQL باستخدام أداة [pgAdmin]

قم بتشغيل خدمة Windows لنظام إدارة قواعد البيانات PostgreSQL (انظر الفقرة السابقة). ثم، بنفس الطريقة التي قمت بها بتشغيل أداة [Services]، قم بتشغيل أداة [pgAdmin]، التي تتيح لك إدارة نظام إدارة قواعد البيانات PostgreSQL [1-3]:

Image

قد يُطلب منك إدخال كلمة مرور المستخدم المتميز في مرحلة ما. اسم المستخدم المتميز هو [postgres]. تقوم بتعيين كلمة المرور هذه أثناء تثبيت نظام إدارة قواعد البيانات. في هذا المستند، قمنا بتعيين كلمة المرور [root] للمستخدم المتميز أثناء التثبيت.

  • في [4]، [pgAdmin] هو تطبيق ويب؛
  • في [5]، قائمة خوادم PostgreSQL التي اكتشفها [pgAdmin]، وهنا 1؛
  • في [6]، خادم PostgreSQL الذي قمنا بتشغيله؛
  • في [7]، قواعد بيانات نظام إدارة قواعد البيانات (DBMS)، وهنا 1؛
  • في [8]، تتم إدارة قاعدة بيانات [postgresql] بواسطة المستخدم المتميز [postgres]؛

أولاً، لنقم بإنشاء مستخدم [admpersonnes] بكلمة مرور [nobody]:

Image

Image

  • في [17]، أدخلنا [nobody]؛

Image

  • في [21]، رمز SQL الذي سترسله أداة [pgAdmin] إلى نظام إدارة قواعد البيانات PostgreSQL. هذه طريقة لتعلم لغة SQL الخاصة بـ PostgreSQL؛
  • في [22]، بعد التأكيد باستخدام معالج [Save]، تم إنشاء المستخدم [admpersonnes]؛

الآن نقوم بإنشاء قاعدة البيانات [dbpersonnes]:

Image

انقر بزر الماوس الأيمن على [23]، ثم [24-25] لإنشاء قاعدة بيانات جديدة. في علامة التبويب [26]، حدد اسم قاعدة البيانات [27] ومالكها [admpersonnes] [28].

Image

  • في [30]، رمز SQL لإنشاء قاعدة البيانات؛
  • في [31]، بعد التأكيد باستخدام معالج [حفظ]، يتم إنشاء قاعدة البيانات [dbpersonnes]؛

سنستخدم قاعدة البيانات [dbpersonnes] مع نصوص Python.

17.3. تثبيت موصل Python لنظام إدارة قواعد البيانات PostgreSQL

Image

يوضح الرسم البياني أعلاه موصلًا يربط نصوص Python بنظام إدارة قواعد البيانات PostgreSQL. هناك العديد من الموصلات المتاحة. سنقوم بتثبيت موصل [psycopg2]. يتم ذلك في محطة Python (بغض النظر عن الدليل الذي تفتح فيه المحطة). يتم تثبيت الموصل باستخدام الأمر [pip install psycopg2]:


(venv) C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\troiscouches\v01\tests>pip install psycopg2
Collecting psycopg2
  Downloading psycopg2-2.8.5-cp38-cp38-win_amd64.whl (1.1 MB)
     || 1.1 MB 3.2 MB/s
Installing collected packages: psycopg2
Successfully installed psycopg2-2.8.5

17.4. تحويل نصوص MySQL إلى نصوص PostgreSQL

Image

  • يتم نسخ المجلد [1] الذي يحتوي على نصوص MySQL (Ctrl-C / Ctrl-V)، ثم يتم تغيير أسماء الملفات لتتوافق مع محتوياتها؛

17.4.1. [pgres_module]

هذه الوحدة هي نسخة من وحدة [mysql_module] (انظر القسم |script [mysql-04]: تنفيذ ملف أمر SQL|). قم بتغيير الاستيرادات:

بدلاً من:

1
2
3
4
#  imports
from mysql.connector import DatabaseError, InterfaceError
from mysql.connector.connection import MySQLConnection
from mysql.connector.cursor import MySQLCursor

نكتب:

1
2
3
#  imports
from psycopg2 import DatabaseError, InterfaceError
from psycopg2.extensions import connection, cursor

كانت توقيعات دالة [display_info] كما يلي:


def afficher_infos(curseur: MySQLCursor):

وتصبح:


def afficher_infos(curseur: cursor)

كانت توقيعات دالة [execute_list_of_commands] كما يلي:


def execute_list_of_commands(connexion: MySQLConnection, sql_commands: list,
                             suivi: bool = False, arrêt: bool = True, with_transaction: bool = True)

أصبحت:


def execute_list_of_commands(connexion: connection, sql_commands: list,
                             suivi: bool = False, arrêt: bool = True, with_transaction: bool = True):

بخلاف ذلك، لا يتغير أي شيء آخر.

17.4.2. البرنامج النصي [pgres_01]

النص البرمجي [pgres_01] هو نسخة من النص البرمجي [mysql_01] (انظر القسم |script [mysql-01]: الاتصال بقاعدة بيانات MySQL - 1|). تم إجراء التغييرات التالية:

بدلاً من:

#  import module mysql.connector
from mysql.connector import connect, DatabaseError, InterfaceError

نكتب:

#  psycopg2 module import
from psycopg2 import connect, DatabaseError, InterfaceError

الباقي لم يتغير. النتائج هي نفسها كما في MySQL.

17.4.3. البرنامج النصي [pgres_02]

البرنامج النصي [pgres_02] هو نسخة من البرنامج النصي [mysql_02] (انظر القسم |script [mysql-02]: الاتصال بقاعدة بيانات MySQL - 2|). قم بإجراء التغييرات التالية:

بدلاً من:

#  import module mysql.connector
from mysql.connector import DatabaseError, InterfaceError, connect

نكتب:

#  psycopg2 module import
from psycopg2 import DatabaseError, InterfaceError, connect

النتائج تختلف عن تلك التي يظهرها البرنامج النصي [mysql_02]:

1
2
3
4
5
C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/databases/postgresql/pgres_02.py
Connexion MySQL réussie à la base database=dbpersonnes, host=localhost sous l'identité user=admpersonnes, passwd=nobody
Déconnexion MySQL réussie

Process finished with exit code 0

النص البرمجي [pgres_02] هو كما يلي:

#  import module mysql.connector
from psycopg2 import DatabaseError, InterfaceError, connect


# ---------------------------------------------------------------------------------
def connexion(host: str, database: str, login: str, pwd: str):
    #  connects then disconnects (login,pwd) from the [database] server [host]
    #  throws DatabaseError exception if problem occurs
    connexion = None
    try:
        #  connection
        connexion = connect(host=host, user=login, password=pwd, database=database)
        print(
            f"Connexion réussie à la base database={database}, host={host} sous l'identité user={login}, passwd={pwd}")
    finally:
        #  close the connection if it has been opened
        if connexion:
            connexion.close()
            print("Déconnexion réussie\n")


#  ---------------------------------------------- main
#  login credentials
USER = "admpersonnes"
PASSWD = "nobody"
HOST = "localhost"
DATABASE = "dbpersonnes"

#  existing user login
try:
    connexion(host=HOST, login=USER, pwd=PASSWD, database=DATABASE)
except (InterfaceError, DatabaseError) as erreur:
    #  error is displayed
    print(erreur)

#  non-existent user login
try:
    connexion(host=HOST, login="xx", pwd="yy", database=DATABASE)
except (InterfaceError, DatabaseError) as erreur:
    #  error is displayed
    print(erreur)

على الرغم من أنه كان من المفترض أن تعرض الأسطر 36–41 رسالة خطأ تشير إلى فشل الاتصال بنظام إدارة قواعد البيانات (DBMS)، إلا أنه لم يتم عرض أي شيء. في الواقع، عند إجراء مزيد من التحقيق، نرى أن الكود يدخل بالفعل إلى كتلة [except] في الأسطر 35–37، ولكن المتغير [error] يتم تعيينه إلى [None]. يحدث هذا مع الإصدار 2.8.4 من موصل [psycopg2].

يمكننا التغلب على هذه المشكلة عن طريق كتابة رسالة عامة ولكن أقل دقة:

1
2
3
4
5
6
#  non-existent user login
try:
    connexion(host=HOST, login="xx", pwd="yy", database=DATABASE)
except (InterfaceError, DatabaseError) as erreur:
    #  error is displayed
    print(f"Erreur de connexion à la base [{DATABASE}] par l'utilisateur [xx/yy]")

النتائج هي كما يلي:


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/databases/postgresql/pgres_02.py
Connexion réussie à la base database=dbpersonnes, host=localhost sous l'identité user=admpersonnes, passwd=nobody
Déconnexion réussie
 
Erreur de connexion à la base [dbpersonnes] par l'utilisateur [xx/yy]
 
Process finished with exit code 0

17.4.4. البرنامج النصي [pgres_03]

البرنامج النصي [pgres_03] هو نسخة من البرنامج النصي [mysql_03] (انظر القسم |البرنامج النصي [mysql-03]: إنشاء جدول MySQL|). تم إجراء التغييرات التالية عليه:

بدلاً من:


from mysql.connector import DatabaseError, InterfaceError, connect
from mysql.connector.connection import MySQLConnection

نكتب:


from psycopg2 import DatabaseError, InterfaceError, connect
from psycopg2.extensions import connection

بالإضافة إلى ذلك، توقيع دالة [execute_sql]، الذي كان:


def execute_sql(connexion: MySQLConnection, update: str):

أصبحت:


def execute_sql(connexion: connection, update: str):

يظل الباقي دون تغيير. والنتيجة هي كما يلي:


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/databases/postgresql/pgres_03.py
create table personnes (id int PRIMARY KEY, prenom varchar(30) NOT NULL, nom varchar(30) NOT NULL, age integer NOT NULL, unique(nom,prenom))  : requête réussie
 
Process finished with exit code 0

يمكنك التحقق من وجود جدول [people] باستخدام أداة الإدارة [pgAdmin]:

Image

17.4.5. البرنامج النصي [pgres_04]

البرنامج النصي [pgres_04] هو نسخة من البرنامج النصي [mysql_04] (انظر القسم |script [mysql-04]: تنفيذ ملف أوامر SQL|). ويستخدم الوحدة النمطية [pgres_module]:

1
2
3
4
5
6
7
8
9
#  retrieve application configuration
import config_04

config = config_04.configure()

#  syspath is configured - imports can be made
import sys
from pgres_module import execute_file_of_commands
from psycopg2 import connect, DatabaseError, InterfaceError

الباقي يبقى دون تغيير.

نقوم بإنشاء تكوين [pgres pgres-04 without_transaction] كما تم في القسم |script [mysql-04]: تنفيذ ملف أوامر SQL|. كما نقوم بإنشاء تكوين [pgres pgres-04 with_transaction].

يؤدي تنفيذ التكوين [pgres pgres-04 without_transaction] إلى النتائج التالية:


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/databases/postgresql/pgres_04.py false
--------------------------------------------------------------------
Exécution du fichier SQL C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\databases\postgresql/data/commandes.sql sans transaction
--------------------------------------------------------------------
[drop table if exists personnes] : Exécution réussie
nombre de lignes modifiées : -1
[create table personnes (id int primary key, prenom varchar(30) not null, nom varchar(30) not null, age integer not null, unique (nom,prenom))] : Exécution réussie
nombre de lignes modifiées : -1
[insert into personnes(id, prenom, nom, age) values(1, 'Paul','Langevin',48)] : Exécution réussie
nombre de lignes modifiées : 1
[insert into personnes(id, prenom, nom, age) values (2, 'Sylvie','Lefur',70)] : Exécution réussie
nombre de lignes modifiées : 1
[select prenom, nom, age from personnes] : Exécution réussie
prenom, nom, age,
*****************
('Paul', 'Langevin', 48)
('Sylvie', 'Lefur', 70)
*****************
xx : Erreur (ERREUR:  erreur de syntaxe sur ou près de « xx »
LINE 1: xx
        ^
)
[insert into personnes(id, prenom, nom, age) values (3, 'Pierre','Nicazou',35)] : Exécution réussie
nombre de lignes modifiées : 1
[insert into personnes(id, prenom, nom, age) values (4, 'Geraldine','Colou',26)] : Exécution réussie
nombre de lignes modifiées : 1
[insert into personnes(id, prenom, nom, age) values (5, 'Paulette','Girond',56)] : Exécution réussie
nombre de lignes modifiées : 1
[select prenom, nom, age from personnes] : Exécution réussie
prenom, nom, age,
*****************
('Paul', 'Langevin', 48)
('Sylvie', 'Lefur', 70)
('Pierre', 'Nicazou', 35)
('Geraldine', 'Colou', 26)
('Paulette', 'Girond', 56)
*****************
[select nom,prenom from personnes order by nom asc, prenom desc] : Exécution réussie
nom, prenom,
************
('Colou', 'Geraldine')
('Girond', 'Paulette')
('Langevin', 'Paul')
('Lefur', 'Sylvie')
('Nicazou', 'Pierre')
************
[select nom,prenom,age from personnes where age between 20 and 40 order by age desc, nom asc, prenom asc] : Exécution réussie
nom, prenom, age,
*****************
('Nicazou', 'Pierre', 35)
('Colou', 'Geraldine', 26)
*****************
[insert into personnes(id, prenom, nom, age) values(6, 'Josette','Bruneau',46)] : Exécution réussie
nombre de lignes modifiées : 1
[update personnes set age=47 where nom='Bruneau'] : Exécution réussie
nombre de lignes modifiées : 1
[select nom,prenom,age from personnes where nom='Bruneau'] : Exécution réussie
nom, prenom, age,
*****************
('Bruneau', 'Josette', 47)
*****************
[delete from personnes where nom='Bruneau'] : Exécution réussie
nombre de lignes modifiées : 1
[select nom,prenom,age from personnes where nom='Bruneau'] : Exécution réussie
nom, prenom, age,
*****************
*****************
--------------------------------------------------------------------
Exécution terminée
--------------------------------------------------------------------
Il y a eu 1 erreur(s)
xx : Erreur (ERREUR:  erreur de syntaxe sur ou près de « xx »
LINE 1: xx
        ^
)
 
Process finished with exit code 0
  • السطر 5: اضطررنا إلى تعديل الأمر لإسقاط الجدول [people]. على عكس موصل MySQL، يطلق موصل PostgreSQL استثناءً إذا كان الجدول المراد إسقاطه غير موجود. يحتوي الأمر [drop table] على متغير، وهو [drop table if existsالذي لا يطلق استثناءً إذا كان الجدول غير موجود. استخدمناه هنا. هذا مثال على أن نظامي إدارة قواعد البيانات لا يتصرفان بنفس الطريقة في مواقف مشابهة؛

جدول [people] في أداة [pgAdmin] هو كما يلي:

Image

يؤدي تشغيل التكوين [pgres pgres_04 with_transaction] إلى النتائج التالية:


C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\venv\Scripts\python.exe C:/Data/st-2020/dev/python/cours-2020/python3-flask-2020/databases/postgresql/pgres_04.py true
--------------------------------------------------------------------
Exécution du fichier SQL C:\Data\st-2020\dev\python\cours-2020\python3-flask-2020\databases\postgresql/data/commandes.sql avec transaction
--------------------------------------------------------------------
[drop table if exists personnes] : Exécution réussie
nombre de lignes modifiées : -1
[create table personnes (id int primary key, prenom varchar(30) not null, nom varchar(30) not null, age integer not null, unique (nom,prenom))] : Exécution réussie
nombre de lignes modifiées : -1
[insert into personnes(id, prenom, nom, age) values(1, 'Paul','Langevin',48)] : Exécution réussie
nombre de lignes modifiées : 1
[insert into personnes(id, prenom, nom, age) values (2, 'Sylvie','Lefur',70)] : Exécution réussie
nombre de lignes modifiées : 1
[select prenom, nom, age from personnes] : Exécution réussie
prenom, nom, age,
*****************
('Paul', 'Langevin', 48)
('Sylvie', 'Lefur', 70)
*****************
xx : Erreur (ERREUR:  erreur de syntaxe sur ou près de « xx »
LINE 1: xx
        ^
)
--------------------------------------------------------------------
Exécution terminée
--------------------------------------------------------------------
Il y a eu 1 erreur(s)
xx : Erreur (ERREUR:  erreur de syntaxe sur ou près de « xx »
LINE 1: xx
        ^
)
 
Process finished with exit code 0

جدول [people] في أداة [pgAdmin] هو كما يلي:

Image

هنا، تختلف النتيجة عن تلك التي تم الحصول عليها باستخدام MySQL. إذا قمنا بتشغيل البرامج النصية في نفس الظروف — أي بعد تشغيل البرنامج النصي بدون معاملة — نحصل على النتائج التالية:

  • مع MySQL، تكون الجدولة [people] فارغة؛
  • مع PostgreSQL، جدول [people] ليس فارغًا؛

يكمن الاختلاف في الطرق المختلفة التي يستخدمها هذان النظامان لإدارة قواعد البيانات (DBMS) في التراجع عن المعاملة:

  • لا يقوم MySQL بإلغاء أوامر [drop table] و [create table]. وينتهي بنا الأمر بجدول [people] فارغ؛
  • يقوم PostgreSQL بإلغاء أوامر [drop table] و[create table]. ويتم إعادة الجدول إلى الحالة التي كان عليها قبل تنفيذ البرنامج النصي ضمن معاملة؛

17.4.6. البرنامج النصي [pgres_05]

البرنامج النصي [pgres_05] هو نسخة من البرنامج النصي [mysql_05] (انظر القسم |البرنامج النصي [mysql-05]: استخدام الاستعلامات المعلمة|). تم تعديل البرنامج النصي على النحو التالي:

بدلاً من:

#  imports
from mysql.connector import connect, DatabaseError, InterfaceError

نكتب:

#  imports
from psycopg2 import connect, DatabaseError, InterfaceError

الباقي لم يتغير.

النتائج التي تم الحصول عليها في [pgAdmin] هي كما يلي:

Image

17.5. الخلاصة

كان تحويل نصوص MySQL إلى نصوص PostgreSQL سهلاً نسبيًا. وهذا استثناء. لا يدعم نظاما إدارة قواعد البيانات نفس قواعد التسمية لكائنات SQL (قواعد البيانات، الجداول، الأعمدة، القيود، أنواع البيانات، إلخ)، ولديهما امتدادات SQL غير متوافقة... لضمان تحويل بسيط، يجب الالتزام بمعيار SQL في كلتا الحالتين دون محاولة استخدام الامتدادات الخاصة بنظام إدارة قواعد البيانات. ويأتي ذلك على حساب الأداء.