Skip to content

17. استخدام SGBD و PostgreSQL

برنامج SGBD PostgreSQL متاح مجانًا. وهو بديل عن الإصدار «المجتمعي» من MySQL.

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

مع SGBD وMySQL، كانت بنية نصوصنا البرمجية كما يلي:

مع SGBD و PostgreSQL، ستكون كما يلي:

Image

17.1. تثبيت SGBD PostgreSQL

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

Image

Image

  • في [1-4]، يتم تنزيل أداة التثبيت من SGBD؛

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

Image

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

Image

  • في [8]، الخيار [Stack Builder] غير ضروري لما نريد القيام به هنا؛
  • في [10]، اترك القيمة التي ستظهر لك؛

Image

  • في [12-13]، تم إدخال كلمة المرور [root] هنا. وستكون هذه كلمة مرور المسؤول في SGBD الذي يُسمى [postgres]. يُطلق عليه أيضًا اسم «المستخدم المتميز» في PostgreSQL؛
  • في [15]، اترك القيمة الافتراضية: فهذا هو منفذ الاستماع الخاص بـ SGBD؛

Image

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

Image

Image

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

Image

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

Image

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

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

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

قم بتشغيل خدمة Windows الخاصة بـ SGBD PostgreSQL (الفقرة السابقة). ثم بنفس الطريقة التي قمت بها بتشغيل الأداة [services]، قم بتشغيل الأداة [pgadmin] التي تتيح إدارة SGBD و PostgreSQL و [1-3]:

Image

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

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

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

Image

Image

  • في [17]، تم إدخال [nobody]؛

Image

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

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

Image

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

Image

  • في [30]، رمز إنشاء قاعدة البيانات SQL؛
  • إلى [31]، وبعد التحقق من صحة المساعد [Save]، يتم إنشاء قاعدة البيانات [dbpersonnes

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

17.3. تثبيت موصل Python الخاص بـ SGBD PostgreSQL

Image

يُظهر المخطط أعلاه موصلًا يربط بين نصوص Python وقاعدة البيانات SGBD و 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] (انظر الفقرة |النص البرمجي [mysql-04]: تنفيذ ملف أوامر SQL|). يتم تغيير الاستيرادات:

بدلاً من:


# عمليات الاستيراد
from mysql.connector import DatabaseError, InterfaceError
from mysql.connector.connection import MySQLConnection
from mysql.connector.cursor import MySQLCursor

نكتب:


# عمليات الاستيراد
from psycopg2 import DatabaseError, InterfaceError
from psycopg2.extensions import connection, cursor

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


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] (انظر الفقرة |البرنامج النصي [mysql-01]: الاتصال بقاعدة بيانات MySQL - 1|). يتم إجراء التعديلات التالية عليه:

بدلاً من:


# استيراد الوحدة النمطية mysql.connector
from mysql.connector import connect, DatabaseError, InterfaceError

نكتب:


# استيراد الوحدة النمطية psycopg2
from psycopg2 import connect, DatabaseError, InterfaceError

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

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

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

بدلاً من:


# استيراد المكون mysql.connector
from mysql.connector import DatabaseError, InterfaceError, connect

نكتب:


# استيراد المكتبة psycopg2
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] هو التالي:


# استيراد المكتبة mysql.connector
from psycopg2 import DatabaseError, InterfaceError, connect


# ---------------------------------------------------------------------------------
def connexion(host: str, database: str, login: str, pwd: str):
    # تقوم بتسجيل الدخول ثم تسجيل الخروج (login,pwd) من قاعدة البيانات [database] على الخادم [host]
    # يطلق الاستثناء DatabaseError في حالة وجود مشكلة
    connexion = None
    try:
        # تسجيل الدخول
        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:
        # يتم إغلاق الاتصال إذا كان قد تم فتحه
        if connexion:
            connexion.close()
            print("Déconnexion réussie\n")


# ---------------------------------------------- main
# بيانات اعتماد الاتصال
USER = "admpersonnes"
PASSWD = "nobody"
HOST = "localhost"
DATABASE = "dbpersonnes"

# تسجيل دخول مستخدم موجود
try:
    connexion(host=HOST, login=USER, pwd=PASSWD, database=DATABASE)
except (InterfaceError, DatabaseError) as erreur:
    # يتم عرض الخطأ
    print(erreur)

# تسجيل دخول مستخدم غير موجود
try:
    connexion(host=HOST, login="xx", pwd="yy", database=DATABASE)
except (InterfaceError, DatabaseError) as erreur:
    # يتم عرض الخطأ
    print(erreur)

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

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


# تسجيل دخول مستخدم غير موجود
try:
    connexion(host=HOST, login="xx", pwd="yy", database=DATABASE)
except (InterfaceError, DatabaseError) as erreur:
    # يتم عرض الخطأ
    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

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

Image

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

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


# يتم استرداد إعدادات التطبيق
import config_04

config = config_04.configure()

# تم تكوين syspath - يمكن إجراء عمليات الاستيراد
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: كان لا بد من تعديل أمر حذف الجدول [personnes]. على عكس الموصل MySQL، فإن الموصل PostgreSQL يطلق استثناءً إذا كان الجدول المراد حذفه غير موجود. يوجد لأمر [drop table] متغير [drop table if exists] الذي لا يطلق استثناءً في حالة عدم وجود الجدول. وقد استخدمناه هنا. وهذا مثال يوضح أن أمرين من نوع SGBD لا يتصرفان بنفس الطريقة في مواقف مماثلة؛

الجدول [personnes] في الأداة [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

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

Image

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

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

ويكمن الاختلاف في الطرق المختلفة التي يستخدمها هذان البرنامجان SGBD لإلغاء المعاملة:

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

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

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

بدلاً من:


# عمليات الاستيراد
from mysql.connector import connect, DatabaseError, InterfaceError

نكتب:


# عمليات الاستيراد
from psycopg2 import connect, DatabaseError, InterfaceError

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

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

Image

17.5. الخلاصة

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