الفرق بين المراجعتين ل"Python/sqlite3"

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث
 
(8 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة)
سطر 6: سطر 6:
  
 
كُتبت وحدة <code>sqlite3</code> من قبل Gerhard Häring، وتقدّم واجهة [[SQL]] متوافقة مع معايير DB-API 2.0 الموصوفة في [https://www.python.org/dev/peps/pep-0249 PEP 249].
 
كُتبت وحدة <code>sqlite3</code> من قبل Gerhard Häring، وتقدّم واجهة [[SQL]] متوافقة مع معايير DB-API 2.0 الموصوفة في [https://www.python.org/dev/peps/pep-0249 PEP 249].
 
+
==الاتصال بقاعدة بيانات SQLite==
== الاتصال بقاعدة بيانات SQLite ==
+
لاستخدام هذه الوحدة يجب إنشاء كائن اتصال <code>[[Python/sqlite3/Connection|Connection]]</code> يمثّل قاعدة البيانات. يبين المثال التالي طريقة استخدام الوحدة مع افتراض أن البيانات مخزّنة في ملف باسم <code>example.db</code>.<syntaxhighlight lang="python3">
لاستخدام هذه الوحدة يجب إنشاء كائن اتصال <code>Connection</code> يمثّل قاعدة البيانات. يبين المثال التالي طريقة استخدام الوحدة مع افتراض أن البيانات مخزّنة في ملف باسم <code>example.db</code>.
 
 
 
<syntaxhighlight lang="python3">
 
 
import sqlite3
 
import sqlite3
 
conn = sqlite3.connect('example.db')
 
conn = sqlite3.connect('example.db')
</syntaxhighlight>
+
</syntaxhighlight>يمكن كذلك استخدام الاسم الخاص <code>:memory:</code> لإنشاء قاعدة البيانات في ذاكرة الوصول العشوائي RAM.
  
يمكن كذلك استخدام الاسم الخاص <code>:memory:</code> لإنشاء قاعدة البيانات في ذاكرة الوصول العشوائي RAM.
+
بعد إجراء الاتصال مع قاعدة البيانات يمكن إنشاء كائن مؤشر <code>Cursor</code> واستدعاء التابع <code>[[Python/Cursor/execute|execute()‎]]</code> لتنفيذ أوامر [[SQL]]:<syntaxhighlight lang="python3">
 
 
بعد إجراء الاتصال مع قاعدة البيانات يمكن إنشاء كائن مؤشر <code>Cursor</code> واستدعاء التابع <code>[[Python/sqlite3/cursor/execute|execute()‎]]</code> لتنفيذ أوامر [[SQL]]:
 
 
 
<syntaxhighlight lang="python3">
 
 
c = conn.cursor()
 
c = conn.cursor()
  
سطر 41: سطر 34:
 
</syntaxhighlight>ستحتاج في العادة إلى استخدام القيم المخزّنة في متغيرات بايثون لإجراء [[SQL|عمليات SQL]]، ولكن عليك أن تتجنب استخدام [[Python/str|سلاسل بايثون النصية]] لإنشاء أوامر الاستعلام عن البيانات لأنّ ذلك غير آمن، إذ يكون برنامجك عرضة لهجمات حقن SQL.
 
</syntaxhighlight>ستحتاج في العادة إلى استخدام القيم المخزّنة في متغيرات بايثون لإجراء [[SQL|عمليات SQL]]، ولكن عليك أن تتجنب استخدام [[Python/str|سلاسل بايثون النصية]] لإنشاء أوامر الاستعلام عن البيانات لأنّ ذلك غير آمن، إذ يكون برنامجك عرضة لهجمات حقن SQL.
  
ينصح باستخدام معامل الاستبدال الخاصّ بواجهة DB-API، حيث يوضع الرمز <code>?</code> عوضًا عن القيم التي تريد إدراجها في جملة الاستعلام، ثم تزويد تابع <code>execute()‎</code> بمعامل ثانٍ يكون على هيئة [[Python/tuple|صفّ tuple]] يتضمّن تلك القيم حسب ترتيبها في جملة الاستعلام. (قد تستخدم وحدات قواعد البيانات الأخرى رموز مختلفة، مثل ‎<code>%s</code> أو ‎<code>:1</code>). فعلى سبيل المثال:
+
ينصح باستخدام معامل الاستبدال الخاصّ بواجهة DB-API، حيث يوضع الرمز <code>?</code> عوضًا عن القيم التي تريد إدراجها في جملة الاستعلام، ثم تزويد تابع<nowiki/>[[Python/Cursor/execute|<code>execute()‎</code>]]<nowiki/>بمعامل ثانٍ يكون على هيئة [[Python/tuple|صفّ tuple]] يتضمّن تلك القيم حسب ترتيبها في جملة الاستعلام. (قد تستخدم وحدات قواعد البيانات الأخرى رموز مختلفة، مثل ‎<code>%s</code> أو ‎<code>:1</code>). فعلى سبيل المثال:<syntaxhighlight lang="python3">
 
 
<syntaxhighlight lang="python3">
 
 
# لا تقم بهذا - هذا خطر.
 
# لا تقم بهذا - هذا خطر.
 
symbol = 'RHAT'
 
symbol = 'RHAT'
سطر 59: سطر 50:
 
             ]
 
             ]
 
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)
 
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)
</syntaxhighlight>
+
</syntaxhighlight>بعد تنفيذ جملة الاستعلام [[SQL/select|SELECT]] يمكن استرجاع البيانات إمّا عن طريق التعامل مع المؤشر كمكرِّر iterator، أو استدعاء التابع <code>[[Python/Cursor/fetchone|fetchone()]]‎</code> لاسترجاع صفّ row واحد فقط، أو استدعاء التابع <code>[[Python/Cursor/fetchall|fetchall()]]‎</code> للحصول على قائمة بالصفوف rows المطابقة.
 
 
بعد تنفيذ جملة الاستعلام [[SQL/select|SELECT]] يمكن استرجاع البيانات إمّا عن طريق التعامل مع المؤشر كمكرِّر iterator، أو استدعاء التابع <code>fetchone()‎</code> لاسترجاع صفّ row واحد فقط، أو استدعاء التابع <code>fetchall()‎</code> للحصول على قائمة بالصفوف rows المطابقة.
 
 
 
يستخدم المثال التالي طريقة المكرِّر:
 
  
<syntaxhighlight lang="python3">
+
يستخدم المثال التالي طريقة المكرِّر:<syntaxhighlight lang="python3">
 
>>> for row in c.execute('SELECT * FROM stocks ORDER BY price'):
 
>>> for row in c.execute('SELECT * FROM stocks ORDER BY price'):
 
         print(row)
 
         print(row)
سطر 74: سطر 61:
 
('2006-04-05', 'BUY', 'MSFT', 1000, 72.0)
 
('2006-04-05', 'BUY', 'MSFT', 1000, 72.0)
 
</syntaxhighlight>
 
</syntaxhighlight>
 
+
==ثوابت الوحدة sqlite==
== ثوابت الوحدة sqlite ==
 
 
 
 
تقدّم وحدة <code>sqlite</code> الثوابت التالية:
 
تقدّم وحدة <code>sqlite</code> الثوابت التالية:
 
+
===الثابت <code>sqlite3.version</code>===
=== الثابت <code>sqlite3.version</code> ===
 
 
رقم الإصدار الخاص بالوحدة -وليس مكتبة SQLite- على هيئة سلسلة نصية.
 
رقم الإصدار الخاص بالوحدة -وليس مكتبة SQLite- على هيئة سلسلة نصية.
 
+
===الثابت <code>sqlite3.version_info</code>===
=== الثابت <code>sqlite3.version_info</code> ===
 
 
رقم الإصدار الخاص بالوحدة -وليس مكتبة SQLite- على هيئة صفّ من الأعداد الصحيحة.
 
رقم الإصدار الخاص بالوحدة -وليس مكتبة SQLite- على هيئة صفّ من الأعداد الصحيحة.
 
+
===الثابت <code>sqlite3.sqlite_version</code>===
=== الثابت <code>sqlite3.sqlite_version</code> ===
 
 
رقم الإصدار الخاص بمكتبة SQLite في وقت التشغيل، على هيئة سلسلة نصية.
 
رقم الإصدار الخاص بمكتبة SQLite في وقت التشغيل، على هيئة سلسلة نصية.
 
+
===الثابت <code>sqlite3.sqlite_version_info</code>===
=== الثابت <code>sqlite3.sqlite_version_info</code> ===
 
 
رقم الإصدار الخاص بمكتبة SQLite في وقت التشغيل، على هيئة صفّ من الأعداد الصحيحة.
 
رقم الإصدار الخاص بمكتبة SQLite في وقت التشغيل، على هيئة صفّ من الأعداد الصحيحة.
 +
===الثابت <code>sqlite3.PARSE_DECLTYPES</code>===
 +
يستخدم هذا الثابت مع معامل <code>detect_types</code> في دالة <code>[[Python/sqlite3/connect|connect()]]‎</code>.
  
=== الثابت <code>sqlite3.PARSE_DECLTYPES</code> ===
+
تفسر وحدة <code>sqlite3</code> -عند تعيين قيمة لهذا الثابت- الأنواع المصرّح عنها لكل عمود تعيده. تفسّر الوحدة أول كلمة في النوع المصرّح عنه، أي تفسر النوع <code>"integer primary key"</code> إلى <code>"integer"</code>، والنوع <code>"number(10)‎"</code> إلى <code>"number"</code>. ثم تبحث الوحدة في قاموس المحوّلات عن الدالة المحوّلة المسجَّلة لذلك النوع.
يستخدم هذا الثابت مع معامل <code>detect_types</code> في دالة <code>connect()</code>.
+
===الثابت <code>sqlite3.PARSE_COLNAMES</code>===
 +
يستخدم هذا الثابت مع معامل <code>detect_types</code> في دالة <code>[[Python/sqlite3/connect|connect()]]</code>.
  
تفسر وحدة <code>sqlite3</code> -عند تعيين قيمة لهذا الثابت- الأنواع المصرّح عنها لكل عمود تعيده. تفسّر الوحدة أول كلمة في النوع المصرّح عنه، أي تفسر النوع <code>"integer primary key"</code> إلى <code>"integer"</code>، والنوع <code>"number(10)‎"</code> إلى <code>"number"</code>. ثم تبحث الوحدة في قاموس المحوّلات عن الدالة المحوّلة المسجَّلة لذلك النوع.
+
تفسّر واجهة SQLite -عند تعيين قيمة لهذا الثابت- اسم العمود لكل عمود تعيده.
  
=== الثابت <code>sqlite3.PARSE_COLNAMES</code> ===
+
ستبحث الواجهة عن سلسلة نصية بهيئة <code>[mytype]</code> في جملة الاستعلام لتقرّر أن العمود هو من نوع <code>'mytype'</code>. ستحاول الواجهة البحث عن مدخل من نوع <code>'mytype'</code> في قاموس المحوّلات ثم تستخدم الدالة المحوّلة التي تجدها لإعادة القيمة.
يستخدم هذا الثابت مع معامل <code>detect_types</code> في دالة <code>connect</code>()‎.
 
  
تفسّر واجهة SQLite -عند تعيين قيمة لهذا الثابت- اسم العمود لكل عمود تعيده.  
+
يكون اسم العمود الموجود في الخاصية <code>[[Python/Cursor#.D8.A7.D9.84.D8.AE.D8.A7.D8.B5.D9.8A.D8.A9 description|Cursor.description]]</code> مقصورًا على الكلمة الأولى من اسم العمود، بمعنى أنّه لو استخدمت مثلًا العبارة  <code>‎'as "x [datetime]"'‎</code> في [[SQL]]، فإنّها ستفسّر إلى حين الوصول إلى أول فراغ في اسم العمود، وبهذا يصبح اسم العمود هو <code>"x"</code> فقط.
 +
==دوال وحدة sqlite3==
 +
===الدالة <code>[[Python/sqlite3/connect|sqlite3.connect()]]‎</code>===
 +
تفتح هذه الدالة اتصالًا مع قاعدة بيانات SQLite عبر الملف المعطى، وتعيد افتراضيًا كائن اتصال.
 +
===الدالة <code>[[Python/sqlite3/register converter|sqlite3.register_converter()‎]]</code>===
 +
تسجّل الدالة كائنًا قابلًا للاستدعاء <code>callable</code> لتحويل سلسلة بايتات نصية من قاعدة البيانات إلى نوع خاص من أنواع بيانات بايثون. 
 +
===الدالة <code>[[Python/sqlite3/register adapter|sqlite3.register_adapter()‎]]</code>===
 +
تسجّل الدالة كائنًا قابلًا للاستدعاء لتحويل نوع بيانات بايثون المعطى إلى إحدى الأنواع التي تدعمها قواعد بيانات SQLite.
 +
===الدالة <code>[[Python/sqlite3/complete statement|sqlite3.complete_statement()‎]]</code>===
 +
تختبر الدالة ما إذا كانت السلسلة النصية المعطاة تتضمن جملة [[SQL]] واحدة أو أكثر تنتهي بالفاصلة المنقوطة. 
 +
===الدالة <code>[[Python/sqlite3/enable callback tracebacks|sqlite3.enable_callback_tracebacks()‎]]</code>===
 +
تتيح هذه الدالة عرض الأخطاء tracebacks الناتجة عن الدوال والمجاميع aggregates  والمحوّلات converters  والاستدعاءات الخلفية authorizer callbacks المفوِّضة المعرّفة من قبل المستخدم.
 +
==[[Python/sqlite3/Connection|كائنات الاتصال Connection]]==
 +
تقدّم كائنات الاتصال Connection عددًا من الخصائص والتوابع التي تساعد المستخدم في التعامل مع قواعد بيانات SQLite، كالاتصال بقاعدة البيانات وتحميل الملحقات وإنشاء النسخ الاحتياطية وغيرها. تنشأ كائنات الاتصال كنتيجة لاستدعاء الدالة <code>[[Python/sqlite3/connect|sqlite3.connect()‎]]</code>.
 +
==[[Python/Cursor|كائنات المؤشر <code>Cursor</code>]]==
 +
كائنات Cursor هي وسيلة التواصل بين المستخدم وقاعدة البيانات، حيث يمكن باستخدام الخصائص والتوابع التي تقدّمها هذه الكائنات تنفيذ جمل [[SQL]] وإجراء الاستعلامات وجلب النتائج من قاعدة البيانات.
 +
==[[Python/Row|كائنات الصف Row]]==
 +
نسخة من الصنف <code>Row</code> وتعدّ صورة محسّنة من الخاصية <code>[[Python/Connection#.D8.A7.D9.84.D8.AE.D8.A7.D8.B5.D9.8A.D8.A9 row factory|row_factory]]</code> في كائنات الاتصال.
 +
==الاستثناءات في وحدة <code>sqlite3</code>==
 +
===الاستثناء <code>sqlite3.Warning</code>===
 +
صنف متفرّع من الصنف <code>[[Python/exceptions|Exception]]</code>.
 +
===الاستثناء <code>sqlite3.Error</code>===
 +
الصنف الأساسي لبقية الاستثناءات في هذه الوحدة، وهو صنف متفرّع من الصنف <code>[[Python/exceptions|Exception]]</code>.
 +
===الاستثناء <code>sqlite3.DatabaseError</code>===
 +
يطلق هذا الاستثناء عند حدوث الأخطاء المتعلّقة بقاعدة البيانات.
 +
===الاستثناء <code>sqlite3.IntegrityError</code>===
 +
يطلق هذا الاستثناء عند حدوث خلل في العلاقات التي تربط بين جداول قاعدة البيانات، كحدوث خلل في المفتاح الخارجي foreign key. هذا الاستثناء متفرّع من الصنف <code>DatabaseError</code>.
 +
===الاستثناء <code>sqlite3.ProgrammingError</code>===
 +
يُطلق هذا الاستثناء عند حدوث أخطاء برمجية، مثل عدم العثور على الجدول المحدّد أو وجود الجدول المراد إنشاؤه أصلًا، أو وجود خلل في جمل [[SQL]]، أو تحديد عدد خاطئ من المعاملات... الخ. هذا الاستثناء متفرّع من الصنف <code>DatabaseError</code>.
 +
===الاستثناء <code>sqlite3.OperationalError</code>===
 +
يُطلق هذا الاستثناء عند حدوث الأخطاء المتعلّقة بالعمليات الخاصّة بقواعد البيانات والتي لا تكون بالضرورة تحت سيطرة المبرمج، مثل: انقطاع الاتصال بقاعدة البيانات على نحو مفاجئ، أو عدم العثور على اسم مصدر البيانات، أو تعذّر معالجة إجراء معيّن... الخ. هذا الاستثناء متفرّع من الصنف <code>DatabaseError</code>.
 +
===الاستثناء <code>sqlite3.NotSupportedError</code>===
 +
يُطلق هذا الاستثناء عند استخدام تابع أو واجهة برمجية لقواعد البيانات لا تدعمها قاعدة البيانات الحالية، مثل: استدعاء التابع <code>[[Python/Connection/rollback|rollback()]]‎</code> مع اتصال لا يدعم الإجراءات transaction أو أنّ الإجراءات تكون مغلقة. هذا الاستثناء متفرّع من الصنف <code>DatabaseError</code>.
  
ستبحث الواجهة عن سلسلة نصية بهيئة <code>[mytype]</code> في جملة الاستعلام لتقرّر أن العمود هو من نوع <code>'mytype'</code>. ستحاول الواجهة البحث عن مدخل من نوع <code>'mytype'</code> في قاموس المحوّلات ثم تستخدم الدالة المحوّلة التي تجدها لإعادة القيمة.
+
== قواعد بيانات SQLite وأنواع بيانات بايثون ==
  
يكون اسم العمود الموجود في <code>Cursor.description</code> مقصورًا على الكلمة الأولى من اسم العمود، بمعنى أنّه لو استخدمت مثلًا العبارة  <code>‎'as "x [datetime]"'‎</code> في [[SQL]]، فإنّها ستفسّر إلى حين الوصول إلى أول فراغ في اسم العمود، وبهذا يصبح اسم العمود هو <code>"x"</code> فقط.
+
=== مقدمة ===
 +
تدعم قواعد بيانات SQLite الأنواع التالية: <code>Null</code>، <code>INTEGER</code>، <code>REAL</code>، <code>TEXT</code>، <code>BLOB</code>.
  
== دوال وحدة sqlite3 ==
+
لذا يمكن إرسال أنواع بيانات بايثون التالية إلى SQLite دون مشاكل:
 +
{| class="wikitable"
 +
!نوع بيانات بايثون
 +
!نوع بيانات SQLite
 +
|-
 +
|<code>[[Python/constants#None|None]]</code>
 +
|<code>Null</code>
 +
|-
 +
|<code>[[Python/int|int]]</code>
 +
|<code>INTEGER</code>
 +
|-
 +
|<code>[[Python/float|float]]</code>
 +
|<code>REAL</code>
 +
|-
 +
|<code>[[Python/str|str]]</code>
 +
|<code>TEXT</code>
 +
|-
 +
|<code>[[Python/bytes|bytes]]</code>
 +
|<code>BLOB</code>
 +
|}
 +
تحوّل أنواع بيانات SQLite إلى أنواع بيانات بايثون -افتراضيًا- على النحو التالي:
 +
{| class="wikitable"
 +
!نوع بيانات SQLite
 +
!نوع بيانات بايثون
 +
|-
 +
|<code>Null</code>
 +
|<code>[[Python/constants#None|None]]</code>
 +
|-
 +
|<code>INTEGER</code>
 +
|<code>[[Python/int|int]]</code>
 +
|-
 +
|<code>REAL</code>
 +
|<code>[[Python/float|float]]</code>
 +
|-
 +
|<code>TEXT</code>
 +
|تعتمد على خاصية [[Python/Connection#.D8.A7.D9.84.D8.AE.D8.A7.D8.B5.D9.8A.D8.A9 text factory|text_factory]] ولكن تحوّل افتراضيًا إلى<code>[[Python/str|str]]</code>
 +
|-
 +
|<code>BLOB</code>
 +
|<code>[[Python/bytes|bytes]]</code>
 +
|}
 +
إن نظام أنواع البيانات في وحدة <code>sqlite3</code> قابلة للتوسع بطريقتين: يمكن تخزين أنواع بايثون إضافية في قاعدة بيانات SQLite عن طريق تكييف الكائنات object adaptation، ويمكن الاعتماد على وحدة <code>sqlite3</code> في تحويل أنواع بيانات SQLite إلى أنواع بيانات بايثون متنوعة عن طريق المحولات.
  
=== الدالة <code>[[Python/sqlite3/connect|sqlite3.connect()]]‎</code> ===
+
=== استخدام المكيّفات adapters لتخزين أنواع بيانات بايثون إضافية في قواعد بيانات SQLite ===
تفتح هذه الدالة اتصالًا مع قاعدة بيانات SQLite عبر الملف database، وتعيد افتراضيًا كائن اتصال.
+
ذكرنا سابقًا أنّ قواعد بيانات SQLite تدعم عددًا محدودًا من أنواع البيانات، ولاستخدام أنواع بيانات بايثون مع SQLite يجب تكييف adapt هذه الأنواع إلى أحد الأنواع التي تدعمها وحدة <code>sqlite3</code> وهي: <code>NoneType</code>، <code>int</code>، <code>float</code>، <code>str</code>، <code>bytes</code>.
  
=== الدالة <code>[[Python/sqlite3/register converter|sqlite3.register_converter()‎]]</code> ===
+
هناك طريقتان لتكييف أحد أنواع بيانات بايثون إلى أنواع البيانات المدعومة من قبل الوحدة:
تسجّل الدالة كائنًا قابلًا للاستدعاء callable لتحويل سلسلة بايتات نصية من قاعدة البيانات إلى نوع خاص من أنواع بيانات بايثون
 
  
=== الدالة <code>[[Python/sqlite3/register adapter|sqlite3.register_adapter()‎]]</code> ===
+
==== ترك الكائن ليكيّف نفسه ====
تسجّل الدالة كائنًا قابلًا للاستدعاء لتحويل نوع بيانات بايثون المعطى إلى إحدى الأنواع التي تدعمها قواعد بيانات SQLite.
+
هذه الطريقة مناسبة إن كنت تكتب الصنف بنفسك. لنفترض أنّ لديك الصنف التالي:<syntaxhighlight lang="python3">
 +
class Point:
 +
    def __init__(self, x, y):
 +
        self.x, self.y = x, y
 +
</syntaxhighlight>تريد الآن تخزين النقطة في عمود SQLite واحد. يجب عليك في البداية اختيار أحد الأنواع المدعومة لاستخدامها في تمثيل النقطة. سنستخدم النوع <code>str</code> وسنفصل إحداثيات النقطة بفاصلة منقوطة. بعد ستحتاج إلى تزويد الصنف بتابع ‎<code>__conform__(self,protocl)‎</code> ومهمّته إعادة القيمة المحوّلة، وسيأخذ المعامل <code>protocol</code> القيمة <code>PrepareProtocol</code>.<syntaxhighlight lang="python3">
 +
import sqlite3
  
=== الدالة <code>[[Python/sqlite3/complete statement|sqlite3.complete_statement()‎]]</code> ===
+
class Point:
تعيد الدالة القيمة <code>True</code> إن كانت السلسلة النصية المعطاة تتضمن جملة [[SQL]] واحدة أو أكثر تنتهي بالفاصلة المنقوطة. 
+
    def __init__(self, x, y):
 +
        self.x, self.y = x, y
  
=== الدالة <code>[[Python/sqlite3/enable callback tracebacks|sqlite3.enable_callback_tracebacks()‎]]</code> ===
+
    def __conform__(self, protocol):
تتيح هذه الدالة عرض الأخطاء tracebacks الناتجة عن الدوال والمجاميع aggregates  والمحوّلات converters  والاستدعاءات الخلفية authorizer callbacks المفوِّضة المعرّفة من قبل المستخدم.
+
        if protocol is sqlite3.PrepareProtocol:
 +
            return "%f;%f" % (self.x, self.y)
  
== كائنات الاتصال Connection ==
+
con = sqlite3.connect(":memory:")
تمتلك كائنات الاتصال بقواعد البيانات SQLite الخصائص والتوابع التالية:
+
cur = con.cursor()
  
=== الخاصية <code>isolation_level</code> ===
+
p = Point(4.0, -3.2)
يمكن استخدام هذه الخاصية لمعرفة مستوى العزل الافتراضي الحالي أو تعيينه. تأخذ الخاصية القيمة <code>None</code> لنمط الحفظ التلقائي <code>autocommit</code> أو إحدى القيم <code>"DEFERRED"</code> أو <code>"IMMEDIATE"</code> أو <code>"EXCLUSIVE"</code>. راجع قسم التحكم بالإجراءات للمزيد من المعلومات.
+
cur.execute("select ?", (p,))
 +
print(cur.fetchone()[0])
  
=== الخاصية <code>in_transaction</code> ===
+
</syntaxhighlight>
تأخذ الخاصية القيمة <code>True</code> إن كان الإجراء فعّالًا (أي في حال وجود تعديلات غير محفوظة) وتأخذ القيمة <code>False</code> فيما عدا ذلك. هذه الخاصية للقراءة فقط.
 
  
=== الخاصية <code>row_factory</code> ===
+
==== تسجيل مكيّف قابل للاستدعاء ====
يمكن تبديل هذه الخاصية إلى كائن قابل للاستدعاء يستقبل كائن المؤشّر والصفّ row الأصلي على هيئة [[Python/tuples|صفّ <code>tuple</code>]] وسيعيد النتيجة الحقيقية للصف row. يمكن بهذه الطريقة تطبيق طرق متقدّمة لإعادة النتائج، مثل إعادة كائن بمقدوره الوصول إلى الأعمدة عن طريق أسمائها، مثال:<syntaxhighlight lang="python3">
+
تتلخص الطريقة الثانية لتكيف الكائنات في إنشاء دالة تحوّل النوع إلى تمثيل نصّي وتسجيل الدالة باستخدام الدالة <code>[[Python/sqlite3/register adapter|register_adapter()]]‎</code>.<syntaxhighlight lang="python3">
 
import sqlite3
 
import sqlite3
  
def dict_factory(cursor, row):
+
class Point:
    d = {}
+
    def __init__(self, x, y):
     for idx, col in enumerate(cursor.description):
+
        self.x, self.y = x, y
        d[col[0]] = row[idx]
+
 
    return d
+
def adapt_point(point):
 +
     return "%f;%f" % (point.x, point.y)
 +
 
 +
sqlite3.register_adapter(Point, adapt_point)
  
 
con = sqlite3.connect(":memory:")
 
con = sqlite3.connect(":memory:")
con.row_factory = dict_factory
 
 
cur = con.cursor()
 
cur = con.cursor()
cur.execute("select 1 as a")
 
print(cur.fetchone()["a"])
 
</syntaxhighlight>إن لم يكن [[Python/type|الصف <code>tuple</code>]] كافيًا، وكنت ترغب في الوصول إلى الأعمدة بواسطة أسمائها، فيمكنك تعيين النوع <code>sqlite3.Row</code> إلى هذه الخاصية. يتيح النوع <code>Row</code> الوصول إلى الأعمدة عن طريق أرقامها وعن طريق أسمائها دون تحسّس حالة الأحرف ودون استهلاك الكثير من الذاكرة. وقد يكون هذا النوع خيارًا أفضل من استخدام [[Python/dict|القواميس]] للوصول إلى الأعمدة، أو أفضل حتى من استخدام <code>db_row</code>.
 
  
=== الخاصية <code>text_factory</code> ===
+
p = Point(4.0, -3.2)
يمكن عن طريق هذه الخاصية التحكم في طبيعة الكائنات المعادة لأنواع البيانات النصية <code>TEXT</code>. القيمة الافتراضية لهذه الخاصية هي <code>str</code> وتعيد وحدة <code>sqlite3</code> كائنات Unicode للأعمدة النصية. يمكن تعيين القيمة <code>bytes</code> لهذه الخاصية إن كان المطلوب إعادة سلاسل بايتات نصية <code>bytestrings</code>.
+
cur.execute("select ?", (p,))
 +
print(cur.fetchone()[0])
 +
</syntaxhighlight>تتضمن وحدة <code>sqlite3</code> نوعين افتراضيين من المكيّفات لنوعي بيانات بايثون الداخليين <code>[[Python/datetime/date|datetime.date]]</code> و [[Python/datetime/datetime|<code>datetime.datetime</code>]]. يبين المثال التالي طريقة تخزين كائن [[Python/datetime/datetime|<code>datetime.datetime</code>]] في قاعدة البيانات كختم زمني وليس بصيغة ISO.<syntaxhighlight lang="python3">
 +
import sqlite3
 +
import datetime
 +
import time
  
يمكن كذلك تعيين أي قيمة قابلة للاستدعاء وتستقبل معامل واحدًا من نوع <code>bytestring</code> وتعيد الكائن الناتج من الاستدعاء.
+
def adapt_datetime(ts):
 +
    return time.mktime(ts.timetuple())
  
يبين المثال التالي طريقة عمل الخاصية:<syntaxhighlight lang="python3">
+
sqlite3.register_adapter(datetime.datetime, adapt_datetime)
import sqlite3
 
  
 
con = sqlite3.connect(":memory:")
 
con = sqlite3.connect(":memory:")
 
cur = con.cursor()
 
cur = con.cursor()
  
AUSTRIA = "\xd6sterreich"
+
now = datetime.datetime.now()
 +
cur.execute("select ?", (now,))
 +
print(cur.fetchone()[0])
 +
</syntaxhighlight>
 +
 
 +
=== تحويل قيم SQLite إلى أنواع بايثون خاصّة ===
 +
يمكن إنشاء مكيّفات خاصّة تسمح بإرسال أنواع بيانات بايثون مخصّصة إلى قاعدة بيانات SQLite. ولكن يجب تمهيد الطريق لتحويل البيانات من بايثون إلى SQLite ثم إلى بايثون رجوعًا، وهنا يأتي دور المحوّلات.
  
# تكون الصفوف المعادة بترميز يونيكود افتراضيًا
+
لنعد إلى صنف <code>Point</code> المعروض سابقًا. جرى في هذا الصنف تخزين قيم الإحداثيات <code>x</code> و <code>y</code> مفصولة بفاصلة منقوطة وعلى هيئة سلسلة نصية في قاعدة بيانات SQLite.
cur.execute("select ?", (AUSTRIA,))
+
 
row = cur.fetchone()
+
في البداية، سنعرّف دالة تحويل تأخذ السلسلة النصية كمعامل وتنشئ كائن <code>Point</code> منها.
assert row[0] == AUSTRIA
+
 
 +
'''ملاحظة:''' يجب استدعاء دوال التحويل دائمًا مع كائن من نوع <code>bytes</code>، بصرف النظر عن نوع البيانات المرسلة إلى SQLite.<syntaxhighlight lang="python3">
 +
def convert_point(s):
 +
    x, y = map(float, s.split(b";"))
 +
    return Point(x, y)
 +
</syntaxhighlight>سنحتاج الآن إلى إخبار وحدة <code>sqlite3</code> بأنّ ما حدّدناه من قاعدة البيانات هو نقطة في الواقع. وهناك طريقتان للقيام بذلك:
 +
* التضمين عن طريق النوع المصرّح عنه.
 +
 
 +
* التصريح عن طريق اسم العمود.
 +
كلتا الطريقتين موضحتان في قسم دوال وثوابت الوحدة، في الثابتين <code>[[Python/sqlite3#.D8.A7.D9.84.D8.AB.D8.A7.D8.A8.D8.AA sqlite3.PARSE DECLTYPES|PARSE_DECLTYPES]]</code> و <code>[[Python/sqlite3#.D8.A7.D9.84.D8.AB.D8.A7.D8.A8.D8.AA sqlite3.PARSE COLNAMES|PARSE_COLNAMES]]</code>.
 +
 
 +
يبين المثال التالي هاتين الطريقتين:<syntaxhighlight lang="python3">
 +
import sqlite3
 +
 
 +
class Point:
 +
    def __init__(self, x, y):
 +
        self.x, self.y = x, y
  
# ولكن يمكن جعل وحدة sqlite3 تعيد سلاسل بايتات نصية دائمًا...
+
    def __repr__(self):
 +
        return "(%f;%f)" % (self.x, self.y)
  
con.text_factory = bytes
+
def adapt_point(point):
cur.execute("select ?", (AUSTRIA,))
+
    return ("%f;%f" % (point.x, point.y)).encode('ascii')
row = cur.fetchone()
 
assert type(row[0]) is bytes
 
# سترمّز سلاسل البايتات النصية بترميز UTF-8
 
  
assert row[0] == AUSTRIA.encode("utf-8")
+
def convert_point(s):
 +
    x, y = list(map(float, s.split(b";")))
 +
    return Point(x, y)
  
# يمكننا كذلك تطبيق text_factory مخصّص
+
# تسجيل المكيف
# هنا ستُلحق السلسلة "foo" بجميع السلاسل النصية
+
sqlite3.register_adapter(Point, adapt_point)
con.text_factory = lambda x: x.decode("utf-8") + "foo"
 
cur.execute("select ?", ("bar",))
 
row = cur.fetchone()
 
assert row[0] == "barfoo"
 
</syntaxhighlight>
 
  
=== الخاصية <code>total_changes</code> ===
+
# تسجيل المحول
تعيد الخاصية العدد الإجمالي للصفوف الخاضعة للتعديلات، أو المدرجة أو المحذوفة من قاعدة البيانات منذ إجراء الاتصال مع قاعدة البيانات.
+
sqlite3.register_converter("point", convert_point)
  
=== التابع [[Python/Connectin/cursor|<code>cursor()‎</code>]] ===
+
p = Point(4.0, -3.2)
يعيد التابع نسخة من صنف [[Python/Cursor|<code>Cursor</code>]] أو أحد أصنافه الفرعية.
 
=== التابع [[Python/Connection/commit|<code>commit()‎</code>]] ===
 
يحفظ التابع الإجراء الحالي.
 
=== التابع [[Python/Connection/rollback|<code>rollback()‎</code>]] ===
 
يلغي التابع جميع التعديلات التي أجريت على قاعدة البيانات بعد آخر استدعاء للتابع [[Python/Connection/commit|<code>commit()‎</code>]].
 
=== التابع [[Python/Connection/close|<code>close()‎</code>]] ===
 
يغلق التابع الاتصال بقاعدة البيانات.
 
=== التابع [[Python/Connection/execute|<code>execute()‎</code>]] ===
 
يستدعي التابع [[Python/Cursor/execute|<code>execute()‎</code>]] في كائن المؤشر مع تمرير المعاملات المعطاة، ثم يعيد كائن المؤشر.
 
=== التابع [[Python/Connection/excutemany|<code>excutemany()‎</code>]] ===
 
يستدعي التابع [[Python/Cursor/executemany|<code>executemany()‎</code>]] في كائن المؤشر مع تمرير المعاملات المعطاة، ثم يعيد كائن المؤشر.
 
=== التابع [[Python/Connection/executescript|<code>executescript()‎</code>]] ===
 
يستدعي التابع [[Python/Cursor/executescript|<code>executescript()‎</code>]] في كائن المؤشر مع تمرير المعاملات المعطاة، ثم يعيد كائن المؤشر.
 
=== التابع [[Python/Connection/create_function|<code>create_function()‎</code>]] ===
 
ينشئ التابع دالة معرفة من قبل المستخدم يمكن استعمالها لاحقًا ضمن جمل [[SQL|SQL]].
 
=== التابع [[Python/Connection/create_aggregate|<code>create_aggregate()‎</code>]] ===
 
ينشئ التابع دالة تجميع aggregate function معرّفة من قبل المستخدم.
 
=== التابع [[Python/Connection/create_collation|<code>create_collation()‎</code>]] ===
 
ينشئ التابع ترتيبًا collation يحمل الاسم المعطى مع الكائن القابل للاستدعاء المعطى.
 
=== التابع [[Python/Connection/interrupt|<code>interrupt()‎</code>]] ===
 
يمكن استدعاء هذا التابع من خيط آخر لتجاهل أي استعلامات قد تكون قيد التنفيذ عبر الاتصال الحالي.
 
=== التابع [[Python/Connection/set_authorizer|<code>set_authorizer()‎</code>]] ===
 
يسجّل هذا التابع كائن استدعاء خلفيٍّ، وينفّذ هذا الكائن في كل محاول للوصول إلى عمود في جدول ضمن قاعدة البيانات.
 
=== التابع [[Python/Connection/set_progress_handler|<code>set_progress_handler()‎</code>]] ===
 
يسجّل هذا التابع استدعاءً خلفيًا يجري تنفيذه لكل n من تعليمات SQLite في الجهاز الافتراضي virtual machine.
 
=== التابع [[Python/Connection/set_trace_callback|<code>set_trace_callback()‎</code>]] ===
 
يسجل التابع trace_callback يجري استدعاؤه لكل جملة SQL تنفّذ بواسطة SQLite.
 
=== التابع [[Python/Connection/enable_load_extension|<code>enable_load_extension()‎</code>]] ===
 
يحدّد هذا التابع ما إذا كان بإمكان محرّك SQLite من تحميل الملحقات من المكتبات المشتركة.
 
=== التابع [[Python/Connection/load_extension|<code>load_extension()‎</code>]] ===
 
يحمل هذا التابع إحدى ملحقات SQlite من المكتبة المشتركة.
 
=== التابع [[Python/Connection/iterdump|<code>iterdump()‎</code>]] ===
 
يعيد التابع مكرِّرًا iterator يمكن استخدامه لعرض dump قاعدة البيانات بصيغة SQL النصية.
 
=== التابع [[Python/Connection/backup|<code>backup()‎</code>]] ===
 
ينشئ هذا التابع نسخة احتياطية من قاعدة بيانات SQLite.
 
  
'''ملاحظة:''' هذه الخاصية جديدة في الإصدار 3.2.
+
#########################
 +
# 1) استخدام الأنواع المصرّح عنها
 +
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
 +
cur = con.cursor()
 +
cur.execute("create table test(p point)")
  
== كائنات المؤشر cursor ==
+
cur.execute("insert into test(p) values (?)", (p,))
 +
cur.execute("select p from test")
 +
print("with declared types:", cur.fetchone()[0])
 +
cur.close()
 +
con.close()
  
== كائنات الصف row ==
+
#######################
 +
# 2) استخدام أسماء الأعمدة
 +
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES)
 +
cur = con.cursor()
 +
cur.execute("create table test(p)")
  
== قواعد بيانات SQLite وأنواع بيانات بايثون ==
+
cur.execute("insert into test(p) values (?)", (p,))
 +
cur.execute('select p as "p [point]" from test')
 +
print("with column names:", cur.fetchone()[0])
 +
cur.close()
 +
con.close()
 +
</syntaxhighlight>
  
== الاستثناءات في وحدة <code>sqlite3</code> ==
+
=== المكيّفات والمحوّلات الافتراضية ===
 +
تتضمن وحدة <code>[[Python/datetime|datetime]]</code> افتراضيًّا بعض المكيّفات لنوعي [[Python/datetime/date|<code>date</code>]] و <code>[[Python/datetime/datetime|datetime]]</code>. يُرسل هذان النوعان كتواريخ أو أختام زمنية بصيغة ISO إلى قاعدة بيانات SQLite.
  
=== الاستثناء <code>sqlite3.Warning</code> ===
+
أما المحوّلات الافتراضية فهي مسجّلة تحت اسم "<code>date</code>" للنوع <code>[[Python/datetime/date|datetime.date]]</code> وتحت اسم "<code>timestamp</code>" للنوع <code>[[Python/datetime/datetime|datetime.datetime]]</code>.
صنف متفرّع من الصنف <code>[[Python/exceptions|Exception]]</code>.
 
  
=== الاستثناء <code>sqlite3.Error</code> ===
+
وبهذه الطريقة يمكنك استخدام date/timestamp من بايثون دون الحاجة إلى القيام بشيء آخر في معظم الحالات. إلى جانب ذلك فإنّ تنسيق المكيّفات متوافق مع دوال date/time التجريبية في SQLite.
الصنف الأساسي لبقية الاستثناءات في هذه الوحدة، وهو صنف متفرّع من الصنف <code>[[Python/exceptions|Exception]]</code>.
 
  
=== الاستثناء <code>sqlite3.DatabaseError</code> ===
+
يمكن توضيح ما سبق في المثال التالي:<syntaxhighlight lang="python3">
يطلق هذا الاستثناء عند حدوث الأخطاء المتعلّقة بقاعدة البيانات.
+
import sqlite3
 +
import datetime
  
=== الاستثناء <code>sqlite3.IntegrityError</code> ===
+
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
يطلق هذا الاستثناء عند حدوث خلل في العلاقات التي تربط بين جداول قاعدة البيانات، كحدوث خلل في المفتاح الخارجي foreign key. هذا الاستثناء متفرّع من الصنف <code>DatabaseError</code>.
+
cur = con.cursor()
 +
cur.execute("create table test(d date, ts timestamp)")
  
=== الاستثناء <code>sqlite3.ProgrammingError</code> ===
+
today = datetime.date.today()
يُطلق هذا الاستثناء عند حدوث أخطاء برمجية، مثل عدم العثور على الجدول المحدّد أو وجود الجدول المراد إنشاؤه أصلًا، أو وجود خلل في جمل [[SQL]]، أو تحديد عدد خاطئ من المعاملات... الخ. هذا الاستثناء متفرّع من الصنف <code>DatabaseError</code>.
+
now = datetime.datetime.now()
  
=== الاستثناء <code>sqlite3.OperationalError</code> ===
+
cur.execute("insert into test(d, ts) values (?, ?)", (today, now))
يُطلق هذا الاستثناء عند حدوث الأخطاء المتعلّقة بالعمليات الخاصّة بقواعد البيانات والتي لا تكون بالضرورة تحت سيطرة المبرمج، مثل: انقطاع الاتصال بقاعدة البيانات على نحو مفاجئ، أو عدم العثور على اسم مصدر البيانات، أو تعذّر معالجة إجراء معيّن... الخ. هذا الاستثناء متفرّع من الصنف <code>DatabaseError</code>.
+
cur.execute("select d, ts from test")
 +
row = cur.fetchone()
 +
print(today, "=>", row[0], type(row[0]))
 +
print(now, "=>", row[1], type(row[1]))
  
=== الاستثناء <code>sqlite3.NotSupportedError</code> ===
+
cur.execute('select current_date as "d [date]", current_timestamp as "ts [timestamp]"')
يُطلق هذا الاستثناء عند استخدام تابع أو واجهة برمجية لقواعد البيانات لا تدعمها قاعدة البيانات الحالية، مثل: استدعاء التابع <code>rollback()</code> مع اتصال لا يدعم الإجراءات transaction أو أنّ الإجراءات تكون مغلقة. هذا الاستثناء متفرّع من الصنف <code>DatabaseError</code>.
+
row = cur.fetchone()
 +
print("current_date", row[0], type(row[0]))
 +
print("current_timestamp", row[1], type(row[1]))
 +
</syntaxhighlight>إن تضمن الختم الزمني المخزّن في قاعدة بيانات SQLite جزءًا كسريًّا يتجاوز ستة أعداد، فإنّ قيمته ستقتطع إلى مايكرو ثانية بواسطة محول الختم الزمني.
  
== التحكم بالإجراءات ==
+
==التحكم بالإجراءات==
 
تعمل مكتبة <code>sqlite3</code> الداخلية افتراضيًا في وضع الحفظ التلقائي <code>autocommit</code>، ولكن وحدة <code>sqlite3</code> في بايثون ليست كذلك افتراضيًا.
 
تعمل مكتبة <code>sqlite3</code> الداخلية افتراضيًا في وضع الحفظ التلقائي <code>autocommit</code>، ولكن وحدة <code>sqlite3</code> في بايثون ليست كذلك افتراضيًا.
  
سطر 262: سطر 334:
 
تطلق وحدة <code>sqlite3</code> في بايثون وعلى نحو تلقائي الجملة <code>[[SQL/begin|BEGIN]]</code> ضمنيًا قبل أي جملة تعديل للبيانات Data Modification Language (DML)‎ (أي الجمل <code>[[SQL/insert|INSERT]]/[[SQL/update|UPDATE]]/[[SQL/delete|DELETE]]/[[SQL/replace|REPLACE]]</code>).
 
تطلق وحدة <code>sqlite3</code> في بايثون وعلى نحو تلقائي الجملة <code>[[SQL/begin|BEGIN]]</code> ضمنيًا قبل أي جملة تعديل للبيانات Data Modification Language (DML)‎ (أي الجمل <code>[[SQL/insert|INSERT]]/[[SQL/update|UPDATE]]/[[SQL/delete|DELETE]]/[[SQL/replace|REPLACE]]</code>).
  
يمكن التحكم في طبيعة جمل <code>[[SQL/begin|BEGIN]]</code> التي تنفّذها <code>sqlite3</code> ضمنيًا بواسطة المعامل <code>isolation_level</code> عند استدعاء الدالة <code>connect()</code>‎، أو عن طريق خاصية <code>isolation_level</code> في كائنات الاتصال. 
+
يمكن التحكم في طبيعة جمل <code>[[SQL/begin|BEGIN]]</code> التي تنفّذها <code>sqlite3</code> ضمنيًا بواسطة المعامل [[Python/Connection#.D8.A7.D9.84.D8.AE.D8.A7.D8.B5.D9.8A.D8.A9 isolation level|<code>isolation_level</code>]] عند استدعاء الدالة <code>[[Python/sqlite3/connect|connect()]]</code>‎، أو عن طريق خاصية <code>[[isolation_level]]</code> في كائنات الاتصال. 
  
 
في حال عدم تعيين قيمة لمستوى العزل <code>isolation_level</code> فستستخدم <code>sqlite3</code> جملة <code>[[SQL/begin|BEGIN]]</code> صرفة، وهذا مكافئ لتعيين القيمة <code>DEFERRED</code>، وهناك قيم أخرى يمكن استخدامها وهي <code>IMMEDIATE</code> و <code>EXCLUSIVE</code>.
 
في حال عدم تعيين قيمة لمستوى العزل <code>isolation_level</code> فستستخدم <code>sqlite3</code> جملة <code>[[SQL/begin|BEGIN]]</code> صرفة، وهذا مكافئ لتعيين القيمة <code>DEFERRED</code>، وهناك قيم أخرى يمكن استخدامها وهي <code>IMMEDIATE</code> و <code>EXCLUSIVE</code>.
  
يمكن تعطيل الآلية الضمنية للتحكم في الإجراءات في وحدة <code>sqlite3</code> عن طريق تعيين القيمة <code>None</code> للمعامل أو الخاصية <code>isolation_level</code>، وسيؤدي هذا إلى تحويل عمل مكتبة <code>sqlite3</code> الداخلية إلى وضع التخزين التلقائي، وعندها يمكنك التحكم في الإجراءات بصورة كاملة عن طريق استخدام جمل [[SQL/begin|<code>BEGIN</code>]] و [[SQL/rollback|<code>ROLLBACK</code>]] و [[SQL/savepoint|<code>SAVEPOINT</code>]] و [[SQL/release|<code>RELEASE</code>]] في شيفرتك.
+
يمكن تعطيل الآلية الضمنية للتحكم في الإجراءات في وحدة <code>sqlite3</code> عن طريق تعيين القيمة <code>None</code> للمعامل أو الخاصية <code>[[Python/Connection#.D8.A7.D9.84.D8.AE.D8.A7.D8.B5.D9.8A.D8.A9 isolation level|isolation_level]]</code>، وسيؤدي هذا إلى تحويل عمل مكتبة <code>sqlite3</code> الداخلية إلى وضع التخزين التلقائي، وعندها يمكنك التحكم في الإجراءات بصورة كاملة عن طريق استخدام جمل [[SQL/begin|<code>BEGIN</code>]] و [[SQL/rollback|<code>ROLLBACK</code>]] و [[SQL/savepoint|<code>SAVEPOINT</code>]] و [[SQL/release|<code>RELEASE</code>]] في شيفرتك.
  
 
'''ملاحظة:''' تحفظ <code>sqlite3</code> الإجراءات المفتوحة ضمنيًا قبل جمل <code>DDL</code>. لم يعد هذا يحدث في الإصدار 3.6 من بايثون.
 
'''ملاحظة:''' تحفظ <code>sqlite3</code> الإجراءات المفتوحة ضمنيًا قبل جمل <code>DDL</code>. لم يعد هذا يحدث في الإصدار 3.6 من بايثون.
== استخدام sqlite3 بكفاءة ==
+
==استخدام sqlite3 بكفاءة==
 
+
===استخدام التوابع المختصرة===
=== استخدام التوابع المختصرة ===
+
يؤدي استخدام التوابع غير المعيارية <code>[[Python/Connection/execute|execute()]]</code>‎ و [[Python/Connection/executemany|<code>executemany()</code>‎]] و <code>[[Python/Connection/executescript|executescript()]]</code>‎ في كائن <code>[[Python/Connection|Connection]]</code> إلى اختصار الشيفرة البرمجية المكتوبة نظرًا لانتفاء الحاجة إلى إنشاء كائن المؤشر <code>[[Python/Cursor|Cursor]]</code> والذي يكون في كثير من الأحيان زائدًا عن الحاجة.
 
 
يؤدي استخدام التوابع غير المعيارية <code>execute()</code>‎ و <code>executemany()</code>‎ و <code>executescript()</code>‎ في كائن <code>[[Python/connection|Connection]]</code> إلى اختصار الشيفرة البرمجية المكتوبة نظرًا لانتفاء الحاجة إلى إنشاء كائن المؤشر [[Python/cursor|<code>Cursor</code>]] والذي يكون في كثير من الأحيان زائدًا عن الحاجة.
 
  
عوضًا عن ذلك، يجري إنشاء كائن [[Python/cursor|<code>Cursor</code>]] ضمنيًا وتعيد هذه التوابع المختصرة كائنات المؤشر، وهكذا يمكنك تنفيذ جملة <code>[[SQL/select|SELECT]]</code> والمرور على النتائج مباشرة وعن طريق تنفيذ استدعاء واحد فقط على كائن الاتصال.
+
عوضًا عن ذلك، يجري إنشاء كائن <code>[[Python/Cursor|Cursor]]</code> ضمنيًا وتعيد هذه التوابع المختصرة كائنات المؤشر، وهكذا يمكنك تنفيذ جملة <code>[[SQL/select|SELECT]]</code> والمرور على النتائج مباشرة وعن طريق تنفيذ استدعاء واحد فقط على كائن الاتصال.<syntaxhighlight lang="python3">
<syntaxhighlight lang="python3">
 
 
import sqlite3
 
import sqlite3
  
سطر 299: سطر 368:
  
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
===الوصول إلى الأعمدة عن طريق أسمائها عوضًا عن فهارسها===
 +
الصنف الداخلي <code>[[Python/Row|sqlite3.Row]]</code> هو من الميزات المفيدة في وحدة <code>sqlite3</code>، وقد صمّم هذا الصنف لاستخدامه كمنتج للصفوف row factory.
  
=== الوصول إلى الأعمدة عن طريق أسمائها عوضًا عن فهارسها ===
+
يمكن الوصول إلى الصفوف <code>rows</code> المغلّفة بهذا الصنف إما عن طريق الفهرس (مثل [[Python/tuples|الصفوف tuples]]) أو عن طريق الاسم دون تحسس حالة الأحرف:<syntaxhighlight lang="python3">
 
 
الصنف الداخلي <code>sqlite3.Row</code> هو من الميزات المفيدة في وحدة <code>sqlite3</code>، وقد صمّم هذا الصنف لاستخدامه كمنتج للصفوف row factory.
 
 
 
يمكن الوصول إلى الصفوف <code>rows</code> المغلّفة بهذا الصنف إما عن طريق الفهرس (مثل [[Python/tuples|الصفوف tuples]]) أو عن طريق الاسم دون تحسس حالة الأحرف:
 
 
 
<syntaxhighlight lang="python3">
 
 
import sqlite3
 
import sqlite3
  
سطر 321: سطر 386:
  
 
</syntaxhighlight>
 
</syntaxhighlight>
 
+
===استخدام الاتصال كمدير للسياق context manager===
=== استخدام الاتصال كمدير للسياق context manager ===
+
يمكن استخدام كائنات الاتصال كمدراء للسياق يمكنها حفظ أو استرجاع الإجراءات على نحو تلقائي. في حال حدوث أي استثناء، يتم التراجع عن الإجراء، وفيما عدا ذلك يُحفظ الإجراء:<syntaxhighlight lang="python3">
 
 
يمكن استخدام كائنات الاتصال كمدراء للسياق يمكنها حفظ أو استرجاع الإجراءات على نحو تلقائي. في حال حدوث أي استثناء، يتم التراجع عن الإجراء، وفيما عدا ذلك يُحفظ الإجراء:
 
 
 
<syntaxhighlight lang="python3">
 
  
 
import sqlite3
 
import sqlite3
سطر 346: سطر 407:
 
     print("couldn't add Joe twice")
 
     print("couldn't add Joe twice")
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
==مشاكل شائعة==
 +
===تعدد الخيوط Multithreading===
 +
تعاني إصدارات SQLite القديمة من مشاكل في مشاركة الاتصال بين خيوط متعددة، ولهذا السبب تمنع وحدة بايثون مشاركة [[Python/Connection|الاتصالات]] و<nowiki/>[[Python/Cursor|المؤشرات]] بين الخيوط، وتطلق اللغة استثناء في وقت التشغيل عند القيام بذلك.
  
== مشاكل شائعة ==
+
الاستثناء الوحيد هو في استدعاء التابع <code>[[Python/Connection/interrupt|interrupt()]]‎</code> والذي يعدّ استدعاؤه من خيط آخر أمرًا منطقيًا.
 
 
=== تعدد الخيوط Multithreading ===
 
تعاني إصدارات SQLite القديمة من مشاكل في مشاركة الاتصال بين خيوط متعددة، ولهذا السبب تمنع وحدة بايثون مشاركة الاتصالات والمؤشرات بين الخيوط، وتطلق اللغة استثناء في وقت التشغيل عند القيام بذلك.
 
  
الاستثناء الوحيد هو في استدعاء التابع <code>interrupt()‎</code> والذي يعدّ استدعاؤه من خيط آخر أمرًا منطقيًا.
+
== انظر أيضًا ==
 +
* [[Python/dbm|وحدة <code>dbm</code>]]: تمثّل وحدة <code>dbm</code> واجهة عامّة للأشكال المختلفة من قواعد بيانات DBM، مثل <code>dbm.gnu</code> أو <code>dbm.ndbm</code>.
  
== مصادر ==
+
==مصادر==
 
* [https://docs.python.org/3/library/sqlite3.html#sqlite-and-python-types صفحة DB-API 2.0 interface for SQLite databases في توثيق بايثون الرسمي.]
 
* [https://docs.python.org/3/library/sqlite3.html#sqlite-and-python-types صفحة DB-API 2.0 interface for SQLite databases في توثيق بايثون الرسمي.]
 
 
[[تصنيف:Python]]
 
[[تصنيف:Python]]
 
[[تصنيف:Python Modules]]
 
[[تصنيف:Python Modules]]

المراجعة الحالية بتاريخ 14:38، 19 سبتمبر 2018


SQLite هي مكتبة مكتوبة بلغة C تتيح إنشاء قواعد بيانات على القرص الصلب ولا تحتاج إلى خادوم خاص لمعالجتها، وتتيح الوصول إلى قاعدة البيانات باستخدام نسخة غير قياسية من لغة الاستعلام SQL.

تستخدم بعض التطبيقات والبرامج قاعدة بيانات SQLite لتخزين بياناتها الداخلية، ويمكن إنشاء نماذج أولية من التطبيق باستخدام SQLite ثم نقل الشيفرة إلى قواعد بيانات أكبر مثل PostgreSQL أو Oracle.

كُتبت وحدة sqlite3 من قبل Gerhard Häring، وتقدّم واجهة SQL متوافقة مع معايير DB-API 2.0 الموصوفة في PEP 249.

الاتصال بقاعدة بيانات SQLite

لاستخدام هذه الوحدة يجب إنشاء كائن اتصال Connection يمثّل قاعدة البيانات. يبين المثال التالي طريقة استخدام الوحدة مع افتراض أن البيانات مخزّنة في ملف باسم example.db.

import sqlite3
conn = sqlite3.connect('example.db')

يمكن كذلك استخدام الاسم الخاص :memory: لإنشاء قاعدة البيانات في ذاكرة الوصول العشوائي RAM. بعد إجراء الاتصال مع قاعدة البيانات يمكن إنشاء كائن مؤشر Cursor واستدعاء التابع execute()‎ لتنفيذ أوامر SQL:

c = conn.cursor()

# إنشاء جدول
c.execute('''CREATE TABLE stocks
             (date text, trans text, symbol text, qty real, price real)''')

# إدراج صف من البيانات
c.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)")

# حفظ التعديلات
conn.commit()

# يمكن كذلك إغلاق الاتصال بعد الانتهاء
# ولكن يجب التأكد من حفظ جميع التعديلات تجنبًا لفقدانها كلّها
conn.close()

تكون البيانات المحفوظة من النوع المستمر persistent وهي متاحة للاستخدام في الجلسات اللاحقة:

import sqlite3
conn = sqlite3.connect('example.db')
c = conn.cursor()

ستحتاج في العادة إلى استخدام القيم المخزّنة في متغيرات بايثون لإجراء عمليات SQL، ولكن عليك أن تتجنب استخدام سلاسل بايثون النصية لإنشاء أوامر الاستعلام عن البيانات لأنّ ذلك غير آمن، إذ يكون برنامجك عرضة لهجمات حقن SQL. ينصح باستخدام معامل الاستبدال الخاصّ بواجهة DB-API، حيث يوضع الرمز ? عوضًا عن القيم التي تريد إدراجها في جملة الاستعلام، ثم تزويد تابعexecute()‎بمعامل ثانٍ يكون على هيئة صفّ tuple يتضمّن تلك القيم حسب ترتيبها في جملة الاستعلام. (قد تستخدم وحدات قواعد البيانات الأخرى رموز مختلفة، مثل ‎%s أو ‎:1). فعلى سبيل المثال:

# لا تقم بهذا - هذا خطر.
symbol = 'RHAT'
c.execute("SELECT * FROM stocks WHERE symbol = '%s'" % symbol)

# استخدم هذه الطريقة
t = ('RHAT',)
c.execute('SELECT * FROM stocks WHERE symbol=?', t)
print(c.fetchone())

# يبين المثال التالي طريقة إدراج عدد من القيم
purchases = [('2006-03-28', 'BUY', 'IBM', 1000, 45.00),
             ('2006-04-05', 'BUY', 'MSFT', 1000, 72.00),
             ('2006-04-06', 'SELL', 'IBM', 500, 53.00),
            ]
c.executemany('INSERT INTO stocks VALUES (?,?,?,?,?)', purchases)

بعد تنفيذ جملة الاستعلام SELECT يمكن استرجاع البيانات إمّا عن طريق التعامل مع المؤشر كمكرِّر iterator، أو استدعاء التابع fetchone() لاسترجاع صفّ row واحد فقط، أو استدعاء التابع fetchall() للحصول على قائمة بالصفوف rows المطابقة. يستخدم المثال التالي طريقة المكرِّر:

>>> for row in c.execute('SELECT * FROM stocks ORDER BY price'):
        print(row)

('2006-01-05', 'BUY', 'RHAT', 100, 35.14)
('2006-03-28', 'BUY', 'IBM', 1000, 45.0)
('2006-04-06', 'SELL', 'IBM', 500, 53.0)
('2006-04-05', 'BUY', 'MSFT', 1000, 72.0)

ثوابت الوحدة sqlite

تقدّم وحدة sqlite الثوابت التالية:

الثابت sqlite3.version

رقم الإصدار الخاص بالوحدة -وليس مكتبة SQLite- على هيئة سلسلة نصية.

الثابت sqlite3.version_info

رقم الإصدار الخاص بالوحدة -وليس مكتبة SQLite- على هيئة صفّ من الأعداد الصحيحة.

الثابت sqlite3.sqlite_version

رقم الإصدار الخاص بمكتبة SQLite في وقت التشغيل، على هيئة سلسلة نصية.

الثابت sqlite3.sqlite_version_info

رقم الإصدار الخاص بمكتبة SQLite في وقت التشغيل، على هيئة صفّ من الأعداد الصحيحة.

الثابت sqlite3.PARSE_DECLTYPES

يستخدم هذا الثابت مع معامل detect_types في دالة connect().

تفسر وحدة sqlite3 -عند تعيين قيمة لهذا الثابت- الأنواع المصرّح عنها لكل عمود تعيده. تفسّر الوحدة أول كلمة في النوع المصرّح عنه، أي تفسر النوع "integer primary key" إلى "integer"، والنوع "number(10)‎" إلى "number". ثم تبحث الوحدة في قاموس المحوّلات عن الدالة المحوّلة المسجَّلة لذلك النوع.

الثابت sqlite3.PARSE_COLNAMES

يستخدم هذا الثابت مع معامل detect_types في دالة connect()‎.

تفسّر واجهة SQLite -عند تعيين قيمة لهذا الثابت- اسم العمود لكل عمود تعيده.

ستبحث الواجهة عن سلسلة نصية بهيئة [mytype] في جملة الاستعلام لتقرّر أن العمود هو من نوع 'mytype'. ستحاول الواجهة البحث عن مدخل من نوع 'mytype' في قاموس المحوّلات ثم تستخدم الدالة المحوّلة التي تجدها لإعادة القيمة.

يكون اسم العمود الموجود في الخاصية Cursor.description مقصورًا على الكلمة الأولى من اسم العمود، بمعنى أنّه لو استخدمت مثلًا العبارة ‎'as "x [datetime]"'‎ في SQL، فإنّها ستفسّر إلى حين الوصول إلى أول فراغ في اسم العمود، وبهذا يصبح اسم العمود هو "x" فقط.

دوال وحدة sqlite3

الدالة sqlite3.connect()

تفتح هذه الدالة اتصالًا مع قاعدة بيانات SQLite عبر الملف المعطى، وتعيد افتراضيًا كائن اتصال.

الدالة sqlite3.register_converter()‎

تسجّل الدالة كائنًا قابلًا للاستدعاء callable لتحويل سلسلة بايتات نصية من قاعدة البيانات إلى نوع خاص من أنواع بيانات بايثون. 

الدالة sqlite3.register_adapter()‎

تسجّل الدالة كائنًا قابلًا للاستدعاء لتحويل نوع بيانات بايثون المعطى إلى إحدى الأنواع التي تدعمها قواعد بيانات SQLite.

الدالة sqlite3.complete_statement()‎

تختبر الدالة ما إذا كانت السلسلة النصية المعطاة تتضمن جملة SQL واحدة أو أكثر تنتهي بالفاصلة المنقوطة. 

الدالة sqlite3.enable_callback_tracebacks()‎

تتيح هذه الدالة عرض الأخطاء tracebacks الناتجة عن الدوال والمجاميع aggregates  والمحوّلات converters  والاستدعاءات الخلفية authorizer callbacks المفوِّضة المعرّفة من قبل المستخدم.

كائنات الاتصال Connection

تقدّم كائنات الاتصال Connection عددًا من الخصائص والتوابع التي تساعد المستخدم في التعامل مع قواعد بيانات SQLite، كالاتصال بقاعدة البيانات وتحميل الملحقات وإنشاء النسخ الاحتياطية وغيرها. تنشأ كائنات الاتصال كنتيجة لاستدعاء الدالة sqlite3.connect()‎.

كائنات المؤشر Cursor

كائنات Cursor هي وسيلة التواصل بين المستخدم وقاعدة البيانات، حيث يمكن باستخدام الخصائص والتوابع التي تقدّمها هذه الكائنات تنفيذ جمل SQL وإجراء الاستعلامات وجلب النتائج من قاعدة البيانات.

كائنات الصف Row

نسخة من الصنف Row وتعدّ صورة محسّنة من الخاصية row_factory في كائنات الاتصال.

الاستثناءات في وحدة sqlite3

الاستثناء sqlite3.Warning

صنف متفرّع من الصنف Exception.

الاستثناء sqlite3.Error

الصنف الأساسي لبقية الاستثناءات في هذه الوحدة، وهو صنف متفرّع من الصنف Exception.

الاستثناء sqlite3.DatabaseError

يطلق هذا الاستثناء عند حدوث الأخطاء المتعلّقة بقاعدة البيانات.

الاستثناء sqlite3.IntegrityError

يطلق هذا الاستثناء عند حدوث خلل في العلاقات التي تربط بين جداول قاعدة البيانات، كحدوث خلل في المفتاح الخارجي foreign key. هذا الاستثناء متفرّع من الصنف DatabaseError.

الاستثناء sqlite3.ProgrammingError

يُطلق هذا الاستثناء عند حدوث أخطاء برمجية، مثل عدم العثور على الجدول المحدّد أو وجود الجدول المراد إنشاؤه أصلًا، أو وجود خلل في جمل SQL، أو تحديد عدد خاطئ من المعاملات... الخ. هذا الاستثناء متفرّع من الصنف DatabaseError.

الاستثناء sqlite3.OperationalError

يُطلق هذا الاستثناء عند حدوث الأخطاء المتعلّقة بالعمليات الخاصّة بقواعد البيانات والتي لا تكون بالضرورة تحت سيطرة المبرمج، مثل: انقطاع الاتصال بقاعدة البيانات على نحو مفاجئ، أو عدم العثور على اسم مصدر البيانات، أو تعذّر معالجة إجراء معيّن... الخ. هذا الاستثناء متفرّع من الصنف DatabaseError.

الاستثناء sqlite3.NotSupportedError

يُطلق هذا الاستثناء عند استخدام تابع أو واجهة برمجية لقواعد البيانات لا تدعمها قاعدة البيانات الحالية، مثل: استدعاء التابع rollback() مع اتصال لا يدعم الإجراءات transaction أو أنّ الإجراءات تكون مغلقة. هذا الاستثناء متفرّع من الصنف DatabaseError.

قواعد بيانات SQLite وأنواع بيانات بايثون

مقدمة

تدعم قواعد بيانات SQLite الأنواع التالية: Null، INTEGER، REAL، TEXT، BLOB.

لذا يمكن إرسال أنواع بيانات بايثون التالية إلى SQLite دون مشاكل:

نوع بيانات بايثون نوع بيانات SQLite
None Null
int INTEGER
float REAL
str TEXT
bytes BLOB

تحوّل أنواع بيانات SQLite إلى أنواع بيانات بايثون -افتراضيًا- على النحو التالي:

نوع بيانات SQLite نوع بيانات بايثون
Null None
INTEGER int
REAL float
TEXT تعتمد على خاصية text_factory ولكن تحوّل افتراضيًا إلىstr
BLOB bytes

إن نظام أنواع البيانات في وحدة sqlite3 قابلة للتوسع بطريقتين: يمكن تخزين أنواع بايثون إضافية في قاعدة بيانات SQLite عن طريق تكييف الكائنات object adaptation، ويمكن الاعتماد على وحدة sqlite3 في تحويل أنواع بيانات SQLite إلى أنواع بيانات بايثون متنوعة عن طريق المحولات.

استخدام المكيّفات adapters لتخزين أنواع بيانات بايثون إضافية في قواعد بيانات SQLite

ذكرنا سابقًا أنّ قواعد بيانات SQLite تدعم عددًا محدودًا من أنواع البيانات، ولاستخدام أنواع بيانات بايثون مع SQLite يجب تكييف adapt هذه الأنواع إلى أحد الأنواع التي تدعمها وحدة sqlite3 وهي: NoneType، int، float، str، bytes.

هناك طريقتان لتكييف أحد أنواع بيانات بايثون إلى أنواع البيانات المدعومة من قبل الوحدة:

ترك الكائن ليكيّف نفسه

هذه الطريقة مناسبة إن كنت تكتب الصنف بنفسك. لنفترض أنّ لديك الصنف التالي:

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

تريد الآن تخزين النقطة في عمود SQLite واحد. يجب عليك في البداية اختيار أحد الأنواع المدعومة لاستخدامها في تمثيل النقطة. سنستخدم النوع str وسنفصل إحداثيات النقطة بفاصلة منقوطة. بعد ستحتاج إلى تزويد الصنف بتابع ‎__conform__(self,protocl)‎ ومهمّته إعادة القيمة المحوّلة، وسيأخذ المعامل protocol القيمة PrepareProtocol.

import sqlite3

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __conform__(self, protocol):
        if protocol is sqlite3.PrepareProtocol:
            return "%f;%f" % (self.x, self.y)

con = sqlite3.connect(":memory:")
cur = con.cursor()

p = Point(4.0, -3.2)
cur.execute("select ?", (p,))
print(cur.fetchone()[0])

تسجيل مكيّف قابل للاستدعاء

تتلخص الطريقة الثانية لتكيف الكائنات في إنشاء دالة تحوّل النوع إلى تمثيل نصّي وتسجيل الدالة باستخدام الدالة register_adapter().

import sqlite3

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

def adapt_point(point):
    return "%f;%f" % (point.x, point.y)

sqlite3.register_adapter(Point, adapt_point)

con = sqlite3.connect(":memory:")
cur = con.cursor()

p = Point(4.0, -3.2)
cur.execute("select ?", (p,))
print(cur.fetchone()[0])

تتضمن وحدة sqlite3 نوعين افتراضيين من المكيّفات لنوعي بيانات بايثون الداخليين datetime.date و datetime.datetime. يبين المثال التالي طريقة تخزين كائن datetime.datetime في قاعدة البيانات كختم زمني وليس بصيغة ISO.

import sqlite3
import datetime
import time

def adapt_datetime(ts):
    return time.mktime(ts.timetuple())

sqlite3.register_adapter(datetime.datetime, adapt_datetime)

con = sqlite3.connect(":memory:")
cur = con.cursor()

now = datetime.datetime.now()
cur.execute("select ?", (now,))
print(cur.fetchone()[0])

تحويل قيم SQLite إلى أنواع بايثون خاصّة

يمكن إنشاء مكيّفات خاصّة تسمح بإرسال أنواع بيانات بايثون مخصّصة إلى قاعدة بيانات SQLite. ولكن يجب تمهيد الطريق لتحويل البيانات من بايثون إلى SQLite ثم إلى بايثون رجوعًا، وهنا يأتي دور المحوّلات.

لنعد إلى صنف Point المعروض سابقًا. جرى في هذا الصنف تخزين قيم الإحداثيات x و y مفصولة بفاصلة منقوطة وعلى هيئة سلسلة نصية في قاعدة بيانات SQLite.

في البداية، سنعرّف دالة تحويل تأخذ السلسلة النصية كمعامل وتنشئ كائن Point منها.

ملاحظة: يجب استدعاء دوال التحويل دائمًا مع كائن من نوع bytes، بصرف النظر عن نوع البيانات المرسلة إلى SQLite.

def convert_point(s):
    x, y = map(float, s.split(b";"))
    return Point(x, y)

سنحتاج الآن إلى إخبار وحدة sqlite3 بأنّ ما حدّدناه من قاعدة البيانات هو نقطة في الواقع. وهناك طريقتان للقيام بذلك:

  • التضمين عن طريق النوع المصرّح عنه.
  • التصريح عن طريق اسم العمود.

كلتا الطريقتين موضحتان في قسم دوال وثوابت الوحدة، في الثابتين PARSE_DECLTYPES و PARSE_COLNAMES.

يبين المثال التالي هاتين الطريقتين:

import sqlite3

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __repr__(self):
        return "(%f;%f)" % (self.x, self.y)

def adapt_point(point):
    return ("%f;%f" % (point.x, point.y)).encode('ascii')

def convert_point(s):
    x, y = list(map(float, s.split(b";")))
    return Point(x, y)

# تسجيل المكيف
sqlite3.register_adapter(Point, adapt_point)

# تسجيل المحول
sqlite3.register_converter("point", convert_point)

p = Point(4.0, -3.2)

#########################
# 1) استخدام الأنواع المصرّح عنها
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES)
cur = con.cursor()
cur.execute("create table test(p point)")

cur.execute("insert into test(p) values (?)", (p,))
cur.execute("select p from test")
print("with declared types:", cur.fetchone()[0])
cur.close()
con.close()

#######################
# 2) استخدام أسماء الأعمدة
con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_COLNAMES)
cur = con.cursor()
cur.execute("create table test(p)")

cur.execute("insert into test(p) values (?)", (p,))
cur.execute('select p as "p [point]" from test')
print("with column names:", cur.fetchone()[0])
cur.close()
con.close()

المكيّفات والمحوّلات الافتراضية

تتضمن وحدة datetime افتراضيًّا بعض المكيّفات لنوعي date و datetime. يُرسل هذان النوعان كتواريخ أو أختام زمنية بصيغة ISO إلى قاعدة بيانات SQLite.

أما المحوّلات الافتراضية فهي مسجّلة تحت اسم "date" للنوع datetime.date وتحت اسم "timestamp" للنوع datetime.datetime.

وبهذه الطريقة يمكنك استخدام date/timestamp من بايثون دون الحاجة إلى القيام بشيء آخر في معظم الحالات. إلى جانب ذلك فإنّ تنسيق المكيّفات متوافق مع دوال date/time التجريبية في SQLite.

يمكن توضيح ما سبق في المثال التالي:

import sqlite3
import datetime

con = sqlite3.connect(":memory:", detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
cur = con.cursor()
cur.execute("create table test(d date, ts timestamp)")

today = datetime.date.today()
now = datetime.datetime.now()

cur.execute("insert into test(d, ts) values (?, ?)", (today, now))
cur.execute("select d, ts from test")
row = cur.fetchone()
print(today, "=>", row[0], type(row[0]))
print(now, "=>", row[1], type(row[1]))

cur.execute('select current_date as "d [date]", current_timestamp as "ts [timestamp]"')
row = cur.fetchone()
print("current_date", row[0], type(row[0]))
print("current_timestamp", row[1], type(row[1]))

إن تضمن الختم الزمني المخزّن في قاعدة بيانات SQLite جزءًا كسريًّا يتجاوز ستة أعداد، فإنّ قيمته ستقتطع إلى مايكرو ثانية بواسطة محول الختم الزمني.

التحكم بالإجراءات

تعمل مكتبة sqlite3 الداخلية افتراضيًا في وضع الحفظ التلقائي autocommit، ولكن وحدة sqlite3 في بايثون ليست كذلك افتراضيًا.

وضع الحفظ التلقائي يعني أنّ الجمل التي تعدّل قاعدة البيانات تأخذ مفعولها على نحو مباشر. تعطّل جملة BEGIN أو SAVEPOINT وضع الحفظ التلقائي، وتفعّل جملة COMMIT أو ROLLBACK أو RELEASE والتي تنهي الإجراء الأخير، وضع الحفظ التلقائي مرة أخرى.

تطلق وحدة sqlite3 في بايثون وعلى نحو تلقائي الجملة BEGIN ضمنيًا قبل أي جملة تعديل للبيانات Data Modification Language (DML)‎ (أي الجمل INSERT/UPDATE/DELETE/REPLACE).

يمكن التحكم في طبيعة جمل BEGIN التي تنفّذها sqlite3 ضمنيًا بواسطة المعامل isolation_level عند استدعاء الدالة connect()‎، أو عن طريق خاصية isolation_level في كائنات الاتصال. 

في حال عدم تعيين قيمة لمستوى العزل isolation_level فستستخدم sqlite3 جملة BEGIN صرفة، وهذا مكافئ لتعيين القيمة DEFERRED، وهناك قيم أخرى يمكن استخدامها وهي IMMEDIATE و EXCLUSIVE.

يمكن تعطيل الآلية الضمنية للتحكم في الإجراءات في وحدة sqlite3 عن طريق تعيين القيمة None للمعامل أو الخاصية isolation_level، وسيؤدي هذا إلى تحويل عمل مكتبة sqlite3 الداخلية إلى وضع التخزين التلقائي، وعندها يمكنك التحكم في الإجراءات بصورة كاملة عن طريق استخدام جمل BEGIN و ROLLBACK و SAVEPOINT و RELEASE في شيفرتك.

ملاحظة: تحفظ sqlite3 الإجراءات المفتوحة ضمنيًا قبل جمل DDL. لم يعد هذا يحدث في الإصدار 3.6 من بايثون.

استخدام sqlite3 بكفاءة

استخدام التوابع المختصرة

يؤدي استخدام التوابع غير المعيارية execute()‎ و executemany() و executescript()‎ في كائن Connection إلى اختصار الشيفرة البرمجية المكتوبة نظرًا لانتفاء الحاجة إلى إنشاء كائن المؤشر Cursor والذي يكون في كثير من الأحيان زائدًا عن الحاجة.

عوضًا عن ذلك، يجري إنشاء كائن Cursor ضمنيًا وتعيد هذه التوابع المختصرة كائنات المؤشر، وهكذا يمكنك تنفيذ جملة SELECT والمرور على النتائج مباشرة وعن طريق تنفيذ استدعاء واحد فقط على كائن الاتصال.

import sqlite3

persons = [
    ("Hugo", "Boss"),
    ("Calvin", "Klein")
    ]

con = sqlite3.connect(":memory:")

# إنشاء الجدول
con.execute("create table person(firstname, lastname)")

# تعبئة الجدول بالبيانات
con.executemany("insert into person(firstname, lastname) values (?, ?)", persons)

# طباعة محتويات الجدول
for row in con.execute("select firstname, lastname from person"):
    print(row)

print("I just deleted", con.execute("delete from person").rowcount, "rows")

الوصول إلى الأعمدة عن طريق أسمائها عوضًا عن فهارسها

الصنف الداخلي sqlite3.Row هو من الميزات المفيدة في وحدة sqlite3، وقد صمّم هذا الصنف لاستخدامه كمنتج للصفوف row factory.

يمكن الوصول إلى الصفوف rows المغلّفة بهذا الصنف إما عن طريق الفهرس (مثل الصفوف tuples) أو عن طريق الاسم دون تحسس حالة الأحرف:

import sqlite3

con = sqlite3.connect(":memory:")
con.row_factory = sqlite3.Row

cur = con.cursor()
cur.execute("select 'John' as name, 42 as age")
for row in cur:
    assert row[0] == row["name"]
    assert row["name"] == row["nAmE"]
    assert row[1] == row["age"]
    assert row[1] == row["AgE"]

استخدام الاتصال كمدير للسياق context manager

يمكن استخدام كائنات الاتصال كمدراء للسياق يمكنها حفظ أو استرجاع الإجراءات على نحو تلقائي. في حال حدوث أي استثناء، يتم التراجع عن الإجراء، وفيما عدا ذلك يُحفظ الإجراء:

import sqlite3

con = sqlite3.connect(":memory:")
con.execute("create table person (id integer primary key, firstname varchar unique)")

# يستدعى التابع con.commit()‎ تلقائيًا بعد ذلك ودون حدوث أي مشاكل

with con:
    con.execute("insert into person(firstname) values (?)", ("Joe",))

# يستدعى التابع con.rollback()‎ بعد انتهاء الإجراء باستثناء، وسيبقى الاستثناء طليقًا ويجب الإمساك به.

try:
    with con:
        con.execute("insert into person(firstname) values (?)", ("Joe",))
except sqlite3.IntegrityError:
    print("couldn't add Joe twice")

مشاكل شائعة

تعدد الخيوط Multithreading

تعاني إصدارات SQLite القديمة من مشاكل في مشاركة الاتصال بين خيوط متعددة، ولهذا السبب تمنع وحدة بايثون مشاركة الاتصالات والمؤشرات بين الخيوط، وتطلق اللغة استثناء في وقت التشغيل عند القيام بذلك.

الاستثناء الوحيد هو في استدعاء التابع interrupt() والذي يعدّ استدعاؤه من خيط آخر أمرًا منطقيًا.

انظر أيضًا

  • وحدة dbm: تمثّل وحدة dbm واجهة عامّة للأشكال المختلفة من قواعد بيانات DBM، مثل dbm.gnu أو dbm.ndbm.

مصادر