> ## 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.

> توثيق الدوال المعرّفة من قبل المستخدم (UDFs)

# الدوال المعرّفة من قبل المستخدم (UDFs)

export const ExperimentalBadge = () => {
  return <div className="experimentalBadge">
            <div className="experimentalIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.25" d="M5.5 2H10.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M9.50015 2V6.19625L13.4283 12.7425C13.4738 12.8183 13.4985 12.9049 13.4996 12.9934C13.5008 13.0818 13.4785 13.169 13.435 13.246C13.3914 13.323 13.3283 13.3871 13.2519 13.4317C13.1755 13.4764 13.0886 13.4999 13.0002 13.5H3.00015C2.91164 13.5 2.8247 13.4766 2.74822 13.432C2.67174 13.3874 2.60847 13.3233 2.56487 13.2463C2.52126 13.1693 2.49889 13.082 2.50004 12.9935C2.50119 12.905 2.52582 12.8184 2.5714 12.7425L6.50015 6.19625V2" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M4.47656 9.56754C5.30344 9.41254 6.47656 9.47942 7.99969 10.25C10.0153 11.2707 11.4216 11.0569 12.2184 10.7282" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
        </div>
            ميزة تجريبية. <u><a href="/docs/docs/beta-and-experimental-features#experimental-features">تعرّف على المزيد.</a></u>
        </div>;
};

export const CloudNotSupportedBadge = () => {
  return <div className="cloudNotSupportedBadge">
            <div className="cloudNotSupportedIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.5" d="M6.33366 12.6666L12.3739 12.6667C13.6593 12.6667 14.7073 11.6187 14.7073 10.3334C14.7073 9.04804 13.6593 8.00003 12.3739 8.00003C12.3739 8.00003 12.3337 7.66659 12.0003 7.33325M10.667 5.33322C8.00033 2.33325 4.45395 4.78537 4.14195 6.68203C2.55728 6.7627 1.29395 8.06203 1.29395 9.6667C1.29395 11.3234 2.66699 12.6666 4.00033 12.6666" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.5" d="M2.66699 14L12.0003 4.66663" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>

        </div>
            غير مدعوم في ClickHouse Cloud
        </div>;
};

export const BetaBadge = ({link, galaxyTrack, galaxyEvent}) => {
  if (link) {
    return <a href={link} target="_blank" rel="noopener noreferrer" className="betaBadge" onClick={galaxyTrack && galaxyEvent ? galaxyOnClick(galaxyEvent) : undefined}>
                <Icon />
                <span>Beta</span>
            </a>;
  }
  return <div className="betaBadge">
            <Icon />
            <span>
                ميزة Beta. 
                <u>
                    <a href="/docs/docs/beta-and-experimental-features#beta-features">
                        مزيد من المعلومات.
                    </a>
                </u>
            </span>
        </div>;
};

يدعم ClickHouse عدة أنواع من الدوال المعرّفة من قبل المستخدم (UDFs):

* تبدأ [Executable UDFs](#executable-user-defined-functions) برنامجًا خارجيًا أو برنامجًا نصيًا (بايثون، Bash، إلخ)، وتُمرِّر إليه blocks من البيانات عبر STDIN / STDOUT. استخدمها لدمج التعليمات البرمجية أو الأدوات الحالية دون الحاجة إلى إعادة تجميع ClickHouse. وهي تفرض overhead أعلى لكل استدعاء مقارنةً بالخيارات التي تعمل داخل العملية، لذا فهي الأنسب للمنطق الأثقل أو عند الحاجة إلى runtime مختلف.
* تُعرَّف [SQL UDFs](#sql-user-defined-functions) باستخدام `CREATE FUNCTION` بالكامل ضمن SQL. وتُضمَّن/تُوسَّع داخل query plan (من دون حدٍّ فاصل على مستوى العملية)، مما يجعلها lightweight ومثالية لإعادة استخدام منطق expression أو تبسيط columns المحسوبة المعقدة.
* تُشغِّل [Experimental WebAssembly UDFs](#webassembly-user-defined-functions) تعليمات برمجية مُجمَّعة إلى WebAssembly داخل sandbox ضمن server process. وهي توفّر overhead أقل لكل استدعاء مقارنةً بالبرامج التنفيذية الخارجية، مع عزل أفضل من الامتدادات native، مما يجعلها مناسبة للخوارزميات المخصّصة المكتوبة بلغات يمكنها الاستهداف إلى WASM (مثل C/C++/Rust).
* تتيح [Experimental driver-based executable UDFs](#driver-based-executable-user-defined-functions) لـ operator يوفّره المشغّل أن يحوّل مقطع شيفرة مُقدَّمًا في `CREATE FUNCTION ... ENGINE = DriverName(...) AS '...'` إلى executable UDF عند وقت إنشاء الدالة (على سبيل المثال، عن طريق تجميعه). وهي تستند إلى executable UDFs وتتطلب إعداد driver على جانب server.

<div id="executable-user-defined-functions">
  ## الدوال المعرّفة من قبل المستخدم القابلة للتنفيذ
</div>

<BetaBadge />

<Note>
  في ClickHouse Cloud، تكون UDFs القابلة للتنفيذ متاحة ضمن الإصدار التجريبي العام، ويتم إنشاؤها عبر واجهة مستخدم Cloud Console. راجع [الدوال المعرّفة من قبل المستخدم في Cloud](/docs/ar/products/cloud/features/sql-console-features/user-defined-functions) للاطلاع على سير العمل الخاص بـ Cloud.
</Note>

يمكن لـ ClickHouse استدعاء أي برنامج خارجي قابل للتنفيذ أو برنامج نصي لمعالجة البيانات.

يمكن أن يوجد تكوين الدوال المعرّفة من قبل المستخدم القابلة للتنفيذ في ملف XML واحد أو أكثر.
ويُحدَّد مسار هذا التكوين في المَعلمة [`user_defined_executable_functions_config`](/docs/ar/reference/settings/server-settings/settings#user_defined_executable_functions_config).

يتضمن تكوين الدالة الإعدادات التالية:

| Parameter                     | الوصف                                                                                                                                                                                                                                                                                                                                                                        | مطلوب   | القيمة الافتراضية      |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | ---------------------- |
| `name`                        | اسم دالة                                                                                                                                                                                                                                                                                                                                                                     | نعم     | -                      |
| `command`                     | اسم البرنامج النصي المطلوب تنفيذه، أو الأمر إذا كانت `execute_direct` تساوي `false`                                                                                                                                                                                                                                                                                          | نعم     | -                      |
| `argument`                    | وصف الوسيطة مع `type` و`name` الاختياري الخاص بها. تُوصَف كل وسيطة في إعداد منفصل. ويكون تحديد الاسم ضروريًا إذا كانت أسماء الوسائط جزءًا من التسلسل لدالة معرّفة من قبل المستخدم بتنسيق مثل [Native](/docs/ar/reference/formats/Native) أو [JSONEachRow](/docs/ar/reference/formats/JSON/JSONEachRow)                                                                                 | نعم     | `c` + argument\_number |
| `format`                      | [تنسيق](/docs/ar/reference/formats/index) تُمرَّر به الوسائط إلى الأمر. ومن المتوقع أيضًا أن يستخدم خرج الأمر التنسيق نفسه                                                                                                                                                                                                                                                        | نعم     | -                      |
| `return_type`                 | نوع القيمة المُعادة                                                                                                                                                                                                                                                                                                                                                          | نعم     | -                      |
| `return_name`                 | اسم القيمة المُعادة. ويكون تحديد اسم الإرجاع ضروريًا إذا كان اسم الإرجاع جزءًا من التسلسل لدالة معرّفة من قبل المستخدم بتنسيق مثل [Native](/docs/ar/reference/formats/Native) أو [JSONEachRow](/docs/ar/reference/formats/JSON/JSONEachRow)                                                                                                                                            | اختياري | `result`               |
| `type`                        | نوع التنفيذ. إذا ضُبطت `type` على `executable`، فسيُشغَّل أمر واحد. وإذا ضُبطت على `executable_pool`، فسيُنشأ مجمّع من الأوامر                                                                                                                                                                                                                                               | نعم     | -                      |
| `max_command_execution_time`  | الحد الأقصى لوقت التنفيذ بالثواني لمعالجة كتلة من البيانات. يكون هذا الإعداد صالحًا فقط لأوامر `executable_pool`                                                                                                                                                                                                                                                             | اختياري | `10`                   |
| `command_termination_timeout` | المدة بالثواني التي يجب أن ينهي خلالها الأمر عمله بعد إغلاق الأنبوب الخاص به. بعد ذلك، تُرسَل الإشارة `SIGTERM` إلى العملية التي تنفذ الأمر                                                                                                                                                                                                                                  | اختياري | `10`                   |
| `command_read_timeout`        | مهلة قراءة البيانات من `stdout` الخاص بالأمر، بالمللي ثانية                                                                                                                                                                                                                                                                                                                  | اختياري | `10000`                |
| `command_write_timeout`       | مهلة كتابة البيانات إلى `stdin` الخاص بالأمر، بالمللي ثانية                                                                                                                                                                                                                                                                                                                  | اختياري | `10000`                |
| `pool_size`                   | حجم مجمّع الأوامر                                                                                                                                                                                                                                                                                                                                                            | اختياري | `16`                   |
| `send_chunk_header`           | يتحكم في ما إذا كان سيتم إرسال عدد الصفوف قبل إرسال دفعة من البيانات إلى العملية                                                                                                                                                                                                                                                                                             | اختياري | `false`                |
| `execute_direct`              | إذا كانت `execute_direct` = `1`، فسيُبحث عن `command` داخل مجلد user\_scripts المحدد بواسطة [user\_scripts\_path](/docs/ar/reference/settings/server-settings/settings#user_scripts_path). ويمكن تحديد وسائط إضافية للبرنامج النصي باستخدام فاصل من المسافات البيضاء. مثال: `script_name arg1 arg2`. وإذا كانت `execute_direct` = `0`، فسيُمرَّر `command` كوسيطة إلى `bin/sh -c` | اختياري | `1`                    |
| `lifetime`                    | فترة إعادة تحميل الدالة بالثواني. إذا ضُبطت على `0` فلن تُعاد تحميل الدالة                                                                                                                                                                                                                                                                                                   | اختياري | `0`                    |
| `deterministic`               | ما إذا كانت الدالة حتمية (تعيد النتيجة نفسها للإدخال نفسه)                                                                                                                                                                                                                                                                                                                   | اختياري | `false`                |
| `stderr_reaction`             | كيفية التعامل مع خرج `stderr` الخاص بالأمر. القيم: `none` (تجاهل)، `log` (تسجيل كل خرج `stderr` فورًا)، `log_first` (تسجيل أول 4 KiB بعد الخروج)، `log_last` (تسجيل آخر 4 KiB بعد الخروج)، `throw` (طرح استثناء فورًا عند أي خرج من `stderr`). عند استخدام `log_first` أو `log_last` مع رمز خروج غير صفري، يُضمَّن محتوى `stderr` في رسالة الاستثناء                         | اختياري | `log_last`             |
| `check_exit_code`             | إذا كانت القيمة `true`، فسيتحقق ClickHouse من رمز خروج الأمر. ويتسبب رمز الخروج غير الصفري في حدوث استثناء                                                                                                                                                                                                                                                                   | اختياري | `true`                 |

يجب أن يقرأ الأمر الوسائط من `STDIN` وأن يكتب النتيجة إلى `STDOUT`. ويجب أن يعالج الأمر الوسائط على نحو تكراري. أي إنه بعد معالجة دفعة من الوسائط، يجب أن ينتظر الدفعة التالية.

<div id="executable-user-defined-functions">
  ## الدوال المعرّفة من قبل المستخدم القابلة للتنفيذ
</div>

<div id="examples">
  ## أمثلة
</div>

<div id="udf-inline">
  ### UDF من برنامج نصي مضمن
</div>

أنشئ `test_function_sum` يدويًا مع ضبط `execute_direct` على القيمة `0` باستخدام إعدادات XML أو YAML.

<Tabs>
  <Tab title="XML">
    الملف `test_function.xml` (`/etc/clickhouse-server/test_function.xml` مع إعدادات المسار الافتراضية).

    ```xml title="/etc/clickhouse-server/test_function.xml" theme={null}
    <functions>
        <function>
            <type>executable</type>
            <name>test_function_sum</name>
            <return_type>UInt64</return_type>
            <argument>
                <type>UInt64</type>
                <name>lhs</name>
            </argument>
            <argument>
                <type>UInt64</type>
                <name>rhs</name>
            </argument>
            <format>TabSeparated</format>
            <command>cd /; clickhouse-local --input-format TabSeparated --output-format TabSeparated --structure 'x UInt64, y UInt64' --query "SELECT x + y FROM table"</command>
            <execute_direct>0</execute_direct>
            <deterministic>true</deterministic>
        </function>
    </functions>
    ```
  </Tab>

  <Tab title="YAML">
    الملف `test_function.yaml` (`/etc/clickhouse-server/test_function.yaml` مع إعدادات المسار الافتراضية).

    ```yml title="/etc/clickhouse-server/test_function.yaml" theme={null}
    functions:
      type: executable
      name: test_function_sum
      return_type: UInt64
      argument:
        - type: UInt64
          name: lhs
        - type: UInt64
          name: rhs
      format: TabSeparated
      command: 'cd /; clickhouse-local --input-format TabSeparated --output-format TabSeparated --structure ''x UInt64, y UInt64'' --query "SELECT x + y FROM table"'
      execute_direct: 0
      deterministic: true
    ```
  </Tab>
</Tabs>

<br />

```sql title="Query" theme={null}
SELECT test_function_sum(2, 2);
```

```text title="Result" theme={null}
┌─test_function_sum(2, 2)─┐
│                       4 │
└─────────────────────────┘
```

<div id="udf-python">
  ### UDF من برنامج نصي بايثون
</div>

في هذا المثال، ننشئ UDF يقرأ قيمة من `STDIN` ويُرجعها كسلسلة نصية.

أنشئ `test_function` باستخدام تهيئة XML أو YAML.

<Tabs>
  <Tab title="XML">
    الملف `test_function.xml` (`/etc/clickhouse-server/test_function.xml` مع إعدادات المسار الافتراضية).

    ```xml title="/etc/clickhouse-server/test_function.xml" theme={null}
    <functions>
        <function>
            <type>executable</type>
            <name>test_function_python</name>
            <return_type>String</return_type>
            <argument>
                <type>UInt64</type>
                <name>value</name>
            </argument>
            <format>TabSeparated</format>
            <command>test_function.py</command>
        </function>
    </functions>
    ```
  </Tab>

  <Tab title="YAML">
    الملف `test_function.yaml` (`/etc/clickhouse-server/test_function.yaml` مع إعدادات المسار الافتراضية).

    ```yml title="/etc/clickhouse-server/test_function.yaml" theme={null}
    functions:
      type: executable
      name: test_function_python
      return_type: String
      argument:
        - type: UInt64
          name: value
      format: TabSeparated
      command: test_function.py
    ```
  </Tab>
</Tabs>

<br />

أنشئ ملف البرنامج النصي `test_function.py` داخل مجلد `user_scripts` (`/var/lib/clickhouse/user_scripts/test_function.py` مع إعدادات المسار الافتراضية).

```python theme={null}
#!/usr/bin/python3

import sys

if __name__ == '__main__':
    for line in sys.stdin:
        print("Value " + line, end='')
        sys.stdout.flush()
```

```sql title="Query" theme={null}
SELECT test_function_python(toUInt64(2));
```

```text title="Result" theme={null}
┌─test_function_python(2)─┐
│ Value 2                 │
└─────────────────────────┘
```

<div id="udf-stdin">
  ### اقرأ قيمتين من `STDIN` وأعِد مجموعهما على شكل كائن JSON
</div>

أنشئ `test_function_sum_json` باستخدام وسيطات مُسمّاة وتنسيق [JSONEachRow](/docs/ar/reference/formats/JSON/JSONEachRow)، وذلك باستخدام تهيئة XML أو YAML.

<Tabs>
  <Tab title="XML">
    الملف `test_function.xml` (`/etc/clickhouse-server/test_function.xml` مع إعدادات المسار الافتراضية).

    ```xml title="/etc/clickhouse-server/test_function.xml" theme={null}
    <functions>
        <function>
            <type>executable</type>
            <name>test_function_sum_json</name>
            <return_type>UInt64</return_type>
            <return_name>result_name</return_name>
            <argument>
                <type>UInt64</type>
                <name>argument_1</name>
            </argument>
            <argument>
                <type>UInt64</type>
                <name>argument_2</name>
            </argument>
            <format>JSONEachRow</format>
            <command>test_function_sum_json.py</command>
        </function>
    </functions>
    ```
  </Tab>

  <Tab title="YAML">
    الملف `test_function.yaml` (`/etc/clickhouse-server/test_function.yaml` مع إعدادات المسار الافتراضية).

    ```yml title="/etc/clickhouse-server/test_function.yaml" theme={null}
    functions:
      type: executable
      name: test_function_sum_json
      return_type: UInt64
      return_name: result_name
      argument:
        - type: UInt64
          name: argument_1
        - type: UInt64
          name: argument_2
      format: JSONEachRow
      command: test_function_sum_json.py
    ```
  </Tab>
</Tabs>

<br />

أنشئ ملف البرنامج النصي `test_function_sum_json.py` داخل المجلد `user_scripts` (`/var/lib/clickhouse/user_scripts/test_function_sum_json.py` مع إعدادات المسار الافتراضية).

```python theme={null}
#!/usr/bin/python3

import sys
import json

if __name__ == '__main__':
    for line in sys.stdin:
        value = json.loads(line)
        first_arg = int(value['argument_1'])
        second_arg = int(value['argument_2'])
        result = {'result_name': first_arg + second_arg}
        print(json.dumps(result), end='\n')
        sys.stdout.flush()
```

```sql title="Query" theme={null}
SELECT test_function_sum_json(2, 2);
```

```text title="Result" theme={null}
┌─test_function_sum_json(2, 2)─┐
│                            4 │
└──────────────────────────────┘
```

<div id="udf-parameters-in-command">
  ### استخدام المعلمات في إعداد `command`
</div>

يمكن للدوال المعرّفة من قبل المستخدم القابلة للتنفيذ أخذ معلمات ثابتة تُضبط في إعداد `command` (يعمل هذا فقط مع الدوال المعرّفة من قبل المستخدم من النوع `executable`).
ويتطلب ذلك أيضًا الخيار `execute_direct` لضمان عدم وجود ثغرة ناتجة عن توسيع وسيطات الصدفة.

<Tabs>
  <Tab title="XML">
    ملف `test_function_parameter_python.xml` (`/etc/clickhouse-server/test_function_parameter_python.xml` مع إعدادات المسار الافتراضية).

    ```xml title="/etc/clickhouse-server/test_function_parameter_python.xml" theme={null}
    <functions>
        <function>
            <type>executable</type>
            <execute_direct>true</execute_direct>
            <name>test_function_parameter_python</name>
            <return_type>String</return_type>
            <argument>
                <type>UInt64</type>
            </argument>
            <format>TabSeparated</format>
            <command>test_function_parameter_python.py {test_parameter:UInt64}</command>
        </function>
    </functions>
    ```
  </Tab>

  <Tab title="YAML">
    ملف `test_function_parameter_python.yaml` (`/etc/clickhouse-server/test_function_parameter_python.yaml` مع إعدادات المسار الافتراضية).

    ```yml title="/etc/clickhouse-server/test_function_parameter_python.yaml" theme={null}
    functions:
      type: executable
      execute_direct: true
      name: test_function_parameter_python
      return_type: String
      argument:
        - type: UInt64
      format: TabSeparated
      command: test_function_parameter_python.py {test_parameter:UInt64}
    ```
  </Tab>
</Tabs>

<br />

أنشئ ملف البرنامج النصي `test_function_parameter_python.py` داخل المجلد `user_scripts` (`/var/lib/clickhouse/user_scripts/test_function_parameter_python.py` مع إعدادات المسار الافتراضية).

```python theme={null}
#!/usr/bin/python3

import sys

if __name__ == "__main__":
    for line in sys.stdin:
        print("Parameter " + str(sys.argv[1]) + " value " + str(line), end="")
        sys.stdout.flush()
```

```sql title="Query" theme={null}
SELECT test_function_parameter_python(1)(2);
```

```text title="Result" theme={null}
┌─test_function_parameter_python(1)(2)─┐
│ Parameter 1 value 2                  │
└──────────────────────────────────────┘
```

<div id="udf-shell-script">
  ### UDF من برنامج نصي shell
</div>

في هذا المثال، ننشئ برنامجًا نصيًا لـ shell يُضاعف كل قيمة.

<Tabs>
  <Tab title="XML">
    ملف `test_function_shell.xml` (`/etc/clickhouse-server/test_function_shell.xml` باستخدام إعدادات المسار الافتراضية).

    ```xml title="/etc/clickhouse-server/test_function_shell.xml" theme={null}
    <functions>
        <function>
            <type>executable</type>
            <name>test_shell</name>
            <return_type>String</return_type>
            <argument>
                <type>UInt8</type>
                <name>value</name>
            </argument>
            <format>TabSeparated</format>
            <command>test_shell.sh</command>
        </function>
    </functions>
    ```
  </Tab>

  <Tab title="YAML">
    ملف `test_function_shell.yaml` (`/etc/clickhouse-server/test_function_shell.yaml` باستخدام إعدادات المسار الافتراضية).

    ```yml title="/etc/clickhouse-server/test_function_shell.yaml" theme={null}
    functions:
      type: executable
      name: test_shell
      return_type: String
      argument:
        - type: UInt8
          name: value
      format: TabSeparated
      command: test_shell.sh
    ```
  </Tab>
</Tabs>

<br />

أنشئ ملف البرنامج النصي `test_shell.sh` داخل المجلد `user_scripts` (`/var/lib/clickhouse/user_scripts/test_shell.sh` باستخدام إعدادات المسار الافتراضية).

```bash title="/var/lib/clickhouse/user_scripts/test_shell.sh" theme={null}
#!/bin/bash

while read read_data;
    do printf "$(expr $read_data \* 2)\n";
done
```

```sql title="Query" theme={null}
SELECT test_shell(number) FROM numbers(10);
```

```text title="Result" theme={null}
    ┌─test_shell(number)─┐
 1. │ 0                  │
 2. │ 2                  │
 3. │ 4                  │
 4. │ 6                  │
 5. │ 8                  │
 6. │ 10                 │
 7. │ 12                 │
 8. │ 14                 │
 9. │ 16                 │
10. │ 18                 │
    └────────────────────┘
```

<div id="error-handling">
  ## معالجة الأخطاء
</div>

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

<div id="evaluation-of-argument-expressions">
  ## تقييم تعبيرات الوسائط
</div>

في معظم لغات البرمجة، قد لا يُقيَّم أحد الوسائط مع بعض المعاملات.
وعادةً ما تكون هذه المعاملات هي `&&` و `||` و `?:`.
في ClickHouse، تُقيَّم وسائط الدوال (المعاملات) دائمًا.
ويرجع ذلك إلى أن أجزاءً كاملة من الأعمدة تُقيَّم دفعةً واحدة، بدلًا من حساب كل صف على حدة.

<div id="performing-functions-for-distributed-query-processing">
  ## تنفيذ الدوال في معالجة الاستعلامات الموزعة
</div>

في معالجة الاستعلامات الموزعة، يُنفَّذ أكبر عدد ممكن من مراحل معالجة الاستعلام على الخوادم البعيدة، وتُنفَّذ بقية المراحل (مثل دمج النتائج الوسيطة وكل ما يلي ذلك) على الخادم الطالب.

وهذا يعني أن الدوال قد تُنفَّذ على خوادم مختلفة.
على سبيل المثال، في الاستعلام `SELECT f(sum(g(x))) FROM distributed_table GROUP BY h(y),`

* إذا كان `distributed_table` يحتوي على shardين على الأقل، فستُنفَّذ الدالتان 'g' و 'h' على الخوادم البعيدة، بينما تُنفَّذ الدالة 'f' على الخادم الطالب.
* إذا كان `distributed_table` يحتوي على shard واحد فقط، فستُنفَّذ جميع الدوال 'f' و 'g' و 'h' على خادم هذا الـ shard.

عادةً لا تعتمد نتيجة الدالة على الخادم الذي تُنفَّذ عليه. لكن في بعض الحالات يكون ذلك مهمًا.
فعلى سبيل المثال، تستخدم الدوال التي تعمل مع القواميس القاموس الموجود على الخادم الذي تعمل عليه.
ومثال آخر هو الدالة `hostName`، التي تُرجع اسم الخادم الذي تعمل عليه، بحيث يمكن تنفيذ `GROUP BY` حسب الخوادم في استعلام `SELECT`.

إذا كانت دالة في استعلام ما تُنفَّذ على الخادم الطالب، لكنك تحتاج إلى تنفيذها على الخوادم البعيدة، فيمكنك تغليفها داخل الدالة التجميعية 'any' أو إضافتها إلى مفتاح في `GROUP BY`.

<div id="sql-user-defined-functions">
  ## دوال SQL المعرفة من قبل المستخدم
</div>

يمكن إنشاء دوال مخصصة من تعبيرات lambda باستخدام عبارة [CREATE FUNCTION](/docs/ar/reference/statements/create/function). ولحذف هذه الدوال، استخدم عبارة [DROP FUNCTION](/docs/ar/reference/statements/drop#drop-function).

<div id="webassembly-user-defined-functions">
  ## دوال WebAssembly المعرّفة من قبل المستخدم
</div>

<CloudNotSupportedBadge />

<ExperimentalBadge />

تتيح لك دوال WebAssembly المعرّفة من قبل المستخدم (WASM UDFs) تشغيل تعليمات برمجية مخصّصة مُجمَّعة إلى WebAssembly داخل عملية خادم ClickHouse.

<div id="quick-start">
  ### البدء السريع
</div>

فعِّل دعم WebAssembly التجريبي في تهيئة ClickHouse:

```xml theme={null}
<clickhouse>
    <allow_experimental_webassembly_udf>true</allow_experimental_webassembly_udf>
</clickhouse>
```

أدرِج وحدة WASM المُجمَّعة في جدول النظام:

```sql theme={null}
INSERT INTO system.webassembly_modules (name, code)
SELECT 'my_module', base64Decode('AGFzbQEAAAA...');
```

أنشئ FUNCTION باستخدام وحدة WASM الخاصة بك:

```sql theme={null}
CREATE FUNCTION my_function
LANGUAGE WASM
ABI ROW_DIRECT
FROM 'my_module'
ARGUMENTS (x UInt32, y UInt32)
RETURNS UInt32;
```

استخدم FUNCTION في استعلاماتك:

```sql theme={null}
SELECT my_function(10, 20);
```

<div id="more-information">
  ### مزيد من المعلومات
</div>

راجِع وثائق [دوال WebAssembly المعرّفة من قبل المستخدم](/docs/ar/reference/functions/regular-functions/wasm_udf) لمزيد من التفاصيل.

<div id="driver-based-executable-user-defined-functions">
  ## الدوال المعرّفة من قبل المستخدم القابلة للتنفيذ المعتمدة على برامج التشغيل
</div>

<CloudNotSupportedBadge />

<ExperimentalBadge />

<Note>
  هذه ميزة تجريبية قد تتغيّر مستقبلاً بطرق قد لا تكون متوافقة مع الإصدارات السابقة. فعِّلها باستخدام إعداد الخادم [`allow_experimental_executable_udf_drivers`](/docs/ar/reference/settings/server-settings/settings#allow_experimental_executable_udf_drivers).
</Note>

*برنامج التشغيل* هو مهايئ يوفّره المشغّل لتحويل مقتطف من شيفرة المستخدم إلى [دالة معرّفة من قبل المستخدم قابلة للتنفيذ](#executable-user-defined-functions) يمكن تشغيلها. عند إنشاء دالة باستخدام `ENGINE = DriverName(...)`، يشغّل ClickHouse الأمر `create_command` الخاص ببرنامج التشغيل، مع تمرير توقيع الدالة ومحتوى الشيفرة إليه. بعد ذلك، يترجم برنامج التشغيل هذا المحتوى أو يعالجه بطريقة أخرى، ثم يطبع إعدادات دالة معرّفة من قبل المستخدم قابلة للتنفيذ، ليقوم ClickHouse بعدها بتخزينها وتحميلها.

يتيح ذلك للمسؤولين توفير طريقة آمنة ومحدودة للمستخدمين لتعريف دوال بلغة برمجة كيفما كانت (على سبيل المثال، C بعد ترجمتها داخل حاوية معزولة) من دون منحهم إمكانية الوصول إلى ملفات تهيئة الخادم أو نظام الملفات. وتظل مجموعة برامج التشغيل المتاحة خاضعة بالكامل لسيطرة المشغّل.

<div id="enabling-drivers">
  ### تمكين برامج التشغيل
</div>

تكون UDFs القابلة للتنفيذ المعتمدة على برامج التشغيل معطّلة افتراضيًا. لتمكينها:

1. عيّن خيار Experimental في إعدادات الخادم:

   ```xml theme={null}
   <clickhouse>
       <allow_experimental_executable_udf_drivers>true</allow_experimental_executable_udf_drivers>
   </clickhouse>
   ```

2. وجّه `user_defined_executable_function_drivers_config` إلى ملف configuration واحد أو أكثر لبرامج التشغيل (مع دعم نمط `glob`)، واضبط اختياريًا [`dynamic_user_defined_executable_functions_path`](/docs/ar/reference/settings/server-settings/settings#dynamic_user_defined_executable_functions_path)، وهو الدليل الذي تُخزَّن فيه ملفات configuration المُولَّدة الخاصة بـ UDFs القابلة للتنفيذ:

   ```xml theme={null}
   <clickhouse>
       <user_defined_executable_function_drivers_config>user_defined_executable_function_drivers_config.d/*_driver.xml</user_defined_executable_function_drivers_config>
       <dynamic_user_defined_executable_functions_path>/var/lib/clickhouse/dynamic_user_defined_executable_functions/</dynamic_user_defined_executable_functions_path>
   </clickhouse>
   ```

يُحمَّل سجل برامج التشغيل عند بدء تشغيل الخادم، ويُحدَّث عند `SYSTEM RELOAD CONFIG`، لذلك يمكن إضافة برامج التشغيل أو تعديلها أو إزالتها دون إعادة تشغيل الخادم.

<div id="driver-configuration">
  ### إعداد برنامج التشغيل
</div>

يُعرَّف برنامج التشغيل من خلال ملف XML (أو YAML) يحتوي على عنصر `<driver>` في المستوى الأعلى. الحقول التالية مدعومة:

| الحقل              | الوصف                                                                                                                                                     | مطلوب |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
| `name`             | اسم برنامج التشغيل، كما يُستخدم في `CREATE FUNCTION ... ENGINE = <name>(...)`.                                                                            | نعم   |
| `create_command`   | المسار إلى البرنامج الذي يُستدعى لإنشاء UDF من مقتطف شيفرة. تُفسَّر المسارات النسبية بالاستناد إلى ملف إعداد برنامج التشغيل.                              | نعم   |
| `drop_command`     | المسار إلى البرنامج الذي يُستدعى عند حذف دالة تستند إلى برنامج التشغيل هذا.                                                                               | لا    |
| `engine_arguments` | يحدّد الوسيطات المسموح بها داخل `ENGINE = DriverName(...)`. كل عنصر فرعي هو اسم وسيطة؛ ويُشير العنصر الفرعي `<required>true</required>` إلى أنها إلزامية. | لا    |
| `env`              | متغيرات البيئة المُصدَّرة عند استدعاء أوامر برنامج التشغيل.                                                                                               | لا    |

مثال على إعداد برنامج التشغيل:

```xml theme={null}
<clickhouse>
    <driver>
        <name>DockerC</name>
        <create_command>../user_defined_executable_function_drivers/docker_c_create.sh</create_command>
        <drop_command>../user_defined_executable_function_drivers/docker_c_drop.sh</drop_command>
        <engine_arguments>
            <opt_level><required>false</required></opt_level>
        </engine_arguments>
        <env>
            <CLICKHOUSE_C_DRIVER_MEMORY>256m</CLICKHOUSE_C_DRIVER_MEMORY>
            <CLICKHOUSE_C_DRIVER_CPUS>1.0</CLICKHOUSE_C_DRIVER_CPUS>
        </env>
    </driver>
</clickhouse>
```

<div id="driver-invocation-contract">
  #### بروتوكول استدعاء برنامج التشغيل
</div>

عند تنفيذ `CREATE FUNCTION`، يُستدعى `create_command` بعد ضبط متغيرات `env` المهيأة، مع تمرير الوسيطات التالية:

* `--name <function_name>`
* `--return <return_type>` (إذا وُجد بند `RETURNS`)
* `--args <signature>` (إذا وُجد بند `ARGUMENTS`)، حيث يمثّل التوقيع قائمة الوسيطات المعلنة، مثل `x UInt8, y DateTime`
* `--<key> <value>` لكل وسيط engine مُعلن وممرَّر في `ENGINE = DriverName(key = value)`

يُرسَل متن شيفرة المستخدم (النص بعد `AS`) إلى الإدخال القياسي للأمر. ويجب أن يطبع الأمر تهيئة UDF executable إلى المخرج القياسي. ويُكتشَف format تلقائيًا: فإذا بدأ المخرج بـ `<` عُدّ XML، وإلا عُدّ YAML. ويجب أن يطابق اسم الدالة المعرَّفة في التهيئة المُولَّدة الاسم الذي يجري إنشاؤه. وإذا أنهى `create_command` التنفيذ بحالة غير صفرية، يفشل statement مع Exception تتضمن رمز الخروج والخطأ القياسي لبرنامج التشغيل.

ويُستدعى `drop_command`، عند وجوده، بالطريقة نفسها (ولكن من دون متن شيفرة على `stdin`) عند حذف الدالة.

<div id="creating-a-function-with-a-driver">
  ### إنشاء function
</div>

```sql theme={null}
CREATE [OR REPLACE] FUNCTION [IF NOT EXISTS] name [ON CLUSTER cluster]
    ARGUMENTS (a UInt8, b String) RETURNS UInt64
    ENGINE = DriverName(key1 = 'value1', key2 = 42)
    AS '...code body...'
```

يشغّل ClickHouse الأمر `create_command` الخاص ببرنامج التشغيل، ويكتب التهيئة الناتجة إلى [`dynamic_user_defined_executable_functions_path`](/docs/ar/reference/settings/server-settings/settings#dynamic_user_defined_executable_functions_path)، ثم يكتشفها مُحمِّل UDF التنفيذي الحالي. بعد ذلك يمكن استدعاء الدالة مثل أي دالة أخرى.

<div id="dropping-a-function-with-a-driver">
  ### حذف دالة
</div>

```sql theme={null}
DROP FUNCTION [IF EXISTS] name [ON CLUSTER cluster]
```

يستدعي `DROP FUNCTION` الأمر `drop_command` الخاص ببرنامج التشغيل (إن وُجد)، ويزيل التهيئة الديناميكية المُنشأة ودليل العمل الخاص بكل دالة، ويُعيد تحميل مُحمِّل UDF التنفيذي، ويزيل الاستعلام المحفوظ.

<div id="driver-persistence-and-restart">
  ### الاستمرارية وإعادة التشغيل
</div>

يُحفَظ الاستعلام الأصلي على هيئة عبارة `ATTACH FUNCTION ...` في دليل كائنات SQL المعرَّفة من قبل المستخدم، بحيث تبقى الدالة بعد إعادة تشغيل الخادم. عند بدء التشغيل، تُحمَّل التهيئات المُولَّدة في [`dynamic_user_defined_executable_functions_path`](/docs/ar/reference/settings/server-settings/settings#dynamic_user_defined_executable_functions_path) مباشرةً من دون إعادة تشغيل برنامج التشغيل. وإذا لم تكن لعبارة `ATTACH FUNCTION` المحفوظة تهيئة مُولَّدة مطابقة (على سبيل المثال، إذا فُقد الدليل الديناميكي)، فستُعاد تشغيل برنامج التشغيل لإعادة إنشائها.

<div id="driver-limitations">
  ### القيود
</div>

* هذه الميزة تجريبية ولا تتاح إلا عند تفعيل `allow_experimental_executable_udf_drivers`.
* الدوال المستندة إلى برامج التشغيل غير مدعومة مع التخزين المُكرَّر للدوال المعرّفة من قبل المستخدم (`ON CLUSTER` و `<user_defined_zookeeper_path>`)، لأن الاستعلام الأصلي فقط هو الذي يُكرَّر، وليس الملفات الناتجة.
* تؤدي عملية `RESTORE` لدالة مستندة إلى برنامج تشغيل جرى أخذ نسخة احتياطية لها إلى الاحتفاظ بالاستعلام، لكنها لا تعيد تشغيل برنامج التشغيل؛ إذ تُطبَّق التهيئة المُولَّدة وتُحفَظ لاحقًا أثناء استرداد إعادة التشغيل.

<div id="example-c-drivers">
  ### مثال على برامج تشغيل C
</div>

تتضمن شجرة المصدر برامج تشغيل تجريبية لإثبات المفهوم ضمن `programs/server/user_defined_executable_function_drivers_config.d/`، وهي تُترجم جسم دالة بلغة C وتُشغّله. وهذه مجرد أمثلة و**لا تُثبَّت عبر الحزم**:

* `DockerC` - يترجم الشيفرة ويشغّلها داخل حاويات Docker معزولة (`--network=none --read-only --cap-drop=ALL --security-opt=no-new-privileges`، بالإضافة إلى حدود الذاكرة/CPU/PID)، ويُنتج UDF من النوع `executable_pool`.
* `GVisorC` - نسخة بديلة تشغّل الملف التنفيذي المترجم ضمن بيئة التشغيل [gVisor](https://gvisor.dev/) `runsc`.
* `UnsafeC` - يترجم الشيفرة ويشغّلها مباشرة على المضيف من دون sandbox. وكما يوحي الاسم، فهو لا يوفّر أي عزل، وهو مخصّص فقط للبيئات الموثوقة ولأغراض الاختبار.

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

<div id="related-content">
  ## محتوى ذو صلة
</div>

* [الدوال المعرَّفة من قبل المستخدم في ClickHouse Cloud](https://clickhouse.com/blog/user-defined-functions-clickhouse-udfs)
