> ## Documentation Index
> Fetch the complete documentation index at: https://clickhouse.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

> برنامج ترميز Rust مُصرَّف اختياري لـ ClickHouse Connect

# برنامج ترميز Rust الأصلي

يستطيع ClickHouse Connect فك ترميز نتائج الاستعلامات وترميز عمليات الإدراج باستخدام برنامج ترميز Rust مُصرَّف بدلاً من التنفيذ الافتراضي القائم على بايثون وCython. ولا ينطبق برنامج ترميز Rust إلا على حركة البيانات بصيغة `FORMAT Native` التي يديرها العميل، وهي تشمل `query` و`query_np` و`query_df` وبدائلها الخاصة ببث الكتل والصفوف، وعمليات الإدراج بما فيها `insert_df`. أما طرق Arrow فتستخدم `FORMAT Arrow` ولا تتأثر، وكذلك الاستعلامات الخام وعمليات الإدراج الخام والصيغ غير الأصلية.

برنامج الترميز هذا تجريبي ويُفعَّل اختيارياً، ويبقى برنامج ترميز بايثون هو الافتراضي.

## التثبيت

يُوزَّع المرمِّز المُصرَّف في حزمة wheel مستقلة باسم `clickhouse-connect-core`، توفّر وحدة الإضافة `_ch_core`. ثبّت المرمِّز مع التكاملات التي يستخدمها تطبيقك:

```bash theme={null}
pip install "clickhouse-connect[rust]"         # Python rows and Native inserts
pip install "clickhouse-connect[rust,numpy]"   # NumPy results
pip install "clickhouse-connect[rust,pandas]"  # Pandas results and inserts
```

تُنشر حزم wheel الأساسية لإصدارات CPython من 3.10 حتى 3.14، وكذلك لإصدار CPython 3.14t الخالي من قفل GIL (free-threaded)، على أنظمة Linux وmacOS وWindows. وفي إصدارات بايثون الخالية من قفل GIL، لا يؤدي استيراد الامتداد الأساسي إلى إعادة تفعيل GIL.

لا يتطلب الإخراج العادي بصيغتي NumPy وPandas المعتمد على Rust مكتبة PyArrow أو أي حزمة Arrow أخرى. ويشمل ذلك `query_np` و`query_df` وبدائلهما المتدفقة، إضافةً إلى `query(..., use_numpy=True)`. كما أن استعلامات NumPy لا تتطلب مكتبة Pandas. أضف مجموعة التبعيات الاختيارية `async` لاستخدام العميل غير المتزامن.

أما طرق Arrow وتخزين Pandas المدعوم بـ Arrow، فلا تزال تتطلب PyArrow. ثبّت مجموعة التبعيات الاختيارية `arrow` لاستخدام هذه الميزات:

```bash theme={null}
pip install "clickhouse-connect[rust,pandas,arrow]"
```

يتبع إخراج string الموسَّع في Pandas خيار `mode.string_storage` في Pandas. عند تثبيت PyArrow، تستخدم السلاسل النصية تحويل Arrow الحالي، مع تحقق كامل من صحة UTF-8، أيًّا كانت الواجهة الخلفية للتخزين. أما في غياب PyArrow، فيستخدم المشغّل تحويل الكائنات في Rust، ويستخدم التخزين الافتراضي في Pandas سلاسل بايثون النصية. ويؤدي طلب تخزين سلاسل Arrow صراحةً دون تثبيت PyArrow إلى إثارة error تبعية. ويظل UTF-8 غير الصالح يُعرض بالصيغة الست عشرية الحالية أيًّا كانت الواجهة الخلفية للتخزين.

يُعدّ المرمِّز وطريقة تحزيمه ومجموعة تبعياته ميزات تجريبية. ويتعامل التحويل المباشر عبر المخازن المؤقتة الآن مع columns الأعداد الصحيحة غير القابلة لقيم NULL بأحجام من 8 إلى 64 بت، وcolumns Float32/64 وBoolean وBFloat16 وInterval وDate وDate32 وDateTime وDateTime64. كما تستخدم columns Time وTime64 المفردة، بما فيها القيم القابلة لـ NULL، المخازن المؤقتة المباشرة، وكذلك columns BFloat16 القابلة لـ NULL وإخراج Pandas الموسَّع للأعداد الصحيحة والعشرية وInterval القابلة لـ NULL. ويحتفظ BFloat16 بإخراج float32 وبسياسة القيم المفقودة الحالية لـ Float32 في Pandas. وتبقى قيم Interval أعدادًا ذات إشارة بالوحدة المُعلنة لها. ويحتفظ التحويل الزمني بالوحدات المُعلنة وبقواعد المنطقة الزمنية الحالية. وأصبحت الأسماء البديلة لـ Time64 من نوع SimpleAggregateFunction القابلة لـ NULL تُرجع الآن مُددًا صحيحة وNaT لقيم NULL. كما تستخدم columns DateTime64(9) المفردة القابلة لـ NULL المخازن المؤقتة للحفاظ على دقة النانوثانية في إخراج NumPy وPandas. أما التواريخ والطوابع الزمنية الأخرى القابلة لـ NULL فتحتفظ بمسارات تحويل الكائنات الخاصة بها.

وتستخدم المخازن المؤقتة المباشرة أيضًا مصفوفاتُ Time/Time64، بما فيها المصفوفات المتداخلة والعناصر الطرفية القابلة لـ NULL، وكذلك LowCardinality(Time)، بما فيها القيم القابلة لـ NULL. ويبقى تداخلها ووحدات المدة وتمثيل القيم الفارغة دون تغيير. ولا يزال LowCardinality(Time64) غير مدعوم في نواة Rust.

بالنسبة إلى columns DateTime64(9) المفردة القابلة لـ NULL، تحافظ `query_df` و`query_df_stream` على الأرقام الكسرية التسعة كاملةً، بما في ذلك عبر الأسماء البديلة من نوع SimpleAggregateFunction. وفي Pandas 3، أصبحت columns التاريخ والوقت في الإخراج الافتراضي تستخدم وحدات النانوثانية بدلًا من الميكروثانية. ويبقى الاستنتاج الحالي لنوع object في الكتل المكوّنة بالكامل من قيم NULL دون تغيير. وإذا كانت منطقة زمنية مُسمّاة ستجعل قيمةً ما تقع خارج نطاق النانوثانية في Pandas، فإن ذلك الـ column يحتفظ بسلوكه السابق في تحويل الكائنات والتعامل مع النطاق.

بالنسبة إلى هذه الـ columns، أصبحت حقول object في `query_np` و`query_np_stream` تحتوي على خلايا `numpy.datetime64` بدلًا من خلايا `datetime` في بايثون، مع `None` لقيم NULL في SQL. وتستخدم قيم المناطق المُسمّاة نبضات UTC دون بيانات وصفية للمنطقة الزمنية، بما يتوافق مع برنامج ترميز بايثون. ويتيح ذلك الحفاظ على دقة النانوثانية دون الحاجة إلى Pandas. استخدم `query_df` إذا كنت بحاجة إلى طوابع زمنية تتضمن المنطقة الزمنية. وتبقى أنواع خلايا NumPy الزمنية الأخرى القابلة لـ NULL دون تغيير.

ترفض استعلامات NumPy وPandas لـ columns DateTime64 المفردة أي دقة غير 0 و3 و6 و9، وتُثير `ProgrammingError`، ويشمل ذلك الـ columns القابلة لـ NULL والأسماء البديلة من نوع SimpleAggregateFunction.

إذا اختير برنامج ترميز Rust ولم تكن الوحدة المُصرَّفة مثبّتة، فإن إنشاء العميل يُثير `NotSupportedError` مع الإشارة إلى أمر التثبيت هذا.

## تمكين الـ codec

حدّد الـ codec باستخدام خيار الـ client التالي `native_codec`:

```python theme={null}
import clickhouse_connect

client = clickhouse_connect.get_client(host="localhost", native_codec="rust")
```

القيم المقبولة:

| Value | السلوك |
| - | - |
| `python` | الافتراضي. برنامج ترميز بايثون وCython الحالي. |
| `rust` | تفضيل برنامج ترميز Rust. تُوجَّه الاستعلامات ذات الخيارات غير المدعومة وعمليات الإدراج ذات الأنواع غير المدعومة إلى برنامج ترميز بايثون. |
| `rust_strict` | إلزام استخدام برنامج ترميز Rust. تؤدي الخيارات والأنواع غير المدعومة إلى إطلاق خطأ بدلًا من إعادة التوجيه. |

يمكن أيضًا ضبط القيمة الافتراضية عبر الإعداد العام `native_codec` أو متغير البيئة `CLICKHOUSE_CONNECT_NATIVE_CODEC`. وترتيب الأسبقية هو: وسيطة الكلمة المفتاحية في العميل، ثم الإعداد العام، ثم متغير البيئة.

يُتجاهل هذا الخيار مع عملاء `interface="chdb"`، إذ يستخدمون برنامج ترميز بايثون دائمًا.

## متى تستخدم مرمِّز Rust

يكون مرمِّز Rust مفيدًا إلى أقصى حد مع نتائج DataFrame الكبيرة التي تتضمن أنواعًا نصية وحاوية وأنواعًا معقدة مثل `String` و`LowCardinality` و`Map` و`Array` و`JSON` و`Decimal` و`UUID`. كما يمكن أن يفيد تدفقات كتل الصفوف والـ columns الكبيرة، وأعباء عمل الاستعلامات المتزامنة، وعمليات الإدراج المجمّعة.

أما النتائج الصغيرة والاستعلامات المقيّدة بالشبكة فقد لا تشهد تغيّرًا يُذكر. كذلك النتائج الرقمية المسطّحة، فهي تستخدم بالفعل مسارات مجمّعة فعّالة في مرمِّز بايثون، ولذلك قد تكون الفائدة منها أقل.

تتجنّب المخازن المؤقتة المباشرة إنشاء مصفوفات Arrow وسيطة للأنواع المدعومة. غير أن التجميع النهائي لنتائج NumPy وPandas قد يظل يتطلب تخصيص الذاكرة والنسخ، ولذلك لا يعني هذا أن كل نتيجة استعلام ستصبح خالية من النسخ.

في غياب PyArrow، يُنشئ تحويل السلاسل النصية في Rust كائنات نصية في بايثون من كل كتلة مفككة الترميز. ومع أحجام الكتل الافتراضية، تكون ذروة الذاكرة لنتائج String الكبيرة مقاربة لما هي عليه مع مرمِّز بايثون. أما الكتل الكبيرة جدًا، مثل كتلة واحدة تضم مليون صف، فتُبقي الكتلة المفككة الترميز بأكملها في الذاكرة أثناء إنشاء سلاسلها النصية، وقد تبلغ ذروة ذاكرة أعلى مما يبلغه مرمِّز بايثون. وبالنسبة إلى نتائج Pandas `StringDtype` الكبيرة، ثبّت الإضافة `arrow` واستخدم تخزين Arrow للسلاسل النصية. يختار Pandas 3 تخزين Arrow افتراضيًا عند تثبيت PyArrow، بينما يتطلب Pandas 2 ضبط `pd.options.mode.string_storage = "pyarrow"`.

قد تكون استدعاءات `query()` المخزَّنة مؤقتًا في الذاكرة أبطأ حاليًا وتستهلك ذروة ذاكرة أعلى مع مرمِّز Rust في حالة النتائج العريضة جدًا أو الرقمية بالكامل. ويُفضَّل استخدام `query_df` أو `query_row_block_stream` أو `query_column_block_stream` مع أعباء العمل هذه. وبالنسبة إلى NumPy وPandas، يمكن أيضًا أن تُسهم `query_np_stream` و`query_df_stream` في خفض ذروة الذاكرة. عالِج كل كتلة ثم حرّرها بدلًا من تجميع الدفق كاملًا. ويظل استهلاك الذاكرة مرهونًا بحجم كل كتلة، لذا فإن بث كتلة واحدة كبيرة لا يحقق الفائدة نفسها.

قِس أداء عبء العمل الخاص بك قبل اعتماد المرمِّز. واستخدم `native_codec="rust_strict"` أثناء القياس بحيث يُثار استثناء عند وجود خيار غير مدعوم أو اعتمادية مفقودة، بدلًا من توجيه الاستعلام إلى بايثون بصمت.

## قواعد الاحتياط

تُتَّخذ قرارات الاحتياط (fallback) قبل قراءة أي بايتات أو إرسالها، لذا لا يحدث تبديل للـ codec في منتصف الـ stream مطلقًا. ففي حالة الـ queries يجري الاختيار قبل استهلاك جسم الاستجابة، أما في حالة الـ inserts فلا يُختار مُرمِّز Rust إلا إذا كانت جميع أنواع الأعمدة مدعومة، وإلا نُفِّذت عملية الـ insert بأكملها باستخدام برنامج ترميز بايثون.

عند تفعيل `naive_datetime_insert="server"`، يوجّه `rust` أي عملية insert تحتوي على عمود من نوع `DateTime` أو `DateTime64` إلى برنامج ترميز بايثون، بحيث يُطبَّق الـ timezone المعلن للعمود أو server timezone. أما `rust_strict` فيرفض هذا المزيج، بينما يواصل الوضع الافتراضي `naive_datetime_insert="local"` استخدام مُرمِّز Rust.

أما استعلامات الـ metadata الداخلية للـ driver، بما في ذلك عبارات reflection الخاصة بـ dialect في SQLAlchemy، فتستخدم برنامج ترميز بايثون دائمًا وبصمت، في جميع الأوضاع.

وتؤدي payloads الـ Native المشوّهة التي يكتشفها برنامج ترميز Rust إلى إطلاق `DataError`.

## Versioning

تصدر إصدارات `clickhouse-connect-core` بشكل مستقل عن `clickhouse-connect`. تتطلب الإضافة `rust` الإصدار `clickhouse-connect-core>=0.2.1,<0.3`. يتحقق المشغّل من كلٍّ من إصدار واجهة برمجة تطبيقات binding وقدرة column-buffer عند اختيار مرمِّز Rust. تفتقر حزمة wheel المنشورة للإصدار الأساسي 0.2.0 إلى قدرة column-buffer. وإذا كانت الحزمة (wheel) المثبّتة غير متوافقة، فإن إنشاء العميل يثير `NotSupportedError` لكلٍّ من `rust` و`rust_strict`، مع أمر الترقية التالي:

```bash theme={null}
pip install --upgrade clickhouse-connect-core
```

تُشحن الإصلاحات وتحسينات الأداء في المرمِّز المُصرَّف ضمن إصدارات (releases) `clickhouse-connect-core`، ويمكن الحصول عليها بترقية (upgrade) حزمة wheel الأساسية إلى إصدار متوافق. أما التغييرات على تكامل المشغّل مع Rust فتتطلب ترقية `clickhouse-connect`.

## اختلافات سلوكية معروفة

يهدف مرمِّز Rust إلى تحقيق تطابق خلية بخلية مع مرمِّز بايثون. وفيما يلي الاختلافات المعروفة.

* تحتوي نتائج `query_np` و`query_df` لـ columns `Variant` على كائنات بايثون عادية بدلاً من قيم مفردة من numpy. القيم متساوية، لكن أنواع الخلايا تختلف.
* قيم `Dynamic` التي تحتوي على `Time64` تُجسَّد على هيئة `datetime.timedelta` في نتائج `query_np` و`query_df` عبر Rust. عند المقاييس 0 و3 و6 و9 تساوي القيمُ خلايا `numpy.timedelta64` الناتجة عن مرمِّز بايثون، لكن أنواع الخلايا تختلف. أما عند المقاييس الأخرى فيُرجع مرمِّز Rust قيمة `datetime.timedelta`، بينما يُثير مرمِّز بايثون `ProgrammingError` لعدم وجود وحدة مطابقة في NumPy. ولا تُتاح بيانات وصفية لأعضاء Dynamic للمشغّل بعد فك الترميز في Rust، لذا استخدم `native_codec="python"` عند الحاجة إلى أنواع خلايا NumPy أو إلى validation للمقاييس غير المدعومة.
* في حالة `query_df`، قد يحوّل مرمِّز بايثون القيم Compound المخزَّنة في shared data داخل JSON إلى نصوص، في حين يُرجع مرمِّز Rust كائنات مفكوكة الترميز، بما يطابق نتائج `query_np` في كلا المرمِّزين.
* ينتج عن البديل `LowCardinality` داخل حاوية تُجسَّد لكل خلية، مثل `Array(Variant(...))`، خلايا متساوية القيمة لا تتشارك هوية الكائن لكل slot في القاموس كما يحدث مع مرمِّز بايثون.
* تُفكّ ترميز columns `Nullable(Tuple(...))` التي تضم عنصراً واحداً أو أكثر بشكل صحيح على مرمِّز Rust، بينما يقرأ مرمِّز بايثون هذا الـ layout قراءةً خاطئة، وتُعد نتيجة Rust هي السلوك المرجعي. ويدعم كلا المرمِّزين النوع `Nullable(Tuple())`.
* يرفض `rust_strict` خيارات الاستعلام التي لا يُنفّذها مسار Rust، مثل `query_formats` المخصصة لكل استعلام، بدلاً من تغيير السلوك بصمت.
* قد تُثير أخطاء التحويل والـ validation عند الإدراج في Rust استثناء `DataError` حيث يُثير مرمِّز بايثون `ValueError`، وقد يختلف نص الرسالة. ومن الأمثلة على ذلك قيم `Time` و`Time64` غير الصالحة، وعناوين IPv6، وأبعاد QBit، وأطوال `FixedString`، ونصوص `Float64`، ومحاولات إدراج elements في column `Tuple()`.
* يرفض المُرمِّز في Rust القيمة `b""` لـ `FixedString(N)` والنصوص الرقمية مثل `"2"` لـ columns الأعداد الصحيحة، في حين يملأ مرمِّز بايثون قيمة `FixedString` الفارغة بالأصفار ويُحوّل النصوص الرقمية قسراً.
* يفك مرمِّز Rust ترميز بعض قيم `Dynamic` من نوع shared-variant إلى أنواع بايثون المقابلة، حيث يُبقي مرمِّز بايثون القيمة على شكل raw bytes. فعلى سبيل المثال، قد تُرجَع قيمة `Decimal` مخزَّنة على هيئة `decimal.Decimal` من Rust وكقيمة ثنائية من بايثون.
* بالنسبة لقيم `Date` في shared storage الخاص بـ `Dynamic`، تُرجع `query_np` و`query_df` خلايا `datetime.date` مع مرمِّز Rust وخلايا `numpy.datetime64` مع مرمِّز بايثون. ويُرجع كلا المرمِّزين القيمة `datetime.date` من `query`.
