Цитата:
Сообщение от
gl00mie
- Действительно ли можно отключить хинтами использование функциональных индексов для Оракла в AX 2009?
- Если да, то каким именно хинтом это можно сделать?
- Где найти описание хинтов для AX 2009?
Я тут на досуге долго э... смотрел в хрустальный шар и увидел там ответы на эти вопросы. Ответы сводятся к тому, что штатно никакими хинтами отключить использование функциональных индексов в AX 2009 уже, в отличие от 3.0, нельзя. Ниже - краткая выжимка того, что удалось разглядеть в хрустальном шаре.
За использование функциональных индексов в ядре отвечают, насколько я смог разглядеть, три функции, чьи настоящие имена удалось-таки недавно узнать: MONOCASE_FIELD(), MONOCASE_LITERAL() и MONOCASE_PLACEHOLDER(). Вот, к примеру, как выглядит
псевдокод функции MONOCASE_FIELD() в ax32serv.exe версии
3.0 KR3X++:
char* MONOCASE_FIELD(char *pszBuf, CSqlFieldInfo *pSqlFieldInfo, bool forceMonoCase)
{
if (gDatabaseCLI == DatabaseCLI::OCI)
{
if ( !forceMonoCase
|| !pSqlFieldInfo
|| ((fnGetSessionInfo()->getSqlSystem()->DatabaseHints >> 14) & 1)
|| ((fnGetSessionInfo()->getSqlSystem()->DatabaseHints >> 15) & 1)
)
{
strcpy(pszBuf, "%s");
}
else
{
sprintf(pszBuf, "SUBSTR(%s,1,%i)", "NLS_LOWER(%s)", pSqlFieldInfo->cbStringFieldBufSize - 1);
}
}
else
{
if (!forceMonoCase || ((fnGetSessionInfo()->getSqlSystem()->DatabaseHints >> 15) & 1))
{
strcpy(pszBuf, "%s");
}
else
{
strcpy(pszBuf, "{fn LCASE(%s)}");
}
}
return pszBuf;
}
Тут видно, что параметр forceMonoCase (название придумано мной) может быть "перекрыт" хинтом 0x8000 - при его использовании к строковому полю не будут применены никакие дополнительные функции. А теперь как эта же функция выглядит в ax32serv.exe версии
2009 SP1 RU7:
X++:
char* MONOCASE_FIELD(wchar_t *pwszBuf, unsigned int cnBufSize, struSqlFieldInfo *pSqlFieldInfo, bool forceMonoCase)
{
int len;
if (sql_dbcli != DatabaseCLI::OCI)
{
if (forceMonoCase)
{
return StringCchCopyW(pwszBuf, cnBufSize, L"{fn LCASE(%s)}");
}
return StringCchCopyW(pwszBuf, cnBufSize, L"%s");
}
if (!forceMonoCase || !pSqlFieldInfo)
{
return StringCchCopyW(pwszBuf, cnBufSize, L"%s");
}
len = pSqlFieldInfo->BaseType == Types::String ? (*&pSqlFieldInfo->cbStringFieldBufSize >> 1) - 1 : 0;
return StringCchPrintfW(pwszBuf, cnBufSize, L"SUBSTR(%s,1,%i)", L"NLS_LOWER(%s)", len);
}
Все упоминания о хинтах пропали, и определяющим стал параметр forceMonoCase, а этот параметр во всех местах, где вызывается MONOCASE_FIELD(), определяется как
X++:
theDatabase()->DatabaseId == DatabaseId::Oracle
исключение составляет лишь SqlSystem.monocaseFmt() - здесь параметр forceMonoCase по умолчанию равен true, но может принять значение false, если при вызове этого метода указать параметр _considerSystemVariables == true и СУБД окажется
НЕ Oracle. Аналогичная картина наблюдается для остальных двух функций. Вот
псевдокод функции MONOCASE_LITERAL() в ядре
3.0 KR3X++:
char* MONOCASE_LITERAL(char *pszBuf, bool forceMonoCase)
{
if (gDatabaseCLI == DatabaseCLI::OCI)
{
if (forceMonoCase && !((fnGetSessionInfo()->getSqlSystem()->DatabaseHints >> 15) & 1))
{
return strcpy(pszBuf, "NLS_LOWER(%s)");
}
}
else
{
if (forceMonoCase && !((fnGetSessionInfo()->getSqlSystem()->DatabaseHints >> 15) & 1))
{
return strcpy(pszBuf, "{fn LCASE(%s)}");
}
}
return strcpy(pszBuf, "%s");
}
А вот она же в ядре
2009 SP1 RU7:
X++:
wchar_t* MONOCASE_LITERAL(wchar_t *pwszBuf, unsigned int cnBufSize, bool forceMonoCase)
{
if (sql_dbcli != DatabaseCLI::OCI)
{
if (forceMonoCase)
{
return StringCchCopyW(pwszBuf, cnBufSize, L"{fn LCASE(%s)}");
}
}
else
{
if (forceMonoCase)
{
return StringCchCopyW(pwszBuf, cnBufSize, L"NLS_LOWER(%s)");
}
}
return StringCchCopyW(pwszBuf, cnBufSize, L"%s");
}
Вот MONOCASE_PLACEHOLDER() в ядре
3.0 KR3X++:
void MONOCASE_PLACEHOLDER(char *pszBuf, void *a2, bool forceMonoCase, char *pszInOutBuf)
{
// ...
if (*pszInOutBuf)
{
v5 = *a2 + 1;
}
else
{
v5 = *(a2 + 4) + 1;
}
if (gDatabaseCLI == DatabaseCLI::OCI)
{
strcpy(pszInOutBuf), *pszInOutBuf ? "in" : "out");
if (!forceMonoCase || ((fnGetSessionInfo()->getSqlSystem()->DatabaseHints >> 15) & 1))
sprintf(pszBuf, ":%s%i", &pszInOutBuf, v5);
else
sprintf(pszBuf, "NLS_LOWER(:%s%i)", &pszInOutBuf, v5);
}
else
{
if (!forceMonoCase || ((fnGetSessionInfo()->getSqlSystem()->DatabaseHints >> 15) & 1))
sprintf(pszBuf, "?");
else
sprintf(pszBuf, "{fn LCASE(?)}");
}
}
И в ядре
2009 SP1 RU7:
X++:
void MONOCASE_PLACEHOLDER(wchar_t *a1, unsigned int *a2, void *pSqlField, void *pSqlMonocaseParamCnt, bool forceMonoCase, bool bIsIn)
{
int v6;
wchar_t v12;
if (bIsIn)
{
++*pSqlMonocaseParamCnt;
v6 = *pSqlMonocaseParamCnt;
}
else
{
++*(pSqlMonocaseParamCnt + 1);
v6 = *(pSqlMonocaseParamCnt + 1);
}
if (sql_dbcli == DatabaseCLI::OCI)
{
StringCchCopyW(&v12, 4, bIsIn ? L"in" : L"out");
StringCchPrintfExW(a1, *a2, &a1, a2, 0, forceMonoCase ? L"NLS_LOWER(:%s%i)" : L":%s%i", &v12, v6);
}
else
{
StringCchPrintfExW(a1, *a2, &a1, a2, 0, forceMonoCase ? L"{fn LCASE(?)}" : L"?");
}
}
Таким образом, если в 3.0 (и, возможно, в 4.0 тоже!) существовал штатный, пусть и не документированный, способ отключить использование функциональных индексов при работе с СУБД Oracle, то в 2009-й из ядра его убрали, а все умоминания про такую возможность в конфигурационной утилите и в документаций - просто не подчищенные хвосты.