| SLAPD-SQL(5) | File Formats Manual | SLAPD-SQL(5) |
نام (NAME)
slapd-sql - بکاند پایگاهداده رابطهای SQL برای slapd
خلاصه (SYNOPSIS)
/etc/openldap/slapd.conf
توضیحات (DESCRIPTION)
هدف اصلی این بکاند slapd(8) ارائه (PRESENT) اطلاعات ذخیرهشده در یک سامانه مدیریت پایگاهداده رابطهای (RDBMS) به صورت یک زیردرخت LDAP بدون نیاز به هیچگونه برنامهنویسی است (البته مقداری SQL و احتمالاً رویههای ذخیرهشده را نمیتوان برنامهنویسی به حساب آورد ;) ).
به عنوان مثال، زمانی که شما (مانند یک ISP) اطلاعات حسابهای کاربری را در یک RDBMS نگهداری میکنید و مایلید از راهکارهای مدرنی استفاده نمایید که انتظار دارند این اطلاعات در LDAP باشد (برای احراز هویت کاربران، جستجوی آدرسهای ایمیل و غیره). یا زمانی که میخواهید اطلاعات را میان سایتها یا برنامههای مختلفی که از RDBMSها و/یا LDAP استفاده میکنند همگامسازی یا توزیع کنید. یا هر سناریوی دیگری...
این بکاند به عنوان یک بکاند عمومی که به جای LMDB از RDBMS استفاده کند (همانطور که بکاند استاندارد MDB عمل میکند) طراحی نشده است، هرچند میتوان با چند محدودیت از آن به این شکل نیز استفاده کرد. برای کسب اطلاعات بیشتر در این خصوص میتوانید به نشانی http://www.openldap.org/faq/index.cgi?file=378 (بخش OpenLDAP FAQ-O-Matic/General LDAP FAQ/Directories vs. conventional databases) مراجعه کنید.
ایده اصلی (که در ادامه با جزئیات آمده است) استفاده از مقداری فراداده (meta-information) برای ترجمه پرسوجوهای LDAP به پرسوجوهای SQL است، به طوری که طرحواره رابطهای (relational schema) دستنخورده باقی بماند تا برنامههای قدیمی بتوانند بدون هیچ تغییری به استفاده از آن ادامه دهند. این امر به برنامههای SQL و LDAP اجازه میدهد تا بدون نیاز به همتاسازی (تکرار دادهها)، با یکدیگر تعامل داشته باشند و دادهها را بر حسب نیاز مبادله نمایند.
بکاند SQL به گونهای طراحی شده است که بدون نیاز به تغییر کد منبع (از طریق فرادادههای ذکر شده)، تقریباً با هر طرحواره رابطهای قابل تنظیم باشد. همچنین، این بکاند از ODBC برای اتصال به RDBMSها استفاده میکند و برای لهجههای مختلف SQL که ممکن است RDBMSها استفاده کنند بسیار پیکربندیپذیر است؛ بنابراین میتوان از آن برای ادغام و توزیع دادهها روی RDBMSها، سیستمعاملها و میزبانهای مختلف یا به عبارت دیگر، در یک محیط کاملاً ناهمگن استفاده نمود.
این بکاند آزمایشی (experimental) است.
پیکربندی (CONFIGURATION)
این گزینههای slapd.conf برای پایگاهداده بکاند SQL اعمال میشوند، به این معنی که باید پس از خط "database sql" و پیش از هر خط بعدی "backend" یا "database" قرار گیرند. سایر گزینههای پایگاهداده که مختص این بکاند نیستند در صفحه راهنمای slapd.conf(5) شرح داده شدهاند.
پیکربندی منبع داده (DATA SOURCE CONFIGURATION)
- dbname <datasource name>
- نام منبع داده ODBC مورد استفاده.
dbhost <hostname>
dbpasswd <password>
dbuser <username>
پیکربندی محدوده جستجو (SCOPING CONFIGURATION)
این گزینهها الگوهای پرسوجوی SQL را برای محدود کردن دامنههای جستجو مشخص میکنند.
- subtree_cond <SQL expression>
- یک الگوی عبارت where را مشخص میکند که برای ایجاد شرط جستجوی زیردرخت (subtree) استفاده میشود (dn="(.+,)?<dn>$"). این الگو ممکن است از یک لهجه SQL به لهجه دیگر متفاوت باشد (نمونهها را ببینید). بهطور پیشفرض، بر اساس نحوه نرمالسازی مقادیر DN ساخته میشود (به عنوان مثال "<upper_func>(ldap_entries.dn) LIKE CONCAT('%',?)")؛ برای جزئیات بیشتر به بخش "پیکربندی توابع کمکی" و توضیحات upper_func، upper_needs_cast، concat_pattern و strcast_func مراجعه کنید.
- children_cond <SQL expression>
- یک الگوی عبارت where را مشخص میکند که برای ایجاد شرط جستجوی فرزندان (children) استفاده میشود (dn=".+,<dn>$"). این الگو ممکن است از یک لهجه SQL به لهجه دیگر متفاوت باشد (نمونهها را ببینید). بهطور پیشفرض، بر اساس نحوه نرمالسازی مقادیر DN ساخته میشود (به عنوان مثال "<upper_func>(ldap_entries.dn) LIKE CONCAT('%,',?)")؛ برای جزئیات بیشتر به بخش "پیکربندی توابع کمکی" و توضیحات upper_func، upper_needs_cast، concat_pattern و strcast_func مراجعه کنید.
- use_subtree_shortcut { YES | no }
- در صورتی که searchBase برابر با پسوند (suffix) پایگاهداده باشد و محدوده جستجو subtree باشد، از شرط subtree استفاده نکن؛ بلکه تمام مدخلها را جمعآوری کن.
پیکربندی دستورات SQL (STATEMENT CONFIGURATION)
این گزینهها الگوهای پرسوجوی SQL را برای بارگذاری فرادادههای نگاشت طرحواره، افزودن و حذف مدخلها در ldap_entries و غیره مشخص میکنند. تمامی این موارد و همچنین subtree_cond باید دارای مقادیر پیشفرض تعیینشده باشند. برای اطلاع از مقدار جاری توصیه میشود به کد منبع یا به خروجی لاگ هنگام اجرای slapd با گزینه "-d 5" یا بالاتر مراجعه فرمایید. توجه داشته باشید که تعداد و ترتیب پارامترها نباید تغییر کند.
- oc_query <SQL expression>
- پرسوجویی که برای جمعآوری دادههای نگاشت objectClass از جدول ldap_oc_mappings استفاده میشود؛ برای جزئیات به بخش "فرادادههای مورد استفاده" مراجعه کنید. مقدار پیشفرض عبارت است از: "SELECT id, name, keytbl, keycol, create_proc, delete_proc, expect_return FROM ldap_oc_mappings".
- at_query <SQL expression>
- پرسوجویی که برای جمعآوری دادههای نگاشت attributeType از جدول ldap_attr_mappings استفاده میشود؛ برای جزئیات به بخش "فرادادههای مورد استفاده" مراجعه کنید. مقدار پیشفرض عبارت است از: "SELECT name, sel_expr, from_tbls, join_where, add_proc, delete_proc, param_order, expect_return FROM ldap_attr_mappings WHERE oc_map_id=?".
- id_query <SQL expression>
- پرسوجویی که برای نگاشت یک DN به یک مدخل در جدول ldap_entries استفاده میشود؛ برای جزئیات به بخش "فرادادههای مورد استفاده" مراجعه کنید. مقدار پیشفرض عبارت است از: "SELECT id,keyval,oc_map_id,dn FROM ldap_entries WHERE <DN match expr>"، که در آن <DN match expr> بر اساس نحوه نرمالسازی مقادیر DN ساخته میشود (برای نمونه "dn=?" اگر ابزاری برای بزرگنویسی رشتهها در دسترس نباشد؛ معمولاً "<upper_func>(dn)=?" استفاده میشود)؛ برای جزئیات بیشتر به بخش "پیکربندی توابع کمکی" و توضیحات upper_func، upper_needs_cast، concat_pattern و strcast_func مراجعه کنید.
- insentry_stmt <SQL expression>
- دستوری که برای درج یک مدخل جدید در جدول ldap_entries استفاده میشود؛ برای جزئیات به بخش "فرادادههای مورد استفاده" مراجعه کنید. مقدار پیشفرض عبارت است از: "INSERT INTO ldap_entries (dn, oc_map_id, parent, keyval) VALUES (?, ?, ?, ?)".
- delentry_stmt <SQL expression>
- دستوری که برای حذف یک مدخل موجود از جدول ldap_entries استفاده میشود؛ برای جزئیات به بخش "فرادادههای مورد استفاده" مراجعه کنید. مقدار پیشفرض عبارت است از: "DELETE FROM ldap_entries WHERE id=?".
- delobjclasses_stmt <SQL expression>
- دستوری که برای حذف شناسه یک مدخل موجود از جدول ldap_objclasses استفاده میشود؛ برای جزئیات به بخش "فرادادههای مورد استفاده" مراجعه کنید. مقدار پیشفرض عبارت است از: "DELETE FROM ldap_entry_objclasses WHERE entry_id=?".
پیکربندی توابع کمکی (HELPER CONFIGURATION)
این دستورالعملها برای تغییر رفتار پیشفرض بکاند متناسب با ویژگیها و رفتارهای لهجه خاص RDBMS به کار میروند. گزینههای نخست اساساً به نرمالسازی رشته و DN هنگام ساخت فیلترها اشاره دارند. نرمالسازی در LDAP چیزی فراتر از تبدیل تمام حروف به بزرگ (یا کوچک) است؛ با این حال، به عنوان یک راهکار میانه و منطقی برای RDBMSهایی که به بزرگی و کوچکی حروف حساس هستند (case-sensitive)، میتوان با ارائه دستورالعمل upper_func به بکاند دستور داد که رشتهها و DNها را با حروف بزرگ بنویسد. برخی از RDBMSها برای استفاده از توابع روی انواع داده دلخواه (مانند ثابتهای رشتهای)، نیازمند تبدیل نوع صریح (cast) هستند که توسط دستورالعمل upper_needs_cast فعال میشود. در صورت نیاز، با استفاده از دستورالعمل strcast_func میتوان یک تابع تبدیل به رشته را نیز معرفی کرد. در نهایت، ممکن است یک الگوی سفارشی برای الحاق رشتهها (concatenation) لازم باشد؛ که این الگو توسط دستورالعمل concat_pattern تعیین میشود.
- upper_func <SQL function name>
- نام تابعی را مشخص میکند که مقدار دادهشده را به حروف بزرگ تبدیل میکند. این گزینه برای تطابق بدون توجه به بزرگی و کوچکی حروف در شرایطی که RDBMS به حروف حساس است استفاده میشود. این تابع ممکن است در لهجههای مختلف SQL تفاوت داشته باشد (مانند UCASE، UPPER یا هر چیز دیگر؛ نمونهها را ببینید). بهطور پیشفرض، از هیچ تابعی استفاده نمیشود؛ یعنی رشتهها با حروف بزرگ بازنویسی نمیشوند و ممکن است تطابقها به بزرگی و کوچکی حروف حساس باشند.
- upper_needs_cast { NO | yes }
- اگر upper_func هنگام اعمال روی ثابتهای رشتهای (literal strings) نیاز به تبدیل نوع صریح (cast) دارد، این دستورالعمل را روی yes تنظیم کنید. یک تبدیل نوع به صورت CAST (<arg> AS VARCHAR(<max DN length>)) به کار گرفته میشود که در آن <max DN length> در back-sql به صورت توکار تعریف شده است؛ ماکروی BACKSQL_MAX_DN_LEN را ببینید (در حال حاضر ۲۵۵؛ توجه کنید که محدودیت توکار slapd در ماکروی SLAP_LDAPDN_MAXLEN، برابر با ۸۱۹۲ تنظیم شده است). این قابلیت بهصورت آزمایشی است و ممکن است در نسخههای آینده تغییر کند.
- strcast_func <SQL function name>
- نام تابعی را مشخص میکند که برای مرتبسازی مناسب، مقدار دادهشده را به یک رشته تبدیل میکند. این تابع در دستورات "SELECT DISTINCT" برای RDBMSهایی با نوعبندی قوی که تبدیل نوع ضمنی اندکی دارند (مانند PostgreSQL)، هنگامی که یک ثابت رشتهای مشخص شده است، استفاده میشود. این قابلیت بهصورت آزمایشی است و ممکن است در نسخههای آینده تغییر کند.
- concat_pattern <pattern>
- این دستورالعمل الگویی را تعریف میکند که برای الحاق رشتهها استفاده میشود. الگوی مشخصشده باید حتماً شامل دو علامت سوال '?' باشد که با دو رشتهای که باید به هم متصل شوند جایگزین میگردند. مقدار پیشفرض CONCAT(?,?) است؛ قالبی که سازگاری بسیار بالایی دارد (مانند IBM db2 و PostgreSQL) عبارت است از ?||?، اما هنگام کار با رشتههای صریح ممکن است نیاز به تبدیل صریح نوع (cast) داشته باشد: CAST(?||? AS VARCHAR(<length>)). در برخی RDBMSها (مانند IBM db2 و MSSQL) قالب ?+? نیز به درستی کار میکند. مستندات RDBMS خود را به دقت بررسی کنید یا به مثالهای مربوط به پایگاههای داده پشتیبانیشده بسنده نمایید. این قابلیت بهصورت آزمایشی است و ممکن است در نسخههای آینده تغییر کند.
- aliasing_keyword <string>
- کلمه کلیدی برای نام مستعار (aliasing) را تعریف میکند. برخی RDBMSها از کلمه "AS" (پیشفرض) استفاده میکنند و برخی دیگر از هیچ کلمهای استفاده نمینمایند.
- aliasing_quote <string>
- کاراکتر نقلقول را برای کلمه کلیدی نام مستعار تعیین میکند. برخی RDBMSها به هیچ کاراکتری نیاز ندارند (پیشفرض)، در حالی که برخی دیگر ممکن است به نقلقول تکی یا جفتی نیاز داشته باشند.
- has_ldapinfo_dn_ru { NO | yes }
- به طور صریح به بکاند اطلاع میدهد که آیا ستون dn_ru (مقدار DN به صورت معکوس و با حروف بزرگ) در جدول ldap_entries وجود دارد یا خیر. این گزینه بررسی خودکار را لغو میکند (برای مثال در PostgreSQL/unixODBC لازم است). این قابلیت بهصورت آزمایشی است و ممکن است در نسخههای آینده تغییر کند.
- fail_if_no_mapping { NO | yes }
- هنگامی که روی yes تنظیم شود، در صورتی که نگاشت مناسبی میان خصیصههای LDAP و دادههای SQL در دسترس نباشد، عملیات نوشتن خصیصه را با شکست مواجه میکند. رفتار پیشفرض نادیده گرفتن تغییراتی است که قابل نگاشت نیستند. این گزینه هیچ تاثیری بر نگاشت objectClass ندارد؛ یعنی اگر structuralObjectClass یک مدخل از طریق جستجوی نام آن در ldap_oc_mappings نتواند به SQL نگاشت شود، یک عملیات add بدون توجه به وضعیت fail_if_no_mapping شکست خواهد خورد؛ برای جزئیات به بخش "فرادادههای مورد استفاده" مراجعه کنید. این قابلیت بهصورت آزمایشی است و ممکن است در نسخههای آینده تغییر کند.
- allow_orphans { NO | yes }
- هنگامی که روی yes تنظیم شود، مدخلهای بدون والد یا یتیم (یعنی بدون وجود مدخل والد در پایگاهداده) میتوانند اضافه شوند. از این گزینه باید با احتیاط استفاده شود، احتمالاً همراه با قاعدهای خاص در سمت RDBMS که والد ناموجود را به صورت پویا ایجاد کند.
- baseObject [ <filename> ]
- به پایگاهداده دستور میدهد تا به جای جستجو به دنبال مدخل baseObject در RDBMS، آن را در حافظه ایجاد و مدیریت کند. اگر آرگومان (اختیاری) <filename> داده شود، مدخل از آن فایل در قالب LDIF(5) خوانده میشود؛ در غیر این صورت، مدخلی با شیء کلاس extensibleObject بر اساس محتویات RDN مربوط به baseObject ایجاد میگردد. این قابلیت بهویژه زمانی مفید است که اطلاعات ldap_entries به جای یک جدول در یک نما (view) ذخیره شده باشد و union در نماها پشتیبانی نشود، به طوری که نما تنها بتواند یک قاعده را برای محاسبه ساختار مدخل برای یک objectClass مشخص کند. این موضوع در بخش "فرادادههای مورد استفاده" بیشتر مورد بحث قرار گرفته است. این قابلیت بهصورت آزمایشی است و ممکن است در نسخههای آینده تغییر کند.
- create_needs_select { NO | yes }
- به پایگاهداده اعلام میکند که آیا ایجاد مدخل در جدول ldap_entries نیازمند یک select متعاقب برای جمعآوری شناسه اختصاصیافته به صورت خودکار است یا خیر، به جای آنکه توسط یک رویه ذخیرهشده بازگردانده شود.
fetch_attrs <attrlist>
fetch_all_attrs { NO | yes }
- check_schema { YES | no }
- به پایگاهداده دستور میدهد که انطباق مدخلها با طرحواره را پس از تغییرات، و همچنین زنجیره structural objectClass را هنگام ساخته شدن مدخلها بررسی کند. به طور پیشفرض روی yes تنظیم شده است.
- sqllayer <name> [...]
- لایه <name> را روی پشتهای از توابع کمکی که برای نگاشت DNها از نمایش LDAP به SQL و برعکس استفاده میشوند، بارگذاری میکند. آرگومانهای بعدی به روتین پیکربندی لایه فرستاده میشوند. این قابلیت بسیار آزمایشی است و باید با نهایت احتیاط استفاده شود. رابط برنامهنویسی کاربردی (API) لایهها هنوز تثبیت نشده و به همین دلیل منتشر نشده است.
- autocommit { NO | yes }
- تأیید خودکار تراکنشها (autocommit) را فعال میکند؛ به طور پیشفرض غیرفعال (off) است.
فرادادههای مورد استفاده (METAINFORMATION USED)
تقریباً تمام مواردی که در ادامه ذکر میشوند در مثالهای واقع در دایرکتوری servers/slapd/back-sql/rdbms_depend/ در درخت کد منبع OpenLDAP نشان داده شدهاند و شامل اسکریپتهایی برای تولید پایگاهداده نمونه برای Oracle، MS SQL Server، MySQL و موارد دیگر (شامل PostgreSQL و IBM db2) هستند.
اولین کاری که باید انجام شود این است که مشخص کنید چه مجموعهای از کلاسهای اشیاء (object classes) در LDAP میتوانند اطلاعات RDBMS شما را ارائه دهند.
سادهترین راه ایجاد یک objectClass برای هر موجودیتی است که هنگام طراحی طرحواره رابطهای در نمودار ER داشتهاید. هر طرحواره رابطهای، هر چقدر هم که نرمالسازی شده باشد، بر اساس مدلی از دامنه برنامه شما طراحی شده است (مثلاً حسابها، سرویسها و غیره در ISP) و بر اساس موجودیتهای آن استفاده میشود، نه صرفاً بر اساس جداول طرحواره نرمالشده. این به این معنی است که برای هر خصیصه از هر یک از این نمونهها، یک پرسوجوی موثر در SQL وجود دارد که مقادیر آن را بارگذاری میکند.
همچنین ممکن است بخواهید کلاسهای اشیاء شما با برخی از طرحوارههای استاندارد مانند inetOrgPerson و غیره مطابقت داشته باشند.
با این حال، هنگام تأمل در این باره، باید روشی برای ترجمه درخواستهای عملیات LDAP به (مجموعهای از) پرسوجوهای SQL تعریف کنیم. بیایید به عملیات جستجو (SEARCH) بپردازیم.
مثال: فرض کنیم اطلاعات مربوط به افراد شاغل در سازمان خود را در دو جدول ذخیره میکنیم:
PERSONS PHONES ---------- ------------- id integer id integer first_name varchar pers_id integer references persons(id) last_name varchar phone middle_name varchar ...
(جدول PHONES حاوی شماره تلفنهای مرتبط با افراد است). یک شخص میتواند چندین شماره داشته باشد، که در این صورت PHONES حاوی چندین رکورد با pers_id مربوطه خواهد بود، یا هیچ شمارهای نداشته باشد (و هیچ رکوردی در PHONES با چنین pers_id وجود نداشته باشد). یک objectclass در LDAP برای ارائه چنین اطلاعاتی میتواند شبیه به این باشد:
person ------- MUST cn MAY telephoneNumber $ firstName $ lastName ...
برای واکشی تمام مقادیر خصیصه cn با داشتن شناسه شخص، پرسوجوی زیر را میسازیم:
SELECT CONCAT(persons.first_name,' ',persons.last_name)
AS cn FROM persons WHERE persons.id=?
برای telephoneNumber میتوانیم از این پرسوجو استفاده کنیم:
SELECT phones.phone AS telephoneNumber FROM persons,phones
WHERE persons.id=phones.pers_id AND persons.id=?
اگر میخواستیم به درخواستهای LDAP با فیلترهایی مانند (telephoneNumber=123*) پاسخ دهیم، چیزی شبیه به این میساختیم:
SELECT ... FROM persons,phones
WHERE persons.id=phones.pers_id
AND persons.id=?
AND phones.phone like '%1%2%3%'
(توجه کنید که چگونه تطابق telephoneNumber به چندین نویسه عمومی (wildcard) گسترش مییابد تا کاراکترهای بیاثر درجشده مانند فاصلهها، خطتیرهها و غیره را در نظر بگیرد؛ این امر از روی طراحی رخ میدهد زیرا telephoneNumber بر اساس نحو شناختهشده خاصی تعریف شده است). بنابراین، اگر اطلاعاتی در این باره داشتیم که چه جداولی حاوی مقادیر هر خصیصه هستند، چگونه این جداول را پیوند (join) دهیم و این مقادیر را مرتب کنیم، میتوانستیم سعی کنیم چنین دستوراتی را به طور خودکار تولید نماییم و فیلترهای جستجو را به عبارتهای WHERE در SQL ترجمه کنیم.
برای ذخیره چنین اطلاعاتی، سه جدول دیگر به طرحواره خود اضافه میکنیم و آن را با دادهها پر مینماییم (نمونهها را ببینید):
ldap_oc_mappings (some columns are not listed for clarity) --------------- id=1 name="person" keytbl="persons" keycol="id"
این جدول نگاشتی بین objectclass (نام آن در ستون "name" نگهداری میشود) و جدولی که کلید اصلی موجودیتهای متناظر را نگه میدارد تعریف میکند. برای مثال، در نمونه ما، موجودیت فرد (person) که در تلاشیم آن را به عنوان شیء کلاس "person" ارائه دهیم، در دو جدول (persons و phones) قرار دارد و با ستون persons.id (که آن را کلید اصلی این موجودیت مینامیم) شناسایی میشود. بنابراین Keytbl و keycol به ترتیب حاوی "persons" (نام جدول) و "id" (نام ستون) هستند.
ldap_attr_mappings (some columns are not listed for clarity) ----------- id=1 oc_map_id=1 name="cn" sel_expr="CONCAT(persons.first_name,' ',persons.last_name)" from_tbls="persons" join_where=NULL ************ id=<n> oc_map_id=1 name="telephoneNumber" sel_expr="phones.phone" from_tbls="persons,phones" join_where="phones.pers_id=persons.id"
این جدول نگاشتهای بین خصیصههای LDAP و پرسوجوهای SQL که مقادیر آنها را بارگذاری میکنند، تعریف میکند. توجه داشته باشید که بر خلاف طرحواره LDAP، اینها انواع خصیصه (attribute types) نیستند؛ خصیصه "cn" برای شیء کلاس "person" میتواند مقادیر خود را در جداولی متفاوت از خصیصه "cn" برای شیء کلاس دیگری داشته باشد، بنابراین نگاشتهای خصیصه به نگاشتهای شیء کلاس وابسته هستند (برخلاف انواع خصیصه در طرحواره LDAP که نسبت به کلاسهای اشیاء بیتفاوت هستند). بنابراین، ما ستون oc_map_id را داریم که پیوندی به جدول oc_mappings دارد.
اکنون پرسوجوی SQL را که مقادیر یک خصیصه مشخص را بارگذاری میکند به ۳ بخش تقسیم میکنیم. بخش اول در ستون sel_expr قرار میگیرد؛ این همان عبارتی است که بین کلمات کلیدی SELECT و FROM داشتیم، که مشخص میکند چه چیزی بارگذاری شود. بخش بعدی لیست جداول است؛ متنی که بین کلمات کلیدی FROM و WHERE قرار دارد. این بخش برای راحتی میتواند شامل نامهای مستعار (aliases) باشد (مثالها را ببینید). بخش آخر، قسمتی از عبارت where است که (در صورت وجود) شرط پیوند (join) جدول حاوی مقادیر با جدول حاوی کلید اصلی را بیان میکند (تساوی کلید خارجی و مواردی از این دست). اگر مقادیر در همان جدول کلید اصلی باشند، این ستون مقدار NULL باقی میماند (مانند خصیصه cn در بالا).
با داشتن این اطلاعات به صورت مجزا، ما نه تنها قادر خواهیم بود پرسوجوهایی بسازیم که مقادیر خصیصهها را با استفاده از شناسه مدخل بارگذاری کنند (برای این کار میتوانستیم کل پرسوجوی SQL را ذخیره کنیم)، بلکه پرسوجوهایی بسازیم که شناسههای اشیائی را که با یک فیلتر جستجوی مشخص (یا حداقل بخشی از آن) مطابقت دارند بارگذاری کنند. برای مثالها به بخشهای بعدی مراجعه کنید.
ldap_entries ------------ id=1 dn=<dn you choose> oc_map_id=... parent=<parent record id> keyval=<value of primary key>
این جدول نگاشتهای بین DNهای مدخلها در درخت LDAP شما و مقادیر کلیدهای اصلی دادههای رابطهای مربوطه را تعریف میکند. این جدول ساختاری بازگشتی دارد (ستون parent به ستون id از همین جدول ارجاع میدهد)، که به شما اجازه میدهد هر ساختار درختی دلخواهی را به دادههای رابطهای تخت خود اضافه کنید. با داشتن شناسه نگاشت objectclass، میتوانیم جدول و ستون مربوط به کلید اصلی را تعیین کنیم و keyval مقدار آن را ذخیره میکند، بنابراین چندتایی (tuple) دقیقی که با مدخل LDAP با این DN مطابقت دارد تعریف میشود.
توجه داشته باشید که چنین طراحی (پرسوجوی دقیق ایجاد جدول SQL را ببینید) یک محدودیت مهم ایجاد میکند: کلید باید یک عدد صحیح (integer) باشد. اما بر اساس تمام دانستههای من از طرحوارههای خوب طراحیشده، این محدودیت خیلی محدودکننده نیست ;) اگر کسی نیاز به پشتیبانی از انواع مختلف کلیدها دارد، میتواند یک وصله (patch) بنویسد و آن را به OpenLDAP ITS ارسال کند، سپس من آن را اضافه خواهم کرد.
همچنین، چندین کاربر ابراز داشتند که واقعاً به درختهای خیلی ساختاریافته نیازی ندارند و نمیخواهند هر بار که نمونهای را در طرحواره رابطهای اضافه یا حذف میکنند، یک جدول دیگر را هم بهروزرسانی نمایند. این افراد میتوانند به جای یک جدول واقعی برای ldap_entries از یک نما (view) استفاده کنند، چیزی شبیه به این (توسط Robin Elfrink):
CREATE VIEW ldap_entries (id, dn, oc_map_id, parent, keyval)
AS
SELECT 0, UPPER('o=MyCompany,c=NL'),
3, 0, 'baseObject' FROM unixusers WHERE userid='root'
UNION
SELECT (1000000000+userid),
UPPER(CONCAT(CONCAT('cn=',gecos),',o=MyCompany,c=NL')),
1, 0, userid FROM unixusers
UNION
SELECT (2000000000+groupnummer),
UPPER(CONCAT(CONCAT('cn=',groupname),',o=MyCompany,c=NL')),
2, 0, groupnummer FROM groups;
اگر RDBMS شما از union در نماها پشتیبانی نمیکند، تنها یک objectClass میتواند در ldap_entries نگاشت شود و baseObject را نمیتوان ایجاد کرد؛ در این حالت، برای یک راهکار جایگزین احتمالی دستورالعمل baseObject را ببینید.
عملیات متداول بکاند SQL (TYPICAL SQL BACKEND OPERATION)
پس از بارگذاری فرادادهها، بکاند SQL از این جداول برای تعیین مجموعهای از کلیدهای اصلی نامزدها (بسته به محدوده جستجو و فیلتر) استفاده میکند. این بکاند تلاش میکند این کار را برای هر شیء کلاس ثبتشده در ldap_objclasses انجام دهد.
مثال: برای پرسوجوی ما با فیلتر (telephoneNumber=123*)، پرسوجوی زیر تولید میشود (که شناسههای نامزدها را بارگذاری میکند):
SELECT ldap_entries.id,persons.id, 'person' AS objectClass,
ldap_entries.dn AS dn
FROM ldap_entries,persons,phones
WHERE persons.id=ldap_entries.keyval
AND ldap_entries.objclass=?
AND ldap_entries.parent=?
AND phones.pers_id=persons.id
AND (phones.phone LIKE '%1%2%3%')
(برای جستجوی ONELEVEL) یا "... AND dn=?" (برای جستجوی BASE) یا "... AND dn LIKE '%?'" (برای جستجوی SUBTREE)
سپس، برای هر نامزد، خصیصههای درخواستی را با استفاده از پرسوجوهای اختصاصی به ازای هر خصیصه مانند زیر بارگذاری میکنیم:
SELECT phones.phone AS telephoneNumber FROM persons,phones WHERE persons.id=? AND phones.pers_id=persons.id
سپس، از تابع ()test_filter از API فرانتاند استفاده میکنیم تا مدخل را برای تطابق کامل با فیلتر جستجوی LDAP بیازماییم (از آنجا که نمیتوانیم به طور موثر از نحو خصیصه در طرحواره LDAP متناظر سر در آوریم، فیلتر را به سهلگیرانهترین شرط SQL برای فیلتر کردن نامزدها ترجمه میکنیم) و آن را برای کاربر ارسال مینماییم.
عملیات ADD، DELETE، MODIFY و MODRDN نیز بر اساس فرادادههای به ازای هر خصیصه (مانند add_proc و غیره) انجام میشوند. در این فیلدها میتوان یک دستور SQL یا فراخوانی رویه ذخیرهشده (stored procedure) را مشخص کرد که میتواند مقادیر دادهشده یک خصیصه معین را با استفاده از keyval مدخل دادهشده اضافه یا حذف کند (مثالها را ببینید -- عمدتاً PostgreSQL، ORACLE و MSSQL - زیرا تا زمان نگارش این متن، هیچ رویه ذخیرهشدهای در MySQL وجود ندارد).
ما صرفاً ستونهای بیشتری به ldap_oc_mappings و ldap_attr_mappings اضافه میکنیم که دستورات قابل اجرا (مانند create_proc، add_proc، del_proc و غیره) و پرچمهای تعیینکننده ترتیب پارامترهای ارسالشده به آن دستورات را نگه میدارند. لطفاً نمونهها را بررسی کنید تا دریابید چه پارامترهایی ارسال میشوند و سایر اطلاعات در این زمینه را بیابید؛ این نمونهها برای کسانی که با مفاهیم بیانشده در بالا آشنا هستند کاملاً گویا و خودتوصیف میباشند.
تکنیکهای رایج (COMMON TECHNIQUES)
پیش از هر چیز، بیایید به یاد آوریم که در میان تفاوتهای عمده با مدل کامل دادههای LDAP، مفهوم شرحدادهشده در بالا مستقیماً از قابلیتهایی مانند چندین شیء کلاس به ازای هر مدخل و ارجاعها (referrals) پشتیبانی نمیکند. خوشبختانه به کارگیری آنها در این طرح آسان است. بکاند SQL نیازمند آن است که یک جدول دیگر به طرحواره اضافه شود: ldap_entry_objectclasses(entry_id,oc_name).
آن جدول حاوی هر تعداد نام شیء کلاس است که مدخلهای مربوطه علاوه بر مورد ذکرشده در نگاشت، دارا خواهند بود. بکاند SQL به طور خودکار نگاشت خصیصه برای خصیصه "objectclass" را به هر نگاشت شیء کلاس که مقادیر را از این جدول بارگذاری میکند اضافه مینماید. بنابراین، برای مثال میتوانید یک نگاشت برای inetOrgPerson داشته باشید و از آن برای پرسوجوهای شیء کلاس "person" استفاده کنید...
پیشتر ارجاعها (referrals) به شیوهای آزادتر و با افزودن یک جدول اضافی پیادهسازی میشدند که به هر مدخل اجازه میداد میزبان یک خصیصه "ref" باشد، همراه با یک شیء کلاس اضافی "referral" در جدول ldap_entry_objclasses. در پیادهسازی فعلی، با ارجاعها مانند هر طرحواره تعریفشده توسط کاربر رفتار میشود، زیرا "referral" یک شیء کلاس ساختاری است. رویکرد پیشنهادی، تعریف یک مدخل "referral" در ldap_oc_mappings است که حاوی یک خصیصه نامگذاری (مانند "ou" یا "cn") و یک خصیصه "ref" شامل نشانی اینترنتی (url) باشد؛ در صورتی که چندین ارجاع به ازای هر مدخل مورد نیاز باشد، میتوان جدول جداگانهای برای نشانیهای url ایجاد کرد که در آن نشانیهای url به مدخلهای مربوطه نگاشت شوند. استفاده از خصیصه نامگذاری معمولاً نیازمند افزودن مقدار "extensibleObject" به ldap_entry_objclasses است.
نکات قابل توجه و هشدارها (CAVEATS)
همانطور که قبلاً ذکر شد، این بکاند نباید به عنوان جایگزینی برای سایر بکاندهای ذخیرهسازی داده در نظر گرفته شود، بلکه به عنوان یک دروازه (gateway) به ذخیرهسازهای RDBMS موجود است که باید در قالب LDAP منتشر شوند.
خصیصه عملیاتی hasSubordinates توسط back-sql در نتایج جستجو و در عملیات مقایسه رعایت میشود؛ همچنین در فیلتر کردن نیز تا حدی پشتیبانی میگردد. به دلیل محدودیتهای طراحی، یک فیلتر (شاید نامعقول) به صورت (!(hasSubordinates=TRUE)) به جای بازگرداندن تمام مدخلهای برگ، هیچ نتیجهای نخواهد داد، زیرا در عمل به صورت ... AND NOT (1=1) گسترش مییابد. اگر نیاز دارید تمام مدخلهای برگ را پیدا کنید، لطفاً به جای آن از (hasSubordinates=FALSE) استفاده کنید.
یک مقدار directoryString به صورت "__First___Last_" (که در آن زیرخطها به معنای فاصلهها، نویسه اسکی 0x20 هستند) متناظر با همتای زیباسازیشده آن یعنی "First_Last" است؛ این مورد در حال حاضر در صورتی که دادههای زیباسازینشده از طریق RDBMS نوشته شوند، توسط back-sql رعایت نمیشود؛ اما هنگامی که دادههای زیباسازینشده از طریق back-sql نوشته شوند، در عمل مقادیر زیباسازیشده به جای آن استفاده میشوند.
باگها (BUGS)
هنگامی که جدول ldap_entry_objclasses خالی باشد، فیلترها روی خصیصه objectClass به اشتباه نتیجهای در بر نخواهند داشت و هیچ نامزدی بازگردانده نمیشود. یک راهکار شامل افزودن حداقل یک سطر به آن جدول است، صرفنظر از اینکه معتبر باشد یا خیر.
لایه رونویس کَش پراکسی (PROXY CACHE OVERLAY)
لایه رونویس کَش پراکسی (proxy cache overlay) امکان ذخیرهسازی موقت (caching) درخواستهای جستجوی LDAP (پرسوجوها) را در یک پایگاهداده محلی فراهم میکند. برای جزئیات بیشتر به slapo-pcache(5) مراجعه کنید.
مثالها (EXAMPLES)
ماژولهای نمونه SQL در دایرکتوری slapd/back-sql/rdbms_depend/ در درخت کد منبع OpenLDAP وجود دارند.
کنترل دسترسی (ACCESS CONTROL)
بکاند sql از قواعد معنایی کنترل دسترسی همانطور که در slapd.access(5) بیان شده است پیروی میکند (شامل امتیاز دسترسی disclose هنگامی که در زمان کامپایل فعال شده باشد).
فایلها (FILES)
- /etc/openldap/slapd.conf
- فایل پیکربندی پیشفرض slapd
همچنین ببینید (SEE ALSO)
| 2026/03/09 | OpenLDAP 2.6.13 |