mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/arangodb/arangodb into devel
This commit is contained in:
commit
ceb072c20d
|
@ -13,6 +13,7 @@
|
||||||
!include "nsDialogs.nsh"
|
!include "nsDialogs.nsh"
|
||||||
!include "WinMessages.nsh"
|
!include "WinMessages.nsh"
|
||||||
!include "MUI2.nsh"
|
!include "MUI2.nsh"
|
||||||
|
; !include "GetTime.nsh"
|
||||||
;--------------------------------
|
;--------------------------------
|
||||||
; get commandline parameters
|
; get commandline parameters
|
||||||
!include FileFunc.nsh
|
!include FileFunc.nsh
|
||||||
|
@ -40,7 +41,7 @@ Var STARTMENU_FOLDER
|
||||||
Var SV_ALLUSERS
|
Var SV_ALLUSERS
|
||||||
Var START_MENU
|
Var START_MENU
|
||||||
|
|
||||||
Var INSTALL_DESKTOP ; x bool: add desktop icon
|
Var ADD_DESKTOP_ICON ; x bool: add desktop icon
|
||||||
Var IS_DEFAULT_INSTALLDIR
|
Var IS_DEFAULT_INSTALLDIR
|
||||||
|
|
||||||
Var STORAGE_ENGINE ; x string auto/mmfiles/rocksdb
|
Var STORAGE_ENGINE ; x string auto/mmfiles/rocksdb
|
||||||
|
@ -49,16 +50,20 @@ Var PASSWORD_AGAIN ; x string / only for comparison
|
||||||
|
|
||||||
Var PURGE_DB ; x bool ; delete DB on uninstall
|
Var PURGE_DB ; x bool ; delete DB on uninstall
|
||||||
|
|
||||||
Var DO_NOT_ADD_TO_PATH ; x bool
|
Var ADD_TO_PATH ; x bool
|
||||||
Var ADD_TO_PATH_ALL_USERS ; x bool
|
|
||||||
Var ADD_TO_PATH_CURRENT_USER ; x bool
|
Var AUTOMATIC_UPDATE
|
||||||
|
Var AUTOMATIC_BACKUP
|
||||||
|
|
||||||
Var AllowGlobalInstall
|
Var AllowGlobalInstall
|
||||||
|
|
||||||
; Variables for definition of instdir
|
Var ChooseInstallPath
|
||||||
; posible values: SingleUser | AllUsers | Service
|
|
||||||
VAR TRI_INSTALL_TYPE ; x
|
Var BackupPath
|
||||||
VAR TRI_INSTALL_SCOPE
|
|
||||||
|
|
||||||
|
VAR TRI_INSTALL_SERVICE ; x bool
|
||||||
|
VAR TRI_INSTALL_SCOPE_ALL ; x bool => All / ThisUser
|
||||||
Var newCfgValues ; keep new config file values
|
Var newCfgValues ; keep new config file values
|
||||||
Var newCfgValuesFile ; write them to a temporary file...
|
Var newCfgValuesFile ; write them to a temporary file...
|
||||||
Var ServiceUp ; did the service start?
|
Var ServiceUp ; did the service start?
|
||||||
|
@ -69,10 +74,15 @@ Var UpgradeInstall
|
||||||
;----------------------------------------
|
;----------------------------------------
|
||||||
; The first dialog page
|
; The first dialog page
|
||||||
Var Dlg1_Dialog
|
Var Dlg1_Dialog
|
||||||
Var Dlg1_CB_as_service
|
|
||||||
Var Dlg1_RB_no_path
|
|
||||||
Var Dlg1_RB_all_users
|
Var Dlg1_RB_all_users
|
||||||
Var Dlg1_RB_cur_user
|
Var Dlg1_RB_cur_user
|
||||||
|
|
||||||
|
Var Dlg1_CB_custom_path
|
||||||
|
Var Dlg1_CB_automatic_update
|
||||||
|
Var Dlg1_CB_keep_backup
|
||||||
|
Var Dlg1_CB_add_path
|
||||||
|
Var Dlg1_CB_as_service
|
||||||
Var Dlg1_CB_DesktopIcon
|
Var Dlg1_CB_DesktopIcon
|
||||||
;----------------------------------------
|
;----------------------------------------
|
||||||
; The second dialog page
|
; The second dialog page
|
||||||
|
@ -104,30 +114,23 @@ RequestExecutionLevel highest
|
||||||
!include "WaitForService.nsh"
|
!include "WaitForService.nsh"
|
||||||
!include "ReadINIFileKeys.nsh"
|
!include "ReadINIFileKeys.nsh"
|
||||||
|
|
||||||
Function determine_install_scope
|
!macro determine_install_scope un
|
||||||
; Now that we know the install scope, calculate directories:
|
Function ${un}determine_install_scope
|
||||||
StrCmp $TRI_INSTALL_TYPE 'Service' 0 noService
|
; Now that we know the install scope, calculate directories:
|
||||||
|
${If} $TRI_INSTALL_SCOPE_ALL == 1
|
||||||
SetShellVarContext all
|
SetShellVarContext all
|
||||||
|
StrCpy $INSTDIR "@CPACK_NSIS_INSTALL_ROOT@\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
|
||||||
StrCpy $DATADIR "$APPDATA\ArangoDB"
|
StrCpy $DATADIR "$APPDATA\ArangoDB"
|
||||||
noService:
|
${Else}
|
||||||
${Switch} $TRI_INSTALL_SCOPE
|
|
||||||
${Case} 'none'
|
|
||||||
SetShellVarContext current
|
|
||||||
StrCpy $INSTDIR "$LOCALAPPDATA\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
|
|
||||||
StrCpy $DATADIR "$APPDATA\ArangoDB"
|
|
||||||
${Break}
|
|
||||||
${Case} 'ThisUser'
|
|
||||||
SetShellVarContext current
|
SetShellVarContext current
|
||||||
StrCpy $INSTDIR "$LOCALAPPDATA\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
|
StrCpy $INSTDIR "$LOCALAPPDATA\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
|
||||||
StrCpy $DATADIR "$LOCALAPPDATA\ArangoDB"
|
StrCpy $DATADIR "$LOCALAPPDATA\ArangoDB"
|
||||||
${Break}
|
${EndIf}
|
||||||
${Case} 'AllUsers'
|
|
||||||
SetShellVarContext all
|
|
||||||
StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
|
|
||||||
StrCpy $DATADIR "$DOCUMENTS\ArangoDB"
|
|
||||||
${Break}
|
|
||||||
${EndSwitch}
|
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
!macroend
|
||||||
|
!insertmacro determine_install_scope ""
|
||||||
|
!insertmacro determine_install_scope "un."
|
||||||
|
|
||||||
|
|
||||||
Function check_previous_install
|
Function check_previous_install
|
||||||
StrCpy $UpgradeInstall "0"
|
StrCpy $UpgradeInstall "0"
|
||||||
|
@ -139,17 +142,22 @@ OldFound:
|
||||||
StrCpy $UpgradeInstall "1"
|
StrCpy $UpgradeInstall "1"
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
|
Function upgradeDatabase
|
||||||
|
|
||||||
|
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
Function disableBackButton
|
Function disableBackButton
|
||||||
GetDlgItem $0 $HWNDParent 3
|
GetDlgItem $0 $HWNDParent 3
|
||||||
EnableWindow $0 0
|
EnableWindow $0 0
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
Function stop_old_service
|
Function stop_old_service
|
||||||
StrCmp $TRI_INSTALL_TYPE 'Service' 0 noServiceToStop
|
${If} $TRI_INSTALL_SERVICE == 1
|
||||||
SimpleSC::StopService '${TRI_SVC_NAME}' 0 30
|
SimpleSC::StopService '${TRI_SVC_NAME}' 0 30
|
||||||
Call WaitForServiceDown
|
Call WaitForServiceDown
|
||||||
SimpleSC::RemoveService '${TRI_SVC_NAME}'
|
SimpleSC::RemoveService '${TRI_SVC_NAME}'
|
||||||
noServiceToStop:
|
${EndIf}
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
Var mycheckbox ; You could just store the HWND in $1 etc if you don't want this extra variable
|
Var mycheckbox ; You could just store the HWND in $1 etc if you don't want this extra variable
|
||||||
|
@ -323,8 +331,18 @@ Var AR_RegFlags
|
||||||
|
|
||||||
Page custom InstallOptionsPage1 InstallOptionsPage1_results
|
Page custom InstallOptionsPage1 InstallOptionsPage1_results
|
||||||
|
|
||||||
|
!define MUI_PAGE_HEADER_TEXT "Choose the database folder for @CPACK_PACKAGE_NAME@"
|
||||||
|
!define MUI_PAGE_HEADER_SUBTEXT ""
|
||||||
|
!define MUI_DIRECTORYPAGE_TEXT_TOP "choose the folder where @CPACK_PACKAGE_NAME@ will create its database files"
|
||||||
|
!define MUI_DIRECTORYPAGE_TEXT_DESTINATION "Database folder"
|
||||||
|
!define MUI_PAGE_CUSTOMFUNCTION_PRE hide_install_directory
|
||||||
|
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE check_database_directory
|
||||||
|
!define MUI_DIRECTORYPAGE_VARIABLE $DATADIR
|
||||||
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
|
||||||
Page custom InstallOptionsPage2 InstallOptionsPage2_results
|
Page custom InstallOptionsPage2 InstallOptionsPage2_results
|
||||||
|
|
||||||
|
!define MUI_PAGE_CUSTOMFUNCTION_PRE hide_install_directory
|
||||||
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE check_installation_directory
|
!define MUI_PAGE_CUSTOMFUNCTION_LEAVE check_installation_directory
|
||||||
!insertmacro MUI_PAGE_DIRECTORY
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
|
||||||
|
@ -403,147 +421,6 @@ Var AR_RegFlags
|
||||||
!insertmacro MUI_LANGUAGE "Ukrainian"
|
!insertmacro MUI_LANGUAGE "Ukrainian"
|
||||||
!insertmacro MUI_LANGUAGE "Welsh"
|
!insertmacro MUI_LANGUAGE "Welsh"
|
||||||
|
|
||||||
;--------------------------------
|
|
||||||
;Installer Sections
|
|
||||||
|
|
||||||
Section "-Core installation"
|
|
||||||
;Use the entire tree produced by the INSTALL target. Keep the
|
|
||||||
;list of directories here in sync with the RMDir commands below.
|
|
||||||
SetOutPath "$INSTDIR"
|
|
||||||
; SetRegView controlls where die regkeys are written to
|
|
||||||
; SetRegView 32 writes the keys into Wow6432
|
|
||||||
SetRegView ${BITS}
|
|
||||||
|
|
||||||
@CPACK_NSIS_FULL_INSTALL@
|
|
||||||
|
|
||||||
;Store installation folder
|
|
||||||
WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR
|
|
||||||
|
|
||||||
;Create uninstaller
|
|
||||||
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
|
||||||
!insertmacro AddToRegistry "DisplayName" "@CPACK_NSIS_DISPLAY_NAME@"
|
|
||||||
!insertmacro AddToRegistry "DisplayVersion" "@CPACK_PACKAGE_VERSION@"
|
|
||||||
!insertmacro AddToRegistry "Publisher" "@CPACK_PACKAGE_VENDOR@"
|
|
||||||
!insertmacro AddToRegistry "UninstallString" "$INSTDIR\Uninstall.exe"
|
|
||||||
!insertmacro AddToRegistry "NoRepair" "1"
|
|
||||||
|
|
||||||
; Optional registration
|
|
||||||
!insertmacro AddToRegistry "DisplayIcon" "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@"
|
|
||||||
!insertmacro AddToRegistry "HelpLink" "@CPACK_NSIS_HELP_LINK@"
|
|
||||||
!insertmacro AddToRegistry "URLInfoAbout" "@CPACK_NSIS_URL_INFO_ABOUT@"
|
|
||||||
!insertmacro AddToRegistry "Contact" "@CPACK_NSIS_CONTACT@"
|
|
||||||
|
|
||||||
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
|
|
||||||
|
|
||||||
;Create shortcuts
|
|
||||||
CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
|
|
||||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Arango Shell.lnk" "$INSTDIR\${BIN_DIR}\arangosh.exe" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
|
||||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Arango Server.lnk" "$INSTDIR\${SBIN_DIR}\arangod.exe" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
|
||||||
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
|
||||||
|
|
||||||
;Read a value from an InstallOptions INI file
|
|
||||||
|
|
||||||
StrCmp "0" "$INSTALL_DESKTOP" noDesktopIcon
|
|
||||||
CreateShortCut "$DESKTOP\Arango Shell.lnk" "$INSTDIR\${BIN_DIR}\arangosh.exe" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
|
||||||
CreateShortCut "$DESKTOP\Arango Management Interface.lnk" "http://127.0.0.1:8529" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
|
||||||
noDesktopIcon:
|
|
||||||
|
|
||||||
; Write special uninstall registry entries
|
|
||||||
!insertmacro AddToRegistry "StartMenu" "$STARTMENU_FOLDER"
|
|
||||||
!insertmacro AddToRegistry "DoNotAddToPath" "$DO_NOT_ADD_TO_PATH"
|
|
||||||
!insertmacro AddToRegistry "AddToPathAllUsers" "$ADD_TO_PATH_ALL_USERS"
|
|
||||||
!insertmacro AddToRegistry "AddToPathCurrentUser" "$ADD_TO_PATH_CURRENT_USER"
|
|
||||||
!insertmacro AddToRegistry "InstallToDesktop" "$INSTALL_DESKTOP"
|
|
||||||
|
|
||||||
!insertmacro MUI_STARTMENU_WRITE_END
|
|
||||||
|
|
||||||
!insertmacro AddToRegistry "DATADIR" "$DATADIR"
|
|
||||||
|
|
||||||
; Create a file containing the settings we want to be overwritten:
|
|
||||||
StrCpy $newCfgValues "[database]$\r$\ndirectory = $DATADIR$\r$\n[server]$\r$\nstorage-engine = $STORAGE_ENGINE$\r$\n"
|
|
||||||
StrCpy $newCfgValuesFile "$INSTDIR\etc\arangodb3\newValues.ini"
|
|
||||||
FileOpen $4 "$newCfgValuesFile" w
|
|
||||||
FileWrite $4 "$newCfgValues"
|
|
||||||
FileClose $4
|
|
||||||
; Alter the shipped file and insert the values from above:
|
|
||||||
push "$newCfgValuesFile"
|
|
||||||
push "$INSTDIR\etc\arangodb3\arangod.conf"
|
|
||||||
call ReadINIFileKeys
|
|
||||||
Delete "$newCfgValuesFile"
|
|
||||||
|
|
||||||
${If} $UpgradeInstall == "1"
|
|
||||||
Goto doneSetPassword ; database directory already present - skip.
|
|
||||||
${EndIf}
|
|
||||||
System::Call 'Kernel32::SetEnvironmentVariable(t, t)i ("ARANGODB_DEFAULT_ROOT_PASSWORD", "$PASSWORD").r0'
|
|
||||||
StrCmp $0 0 error
|
|
||||||
ExecWait "$INSTDIR\${SBIN_DIR}\arangod.exe --database.init-database --server.rest-server false --server.statistics false --foxx.queues false" $0
|
|
||||||
${If} $0 == 0
|
|
||||||
Goto doneSetPassword
|
|
||||||
${EndIf}
|
|
||||||
error:
|
|
||||||
MessageBox MB_OK "Failed to initialize database password."
|
|
||||||
Abort
|
|
||||||
doneSetPassword:
|
|
||||||
StrCmp $TRI_INSTALL_TYPE 'Service' 0 nothing
|
|
||||||
DetailPrint "Installing service ${TRI_SVC_NAME}: "
|
|
||||||
SimpleSC::InstallService '${TRI_SVC_NAME}' '' '16' '2' '"$INSTDIR\${SBIN_DIR}\arangod.exe" --start-service' '' '' ''
|
|
||||||
Pop $0
|
|
||||||
DetailPrint "Status: $0; Setting Description: ${TRI_FRIENDLY_SVC_NAME}"
|
|
||||||
SimpleSC::SetServiceDescription '${TRI_SVC_NAME}' '${TRI_FRIENDLY_SVC_NAME}'
|
|
||||||
Pop $0
|
|
||||||
DetailPrint "Status: $0; Starting Service"
|
|
||||||
SimpleSC::StartService '${TRI_SVC_NAME}' '' 45
|
|
||||||
Pop $0
|
|
||||||
DetailPrint "Status: $0"
|
|
||||||
${If} $0 != "0"
|
|
||||||
Call QueryServiceStatus
|
|
||||||
Pop $2
|
|
||||||
Pop $1
|
|
||||||
Pop $0
|
|
||||||
!define SC_WAITED "Waited 40 seconds for the ArangoDB service to come up;"
|
|
||||||
!define SC_SV "Please look at $\r$\n`sc query ${TRI_SVC_NAME}`"
|
|
||||||
!define SC_EVLOG "and the Windows Eventlog for eventual errors!"
|
|
||||||
${If} $1 == "1066"
|
|
||||||
${If} $2 == "1"
|
|
||||||
MessageBox MB_OK "${SC_WAITED}$\r$\nbut it exited with an error; $\r$\n${SC_SV}$\r$\n${SC_EVLOG}"
|
|
||||||
Abort
|
|
||||||
${ElseIf} $2 == "2"
|
|
||||||
MessageBox MB_OK "${SC_WAITED}$\r$\nbut it exited with a fatal error; $\r$\n${SC_SV}$\r$\n${SC_EVLOG}"
|
|
||||||
Abort
|
|
||||||
${EndIf}
|
|
||||||
${ElseIf} $1 != "0"
|
|
||||||
MessageBox MB_OK "${SC_WAITED}$\r$\n${SC_SV}$\r$\n${SC_EVLOG} $0 $1 $2"
|
|
||||||
Abort
|
|
||||||
${EndIf}
|
|
||||||
Abort
|
|
||||||
${EndIf}
|
|
||||||
nothing:
|
|
||||||
SectionEnd
|
|
||||||
|
|
||||||
Function .onInstSuccess
|
|
||||||
IfSilent 0 continueUI
|
|
||||||
Call insert_registration_keys
|
|
||||||
StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0
|
|
||||||
!insertmacro AddToPath "$INSTDIR/${BIN_DIR}" $ADD_TO_PATH_ALL_USERS
|
|
||||||
doNotAddToPath:
|
|
||||||
Return
|
|
||||||
|
|
||||||
continueUI:
|
|
||||||
ifErrors +3
|
|
||||||
${If} $TRI_INSTALL_TYPE == 'Service'
|
|
||||||
${AndIf} $ServiceUp == 0
|
|
||||||
${OpenURL} ${TRI_AARDVARK_URL}
|
|
||||||
${EndIf}
|
|
||||||
FunctionEnd
|
|
||||||
|
|
||||||
Section "-Add to path"
|
|
||||||
Push "$INSTDIR/${BIN_DIR}"
|
|
||||||
StrCmp "@CPACK_NSIS_MODIFY_PATH@" "ON" 0 doNotAddToPath
|
|
||||||
StrCmp $DO_NOT_ADD_TO_PATH "1" doNotAddToPath 0
|
|
||||||
!insertmacro AddToPath "$INSTDIR/${BIN_DIR}" $ADD_TO_PATH_ALL_USERS
|
|
||||||
doNotAddToPath:
|
|
||||||
SectionEnd
|
|
||||||
|
|
||||||
;--------------------------------
|
;--------------------------------
|
||||||
; Create custom pages
|
; Create custom pages
|
||||||
Function InstallOptionsPage1
|
Function InstallOptionsPage1
|
||||||
|
@ -563,25 +440,37 @@ displayAgain:
|
||||||
${If} $Dlg1_Dialog == error
|
${If} $Dlg1_Dialog == error
|
||||||
Abort
|
Abort
|
||||||
${EndIf}
|
${EndIf}
|
||||||
${NSD_CreateLabel} "Install @CPACK_PACKAGE_NAME@"
|
|
||||||
|
${NSD_CreateLabel} 0 0 100% 6% "Install @CPACK_PACKAGE_NAME@"
|
||||||
Pop $0 ; Don't care...
|
Pop $0 ; Don't care...
|
||||||
|
|
||||||
|
|
||||||
${NSD_CreateLabel} 0 10 100% 6% "Choose whether @CPACK_PACKAGE_INSTALL_DIRECTORY@ should be added to a Path:"
|
${NSD_CreateLabel} 0 20 100% 6% "Choose to install @CPACK_PACKAGE_NAME@ for all users or the current user:"
|
||||||
Pop $0 ; Don't care...
|
Pop $0 ; Don't care...
|
||||||
|
|
||||||
${NSD_CreateRadioButton} 5 30 60% 6% "don't add @CPACK_PACKAGE_NAME@ to the Path"
|
${NSD_CreateRadioButton} 5 40 40% 6% "for all users"
|
||||||
Pop $Dlg1_RB_no_path
|
|
||||||
${NSD_AddStyle} $Dlg1_RB_no_path ${WS_GROUP}
|
|
||||||
|
|
||||||
${NSD_CreateRadioButton} 5 45 40% 6% "for all users"
|
|
||||||
Pop $Dlg1_RB_all_users
|
Pop $Dlg1_RB_all_users
|
||||||
${NSD_SetState} $Dlg1_RB_all_users ${BST_CHECKED}
|
${NSD_SetState} $Dlg1_RB_all_users ${BST_CHECKED}
|
||||||
|
|
||||||
${NSD_CreateRadioButton} 5 60 50% 6% "for the current user"
|
${NSD_CreateRadioButton} 5 60 50% 6% "for the current user"
|
||||||
Pop $Dlg1_RB_cur_user
|
Pop $Dlg1_RB_cur_user
|
||||||
|
|
||||||
|
; Checkboxes
|
||||||
|
${NSD_CreateCheckBox} 0 -120 100% 6% "Choose custom install paths for databases and installation"
|
||||||
|
Pop $Dlg1_CB_custom_path
|
||||||
|
|
||||||
|
${NSD_CreateCheckBox} 0 -100 100% 6% "Automatically update existing ArangoDB database"
|
||||||
|
Pop $Dlg1_CB_automatic_update
|
||||||
|
${NSD_SetState} $Dlg1_CB_automatic_update ${BST_CHECKED}
|
||||||
|
|
||||||
|
${NSD_CreateCheckBox} 0 -80 100% 6% "Keep a backup of databases"
|
||||||
|
Pop $Dlg1_CB_keep_backup
|
||||||
|
${NSD_SetState} $Dlg1_CB_keep_backup ${BST_CHECKED}
|
||||||
|
|
||||||
|
${NSD_CreateCheckBox} 0 -60 100% 6% "add @CPACK_PACKAGE_NAME@ to the Path"
|
||||||
|
Pop $Dlg1_CB_add_path
|
||||||
|
${NSD_SetState} $Dlg1_CB_add_path ${BST_CHECKED}
|
||||||
|
|
||||||
${NSD_CreateCheckBox} 0 -40 100% 6% "Start @CPACK_PACKAGE_NAME@ as system service"
|
${NSD_CreateCheckBox} 0 -40 100% 6% "Start @CPACK_PACKAGE_NAME@ as system service"
|
||||||
Pop $Dlg1_CB_as_service
|
Pop $Dlg1_CB_as_service
|
||||||
|
|
||||||
|
@ -589,12 +478,12 @@ displayAgain:
|
||||||
Pop $Dlg1_CB_DesktopIcon
|
Pop $Dlg1_CB_DesktopIcon
|
||||||
${NSD_SetState} $Dlg1_CB_DesktopIcon ${BST_CHECKED}
|
${NSD_SetState} $Dlg1_CB_DesktopIcon ${BST_CHECKED}
|
||||||
|
|
||||||
|
|
||||||
${If} $AllowGlobalInstall == "0"
|
${If} $AllowGlobalInstall == "0"
|
||||||
EnableWindow $Dlg1_RB_all_users 0
|
EnableWindow $Dlg1_RB_all_users 0
|
||||||
EnableWindow $Dlg1_CB_as_service 0
|
EnableWindow $Dlg1_CB_as_service 0
|
||||||
${Else}
|
${Else}
|
||||||
${NSD_SetState} $Dlg1_CB_as_service ${BST_CHECKED}
|
${NSD_SetState} $Dlg1_CB_as_service ${BST_CHECKED}
|
||||||
|
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
nsDialogs::Show
|
nsDialogs::Show
|
||||||
|
@ -606,38 +495,59 @@ Function InstallOptionsPage1_results
|
||||||
Push $R0
|
Push $R0
|
||||||
Push $R1
|
Push $R1
|
||||||
Push $R2
|
Push $R2
|
||||||
${NSD_GetState} $Dlg1_CB_DesktopIcon $R0
|
${NSD_GetState} $Dlg1_RB_all_users $R0
|
||||||
${If} $R0 = ${BST_CHECKED}
|
${NSD_GetState} $Dlg1_RB_cur_user $R1
|
||||||
StrCpy $INSTALL_DESKTOP "1"
|
|
||||||
${Else}
|
|
||||||
StrCpy $INSTALL_DESKTOP "0"
|
|
||||||
${EndIf}
|
|
||||||
|
|
||||||
|
|
||||||
${NSD_GetState} $Dlg1_RB_no_path $R0
|
|
||||||
${NSD_GetState} $Dlg1_RB_all_users $R1
|
|
||||||
${NSD_GetState} $Dlg1_RB_cur_user $R2
|
|
||||||
|
|
||||||
${If} $R0 = ${BST_CHECKED}
|
${If} $R0 = ${BST_CHECKED}
|
||||||
StrCpy $TRI_INSTALL_SCOPE "none"
|
StrCpy $TRI_INSTALL_SCOPE_ALL "1"
|
||||||
StrCpy $DO_NOT_ADD_TO_PATH '1'
|
|
||||||
${ElseIf} $R1 = ${BST_CHECKED}
|
|
||||||
StrCpy $TRI_INSTALL_SCOPE "ThisUsers"
|
|
||||||
StrCpy $ADD_TO_PATH_ALL_USERS '1'
|
|
||||||
${ElseIf} $R2 = ${BST_CHECKED}
|
|
||||||
StrCpy $TRI_INSTALL_SCOPE "AllUsers"
|
|
||||||
StrCpy $ADD_TO_PATH_CURRENT_USER '1'
|
|
||||||
${Else}
|
${Else}
|
||||||
; WHUT?
|
StrCpy $TRI_INSTALL_SCOPE_ALL "0"
|
||||||
Abort
|
${EndIf}
|
||||||
|
|
||||||
|
|
||||||
|
${NSD_GetState} $Dlg1_CB_custom_path $R0
|
||||||
|
${If} $R0 = ${BST_CHECKED}
|
||||||
|
StrCpy $ChooseInstallPath "1"
|
||||||
|
${Else}
|
||||||
|
StrCpy $ChooseInstallPath "0"
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
${NSD_GetState} $Dlg1_CB_automatic_update $R0
|
||||||
|
${If} $R0 = ${BST_CHECKED}
|
||||||
|
StrCpy $AUTOMATIC_UPDATE "1"
|
||||||
|
${Else}
|
||||||
|
StrCpy $AUTOMATIC_UPDATE "0"
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
${NSD_GetState} $Dlg1_CB_keep_backup $R0
|
||||||
|
${If} $R0 = ${BST_CHECKED}
|
||||||
|
StrCpy $AUTOMATIC_BACKUP "1"
|
||||||
|
${Else}
|
||||||
|
StrCpy $AUTOMATIC_BACKUP "0"
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
${NSD_GetState} $Dlg1_CB_add_path $R0
|
||||||
|
${If} $R0 = ${BST_CHECKED}
|
||||||
|
StrCpy $ADD_TO_PATH '1'
|
||||||
|
${Else}
|
||||||
|
StrCpy $ADD_TO_PATH '0'
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
${NSD_GetState} $Dlg1_CB_as_service $R0
|
${NSD_GetState} $Dlg1_CB_as_service $R0
|
||||||
${If} $R0 = ${BST_CHECKED}
|
${If} $R0 = ${BST_CHECKED}
|
||||||
StrCpy $TRI_INSTALL_TYPE "Service"
|
StrCpy $TRI_INSTALL_SERVICE "1"
|
||||||
${Else}
|
${Else}
|
||||||
StrCpy $TRI_INSTALL_TYPE "Manual"
|
StrCpy $TRI_INSTALL_SERVICE "0"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
|
${NSD_GetState} $Dlg1_CB_DesktopIcon $R0
|
||||||
|
${If} $R0 = ${BST_CHECKED}
|
||||||
|
StrCpy $ADD_DESKTOP_ICON "1"
|
||||||
|
${Else}
|
||||||
|
StrCpy $ADD_DESKTOP_ICON "0"
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
|
||||||
Call determine_install_scope
|
Call determine_install_scope
|
||||||
Call check_previous_install
|
Call check_previous_install
|
||||||
Pop $R2
|
Pop $R2
|
||||||
|
@ -711,11 +621,175 @@ Function InstallOptionsPage2_results
|
||||||
return
|
return
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
|
;--------------------------------
|
||||||
|
Function hide_install_directory
|
||||||
|
${If} $ChooseInstallPath == "0"
|
||||||
|
Abort
|
||||||
|
${EndIf}
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
;--------------------------------
|
;--------------------------------
|
||||||
Function skip_page
|
Function skip_page
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
|
Function UpgradeExisting
|
||||||
|
; Check whether we acutally should upgrade:
|
||||||
|
ExecWait "$INSTDIR\${SBIN_DIR}\arangod.exe --server.rest-server false --log.foreground-tty false --database.check-version" $0
|
||||||
|
${If} $0 == 1
|
||||||
|
${AndIf} $AUTOMATIC_UPDATE == "1"
|
||||||
|
|
||||||
|
${If} $AUTOMATIC_BACKUP == "1"
|
||||||
|
; We should and we should keep a backup:
|
||||||
|
${GetTime} "" "L" $0 $1 $2 $3 $4 $5 $6
|
||||||
|
StrCpy $BackupPath "$DATADIR_$2-$1-$0_$4_$5_$6"
|
||||||
|
CreateDirectory "$BackupPath"
|
||||||
|
ClearErrors
|
||||||
|
CopyFiles "$DATADIR" "$BackupPath"
|
||||||
|
IfErrors 0 +2
|
||||||
|
MessageBox MB_ICONEXCLAMATION "The upgrade failed to copy the files $\r$\nfrom '$DATADIR'$\r$\nto '$BackupPath'; please do it manually.$\r$\n$\r$\nClick OK to continue."
|
||||||
|
${EndIf}
|
||||||
|
; Now actually do the upgrade
|
||||||
|
ExecWait "$INSTDIR\${SBIN_DIR}\arangod.exe --server.rest-server false --log.level error --database.auto-upgrade true" $0
|
||||||
|
${If} $0 == 1
|
||||||
|
MessageBox MB_ICONEXCLAMATION "the Upgrade failed, please do a manual upgrade"
|
||||||
|
Abort
|
||||||
|
${EndIf}
|
||||||
|
${EndIf}
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
|
;--------------------------------
|
||||||
|
;Installer Sections
|
||||||
|
|
||||||
|
Section "-Core installation"
|
||||||
|
;Use the entire tree produced by the INSTALL target. Keep the
|
||||||
|
;list of directories here in sync with the RMDir commands below.
|
||||||
|
SetOutPath "$INSTDIR"
|
||||||
|
; SetRegView controlls where die regkeys are written to
|
||||||
|
; SetRegView 32 writes the keys into Wow6432
|
||||||
|
SetRegView ${BITS}
|
||||||
|
|
||||||
|
@CPACK_NSIS_FULL_INSTALL@
|
||||||
|
|
||||||
|
;Store installation folder
|
||||||
|
WriteRegStr SHCTX "Software\@CPACK_PACKAGE_VENDOR@\@CPACK_PACKAGE_INSTALL_REGISTRY_KEY@" "" $INSTDIR
|
||||||
|
|
||||||
|
;Create uninstaller
|
||||||
|
WriteUninstaller "$INSTDIR\Uninstall.exe"
|
||||||
|
!insertmacro AddToRegistry "DisplayName" "@CPACK_NSIS_DISPLAY_NAME@"
|
||||||
|
!insertmacro AddToRegistry "DisplayVersion" "@CPACK_PACKAGE_VERSION@"
|
||||||
|
!insertmacro AddToRegistry "Publisher" "@CPACK_PACKAGE_VENDOR@"
|
||||||
|
!insertmacro AddToRegistry "UninstallString" "$INSTDIR\Uninstall.exe"
|
||||||
|
!insertmacro AddToRegistry "NoRepair" "1"
|
||||||
|
|
||||||
|
; Optional registration
|
||||||
|
!insertmacro AddToRegistry "DisplayIcon" "$INSTDIR\@CPACK_NSIS_INSTALLED_ICON_NAME@"
|
||||||
|
!insertmacro AddToRegistry "HelpLink" "@CPACK_NSIS_HELP_LINK@"
|
||||||
|
!insertmacro AddToRegistry "URLInfoAbout" "@CPACK_NSIS_URL_INFO_ABOUT@"
|
||||||
|
!insertmacro AddToRegistry "Contact" "@CPACK_NSIS_CONTACT@"
|
||||||
|
|
||||||
|
!insertmacro MUI_STARTMENU_WRITE_BEGIN Application
|
||||||
|
|
||||||
|
;Create shortcuts
|
||||||
|
CreateDirectory "$SMPROGRAMS\$STARTMENU_FOLDER"
|
||||||
|
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Arango Shell.lnk" "$INSTDIR\${BIN_DIR}\arangosh.exe" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||||
|
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Arango Server.lnk" "$INSTDIR\${SBIN_DIR}\arangod.exe" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||||
|
CreateShortCut "$SMPROGRAMS\$STARTMENU_FOLDER\Uninstall.lnk" "$INSTDIR\Uninstall.exe"
|
||||||
|
|
||||||
|
;Read a value from an InstallOptions INI file
|
||||||
|
|
||||||
|
StrCmp "0" "$ADD_DESKTOP_ICON" noDesktopIcon
|
||||||
|
CreateShortCut "$DESKTOP\Arango Shell.lnk" "$INSTDIR\${BIN_DIR}\arangosh.exe" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||||
|
CreateShortCut "$DESKTOP\Arango Management Interface.lnk" "http://127.0.0.1:8529" '' '$INSTDIR\resources\arangodb.ico' '0' SW_SHOWMAXIMIZED
|
||||||
|
noDesktopIcon:
|
||||||
|
|
||||||
|
; Write special uninstall registry entries
|
||||||
|
!insertmacro AddToRegistry "StartMenu" "$STARTMENU_FOLDER"
|
||||||
|
!insertmacro AddToRegistry "AddToPath" "$ADD_TO_PATH"
|
||||||
|
!insertmacro AddToRegistry "InstallToDesktop" "$ADD_DESKTOP_ICON"
|
||||||
|
|
||||||
|
!insertmacro MUI_STARTMENU_WRITE_END
|
||||||
|
|
||||||
|
!insertmacro AddToRegistry "DATADIR" "$DATADIR"
|
||||||
|
|
||||||
|
; Create a file containing the settings we want to be overwritten:
|
||||||
|
StrCpy $newCfgValues "[database]$\r$\ndirectory = $DATADIR$\r$\n[server]$\r$\nstorage-engine = $STORAGE_ENGINE$\r$\n"
|
||||||
|
StrCpy $newCfgValuesFile "$INSTDIR\etc\arangodb3\newValues.ini"
|
||||||
|
FileOpen $4 "$newCfgValuesFile" w
|
||||||
|
FileWrite $4 "$newCfgValues"
|
||||||
|
FileClose $4
|
||||||
|
; Alter the shipped file and insert the values from above:
|
||||||
|
push "$newCfgValuesFile"
|
||||||
|
push "$INSTDIR\etc\arangodb3\arangod.conf"
|
||||||
|
call ReadINIFileKeys
|
||||||
|
Delete "$newCfgValuesFile"
|
||||||
|
|
||||||
|
${If} $UpgradeInstall == "1"
|
||||||
|
Call UpgradeExisting
|
||||||
|
${Else}
|
||||||
|
System::Call 'Kernel32::SetEnvironmentVariable(t, t)i ("ARANGODB_DEFAULT_ROOT_PASSWORD", "$PASSWORD").r0'
|
||||||
|
StrCmp $0 0 error
|
||||||
|
ExecWait "$INSTDIR\${SBIN_DIR}\arangod.exe --database.init-database --server.rest-server false --server.statistics false --foxx.queues false" $0
|
||||||
|
${If} $0 == 0
|
||||||
|
Goto doneUpgrade
|
||||||
|
${EndIf}
|
||||||
|
error:
|
||||||
|
MessageBox MB_OK "Failed to initialize database password."
|
||||||
|
Abort
|
||||||
|
doneUpgrade:
|
||||||
|
${EndIf}
|
||||||
|
${If} $TRI_INSTALL_SERVICE == "1"
|
||||||
|
DetailPrint "Installing service ${TRI_SVC_NAME}: "
|
||||||
|
SimpleSC::InstallService '${TRI_SVC_NAME}' '' '16' '2' '"$INSTDIR\${SBIN_DIR}\arangod.exe" --start-service' '' '' ''
|
||||||
|
Pop $0
|
||||||
|
DetailPrint "Status: $0; Setting Description: ${TRI_FRIENDLY_SVC_NAME}"
|
||||||
|
SimpleSC::SetServiceDescription '${TRI_SVC_NAME}' '${TRI_FRIENDLY_SVC_NAME}'
|
||||||
|
Pop $0
|
||||||
|
DetailPrint "Status: $0; Starting Service"
|
||||||
|
SimpleSC::StartService '${TRI_SVC_NAME}' '' 45
|
||||||
|
Pop $0
|
||||||
|
DetailPrint "Status: $0"
|
||||||
|
${If} $0 != "0"
|
||||||
|
Call QueryServiceStatus
|
||||||
|
Pop $2
|
||||||
|
Pop $1
|
||||||
|
Pop $0
|
||||||
|
!define SC_WAITED "Waited 40 seconds for the ArangoDB service to come up;"
|
||||||
|
!define SC_SV "Please look at $\r$\n`sc query ${TRI_SVC_NAME}`"
|
||||||
|
!define SC_EVLOG "and the Windows Eventlog for eventual errors!"
|
||||||
|
${If} $1 == "1066"
|
||||||
|
${If} $2 == "1"
|
||||||
|
MessageBox MB_OK "${SC_WAITED}$\r$\nbut it exited with an error; $\r$\n${SC_SV}$\r$\n${SC_EVLOG}"
|
||||||
|
Abort
|
||||||
|
${ElseIf} $2 == "2"
|
||||||
|
MessageBox MB_OK "${SC_WAITED}$\r$\nbut it exited with a fatal error; $\r$\n${SC_SV}$\r$\n${SC_EVLOG}"
|
||||||
|
Abort
|
||||||
|
${EndIf}
|
||||||
|
${ElseIf} $1 != "0"
|
||||||
|
MessageBox MB_OK "${SC_WAITED}$\r$\n${SC_SV}$\r$\n${SC_EVLOG} $0 $1 $2"
|
||||||
|
Abort
|
||||||
|
${EndIf}
|
||||||
|
Abort
|
||||||
|
${Else}
|
||||||
|
StrCpy $ServiceUp "1"
|
||||||
|
${EndIf}
|
||||||
|
${EndIf}
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
Function .onInstSuccess
|
||||||
|
Call insert_registration_keys
|
||||||
|
${If} $ADD_TO_PATH == "1"
|
||||||
|
!insertmacro AddToPath "$INSTDIR/${BIN_DIR}" $TRI_INSTALL_SCOPE_ALL
|
||||||
|
${EndIf}
|
||||||
|
|
||||||
|
IfSilent 0 continueUI
|
||||||
|
Return
|
||||||
|
|
||||||
|
continueUI:
|
||||||
|
${If} $TRI_INSTALL_SERVICE == '1'
|
||||||
|
${AndIf} $ServiceUp == 1
|
||||||
|
${OpenURL} ${TRI_AARDVARK_URL}
|
||||||
|
${EndIf}
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
Function assign_proper_access_rights
|
Function assign_proper_access_rights
|
||||||
StrCpy $0 "0"
|
StrCpy $0 "0"
|
||||||
|
@ -732,12 +806,16 @@ FunctionEnd
|
||||||
|
|
||||||
Function is_writable
|
Function is_writable
|
||||||
; is does not matter if we do some errors here
|
; is does not matter if we do some errors here
|
||||||
${If} $TRI_INSTALL_ALL_USERS == '1'
|
${If} $TRI_INSTALL_SCOPE_ALL == '1'
|
||||||
CreateDirectory $INSTDIR
|
CreateDirectory $INSTDIR
|
||||||
Call assign_proper_access_rights
|
Call assign_proper_access_rights
|
||||||
${EndIf}
|
${EndIf}
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
|
Function check_database_directory
|
||||||
|
call check_previous_install
|
||||||
|
FunctionEnd
|
||||||
|
|
||||||
Function check_installation_directory
|
Function check_installation_directory
|
||||||
ClearErrors
|
ClearErrors
|
||||||
Call is_writable
|
Call is_writable
|
||||||
|
@ -751,37 +829,14 @@ FunctionEnd
|
||||||
|
|
||||||
Function insert_registration_keys
|
Function insert_registration_keys
|
||||||
ClearErrors
|
ClearErrors
|
||||||
; MessageBox MB_OK "XXXX insert_registration_keys in HKCC ${BITS}"
|
|
||||||
${Switch} $TRI_INSTALL_TYPE
|
WriteRegExpandStr HKCC "Software\@CPACK_NSIS_PACKAGE_NAME@" "service" "$TRI_INSTALL_SERVICE"
|
||||||
${Case} 'Service'
|
IfErrors there_are_erros
|
||||||
WriteRegExpandStr HKCC "Software\@CPACK_NSIS_PACKAGE_NAME@" "type" 'Service'
|
WriteRegExpandStr HKCC "Software\@CPACK_NSIS_PACKAGE_NAME@" "scopeAll" "$TRI_INSTALL_SCOPE_ALL"
|
||||||
; MessageBox MB_OK "Sevice in HKCC"
|
IfErrors there_are_erros
|
||||||
IfErrors there_are_erros
|
Return
|
||||||
${Break}
|
there_are_erros: ;nothing
|
||||||
|
MessageBox MB_OK "There was an error during adding the installation keys to the registry$\nArango will work fine but there may be trouble during the deinstallation$\nplease contact @CPACK_NSIS_CONTACT@"
|
||||||
${Case} 'SingleUser'
|
|
||||||
${If} ${UAC_IsAdmin}
|
|
||||||
WriteRegExpandStr HKCC "Software\@CPACK_NSIS_PACKAGE_NAME@" "type" 'SingleUser'
|
|
||||||
; MessageBox MB_OK "SingleUser in HKCC"
|
|
||||||
${Else}
|
|
||||||
; normal user has not write rights to HKCC
|
|
||||||
WriteRegExpandStr HKCU "Software\@CPACK_NSIS_PACKAGE_NAME@" "type" 'SingleUser'
|
|
||||||
; MessageBox MB_OK "SingleUser in HKCU"
|
|
||||||
IfErrors there_are_erros
|
|
||||||
${EndIf}
|
|
||||||
${Break}
|
|
||||||
|
|
||||||
${Case} 'AllUsers'
|
|
||||||
WriteRegExpandStr HKCC "Software\@CPACK_NSIS_PACKAGE_NAME@" "type" 'Service'
|
|
||||||
StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
|
|
||||||
; MessageBox MB_OK "AllUsers in HKCC"
|
|
||||||
IfErrors there_are_erros
|
|
||||||
${Break}
|
|
||||||
${EndSwitch}
|
|
||||||
Return
|
|
||||||
|
|
||||||
there_are_erros: ;nothing
|
|
||||||
MessageBox MB_OK "There was an error during adding the installation keys to the registry$\nArango will work fine but there may be trouble during the deinstallation$\nplease contact @CPACK_NSIS_CONTACT@"
|
|
||||||
|
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
|
@ -804,19 +859,15 @@ Function un.onInit
|
||||||
StrCpy $PURGE_DB "0"
|
StrCpy $PURGE_DB "0"
|
||||||
|
|
||||||
Pop $0
|
Pop $0
|
||||||
; temporary variable used as flag for decide the change to administration rights
|
SetShellVarContext current
|
||||||
StrCpy $R0 "admin"
|
ReadRegStr $TRI_INSTALL_SERVICE HKCC "Software\@CPACK_NSIS_PACKAGE_NAME@" "service"
|
||||||
${If} ${UAC_IsAdmin}
|
ReadRegStr $TRI_INSTALL_SCOPE_ALL HKCC "Software\@CPACK_NSIS_PACKAGE_NAME@" "scopeAll"
|
||||||
ReadRegStr $0 HKCC "Software\@CPACK_NSIS_PACKAGE_NAME@" "type"
|
|
||||||
|
${If} $TRI_INSTALL_SCOPE_ALL == 1
|
||||||
|
SetShellVarContext all
|
||||||
${Else}
|
${Else}
|
||||||
ReadRegStr $0 HKCU "Software\@CPACK_NSIS_PACKAGE_NAME@" "type"
|
SetShellVarContext current
|
||||||
${If} $0 == "SingleUser"
|
|
||||||
StrCpy $R0 "user"
|
|
||||||
${EndIf}
|
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
SetShellVarContext current
|
|
||||||
|
|
||||||
FunctionEnd
|
FunctionEnd
|
||||||
|
|
||||||
;--- Add/Remove callback functions: ---
|
;--- Add/Remove callback functions: ---
|
||||||
|
@ -848,68 +899,59 @@ Section "Uninstall"
|
||||||
; we probably need this for the install/uninstall software list.
|
; we probably need this for the install/uninstall software list.
|
||||||
SetRegView ${BITS}
|
SetRegView ${BITS}
|
||||||
; A single user isn''t in HKCC...
|
; A single user isn''t in HKCC...
|
||||||
StrCpy $TRI_INSTALL_TYPE 'SingleUser'
|
StrCpy $TRI_INSTALL_SCOPE_ALL '0'
|
||||||
ReadRegStr $TRI_INSTALL_TYPE HKCC "Software\@CPACK_NSIS_PACKAGE_NAME@" "type"
|
ReadRegStr $TRI_INSTALL_SCOPE_ALL HKCC "Software\@CPACK_NSIS_PACKAGE_NAME@" "scopeAll"
|
||||||
;MessageBox MB_OK "Type: $TRI_INSTALL_TYPE"
|
ReadRegStr $TRI_INSTALL_SERVICE HKCC "Software\@CPACK_NSIS_PACKAGE_NAME@" "service"
|
||||||
${If} $TRI_INSTALL_TYPE == 'Service'
|
|
||||||
SetShellVarContext all
|
|
||||||
;MessageBox MB_OK "Service : $INSTDIR"
|
|
||||||
${EndIf}
|
|
||||||
|
|
||||||
${If} $TRI_INSTALL_SCOPE == 'AllUsers'
|
call un.determine_install_scope
|
||||||
SetShellVarContext all
|
|
||||||
StrCpy $INSTDIR "$DOCUMENTS\@CPACK_PACKAGE_INSTALL_DIRECTORY@"
|
|
||||||
;MessageBox MB_OK "AllUsers : $INSTDIR"
|
|
||||||
${EndIf}
|
|
||||||
|
|
||||||
ReadRegStr $START_MENU SHCTX "${TRI_UNINSTALL_REG_PATH}" "StartMenu"
|
ReadRegStr $START_MENU SHCTX "${TRI_UNINSTALL_REG_PATH}" "StartMenu"
|
||||||
;MessageBox MB_OK "Start menu is in: $START_MENU"
|
;MessageBox MB_OK "Start menu is in: $START_MENU"
|
||||||
ReadRegStr $DO_NOT_ADD_TO_PATH SHCTX "${TRI_UNINSTALL_REG_PATH}" "DoNotAddToPath"
|
ReadRegStr $ADD_TO_PATH SHCTX "${TRI_UNINSTALL_REG_PATH}" "AddToPath"
|
||||||
ReadRegStr $ADD_TO_PATH_ALL_USERS SHCTX "${TRI_UNINSTALL_REG_PATH}" "AddToPathAllUsers"
|
|
||||||
ReadRegStr $ADD_TO_PATH_CURRENT_USER SHCTX "${TRI_UNINSTALL_REG_PATH}" "AddToPathCurrentUser"
|
;MessageBox MB_OK "Add to path: $ADD_TO_PATH"
|
||||||
;MessageBox MB_OK "Add to path: $DO_NOT_ADD_TO_PATH all users: $ADD_TO_PATH_ALL_USERS"
|
ReadRegStr $ADD_DESKTOP_ICON SHCTX "${TRI_UNINSTALL_REG_PATH}" "InstallToDesktop"
|
||||||
ReadRegStr $INSTALL_DESKTOP SHCTX "${TRI_UNINSTALL_REG_PATH}" "InstallToDesktop"
|
|
||||||
ReadRegStr $DATADIR SHCTX "${TRI_UNINSTALL_REG_PATH}" "DATADIR"
|
ReadRegStr $DATADIR SHCTX "${TRI_UNINSTALL_REG_PATH}" "DATADIR"
|
||||||
|
|
||||||
;MessageBox MB_OK "Install to desktop: $INSTALL_DESKTOP "
|
;MessageBox MB_OK "Install to desktop: $ADD_DESKTOP_ICON "
|
||||||
|
|
||||||
StrCmp "0" "$INSTALL_DESKTOP" noDesktopIconRemove
|
StrCmp "0" "$ADD_DESKTOP_ICON" noDesktopIconRemove
|
||||||
Delete "$DESKTOP\Arango Shell.lnk"
|
Delete "$DESKTOP\Arango Shell.lnk"
|
||||||
Delete "$DESKTOP\Arango Management Interface.lnk"
|
Delete "$DESKTOP\Arango Management Interface.lnk"
|
||||||
noDesktopIconRemove:
|
noDesktopIconRemove:
|
||||||
|
|
||||||
|
|
||||||
;MessageBox MB_OK "Deleting Directory: $SMPROGRAMS\$START_MENU\ $TRI_INSTALL_TYPE "
|
;MessageBox MB_OK "Deleting Directory: $SMPROGRAMS\$START_MENU\ $TRI_INSTALL_SERVICE "
|
||||||
Delete "$SMPROGRAMS\$START_MENU"
|
Delete "$SMPROGRAMS\$START_MENU"
|
||||||
|
|
||||||
StrCmp $TRI_INSTALL_TYPE 'Service' 0 nothing
|
${If} $TRI_INSTALL_SERVICE == "1"
|
||||||
;SimpleSC::GetServiceName '${TRI_SVC_NAME}'
|
;SimpleSC::GetServiceName '${TRI_SVC_NAME}'
|
||||||
;Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
;Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||||
;Pop $1 ; returns the binary path of the service
|
;Pop $1 ; returns the binary path of the service
|
||||||
;MessageBox MB_OK "GetServiceName: : $0 $1 "
|
;MessageBox MB_OK "GetServiceName: : $0 $1 "
|
||||||
; First get the installed service command.
|
; First get the installed service command.
|
||||||
SimpleSC::GetServiceBinaryPath '${TRI_SVC_NAME}'
|
SimpleSC::GetServiceBinaryPath '${TRI_SVC_NAME}'
|
||||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||||
Pop $1 ; returns the binary path of the service
|
Pop $1 ; returns the binary path of the service
|
||||||
; $1 should contain '"$INSTDIR\${SBIN_DIR}\arangod.exe" --start-service' - if $INSTDIR is equal
|
; $1 should contain '"$INSTDIR\${SBIN_DIR}\arangod.exe" --start-service' - if $INSTDIR is equal
|
||||||
; to our $INSTDIR uninstall the service - else its another installation and we jump to Done instead.
|
; to our $INSTDIR uninstall the service - else its another installation and we jump to Done instead.
|
||||||
; MessageBox MB_OK ' current service: $1 ---- "$INSTDIR\${SBIN_DIR}\arangod.exe"'
|
; MessageBox MB_OK ' current service: $1 ---- "$INSTDIR\${SBIN_DIR}\arangod.exe"'
|
||||||
StrCmp $1 '"$INSTDIR\${SBIN_DIR}\arangod.exe" --start-service' '' Done
|
StrCmp $1 '"$INSTDIR\${SBIN_DIR}\arangod.exe" --start-service' '' Done
|
||||||
DetailPrint 'Shutting down Service ${TRI_SVC_NAME}'
|
DetailPrint 'Shutting down Service ${TRI_SVC_NAME}'
|
||||||
SimpleSC::StopService '${TRI_SVC_NAME}' 0 30
|
SimpleSC::StopService '${TRI_SVC_NAME}' 0 30
|
||||||
Call un.WaitForServiceDown
|
Call un.WaitForServiceDown
|
||||||
DetailPrint 'Removing ArangoDB Service'
|
DetailPrint 'Removing ArangoDB Service'
|
||||||
SimpleSC::RemoveService '${TRI_SVC_NAME}'
|
SimpleSC::RemoveService '${TRI_SVC_NAME}'
|
||||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||||
IntCmp $0 0 Done +1 +1
|
IntCmp $0 0 Done
|
||||||
Push $0
|
Push $0
|
||||||
SimpleSC::GetErrorMessage
|
SimpleSC::GetErrorMessage
|
||||||
Pop $0
|
Pop $0
|
||||||
DetailPrint 'Stopping ArangoDB fails - Reason: $0'
|
DetailPrint 'Stopping ArangoDB fails - Reason: $0'
|
||||||
MessageBox MB_OK 'Stopping ArangoDB fails - Reason: $0'
|
MessageBox MB_OK 'Stopping ArangoDB fails - Reason: $0'
|
||||||
|
|
||||||
Done:
|
${EndIf}
|
||||||
nothing:
|
Done:
|
||||||
DetailPrint 'Removing files'
|
DetailPrint 'Removing files'
|
||||||
|
|
||||||
Delete "$INSTDIR\etc\arangodb3\arangod.conf.old"
|
Delete "$INSTDIR\etc\arangodb3\arangod.conf.old"
|
||||||
|
@ -921,7 +963,9 @@ Section "Uninstall"
|
||||||
RMDir "$INSTDIR\var\lib"
|
RMDir "$INSTDIR\var\lib"
|
||||||
RMDir /r "$INSTDIR\var\log\arangodb3"
|
RMDir /r "$INSTDIR\var\log\arangodb3"
|
||||||
dontDeleteDatabases:
|
dontDeleteDatabases:
|
||||||
DetailPrint 'Removing programm files:'
|
DetailPrint 'Removing programm files:'
|
||||||
|
DetailPrint " RMDir $INSTDIR\usr\share\arangodb3\js\node\node_modules\graphql-sync"
|
||||||
|
|
||||||
;Remove files we installed.
|
;Remove files we installed.
|
||||||
;Keep the list of directories here in sync with the File commands above.
|
;Keep the list of directories here in sync with the File commands above.
|
||||||
@CPACK_NSIS_DELETE_FILES@
|
@CPACK_NSIS_DELETE_FILES@
|
||||||
|
@ -993,9 +1037,9 @@ Section "Uninstall"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
DeleteRegKey HKLM "${TRI_UNINSTALL_REG_PATH}"
|
DeleteRegKey HKLM "${TRI_UNINSTALL_REG_PATH}"
|
||||||
|
|
||||||
StrCmp $DO_NOT_ADD_TO_PATH "1" doNotRemoveFromPath 0
|
${If} $ADD_TO_PATH == 1
|
||||||
!InsertMacro un.RemoveFromPath "$INSTDIR/${BIN_DIR}"
|
!InsertMacro un.RemoveFromPath "$INSTDIR/${BIN_DIR}"
|
||||||
doNotRemoveFromPath:
|
${EndIf}
|
||||||
SectionEnd
|
SectionEnd
|
||||||
|
|
||||||
|
|
||||||
|
@ -1041,60 +1085,29 @@ Function .onInit
|
||||||
StrCpy $STORAGE_ENGINE "auto"
|
StrCpy $STORAGE_ENGINE "auto"
|
||||||
|
|
||||||
${GetParameters} $R0
|
${GetParameters} $R0
|
||||||
${GetOptions} $R0 "/DESKTOPICON=" $INSTALL_DESKTOP
|
${GetOptions} $R0 "/DESKTOPICON=" $ADD_DESKTOP_ICON
|
||||||
IfErrors 0 +2
|
IfErrors 0 +2
|
||||||
StrCpy $INSTALL_DESKTOP "1"
|
StrCpy $ADD_DESKTOP_ICON "1"
|
||||||
|
|
||||||
${GetParameters} $R0
|
${GetParameters} $R0
|
||||||
ClearErrors
|
ClearErrors
|
||||||
${GetOptions} $R0 "/NOPATH=" $DO_NOT_ADD_TO_PATH
|
${GetOptions} $R0 "/PATH=" $ADD_TO_PATH
|
||||||
IfErrors 0 +2
|
IfErrors 0 +2
|
||||||
StrCpy $DO_NOT_ADD_TO_PATH "0"
|
StrCpy $ADD_TO_PATH "0"
|
||||||
|
|
||||||
${GetParameters} $R0
|
${GetOptions} $R0 "/INSTALL_SCOPE_ALL=" $0
|
||||||
ClearErrors
|
${If} $0 == 1
|
||||||
${GetOptions} $R0 "/ALLPATH=" $ADD_TO_PATH_ALL_USERS
|
StrCpy $TRI_INSTALL_SCOPE_ALL "1"
|
||||||
IfErrors 0 +2
|
|
||||||
StrCpy $ADD_TO_PATH_ALL_USERS "0"
|
|
||||||
|
|
||||||
${GetParameters} $R0
|
|
||||||
ClearErrors
|
|
||||||
${GetOptions} $R0 "/CURPATH=" $ADD_TO_PATH_CURRENT_USER
|
|
||||||
IfErrors 0 +2
|
|
||||||
StrCpy $ADD_TO_PATH_CURRENT_USER "0"
|
|
||||||
|
|
||||||
noService:
|
|
||||||
IfSilent 0 dontValidatePathOption
|
|
||||||
StrCpy $allPathOpts "0"
|
|
||||||
IntOp $allPathOpts $allPathOpts + $DO_NOT_ADD_TO_PATH
|
|
||||||
IntOp $allPathOpts $allPathOpts + $ADD_TO_PATH_ALL_USERS
|
|
||||||
IntOp $allPathOpts $allPathOpts + $ADD_TO_PATH_CURRENT_USER
|
|
||||||
${If} $allPathOpts != 1
|
|
||||||
Goto PathWrong
|
|
||||||
${EndIf}
|
|
||||||
|
|
||||||
${If} $DO_NOT_ADD_TO_PATH == "1"
|
|
||||||
${ElseIf} $ADD_TO_PATH_ALL_USERS == "1"
|
|
||||||
StrCpy $TRI_INSTALL_SCOPE "global"
|
|
||||||
${ElseIf} $ADD_TO_PATH_CURRENT_USER == "1"
|
|
||||||
StrCpy $TRI_INSTALL_SCOPE "ThisUsers"
|
|
||||||
${Else}
|
${Else}
|
||||||
Goto PathWrong
|
StrCpy $TRI_INSTALL_SCOPE_ALL "0"
|
||||||
${EndIf}
|
${EndIf}
|
||||||
|
|
||||||
Goto dontValidatePathOption
|
|
||||||
PathWrong:
|
|
||||||
MessageBox MB_OK "You have to exactly set one of /NOPATH=$DO_NOT_ADD_TO_PATH, /ALLPATH=$ADD_TO_PATH_ALL_USERS or /CURPATH=$ADD_TO_PATH_CURRENT_USER to 1!"
|
|
||||||
Abort
|
|
||||||
|
|
||||||
dontValidatePathOption:
|
|
||||||
|
|
||||||
IfSilent 0 dontFetchPath
|
IfSilent 0 dontFetchPath
|
||||||
${GetParameters} $R0
|
${GetParameters} $R0
|
||||||
ClearErrors
|
ClearErrors
|
||||||
${GetOptions} $R0 "/INSTALLTYPE=" $TRI_INSTALL_TYPE
|
StrCpy $TRI_INSTALL_SERVICE "1"
|
||||||
|
${GetOptions} $R0 "/INSTALL_SERVICE=" $TRI_INSTALL_SERVICE
|
||||||
|
|
||||||
|
|
||||||
StrLen $0 "$INSTDIR"
|
StrLen $0 "$INSTDIR"
|
||||||
${If} $0 < 3
|
${If} $0 < 3
|
||||||
MessageBox MB_OK 'Refusing to install flat on drive "$INSTDIR"'
|
MessageBox MB_OK 'Refusing to install flat on drive "$INSTDIR"'
|
||||||
|
|
|
@ -2582,6 +2582,28 @@ void AstNode::stealComputedValue() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief Removes all members from the current node that are also
|
||||||
|
/// members of the other node (ignoring ording)
|
||||||
|
/// Can only be applied if this and other are of type
|
||||||
|
/// n-ary-and
|
||||||
|
void AstNode::removeMembersInOtherAndNode(AstNode const* other) {
|
||||||
|
TRI_ASSERT(type == NODE_TYPE_OPERATOR_NARY_AND);
|
||||||
|
TRI_ASSERT(other->type == NODE_TYPE_OPERATOR_NARY_AND);
|
||||||
|
for (size_t i = 0; i < other->numMembers(); ++i) {
|
||||||
|
auto theirs = other->getMemberUnchecked(i);
|
||||||
|
for (size_t j = 0; j < numMembers(); ++j) {
|
||||||
|
auto ours = getMemberUnchecked(j);
|
||||||
|
// NOTE: Pointer comparison on purpose.
|
||||||
|
// We do not want to reduce equivalent but identical nodes
|
||||||
|
if (ours == theirs) {
|
||||||
|
removeMemberUnchecked(j);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief append the AstNode to an output stream
|
/// @brief append the AstNode to an output stream
|
||||||
std::ostream& operator<<(std::ostream& stream,
|
std::ostream& operator<<(std::ostream& stream,
|
||||||
arangodb::aql::AstNode const* node) {
|
arangodb::aql::AstNode const* node) {
|
||||||
|
|
|
@ -659,6 +659,13 @@ struct AstNode {
|
||||||
/// @brief Steals the computed value and frees it.
|
/// @brief Steals the computed value and frees it.
|
||||||
void stealComputedValue();
|
void stealComputedValue();
|
||||||
|
|
||||||
|
|
||||||
|
/// @brief Removes all members from the current node that are also
|
||||||
|
/// members of the other node (ignoring ording)
|
||||||
|
/// Can only be applied if this and other are of type
|
||||||
|
/// n-ary-and
|
||||||
|
void removeMembersInOtherAndNode(AstNode const* other);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// @brief the node type
|
/// @brief the node type
|
||||||
AstNodeType const type;
|
AstNodeType const type;
|
||||||
|
@ -677,7 +684,7 @@ struct AstNode {
|
||||||
std::vector<AstNode*> members;
|
std::vector<AstNode*> members;
|
||||||
};
|
};
|
||||||
|
|
||||||
int CompareAstNodes(AstNode const*, AstNode const*, bool);
|
int CompareAstNodes(AstNode const* lhs, AstNode const* rhs, bool compareUtf8);
|
||||||
|
|
||||||
/// @brief less comparator for Ast value nodes
|
/// @brief less comparator for Ast value nodes
|
||||||
template <bool useUtf8>
|
template <bool useUtf8>
|
||||||
|
|
|
@ -182,11 +182,12 @@ ConditionPart::ConditionPart(
|
||||||
ConditionPart::~ConditionPart() {}
|
ConditionPart::~ConditionPart() {}
|
||||||
|
|
||||||
/// @brief true if the condition is completely covered by the other condition
|
/// @brief true if the condition is completely covered by the other condition
|
||||||
bool ConditionPart::isCoveredBy(ConditionPart const& other, bool isReversed) const {
|
bool ConditionPart::isCoveredBy(ConditionPart const& other,
|
||||||
|
bool isReversed) const {
|
||||||
if (variable != other.variable || attributeName != other.attributeName) {
|
if (variable != other.variable || attributeName != other.attributeName) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isExpanded && !other.isExpanded &&
|
if (!isExpanded && !other.isExpanded &&
|
||||||
other.operatorType == NODE_TYPE_OPERATOR_BINARY_IN &&
|
other.operatorType == NODE_TYPE_OPERATOR_BINARY_IN &&
|
||||||
other.valueNode->isConstant() && isReversed) {
|
other.valueNode->isConstant() && isReversed) {
|
||||||
|
@ -197,12 +198,11 @@ bool ConditionPart::isCoveredBy(ConditionPart const& other, bool isReversed) con
|
||||||
|
|
||||||
TRI_ASSERT(valueNode != nullptr);
|
TRI_ASSERT(valueNode != nullptr);
|
||||||
TRI_ASSERT(other.valueNode != nullptr);
|
TRI_ASSERT(other.valueNode != nullptr);
|
||||||
|
|
||||||
if (!valueNode->isConstant() || !other.valueNode->isConstant()) {
|
if (!valueNode->isConstant() || !other.valueNode->isConstant()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// special cases for IN...
|
// special cases for IN...
|
||||||
if (!isExpanded && !other.isExpanded &&
|
if (!isExpanded && !other.isExpanded &&
|
||||||
other.operatorType == NODE_TYPE_OPERATOR_BINARY_IN &&
|
other.operatorType == NODE_TYPE_OPERATOR_BINARY_IN &&
|
||||||
|
@ -225,8 +225,8 @@ bool ConditionPart::isCoveredBy(ConditionPart const& other, bool isReversed) con
|
||||||
auto w = other.valueNode->getMemberUnchecked(j);
|
auto w = other.valueNode->getMemberUnchecked(j);
|
||||||
|
|
||||||
ConditionPartCompareResult res =
|
ConditionPartCompareResult res =
|
||||||
ConditionPart::ResultsTable[CompareAstNodes(v, w, true) +
|
ConditionPart::ResultsTable[CompareAstNodes(v, w, true) + 1][0]
|
||||||
1][0][0];
|
[0];
|
||||||
|
|
||||||
if (res != CompareResult::OTHER_CONTAINED_IN_SELF &&
|
if (res != CompareResult::OTHER_CONTAINED_IN_SELF &&
|
||||||
res != CompareResult::CONVERT_EQUAL &&
|
res != CompareResult::CONVERT_EQUAL &&
|
||||||
|
@ -270,8 +270,8 @@ bool ConditionPart::isCoveredBy(ConditionPart const& other, bool isReversed) con
|
||||||
|
|
||||||
// Results are -1, 0, 1, move to 0, 1, 2 for the lookup:
|
// Results are -1, 0, 1, move to 0, 1, 2 for the lookup:
|
||||||
ConditionPartCompareResult res = ConditionPart::ResultsTable
|
ConditionPartCompareResult res = ConditionPart::ResultsTable
|
||||||
[CompareAstNodes(other.valueNode, valueNode, true) +
|
[CompareAstNodes(other.valueNode, valueNode, true) + 1]
|
||||||
1][other.whichCompareOperation()][whichCompareOperation()];
|
[other.whichCompareOperation()][whichCompareOperation()];
|
||||||
|
|
||||||
if (res == CompareResult::OTHER_CONTAINED_IN_SELF ||
|
if (res == CompareResult::OTHER_CONTAINED_IN_SELF ||
|
||||||
res == CompareResult::CONVERT_EQUAL || res == CompareResult::IMPOSSIBLE) {
|
res == CompareResult::CONVERT_EQUAL || res == CompareResult::IMPOSSIBLE) {
|
||||||
|
@ -283,7 +283,8 @@ bool ConditionPart::isCoveredBy(ConditionPart const& other, bool isReversed) con
|
||||||
|
|
||||||
/// @brief clears the attribute access data
|
/// @brief clears the attribute access data
|
||||||
static inline void clearAttributeAccess(
|
static inline void clearAttributeAccess(
|
||||||
std::pair<Variable const*, std::vector<arangodb::basics::AttributeName>>& parts) {
|
std::pair<Variable const*, std::vector<arangodb::basics::AttributeName>>&
|
||||||
|
parts) {
|
||||||
parts.first = nullptr;
|
parts.first = nullptr;
|
||||||
parts.second.clear();
|
parts.second.clear();
|
||||||
}
|
}
|
||||||
|
@ -369,7 +370,7 @@ std::pair<bool, bool> Condition::findIndexes(
|
||||||
TRI_ASSERT(usedIndexes.empty());
|
TRI_ASSERT(usedIndexes.empty());
|
||||||
Variable const* reference = node->outVariable();
|
Variable const* reference = node->outVariable();
|
||||||
std::string collectionName = node->collection()->getName();
|
std::string collectionName = node->collection()->getName();
|
||||||
|
|
||||||
transaction::Methods* trx = _ast->query()->trx();
|
transaction::Methods* trx = _ast->query()->trx();
|
||||||
|
|
||||||
size_t const itemsInIndex = node->collection()->count(trx);
|
size_t const itemsInIndex = node->collection()->count(trx);
|
||||||
|
@ -387,8 +388,8 @@ std::pair<bool, bool> Condition::findIndexes(
|
||||||
|
|
||||||
/// @brief get the attributes for a sub-condition that are const
|
/// @brief get the attributes for a sub-condition that are const
|
||||||
/// (i.e. compared with equality)
|
/// (i.e. compared with equality)
|
||||||
std::vector<std::vector<arangodb::basics::AttributeName>> Condition::getConstAttributes(Variable const* reference,
|
std::vector<std::vector<arangodb::basics::AttributeName>>
|
||||||
bool includeNull) {
|
Condition::getConstAttributes(Variable const* reference, bool includeNull) {
|
||||||
std::vector<std::vector<arangodb::basics::AttributeName>> result;
|
std::vector<std::vector<arangodb::basics::AttributeName>> result;
|
||||||
|
|
||||||
if (_root == nullptr) {
|
if (_root == nullptr) {
|
||||||
|
@ -401,7 +402,8 @@ std::vector<std::vector<arangodb::basics::AttributeName>> Condition::getConstAtt
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<Variable const*, std::vector<arangodb::basics::AttributeName>> parts;
|
std::pair<Variable const*, std::vector<arangodb::basics::AttributeName>>
|
||||||
|
parts;
|
||||||
AstNode const* node = _root->getMember(0);
|
AstNode const* node = _root->getMember(0);
|
||||||
n = node->numMembers();
|
n = node->numMembers();
|
||||||
|
|
||||||
|
@ -416,13 +418,16 @@ std::vector<std::vector<arangodb::basics::AttributeName>> Condition::getConstAtt
|
||||||
|
|
||||||
if (lhs->isAttributeAccessForVariable(parts) &&
|
if (lhs->isAttributeAccessForVariable(parts) &&
|
||||||
parts.first == reference) {
|
parts.first == reference) {
|
||||||
if (includeNull || ((rhs->isConstant() || rhs->type == NODE_TYPE_REFERENCE) && !rhs->isNullValue())) {
|
if (includeNull ||
|
||||||
|
((rhs->isConstant() || rhs->type == NODE_TYPE_REFERENCE) &&
|
||||||
|
!rhs->isNullValue())) {
|
||||||
result.emplace_back(std::move(parts.second));
|
result.emplace_back(std::move(parts.second));
|
||||||
}
|
}
|
||||||
}
|
} else if (rhs->isAttributeAccessForVariable(parts) &&
|
||||||
else if (rhs->isAttributeAccessForVariable(parts) &&
|
parts.first == reference) {
|
||||||
parts.first == reference) {
|
if (includeNull ||
|
||||||
if (includeNull || ((lhs->isConstant() || lhs->type == NODE_TYPE_REFERENCE) && !lhs->isNullValue())) {
|
((lhs->isConstant() || lhs->type == NODE_TYPE_REFERENCE) &&
|
||||||
|
!lhs->isNullValue())) {
|
||||||
result.emplace_back(std::move(parts.second));
|
result.emplace_back(std::move(parts.second));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -474,6 +479,55 @@ void Condition::normalize() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Condition::CollectOverlappingMembers(
|
||||||
|
ExecutionPlan const* plan, Variable const* variable, AstNode* andNode,
|
||||||
|
AstNode* otherAndNode, std::unordered_set<size_t>& toRemove) {
|
||||||
|
std::pair<Variable const*, std::vector<arangodb::basics::AttributeName>>
|
||||||
|
result;
|
||||||
|
|
||||||
|
size_t const n = andNode->numMembers();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < n; ++i) {
|
||||||
|
auto operand = andNode->getMemberUnchecked(i);
|
||||||
|
|
||||||
|
if (operand->isComparisonOperator() &&
|
||||||
|
operand->type != NODE_TYPE_OPERATOR_BINARY_NE &&
|
||||||
|
operand->type != NODE_TYPE_OPERATOR_BINARY_NIN) {
|
||||||
|
auto lhs = operand->getMember(0);
|
||||||
|
auto rhs = operand->getMember(1);
|
||||||
|
|
||||||
|
if (lhs->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
|
||||||
|
clearAttributeAccess(result);
|
||||||
|
|
||||||
|
if (lhs->isAttributeAccessForVariable(result) &&
|
||||||
|
result.first == variable) {
|
||||||
|
ConditionPart current(variable, result.second, operand,
|
||||||
|
ATTRIBUTE_LEFT, nullptr);
|
||||||
|
|
||||||
|
if (CanRemove(plan, current, otherAndNode)) {
|
||||||
|
toRemove.emplace(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rhs->type == NODE_TYPE_ATTRIBUTE_ACCESS ||
|
||||||
|
rhs->type == NODE_TYPE_EXPANSION) {
|
||||||
|
clearAttributeAccess(result);
|
||||||
|
|
||||||
|
if (rhs->isAttributeAccessForVariable(result) &&
|
||||||
|
result.first == variable) {
|
||||||
|
ConditionPart current(variable, result.second, operand,
|
||||||
|
ATTRIBUTE_RIGHT, nullptr);
|
||||||
|
|
||||||
|
if (CanRemove(plan, current, otherAndNode)) {
|
||||||
|
toRemove.emplace(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// @brief removes condition parts from another
|
/// @brief removes condition parts from another
|
||||||
AstNode* Condition::removeIndexCondition(ExecutionPlan const* plan,
|
AstNode* Condition::removeIndexCondition(ExecutionPlan const* plan,
|
||||||
Variable const* variable,
|
Variable const* variable,
|
||||||
|
@ -494,51 +548,13 @@ AstNode* Condition::removeIndexCondition(ExecutionPlan const* plan,
|
||||||
|
|
||||||
auto andNode = _root->getMemberUnchecked(0);
|
auto andNode = _root->getMemberUnchecked(0);
|
||||||
TRI_ASSERT(andNode->type == NODE_TYPE_OPERATOR_NARY_AND);
|
TRI_ASSERT(andNode->type == NODE_TYPE_OPERATOR_NARY_AND);
|
||||||
|
auto otherAndNode = other->getMemberUnchecked(0);
|
||||||
|
TRI_ASSERT(otherAndNode->type == NODE_TYPE_OPERATOR_NARY_AND);
|
||||||
size_t const n = andNode->numMembers();
|
size_t const n = andNode->numMembers();
|
||||||
|
|
||||||
std::pair<Variable const*, std::vector<arangodb::basics::AttributeName>> result;
|
|
||||||
std::unordered_set<size_t> toRemove;
|
std::unordered_set<size_t> toRemove;
|
||||||
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
CollectOverlappingMembers(plan, variable, andNode, otherAndNode, toRemove);
|
||||||
auto operand = andNode->getMemberUnchecked(i);
|
|
||||||
|
|
||||||
if (operand->isComparisonOperator() &&
|
|
||||||
operand->type != NODE_TYPE_OPERATOR_BINARY_NE &&
|
|
||||||
operand->type != NODE_TYPE_OPERATOR_BINARY_NIN) {
|
|
||||||
|
|
||||||
auto lhs = operand->getMember(0);
|
|
||||||
auto rhs = operand->getMember(1);
|
|
||||||
|
|
||||||
if (lhs->type == NODE_TYPE_ATTRIBUTE_ACCESS) {
|
|
||||||
clearAttributeAccess(result);
|
|
||||||
|
|
||||||
if (lhs->isAttributeAccessForVariable(result) &&
|
|
||||||
result.first == variable) {
|
|
||||||
ConditionPart current(variable, result.second, operand,
|
|
||||||
ATTRIBUTE_LEFT, nullptr);
|
|
||||||
|
|
||||||
if (canRemove(plan, current, other)) {
|
|
||||||
toRemove.emplace(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rhs->type == NODE_TYPE_ATTRIBUTE_ACCESS ||
|
|
||||||
rhs->type == NODE_TYPE_EXPANSION) {
|
|
||||||
clearAttributeAccess(result);
|
|
||||||
|
|
||||||
if (rhs->isAttributeAccessForVariable(result) &&
|
|
||||||
result.first == variable) {
|
|
||||||
ConditionPart current(variable, result.second, operand,
|
|
||||||
ATTRIBUTE_RIGHT, nullptr);
|
|
||||||
|
|
||||||
if (canRemove(plan, current, other)) {
|
|
||||||
toRemove.emplace(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toRemove.empty()) {
|
if (toRemove.empty()) {
|
||||||
return _root;
|
return _root;
|
||||||
|
@ -623,12 +639,13 @@ void Condition::optimize(ExecutionPlan* plan) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction::Methods* trx = plan->getAst()->query()->trx();
|
transaction::Methods* trx = plan->getAst()->query()->trx();
|
||||||
|
|
||||||
TRI_ASSERT(_root != nullptr);
|
TRI_ASSERT(_root != nullptr);
|
||||||
TRI_ASSERT(_root->type == NODE_TYPE_OPERATOR_NARY_OR);
|
TRI_ASSERT(_root->type == NODE_TYPE_OPERATOR_NARY_OR);
|
||||||
|
|
||||||
std::pair<Variable const*, std::vector<arangodb::basics::AttributeName>> varAccess;
|
std::pair<Variable const*, std::vector<arangodb::basics::AttributeName>>
|
||||||
|
varAccess;
|
||||||
|
|
||||||
// handle sub nodes of top-level OR node
|
// handle sub nodes of top-level OR node
|
||||||
size_t n = _root->numMembers();
|
size_t n = _root->numMembers();
|
||||||
|
@ -662,23 +679,32 @@ void Condition::optimize(ExecutionPlan* plan) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TRI_ASSERT(andNumMembers > 1);
|
TRI_ASSERT(andNumMembers > 1);
|
||||||
|
|
||||||
// sort AND parts of each sub-condition so > and >= come before < and <=
|
// sort AND parts of each sub-condition so > and >= come before < and <=
|
||||||
// we use this to some advantage when we check the conditions for a sparse index
|
// we use this to some advantage when we check the conditions for a sparse
|
||||||
|
// index
|
||||||
// later.
|
// later.
|
||||||
// if a sparse index is asked whether it can supported a condition such as `attr < value1`,
|
// if a sparse index is asked whether it can supported a condition such as
|
||||||
// this range would include `null`, which the sparse index cannot provide. however, if we
|
// `attr < value1`,
|
||||||
// first check other conditions we may find a condition on the same attribute, e.g. `attr > value2`.
|
// this range would include `null`, which the sparse index cannot provide.
|
||||||
// this other condition may exclude `null` so we then use the full range `value2 < attr < value1`
|
// however, if we
|
||||||
|
// first check other conditions we may find a condition on the same
|
||||||
|
// attribute, e.g. `attr > value2`.
|
||||||
|
// this other condition may exclude `null` so we then use the full range
|
||||||
|
// `value2 < attr < value1`
|
||||||
// and do not have to discard sub-conditions anymore
|
// and do not have to discard sub-conditions anymore
|
||||||
andNode->sortMembers([](AstNode const* lhs, AstNode const* rhs) {
|
andNode->sortMembers([](AstNode const* lhs, AstNode const* rhs) {
|
||||||
if ((lhs->type != NODE_TYPE_OPERATOR_BINARY_LT && lhs->type != NODE_TYPE_OPERATOR_BINARY_LE) &&
|
if ((lhs->type != NODE_TYPE_OPERATOR_BINARY_LT &&
|
||||||
(rhs->type == NODE_TYPE_OPERATOR_BINARY_LT || rhs->type == NODE_TYPE_OPERATOR_BINARY_LE)) {
|
lhs->type != NODE_TYPE_OPERATOR_BINARY_LE) &&
|
||||||
|
(rhs->type == NODE_TYPE_OPERATOR_BINARY_LT ||
|
||||||
|
rhs->type == NODE_TYPE_OPERATOR_BINARY_LE)) {
|
||||||
// sort < and <= after other comparison operators
|
// sort < and <= after other comparison operators
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((lhs->type == NODE_TYPE_OPERATOR_BINARY_LT || lhs->type == NODE_TYPE_OPERATOR_BINARY_LE) &&
|
if ((lhs->type == NODE_TYPE_OPERATOR_BINARY_LT ||
|
||||||
(rhs->type != NODE_TYPE_OPERATOR_BINARY_LT && rhs->type != NODE_TYPE_OPERATOR_BINARY_LE)) {
|
lhs->type == NODE_TYPE_OPERATOR_BINARY_LE) &&
|
||||||
|
(rhs->type != NODE_TYPE_OPERATOR_BINARY_LT &&
|
||||||
|
rhs->type != NODE_TYPE_OPERATOR_BINARY_LE)) {
|
||||||
// sort < and <= after other comparison operators
|
// sort < and <= after other comparison operators
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -686,7 +712,6 @@ void Condition::optimize(ExecutionPlan* plan) {
|
||||||
return (lhs->type < rhs->type);
|
return (lhs->type < rhs->type);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (inComparisons > 0) {
|
if (inComparisons > 0) {
|
||||||
// move IN operations to the front to make comparison code below simpler
|
// move IN operations to the front to make comparison code below simpler
|
||||||
std::vector<AstNode*> stack;
|
std::vector<AstNode*> stack;
|
||||||
|
@ -715,7 +740,7 @@ void Condition::optimize(ExecutionPlan* plan) {
|
||||||
stack.pop_back();
|
stack.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// optimization is only necessary if an AND node has multiple members
|
// optimization is only necessary if an AND node has multiple members
|
||||||
VariableUsageType variableUsage;
|
VariableUsageType variableUsage;
|
||||||
|
|
||||||
|
@ -730,14 +755,16 @@ void Condition::optimize(ExecutionPlan* plan) {
|
||||||
if (lhs->isConstant()) {
|
if (lhs->isConstant()) {
|
||||||
lhs = Ast::resolveConstAttributeAccess(lhs);
|
lhs = Ast::resolveConstAttributeAccess(lhs);
|
||||||
}
|
}
|
||||||
storeAttributeAccess(varAccess, variableUsage, lhs, j, ATTRIBUTE_LEFT);
|
storeAttributeAccess(varAccess, variableUsage, lhs, j,
|
||||||
|
ATTRIBUTE_LEFT);
|
||||||
}
|
}
|
||||||
if (rhs->type == NODE_TYPE_ATTRIBUTE_ACCESS ||
|
if (rhs->type == NODE_TYPE_ATTRIBUTE_ACCESS ||
|
||||||
rhs->type == NODE_TYPE_EXPANSION) {
|
rhs->type == NODE_TYPE_EXPANSION) {
|
||||||
if (rhs->type == NODE_TYPE_ATTRIBUTE_ACCESS && rhs->isConstant()) {
|
if (rhs->type == NODE_TYPE_ATTRIBUTE_ACCESS && rhs->isConstant()) {
|
||||||
rhs = Ast::resolveConstAttributeAccess(rhs);
|
rhs = Ast::resolveConstAttributeAccess(rhs);
|
||||||
}
|
}
|
||||||
storeAttributeAccess(varAccess, variableUsage, rhs, j, ATTRIBUTE_RIGHT);
|
storeAttributeAccess(varAccess, variableUsage, rhs, j,
|
||||||
|
ATTRIBUTE_RIGHT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -807,8 +834,8 @@ void Condition::optimize(ExecutionPlan* plan) {
|
||||||
for (size_t k = 0; k < values->numMembers(); ++k) {
|
for (size_t k = 0; k < values->numMembers(); ++k) {
|
||||||
auto value = values->getMemberUnchecked(k);
|
auto value = values->getMemberUnchecked(k);
|
||||||
ConditionPartCompareResult res = ConditionPart::ResultsTable
|
ConditionPartCompareResult res = ConditionPart::ResultsTable
|
||||||
[CompareAstNodes(value, other.valueNode, true) +
|
[CompareAstNodes(value, other.valueNode, true) + 1]
|
||||||
1][0 /*NODE_TYPE_OPERATOR_BINARY_EQ*/]
|
[0 /*NODE_TYPE_OPERATOR_BINARY_EQ*/]
|
||||||
[other.whichCompareOperation()];
|
[other.whichCompareOperation()];
|
||||||
|
|
||||||
bool const keep =
|
bool const keep =
|
||||||
|
@ -902,11 +929,10 @@ void Condition::optimize(ExecutionPlan* plan) {
|
||||||
|
|
||||||
/// @brief registers an attribute access for a particular (collection) variable
|
/// @brief registers an attribute access for a particular (collection) variable
|
||||||
void Condition::storeAttributeAccess(
|
void Condition::storeAttributeAccess(
|
||||||
std::pair<Variable const*, std::vector<arangodb::basics::AttributeName>>& varAccess,
|
std::pair<Variable const*, std::vector<arangodb::basics::AttributeName>>&
|
||||||
VariableUsageType& variableUsage,
|
varAccess,
|
||||||
AstNode const* node, size_t position,
|
VariableUsageType& variableUsage, AstNode const* node, size_t position,
|
||||||
AttributeSideType side) {
|
AttributeSideType side) {
|
||||||
|
|
||||||
if (!node->isAttributeAccessForVariable(varAccess)) {
|
if (!node->isAttributeAccessForVariable(varAccess)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -969,20 +995,22 @@ void Condition::validateAst(AstNode const* node, int level) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// @brief checks if the current condition is covered by the other
|
/// @brief checks if the current condition is covered by the other
|
||||||
bool Condition::canRemove(ExecutionPlan const* plan, ConditionPart const& me,
|
bool Condition::CanRemove(ExecutionPlan const* plan, ConditionPart const& me,
|
||||||
arangodb::aql::AstNode const* otherCondition) const {
|
arangodb::aql::AstNode const* andNode) {
|
||||||
TRI_ASSERT(otherCondition != nullptr);
|
TRI_ASSERT(andNode != nullptr);
|
||||||
TRI_ASSERT(otherCondition->type == NODE_TYPE_OPERATOR_NARY_OR);
|
|
||||||
|
|
||||||
std::pair<Variable const*, std::vector<arangodb::basics::AttributeName>> result;
|
|
||||||
auto andNode = otherCondition->getMemberUnchecked(0);
|
|
||||||
TRI_ASSERT(andNode->type == NODE_TYPE_OPERATOR_NARY_AND);
|
TRI_ASSERT(andNode->type == NODE_TYPE_OPERATOR_NARY_AND);
|
||||||
|
|
||||||
|
std::pair<Variable const*, std::vector<arangodb::basics::AttributeName>>
|
||||||
|
result;
|
||||||
|
|
||||||
size_t const n = andNode->numMembers();
|
size_t const n = andNode->numMembers();
|
||||||
|
|
||||||
auto normalize = [&plan](AstNode const* node) -> std::string {
|
auto normalize = [&plan](AstNode const* node) -> std::string {
|
||||||
if (node->type == NODE_TYPE_REFERENCE) {
|
if (node->type == NODE_TYPE_REFERENCE) {
|
||||||
auto setter = plan->getVarSetBy(static_cast<Variable const*>(node->getData())->id);
|
auto setter =
|
||||||
if (setter != nullptr && setter->getType() == ExecutionNode::CALCULATION) {
|
plan->getVarSetBy(static_cast<Variable const*>(node->getData())->id);
|
||||||
|
if (setter != nullptr &&
|
||||||
|
setter->getType() == ExecutionNode::CALCULATION) {
|
||||||
auto cn = static_cast<CalculationNode const*>(setter);
|
auto cn = static_cast<CalculationNode const*>(setter);
|
||||||
// use expression node instead
|
// use expression node instead
|
||||||
node = cn->expression()->node();
|
node = cn->expression()->node();
|
||||||
|
@ -1006,7 +1034,7 @@ bool Condition::canRemove(ExecutionPlan const* plan, ConditionPart const& me,
|
||||||
if (lhs->isAttributeAccessForVariable(result)) {
|
if (lhs->isAttributeAccessForVariable(result)) {
|
||||||
if (rhs->isConstant()) {
|
if (rhs->isConstant()) {
|
||||||
ConditionPart indexCondition(result.first, result.second, operand,
|
ConditionPart indexCondition(result.first, result.second, operand,
|
||||||
ATTRIBUTE_LEFT, nullptr);
|
ATTRIBUTE_LEFT, nullptr);
|
||||||
|
|
||||||
if (me.isCoveredBy(indexCondition, false)) {
|
if (me.isCoveredBy(indexCondition, false)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1014,7 +1042,7 @@ bool Condition::canRemove(ExecutionPlan const* plan, ConditionPart const& me,
|
||||||
}
|
}
|
||||||
// non-constant condition
|
// non-constant condition
|
||||||
else if (me.operatorType == operand->type &&
|
else if (me.operatorType == operand->type &&
|
||||||
normalize(me.valueNode) == normalize(rhs)) {
|
normalize(me.valueNode) == normalize(rhs)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1027,7 +1055,7 @@ bool Condition::canRemove(ExecutionPlan const* plan, ConditionPart const& me,
|
||||||
if (rhs->isAttributeAccessForVariable(result)) {
|
if (rhs->isAttributeAccessForVariable(result)) {
|
||||||
if (lhs->isConstant()) {
|
if (lhs->isConstant()) {
|
||||||
ConditionPart indexCondition(result.first, result.second, operand,
|
ConditionPart indexCondition(result.first, result.second, operand,
|
||||||
ATTRIBUTE_RIGHT, nullptr);
|
ATTRIBUTE_RIGHT, nullptr);
|
||||||
|
|
||||||
if (me.isCoveredBy(indexCondition, true)) {
|
if (me.isCoveredBy(indexCondition, true)) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -1035,7 +1063,7 @@ bool Condition::canRemove(ExecutionPlan const* plan, ConditionPart const& me,
|
||||||
}
|
}
|
||||||
// non-constant condition
|
// non-constant condition
|
||||||
else if (me.operatorType == operand->type &&
|
else if (me.operatorType == operand->type &&
|
||||||
normalize(me.valueNode) == normalize(lhs)) {
|
normalize(me.valueNode) == normalize(lhs)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1074,7 +1102,8 @@ void Condition::deduplicateInOperation(AstNode* operation) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief merge the values from two IN operations
|
/// @brief merge the values from two IN operations
|
||||||
AstNode* Condition::mergeInOperations(transaction::Methods* trx, AstNode const* lhs, AstNode const* rhs) {
|
AstNode* Condition::mergeInOperations(transaction::Methods* trx,
|
||||||
|
AstNode const* lhs, AstNode const* rhs) {
|
||||||
TRI_ASSERT(lhs->type == NODE_TYPE_OPERATOR_BINARY_IN);
|
TRI_ASSERT(lhs->type == NODE_TYPE_OPERATOR_BINARY_IN);
|
||||||
TRI_ASSERT(rhs->type == NODE_TYPE_OPERATOR_BINARY_IN);
|
TRI_ASSERT(rhs->type == NODE_TYPE_OPERATOR_BINARY_IN);
|
||||||
|
|
||||||
|
@ -1099,9 +1128,11 @@ AstNode* Condition::collapse(AstNode const* node) {
|
||||||
for (size_t i = 0; i < n; ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
auto sub = node->getMemberUnchecked(i);
|
auto sub = node->getMemberUnchecked(i);
|
||||||
|
|
||||||
bool const isSame = (node->type == sub->type) ||
|
bool const isSame = (node->type == sub->type) ||
|
||||||
(node->type == NODE_TYPE_OPERATOR_NARY_OR && sub->type == NODE_TYPE_OPERATOR_BINARY_OR) ||
|
(node->type == NODE_TYPE_OPERATOR_NARY_OR &&
|
||||||
(node->type == NODE_TYPE_OPERATOR_NARY_AND && sub->type == NODE_TYPE_OPERATOR_BINARY_AND);
|
sub->type == NODE_TYPE_OPERATOR_BINARY_OR) ||
|
||||||
|
(node->type == NODE_TYPE_OPERATOR_NARY_AND &&
|
||||||
|
sub->type == NODE_TYPE_OPERATOR_BINARY_AND);
|
||||||
|
|
||||||
if (isSame) {
|
if (isSame) {
|
||||||
// merge
|
// merge
|
||||||
|
@ -1121,7 +1152,7 @@ AstNode* Condition::transformNode(AstNode* node) {
|
||||||
if (node == nullptr) {
|
if (node == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node->type == NODE_TYPE_OPERATOR_BINARY_AND ||
|
if (node->type == NODE_TYPE_OPERATOR_BINARY_AND ||
|
||||||
node->type == NODE_TYPE_OPERATOR_BINARY_OR) {
|
node->type == NODE_TYPE_OPERATOR_BINARY_OR) {
|
||||||
// convert binary AND/OR into n-ary AND/OR
|
// convert binary AND/OR into n-ary AND/OR
|
||||||
|
@ -1142,7 +1173,7 @@ AstNode* Condition::transformNode(AstNode* node) {
|
||||||
bool processChildren = false;
|
bool processChildren = false;
|
||||||
bool mustCollapse = false;
|
bool mustCollapse = false;
|
||||||
size_t const n = node->numMembers();
|
size_t const n = node->numMembers();
|
||||||
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
// process subnodes first
|
// process subnodes first
|
||||||
auto sub = transformNode(node->getMemberUnchecked(i));
|
auto sub = transformNode(node->getMemberUnchecked(i));
|
||||||
|
@ -1154,7 +1185,7 @@ AstNode* Condition::transformNode(AstNode* node) {
|
||||||
mustCollapse = true;
|
mustCollapse = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (processChildren) {
|
if (processChildren) {
|
||||||
// we found an AND with at least one OR child, e.g.
|
// we found an AND with at least one OR child, e.g.
|
||||||
// AND
|
// AND
|
||||||
|
@ -1174,7 +1205,7 @@ AstNode* Condition::transformNode(AstNode* node) {
|
||||||
for (size_t i = 0; i < n; ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
auto sub = node->getMemberUnchecked(i);
|
auto sub = node->getMemberUnchecked(i);
|
||||||
|
|
||||||
if (sub->type == NODE_TYPE_OPERATOR_NARY_OR) {
|
if (sub->type == NODE_TYPE_OPERATOR_NARY_OR) {
|
||||||
permutationStates.emplace_back(sub, sub->numMembers());
|
permutationStates.emplace_back(sub, sub->numMembers());
|
||||||
} else {
|
} else {
|
||||||
permutationStates.emplace_back(sub, 1);
|
permutationStates.emplace_back(sub, 1);
|
||||||
|
@ -1228,7 +1259,7 @@ AstNode* Condition::transformNode(AstNode* node) {
|
||||||
if (node->type == NODE_TYPE_OPERATOR_NARY_OR) {
|
if (node->type == NODE_TYPE_OPERATOR_NARY_OR) {
|
||||||
size_t const n = node->numMembers();
|
size_t const n = node->numMembers();
|
||||||
bool mustCollapse = false;
|
bool mustCollapse = false;
|
||||||
|
|
||||||
for (size_t i = 0; i < n; ++i) {
|
for (size_t i = 0; i < n; ++i) {
|
||||||
auto sub = transformNode(node->getMemberUnchecked(i));
|
auto sub = transformNode(node->getMemberUnchecked(i));
|
||||||
node->changeMember(i, sub);
|
node->changeMember(i, sub);
|
||||||
|
@ -1237,7 +1268,7 @@ AstNode* Condition::transformNode(AstNode* node) {
|
||||||
mustCollapse = true;
|
mustCollapse = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mustCollapse) {
|
if (mustCollapse) {
|
||||||
node = collapse(node);
|
node = collapse(node);
|
||||||
}
|
}
|
||||||
|
|
|
@ -178,6 +178,10 @@ class Condition {
|
||||||
~Condition();
|
~Condition();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
static void CollectOverlappingMembers(
|
||||||
|
ExecutionPlan const* plan, Variable const* variable, AstNode* andNode,
|
||||||
|
AstNode* otherAndNode, std::unordered_set<size_t>& toRemove);
|
||||||
|
|
||||||
/// @brief return the condition root
|
/// @brief return the condition root
|
||||||
inline AstNode* root() const { return _root; }
|
inline AstNode* root() const { return _root; }
|
||||||
|
|
||||||
|
@ -235,6 +239,7 @@ class Condition {
|
||||||
std::vector<std::vector<arangodb::basics::AttributeName>> getConstAttributes (Variable const*, bool);
|
std::vector<std::vector<arangodb::basics::AttributeName>> getConstAttributes (Variable const*, bool);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/// @brief sort ORs for the same attribute so they are in ascending value
|
/// @brief sort ORs for the same attribute so they are in ascending value
|
||||||
/// order. this will only work if the condition is for a single attribute
|
/// order. this will only work if the condition is for a single attribute
|
||||||
bool sortOrs(Variable const*, std::vector<Index const*>&);
|
bool sortOrs(Variable const*, std::vector<Index const*>&);
|
||||||
|
@ -254,7 +259,7 @@ class Condition {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/// @brief checks if the current condition covers the other
|
/// @brief checks if the current condition covers the other
|
||||||
bool canRemove(ExecutionPlan const*, ConditionPart const&, AstNode const*) const;
|
static bool CanRemove(ExecutionPlan const*, ConditionPart const&, AstNode const*);
|
||||||
|
|
||||||
/// @brief deduplicate IN condition values
|
/// @brief deduplicate IN condition values
|
||||||
/// this may modify the node in place
|
/// this may modify the node in place
|
||||||
|
|
|
@ -322,17 +322,17 @@ void ShortestPathNode::prepareOptions() {
|
||||||
auto dir = _directions[i];
|
auto dir = _directions[i];
|
||||||
switch (dir) {
|
switch (dir) {
|
||||||
case TRI_EDGE_IN:
|
case TRI_EDGE_IN:
|
||||||
opts->addLookupInfo(ast, _edgeColls[i]->getName(),
|
opts->addLookupInfo(_plan, _edgeColls[i]->getName(),
|
||||||
StaticStrings::ToString, _toCondition->clone(ast));
|
StaticStrings::ToString, _toCondition->clone(ast));
|
||||||
opts->addReverseLookupInfo(ast, _edgeColls[i]->getName(),
|
opts->addReverseLookupInfo(_plan, _edgeColls[i]->getName(),
|
||||||
StaticStrings::FromString,
|
StaticStrings::FromString,
|
||||||
_fromCondition->clone(ast));
|
_fromCondition->clone(ast));
|
||||||
break;
|
break;
|
||||||
case TRI_EDGE_OUT:
|
case TRI_EDGE_OUT:
|
||||||
opts->addLookupInfo(ast, _edgeColls[i]->getName(),
|
opts->addLookupInfo(_plan, _edgeColls[i]->getName(),
|
||||||
StaticStrings::FromString,
|
StaticStrings::FromString,
|
||||||
_fromCondition->clone(ast));
|
_fromCondition->clone(ast));
|
||||||
opts->addReverseLookupInfo(ast, _edgeColls[i]->getName(),
|
opts->addReverseLookupInfo(_plan, _edgeColls[i]->getName(),
|
||||||
StaticStrings::ToString,
|
StaticStrings::ToString,
|
||||||
_toCondition->clone(ast));
|
_toCondition->clone(ast));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -496,12 +496,12 @@ void TraversalNode::prepareOptions() {
|
||||||
switch (dir) {
|
switch (dir) {
|
||||||
case TRI_EDGE_IN:
|
case TRI_EDGE_IN:
|
||||||
_options->addLookupInfo(
|
_options->addLookupInfo(
|
||||||
ast, _edgeColls[i]->getName(), StaticStrings::ToString,
|
_plan, _edgeColls[i]->getName(), StaticStrings::ToString,
|
||||||
globalEdgeConditionBuilder.getInboundCondition()->clone(ast));
|
globalEdgeConditionBuilder.getInboundCondition()->clone(ast));
|
||||||
break;
|
break;
|
||||||
case TRI_EDGE_OUT:
|
case TRI_EDGE_OUT:
|
||||||
_options->addLookupInfo(
|
_options->addLookupInfo(
|
||||||
ast, _edgeColls[i]->getName(), StaticStrings::FromString,
|
_plan, _edgeColls[i]->getName(), StaticStrings::FromString,
|
||||||
globalEdgeConditionBuilder.getOutboundCondition()->clone(ast));
|
globalEdgeConditionBuilder.getOutboundCondition()->clone(ast));
|
||||||
break;
|
break;
|
||||||
case TRI_EDGE_ANY:
|
case TRI_EDGE_ANY:
|
||||||
|
@ -529,12 +529,12 @@ void TraversalNode::prepareOptions() {
|
||||||
switch (dir) {
|
switch (dir) {
|
||||||
case TRI_EDGE_IN:
|
case TRI_EDGE_IN:
|
||||||
opts->addDepthLookupInfo(
|
opts->addDepthLookupInfo(
|
||||||
ast, _edgeColls[i]->getName(), StaticStrings::ToString,
|
_plan, _edgeColls[i]->getName(), StaticStrings::ToString,
|
||||||
builder->getInboundCondition()->clone(ast), depth);
|
builder->getInboundCondition()->clone(ast), depth);
|
||||||
break;
|
break;
|
||||||
case TRI_EDGE_OUT:
|
case TRI_EDGE_OUT:
|
||||||
opts->addDepthLookupInfo(
|
opts->addDepthLookupInfo(
|
||||||
ast, _edgeColls[i]->getName(), StaticStrings::FromString,
|
_plan, _edgeColls[i]->getName(), StaticStrings::FromString,
|
||||||
builder->getOutboundCondition()->clone(ast), depth);
|
builder->getOutboundCondition()->clone(ast), depth);
|
||||||
break;
|
break;
|
||||||
case TRI_EDGE_ANY:
|
case TRI_EDGE_ANY:
|
||||||
|
|
|
@ -23,10 +23,12 @@
|
||||||
|
|
||||||
#include "BaseOptions.h"
|
#include "BaseOptions.h"
|
||||||
#include "Aql/Ast.h"
|
#include "Aql/Ast.h"
|
||||||
|
#include "Aql/Condition.h"
|
||||||
|
#include "Aql/ExecutionPlan.h"
|
||||||
#include "Aql/Expression.h"
|
#include "Aql/Expression.h"
|
||||||
#include "Aql/Query.h"
|
#include "Aql/Query.h"
|
||||||
#include "Graph/SingleServerEdgeCursor.h"
|
|
||||||
#include "Graph/ShortestPathOptions.h"
|
#include "Graph/ShortestPathOptions.h"
|
||||||
|
#include "Graph/SingleServerEdgeCursor.h"
|
||||||
#include "Graph/TraverserCache.h"
|
#include "Graph/TraverserCache.h"
|
||||||
#include "Graph/TraverserCacheFactory.h"
|
#include "Graph/TraverserCacheFactory.h"
|
||||||
#include "Indexes/Index.h"
|
#include "Indexes/Index.h"
|
||||||
|
@ -91,13 +93,12 @@ BaseOptions::LookupInfo::LookupInfo(arangodb::aql::Query* query,
|
||||||
}
|
}
|
||||||
|
|
||||||
read = info.get("expression");
|
read = info.get("expression");
|
||||||
if (!read.isObject()) {
|
if (read.isObject()) {
|
||||||
THROW_ARANGO_EXCEPTION_MESSAGE(
|
expression = new aql::Expression(query->ast(), read);
|
||||||
TRI_ERROR_BAD_PARAMETER,
|
} else {
|
||||||
"Each lookup requires expression to be an object");
|
expression = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
expression = new aql::Expression(query->ast(), read);
|
|
||||||
|
|
||||||
read = info.get("condition");
|
read = info.get("condition");
|
||||||
if (!read.isObject()) {
|
if (!read.isObject()) {
|
||||||
|
@ -114,7 +115,9 @@ BaseOptions::LookupInfo::LookupInfo(LookupInfo const& other)
|
||||||
indexCondition(other.indexCondition),
|
indexCondition(other.indexCondition),
|
||||||
conditionNeedUpdate(other.conditionNeedUpdate),
|
conditionNeedUpdate(other.conditionNeedUpdate),
|
||||||
conditionMemberToUpdate(other.conditionMemberToUpdate) {
|
conditionMemberToUpdate(other.conditionMemberToUpdate) {
|
||||||
expression = other.expression->clone(nullptr);
|
if (other.expression != nullptr) {
|
||||||
|
expression = other.expression->clone(nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseOptions::LookupInfo::buildEngineInfo(VPackBuilder& result) const {
|
void BaseOptions::LookupInfo::buildEngineInfo(VPackBuilder& result) const {
|
||||||
|
@ -122,15 +125,17 @@ void BaseOptions::LookupInfo::buildEngineInfo(VPackBuilder& result) const {
|
||||||
result.add(VPackValue("handle"));
|
result.add(VPackValue("handle"));
|
||||||
// We only run toVelocyPack on Coordinator.
|
// We only run toVelocyPack on Coordinator.
|
||||||
TRI_ASSERT(idxHandles.size() == 1);
|
TRI_ASSERT(idxHandles.size() == 1);
|
||||||
// result.openObject();
|
|
||||||
idxHandles[0].toVelocyPack(result, false);
|
idxHandles[0].toVelocyPack(result, false);
|
||||||
// result.close();
|
|
||||||
result.add(VPackValue("expression"));
|
if (expression != nullptr) {
|
||||||
result.openObject(); // We need to encapsulate the expression into an
|
result.add(VPackValue("expression"));
|
||||||
// expression object
|
result.openObject(); // We need to encapsulate the expression into an
|
||||||
result.add(VPackValue("expression"));
|
// expression object
|
||||||
expression->toVelocyPack(result, true);
|
result.add(VPackValue("expression"));
|
||||||
result.close();
|
expression->toVelocyPack(result, true);
|
||||||
|
result.close();
|
||||||
|
}
|
||||||
result.add(VPackValue("condition"));
|
result.add(VPackValue("condition"));
|
||||||
indexCondition->toVelocyPack(result, true);
|
indexCondition->toVelocyPack(result, true);
|
||||||
result.add("condNeedUpdate", VPackValue(conditionNeedUpdate));
|
result.add("condNeedUpdate", VPackValue(conditionNeedUpdate));
|
||||||
|
@ -153,7 +158,6 @@ double BaseOptions::LookupInfo::estimateCost(size_t& nrItems) const {
|
||||||
return 1000.0;
|
return 1000.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::unique_ptr<BaseOptions> BaseOptions::createOptionsFromSlice(
|
std::unique_ptr<BaseOptions> BaseOptions::createOptionsFromSlice(
|
||||||
transaction::Methods* trx, VPackSlice const& definition) {
|
transaction::Methods* trx, VPackSlice const& definition) {
|
||||||
VPackSlice type = definition.get("type");
|
VPackSlice type = definition.get("type");
|
||||||
|
@ -226,22 +230,21 @@ void BaseOptions::setVariable(aql::Variable const* variable) {
|
||||||
_tmpVar = variable;
|
_tmpVar = variable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseOptions::addLookupInfo(aql::Ast* ast,
|
void BaseOptions::addLookupInfo(aql::ExecutionPlan* plan,
|
||||||
std::string const& collectionName,
|
std::string const& collectionName,
|
||||||
std::string const& attributeName,
|
std::string const& attributeName,
|
||||||
aql::AstNode* condition) {
|
aql::AstNode* condition) {
|
||||||
injectLookupInfoInList(_baseLookupInfos, ast, collectionName, attributeName,
|
injectLookupInfoInList(_baseLookupInfos, plan, collectionName, attributeName,
|
||||||
condition);
|
condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseOptions::injectLookupInfoInList(std::vector<LookupInfo>& list,
|
void BaseOptions::injectLookupInfoInList(std::vector<LookupInfo>& list,
|
||||||
aql::Ast* ast,
|
aql::ExecutionPlan* plan,
|
||||||
std::string const& collectionName,
|
std::string const& collectionName,
|
||||||
std::string const& attributeName,
|
std::string const& attributeName,
|
||||||
aql::AstNode* condition) {
|
aql::AstNode* condition) {
|
||||||
LookupInfo info;
|
LookupInfo info;
|
||||||
info.indexCondition = condition;
|
info.indexCondition = condition->clone(plan->getAst());
|
||||||
info.expression = new aql::Expression(ast, condition->clone(ast));
|
|
||||||
bool res = _trx->getBestIndexHandleForFilterCondition(
|
bool res = _trx->getBestIndexHandleForFilterCondition(
|
||||||
collectionName, info.indexCondition, _tmpVar, 1000, info.idxHandles[0]);
|
collectionName, info.indexCondition, _tmpVar, 1000, info.idxHandles[0]);
|
||||||
TRI_ASSERT(res); // Right now we have an enforced edge index which will
|
TRI_ASSERT(res); // Right now we have an enforced edge index which will
|
||||||
|
@ -282,6 +285,23 @@ void BaseOptions::injectLookupInfoInList(std::vector<LookupInfo>& list,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::unordered_set<size_t> toRemove;
|
||||||
|
aql::Condition::CollectOverlappingMembers(plan, _tmpVar, condition, info.indexCondition, toRemove);
|
||||||
|
size_t n = condition->numMembers();
|
||||||
|
if (n == toRemove.size()) {
|
||||||
|
// FastPath, all covered.
|
||||||
|
info.expression = nullptr;
|
||||||
|
} else {
|
||||||
|
// Slow path need to explicitly remove nodes.
|
||||||
|
for (; n > 0; --n) {
|
||||||
|
// Now n is one more than the idx we actually check
|
||||||
|
if (toRemove.find(n - 1) != toRemove.end()) {
|
||||||
|
// This index has to be removed.
|
||||||
|
condition->removeMemberUnchecked(n - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.expression = new aql::Expression(plan->getAst(), condition);
|
||||||
|
}
|
||||||
list.emplace_back(std::move(info));
|
list.emplace_back(std::move(info));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,9 +352,10 @@ void BaseOptions::injectEngineInfo(VPackBuilder& result) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
arangodb::aql::Expression* BaseOptions::getEdgeExpression(
|
arangodb::aql::Expression* BaseOptions::getEdgeExpression(
|
||||||
size_t cursorId) const {
|
size_t cursorId, bool& needToInjectVertex) const {
|
||||||
TRI_ASSERT(!_baseLookupInfos.empty());
|
TRI_ASSERT(!_baseLookupInfos.empty());
|
||||||
TRI_ASSERT(_baseLookupInfos.size() > cursorId);
|
TRI_ASSERT(_baseLookupInfos.size() > cursorId);
|
||||||
|
needToInjectVertex = !_baseLookupInfos[cursorId].conditionNeedUpdate;
|
||||||
return _baseLookupInfos[cursorId].expression;
|
return _baseLookupInfos[cursorId].expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -417,7 +438,9 @@ TraverserCache* BaseOptions::cache() {
|
||||||
return _cache.get();
|
return _cache.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseOptions::activateCache(bool enableDocumentCache, std::unordered_map<ServerID, traverser::TraverserEngineID> const* engines) {
|
void BaseOptions::activateCache(
|
||||||
|
bool enableDocumentCache,
|
||||||
|
std::unordered_map<ServerID, traverser::TraverserEngineID> const* engines) {
|
||||||
// Do not call this twice.
|
// Do not call this twice.
|
||||||
TRI_ASSERT(_cache == nullptr);
|
TRI_ASSERT(_cache == nullptr);
|
||||||
_cache.reset(cacheFactory::CreateCache(_trx, enableDocumentCache, engines));
|
_cache.reset(cacheFactory::CreateCache(_trx, enableDocumentCache, engines));
|
||||||
|
|
|
@ -35,6 +35,7 @@ namespace arangodb {
|
||||||
|
|
||||||
namespace aql {
|
namespace aql {
|
||||||
struct AstNode;
|
struct AstNode;
|
||||||
|
class ExecutionPlan;
|
||||||
class Expression;
|
class Expression;
|
||||||
class Query;
|
class Query;
|
||||||
}
|
}
|
||||||
|
@ -98,7 +99,7 @@ struct BaseOptions {
|
||||||
|
|
||||||
void setVariable(aql::Variable const*);
|
void setVariable(aql::Variable const*);
|
||||||
|
|
||||||
void addLookupInfo(aql::Ast* ast, std::string const& collectionName,
|
void addLookupInfo(aql::ExecutionPlan* plan, std::string const& collectionName,
|
||||||
std::string const& attributeName, aql::AstNode* condition);
|
std::string const& attributeName, aql::AstNode* condition);
|
||||||
|
|
||||||
void clearVariableValues();
|
void clearVariableValues();
|
||||||
|
@ -142,12 +143,12 @@ struct BaseOptions {
|
||||||
// Does not close the builder.
|
// Does not close the builder.
|
||||||
void injectEngineInfo(arangodb::velocypack::Builder&) const;
|
void injectEngineInfo(arangodb::velocypack::Builder&) const;
|
||||||
|
|
||||||
aql::Expression* getEdgeExpression(size_t cursorId) const;
|
aql::Expression* getEdgeExpression(size_t cursorId, bool& needToInjectVertex) const;
|
||||||
|
|
||||||
bool evaluateExpression(aql::Expression*,
|
bool evaluateExpression(aql::Expression*,
|
||||||
arangodb::velocypack::Slice varValue) const;
|
arangodb::velocypack::Slice varValue) const;
|
||||||
|
|
||||||
void injectLookupInfoInList(std::vector<LookupInfo>&, aql::Ast* ast,
|
void injectLookupInfoInList(std::vector<LookupInfo>&, aql::ExecutionPlan* plan,
|
||||||
std::string const& collectionName,
|
std::string const& collectionName,
|
||||||
std::string const& attributeName,
|
std::string const& attributeName,
|
||||||
aql::AstNode* condition);
|
aql::AstNode* condition);
|
||||||
|
|
|
@ -169,9 +169,9 @@ double ShortestPathOptions::estimateCost(size_t& nrItems) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShortestPathOptions::addReverseLookupInfo(
|
void ShortestPathOptions::addReverseLookupInfo(
|
||||||
aql::Ast* ast, std::string const& collectionName,
|
aql::ExecutionPlan* plan, std::string const& collectionName,
|
||||||
std::string const& attributeName, aql::AstNode* condition) {
|
std::string const& attributeName, aql::AstNode* condition) {
|
||||||
injectLookupInfoInList(_reverseLookupInfos, ast, collectionName,
|
injectLookupInfoInList(_reverseLookupInfos, plan, collectionName,
|
||||||
attributeName, condition);
|
attributeName, condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
namespace arangodb {
|
namespace arangodb {
|
||||||
|
|
||||||
namespace aql {
|
namespace aql {
|
||||||
|
class ExecutionPlan;
|
||||||
class Query;
|
class Query;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +91,7 @@ struct ShortestPathOptions : public BaseOptions {
|
||||||
|
|
||||||
// Creates a complete Object containing all EngineInfo
|
// Creates a complete Object containing all EngineInfo
|
||||||
// in the given builder.
|
// in the given builder.
|
||||||
void addReverseLookupInfo(aql::Ast* ast, std::string const& collectionName,
|
void addReverseLookupInfo(aql::ExecutionPlan* plan, std::string const& collectionName,
|
||||||
std::string const& attributeName,
|
std::string const& attributeName,
|
||||||
aql::AstNode* condition);
|
aql::AstNode* condition);
|
||||||
|
|
||||||
|
|
|
@ -398,13 +398,13 @@ void TraverserOptions::buildEngineInfo(VPackBuilder& result) const {
|
||||||
result.close();
|
result.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TraverserOptions::addDepthLookupInfo(aql::Ast* ast,
|
void TraverserOptions::addDepthLookupInfo(aql::ExecutionPlan* plan,
|
||||||
std::string const& collectionName,
|
std::string const& collectionName,
|
||||||
std::string const& attributeName,
|
std::string const& attributeName,
|
||||||
aql::AstNode* condition,
|
aql::AstNode* condition,
|
||||||
uint64_t depth) {
|
uint64_t depth) {
|
||||||
auto& list = _depthLookupInfo[depth];
|
auto& list = _depthLookupInfo[depth];
|
||||||
injectLookupInfoInList(list, ast, collectionName, attributeName, condition);
|
injectLookupInfoInList(list, plan, collectionName, attributeName, condition);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TraverserOptions::vertexHasFilter(uint64_t depth) const {
|
bool TraverserOptions::vertexHasFilter(uint64_t depth) const {
|
||||||
|
@ -428,7 +428,8 @@ bool TraverserOptions::hasEdgeFilter(int64_t depth, size_t cursorId) const {
|
||||||
TRI_ASSERT(specific->second.size() > cursorId);
|
TRI_ASSERT(specific->second.size() > cursorId);
|
||||||
expression = specific->second[cursorId].expression;
|
expression = specific->second[cursorId].expression;
|
||||||
} else {
|
} else {
|
||||||
expression = getEdgeExpression(cursorId);
|
bool unused;
|
||||||
|
expression = getEdgeExpression(cursorId, unused);
|
||||||
}
|
}
|
||||||
return expression != nullptr;
|
return expression != nullptr;
|
||||||
}
|
}
|
||||||
|
@ -445,32 +446,40 @@ bool TraverserOptions::evaluateEdgeExpression(arangodb::velocypack::Slice edge,
|
||||||
arangodb::aql::Expression* expression = nullptr;
|
arangodb::aql::Expression* expression = nullptr;
|
||||||
|
|
||||||
auto specific = _depthLookupInfo.find(depth);
|
auto specific = _depthLookupInfo.find(depth);
|
||||||
|
auto needToInjectVertex = false;
|
||||||
|
|
||||||
if (specific != _depthLookupInfo.end()) {
|
if (specific != _depthLookupInfo.end()) {
|
||||||
TRI_ASSERT(!specific->second.empty());
|
TRI_ASSERT(!specific->second.empty());
|
||||||
TRI_ASSERT(specific->second.size() > cursorId);
|
TRI_ASSERT(specific->second.size() > cursorId);
|
||||||
expression = specific->second[cursorId].expression;
|
expression = specific->second[cursorId].expression;
|
||||||
|
needToInjectVertex = !specific->second[cursorId].conditionNeedUpdate;
|
||||||
} else {
|
} else {
|
||||||
expression = getEdgeExpression(cursorId);
|
expression = getEdgeExpression(cursorId, needToInjectVertex);
|
||||||
|
|
||||||
}
|
}
|
||||||
if (expression == nullptr) {
|
if (expression == nullptr) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// inject _from/_to value
|
if (needToInjectVertex) {
|
||||||
auto node = expression->nodeForModification();
|
// If we have to inject the vertex value it has to be within
|
||||||
|
// the last member of the condition.
|
||||||
|
// We only get into this case iff the index used does
|
||||||
|
// not cover _from resp. _to.
|
||||||
|
// inject _from/_to value
|
||||||
|
auto node = expression->nodeForModification();
|
||||||
|
|
||||||
TRI_ASSERT(node->numMembers() > 0);
|
TRI_ASSERT(node->numMembers() > 0);
|
||||||
auto dirCmp = node->getMemberUnchecked(node->numMembers() - 1);
|
auto dirCmp = node->getMemberUnchecked(node->numMembers() - 1);
|
||||||
TRI_ASSERT(dirCmp->type == aql::NODE_TYPE_OPERATOR_BINARY_EQ);
|
TRI_ASSERT(dirCmp->type == aql::NODE_TYPE_OPERATOR_BINARY_EQ);
|
||||||
TRI_ASSERT(dirCmp->numMembers() == 2);
|
TRI_ASSERT(dirCmp->numMembers() == 2);
|
||||||
|
|
||||||
auto idNode = dirCmp->getMemberUnchecked(1);
|
|
||||||
TRI_ASSERT(idNode->type == aql::NODE_TYPE_VALUE);
|
|
||||||
TRI_ASSERT(idNode->isValueType(aql::VALUE_TYPE_STRING));
|
|
||||||
idNode->stealComputedValue();
|
|
||||||
idNode->setStringValue(vertexId.data(), vertexId.length());
|
|
||||||
|
|
||||||
|
auto idNode = dirCmp->getMemberUnchecked(1);
|
||||||
|
TRI_ASSERT(idNode->type == aql::NODE_TYPE_VALUE);
|
||||||
|
TRI_ASSERT(idNode->isValueType(aql::VALUE_TYPE_STRING));
|
||||||
|
idNode->stealComputedValue();
|
||||||
|
idNode->setStringValue(vertexId.data(), vertexId.length());
|
||||||
|
}
|
||||||
return evaluateExpression(expression, edge);
|
return evaluateExpression(expression, edge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -106,7 +106,7 @@ struct TraverserOptions : public graph::BaseOptions {
|
||||||
void buildEngineInfo(arangodb::velocypack::Builder&) const;
|
void buildEngineInfo(arangodb::velocypack::Builder&) const;
|
||||||
|
|
||||||
/// @brief Add a lookup info for specific depth
|
/// @brief Add a lookup info for specific depth
|
||||||
void addDepthLookupInfo(aql::Ast* ast, std::string const& collectionName,
|
void addDepthLookupInfo(aql::ExecutionPlan* plan, std::string const& collectionName,
|
||||||
std::string const& attributeName,
|
std::string const& attributeName,
|
||||||
aql::AstNode* condition, uint64_t depth);
|
aql::AstNode* condition, uint64_t depth);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue