From 82609f5fc1fe4858cf4b87e8d67bf01af0f5aa1e Mon Sep 17 00:00:00 2001 From: KammM Date: Mon, 13 Apr 2026 12:08:30 +0200 Subject: [PATCH] Serverumzug --- .../Packtisch 3.0.0.3 - Setup/Thumbs.db | Bin 12288 -> 0 bytes .../Dokumentation/Thumbs.db | Bin 12800 -> 0 bytes .../Packtisch 3.0.0.4 - Setup/Thumbs.db | Bin 12288 -> 0 bytes .../Dokumentation/Thumbs.db | Bin 12800 -> 0 bytes .../Packtisch 3.0.0.5 - Setup/Thumbs.db | Bin 12288 -> 0 bytes .../Dokumentation/Thumbs.db | Bin 12800 -> 0 bytes .../Thumbs.db | Bin 12288 -> 0 bytes .../Install-WindowsService_Settings.ini | 2 +- .../Remove-AzureArcSetup.ps1 | 30 + .../Import-FileContentToDB.ps1 | Bin 0 -> 162784 bytes .../Import-FileContentToDB_History.txt | 87 ++ current/MoveOrCopy-Files/MoveOrCopy-Files.ps1 | Bin 0 -> 189308 bytes .../MoveOrCopy-Files_History.txt | 127 +++ .../Set-FolderAttributes_Caller.cmd | 45 + .../Set-FolderAttributes_History.txt | 24 + .../ReC/[PRREC_DELETE_OBJECT].sql | 245 +++++ .../ReC/[PRREC_INSERT_OBJECT].sql | 460 +++++++++ .../ReC/[PRREC_UPDATE_OBJECT].sql | 453 +++++++++ .../ReC/[TBREC_CFG_ACTION].sql | 137 +++ .../ReC/[TBREC_CFG_ENDPOINT].sql | 64 ++ .../ReC/[TBREC_CFG_ENDPOINT_AUTH].sql | 102 ++ .../ReC/[TBREC_CFG_ENDPOINT_PARAMS].sql | 79 ++ .../ReC/[TBREC_CFG_PROFILE].sql | 96 ++ .../ReC/[TBREC_OUT_RESULT].sql | 66 ++ .../ReC/[TBREC_RUN_PROFILE].sql | 32 + .../[DD_ECM]-Database/ReC/[VWREC_ACTION].sql | 131 +++ .../[DD_ECM]-Database/ReC/[VWREC_PROFILE].sql | 86 ++ .../[DD_ECM]-Database/ReC/[VWREC_RESULT].sql | 77 ++ .../[FNCUST_GET_EDMI_ITEM_VALUE].sql | 190 ++++ .../[PRDD_TEST_PERFORMANCE].sql | 374 +++++++ .../[TBEDMI_ITEM_VALUE].sql | 35 + current/[DD_IIM]-Database/[MASTER_DEPLOY].sql | 36 + current/[DD_IIM]-Database/[SCHEMA_META].sql | 12 + .../[DD_IIM]-Database/[SECURITY_META_CFG].sql | 28 + .../[TBDD_CFG_FUNCTION_MODULE].sql | 83 ++ .../[TBDD_CFG_FUNCTION_MODULE_PROCEDURES].sql | 207 ++++ .../[TBDD_CFG_FUNCTION_MODULE_TRIGGER].sql | 58 ++ .../[TBDD_CFG_SYSTEM_INFO].sql | 74 ++ .../[TBDD_CFG_SYSTEM_INFO_PROCEDURES].sql | 139 +++ .../[TBDD_CFG_SYSTEM_INFO_TRIGGER].sql | 114 +++ .../[PRDD_MIGRATE_DATABASE].sql | 945 ++++++++++++------ .../[PRDD_SYNC_DATABASE].sql | 789 +++++++++------ ...[PRMOT_MON_GET_TREEVIEW_RESULTS]_error.sql | 169 ++++ .../[PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql | 174 ++++ .../[PRMOT_MON_GET_TREEVIEW_RESULTS]_safe.sql | 249 +++++ dev/[DD_ECM_REF]-Database/plan.md | 39 + .../[PRDD_GET_DATABASE_DEADLOCK].sql | 2 +- ...ST_WINLINE_EMAIL_OUT_DD_CWLDATEN_DDVP].sql | 47 + 48 files changed, 5489 insertions(+), 618 deletions(-) delete mode 100644 archive/Packtisch Modul/Packtisch 3.0.0.3 - Setup/Thumbs.db delete mode 100644 archive/Packtisch Modul/Packtisch 3.0.0.4 - Setup/Dokumentation/Thumbs.db delete mode 100644 archive/Packtisch Modul/Packtisch 3.0.0.4 - Setup/Thumbs.db delete mode 100644 archive/Packtisch Modul/Packtisch 3.0.0.5 - Setup/Dokumentation/Thumbs.db delete mode 100644 archive/Packtisch Modul/Packtisch 3.0.0.5 - Setup/Thumbs.db delete mode 100644 archive/Packtisch Modul/Packtisch 3.0.0.6 - Setup (in Progress...)/Dokumentation/Thumbs.db delete mode 100644 archive/Packtisch Modul/Packtisch 3.0.0.6 - Setup (in Progress...)/Thumbs.db create mode 100644 current/DD-Internal/Remove-AzureArcSetup/Remove-AzureArcSetup.ps1 create mode 100644 current/Import-FileContentToDB/Import-FileContentToDB.ps1 create mode 100644 current/Import-FileContentToDB/Import-FileContentToDB_History.txt create mode 100644 current/MoveOrCopy-Files/MoveOrCopy-Files.ps1 create mode 100644 current/MoveOrCopy-Files/MoveOrCopy-Files_History.txt create mode 100644 current/Set-FolderAttributes/Set-FolderAttributes_Caller.cmd create mode 100644 current/Set-FolderAttributes/Set-FolderAttributes_History.txt create mode 100644 current/[DD_ECM]-Database/ReC/[PRREC_DELETE_OBJECT].sql create mode 100644 current/[DD_ECM]-Database/ReC/[PRREC_INSERT_OBJECT].sql create mode 100644 current/[DD_ECM]-Database/ReC/[PRREC_UPDATE_OBJECT].sql create mode 100644 current/[DD_ECM]-Database/ReC/[TBREC_CFG_ACTION].sql create mode 100644 current/[DD_ECM]-Database/ReC/[TBREC_CFG_ENDPOINT].sql create mode 100644 current/[DD_ECM]-Database/ReC/[TBREC_CFG_ENDPOINT_AUTH].sql create mode 100644 current/[DD_ECM]-Database/ReC/[TBREC_CFG_ENDPOINT_PARAMS].sql create mode 100644 current/[DD_ECM]-Database/ReC/[TBREC_CFG_PROFILE].sql create mode 100644 current/[DD_ECM]-Database/ReC/[TBREC_OUT_RESULT].sql create mode 100644 current/[DD_ECM]-Database/ReC/[TBREC_RUN_PROFILE].sql create mode 100644 current/[DD_ECM]-Database/ReC/[VWREC_ACTION].sql create mode 100644 current/[DD_ECM]-Database/ReC/[VWREC_PROFILE].sql create mode 100644 current/[DD_ECM]-Database/ReC/[VWREC_RESULT].sql create mode 100644 current/[DD_ECM]-Database/[FNCUST_GET_EDMI_ITEM_VALUE]/[FNCUST_GET_EDMI_ITEM_VALUE].sql create mode 100644 current/[DD_ECM]-Database/[FNCUST_GET_EDMI_ITEM_VALUE]/[PRDD_TEST_PERFORMANCE].sql create mode 100644 current/[DD_ECM]-Database/[FNCUST_GET_EDMI_ITEM_VALUE]/[TBEDMI_ITEM_VALUE].sql create mode 100644 current/[DD_IIM]-Database/[MASTER_DEPLOY].sql create mode 100644 current/[DD_IIM]-Database/[SCHEMA_META].sql create mode 100644 current/[DD_IIM]-Database/[SECURITY_META_CFG].sql create mode 100644 current/[DD_IIM]-Database/[TBDD_CFG_FUNCTION_MODULE].sql create mode 100644 current/[DD_IIM]-Database/[TBDD_CFG_FUNCTION_MODULE_PROCEDURES].sql create mode 100644 current/[DD_IIM]-Database/[TBDD_CFG_FUNCTION_MODULE_TRIGGER].sql create mode 100644 current/[DD_IIM]-Database/[TBDD_CFG_SYSTEM_INFO].sql create mode 100644 current/[DD_IIM]-Database/[TBDD_CFG_SYSTEM_INFO_PROCEDURES].sql create mode 100644 current/[DD_IIM]-Database/[TBDD_CFG_SYSTEM_INFO_TRIGGER].sql create mode 100644 dev/[DD_ECM_REF]-Database/[PRMOT_MON_GET_TREEVIEW_RESULTS]_error.sql create mode 100644 dev/[DD_ECM_REF]-Database/[PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql create mode 100644 dev/[DD_ECM_REF]-Database/[PRMOT_MON_GET_TREEVIEW_RESULTS]_safe.sql create mode 100644 dev/[DD_ECM_REF]-Database/plan.md rename {current => dev}/[DD_SYS]-Database/[PRDD_GET_DATABASE_DEADLOCK]/[PRDD_GET_DATABASE_DEADLOCK].sql (99%) create mode 100644 dev/[VWCUST_WINLINE_EMAIL_OUT_DD_CWLDATEN_DDVP].sql diff --git a/archive/Packtisch Modul/Packtisch 3.0.0.3 - Setup/Thumbs.db b/archive/Packtisch Modul/Packtisch 3.0.0.3 - Setup/Thumbs.db deleted file mode 100644 index 9c61d64599e9166fc11ff94b42d4b4117c9e4140..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 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 diff --git a/archive/Packtisch Modul/Packtisch 3.0.0.4 - Setup/Dokumentation/Thumbs.db b/archive/Packtisch Modul/Packtisch 3.0.0.4 - Setup/Dokumentation/Thumbs.db deleted file mode 100644 index 9c72fa2551837f67f0eb0f7772660d9171022dd7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12800 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 diff --git a/archive/Packtisch Modul/Packtisch 3.0.0.4 - Setup/Thumbs.db b/archive/Packtisch Modul/Packtisch 3.0.0.4 - Setup/Thumbs.db deleted file mode 100644 index 408564c37f69eaac907cc4e0c89275d8cb43ea76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 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 diff --git a/archive/Packtisch Modul/Packtisch 3.0.0.5 - Setup/Dokumentation/Thumbs.db b/archive/Packtisch Modul/Packtisch 3.0.0.5 - Setup/Dokumentation/Thumbs.db deleted file mode 100644 index 3f3321a41729b84846b8ceab09467d469ce5e2b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12800 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 diff --git a/archive/Packtisch Modul/Packtisch 3.0.0.6 - Setup (in Progress...)/Dokumentation/Thumbs.db b/archive/Packtisch Modul/Packtisch 3.0.0.6 - Setup (in Progress...)/Dokumentation/Thumbs.db deleted file mode 100644 index cf438f066221e64685026b783a80aad008bc1486..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12800 zcmeHtcRZZk+U_$3ql+4%8$z@w2?jC9tECX4m*_3}5G6Vx38F@g5|<#@80ju-rsqD=R4>7=R4=@HNWdwYu(SRa^3f;_sqyJ%|cGarA6Rhf;<2Q zusBkH_!l_{pZo_>4W@uaf^-`hU0m|5|JRvGjkX z{a?%eJN^Hk2AJ@}35>_Rzs(0FWgZUxYXcSkag_aA^8ca+{>uKiDck~Z;g*WJ3IGEA zZDGeDftvs!7)%Hzgb)%!NFhWJQgTv!Ag7}E8K`J}k0|~Y{gL_C=g&$&gv7)YBovGk z6pZv#R8;goA5`>z6r=f1RniL3kO1i*01V;=2xvfH8W64n;J_b8iSWJsv%~m20ho}8 z7(zlyMvnhN^#%NH0R|Hgf{BO-@w)&h0RJ8!q#>f^5>q6m)3ShYyVHw@#OIJel`7g8 zv`4@5NLV65Ny!*5GBID`z0AjdMc~?XNhxWV%+24FRaDi~Z{63?)zddHG_ta`v9+^z zcK={)x zKY4)&ynhm>Atd4wBc@f^lIaf^qL&@08~RJ4&oCA7aYSRzKr7m(cN!XJI}+58 zBXlA9F;Si*X4~h|p{mkQ_C}|*ar4841^)?SgD=&YV#3fdE_JO0VdTqSpoQTCHI=c|vbuj}xg(}x&DSG?@2ekWoAK2czjpg_uX**i_ za#dJX!=ix+1|f{`SXmCqh;@oybG|G8?2{tOz~Gu)=}H?b$8Ve~6&oR2ns;6HUP^Em za?*gB)@sBU0?B z_Xj_Ec956Xj;IoGfP7rgd>#%U%RT?_=zIbbdoucGV&GFx(|H*F^2)8 zHh>ccw5Vel$Tqz>EYsI)H=u;?`B%y%LK28I6%!zZrFv!;Pu|RM;{coDZ~b+tE4sSq z=CvUeL!B5OeetTH1}xS<-1hoH#sWa|9EDH^Gj-o^ynkl9bykGt*emdo^a|w zE?3b5sox-2f}pOHGreQ1Z|oTguU6Ipp{VR%+TzEyeGXdtOnvqvdr>E*#7E{e4rtaq z`HTY|&f$rR;Q;^az1+0$c#psAt=z-Y_>ZBy!Pi8P)`5zOF;vth*(ot9ifzo@imDP+ zI(9g~d;@;40XaX_{GR)3HTGJn668?$ucCj_gHj|c)sPtn{6&9_=(X@B8vccW>OW~? z}$$rt0UO2snXr%-W_=nQ8el>R$|4-i8zl#281mq~=l^H|b;mpKnvHa0> zhTzh?m#iDox3?FGWT|IEr!Lnr$6_yMd&-0k$B6|?9&T;Qpn^!di#Kq<-Wv6}hZ#y> zklI~1hWeJZpDqb6*KHA7I7~nd##aW7eb~fmsj35G=Cs=~eZ;`aZb4K$XURRiso*T4 zv2anKAvANKNsUaDdVr*BHopp9H6=f05fn0x7VsUS62*jMejOIfK#2OC@`JO=$MlY7 zMOgfWmM_ETiOnoQ(8CQqcm)&(WVICFfCn}9uPKZhls}BQ=nHf5YtZeo%UnHEt!?t{ zjrofBB&-<^F&QHQ!%)X|Zn(>xNQ5e3Msu$VA5pH9ah3;aB}0a;OCxM(PIw?*_Wx0}bM z2;Q_WqPa`e&jGAB<4rteQeU8PNLPx5-(Xu`Tk7N}Zjy4kLPcuVshncljb@OhK*nV5bO zL3cvk8WqBApnltDU9mJu_(uJcEGD|Z4H^F}eL5E+4hP%vc=QeTwc5Tta z2`W2Y}LU+QNDR(<1w_LKq8Y7!Bd0K1gU|5`)LAMsBWt- z{AFS4-S_f;PXIH&NQp|{`pl_f$bzN#i#01Y&F1096C76KEzLo@ z?*ZhS3i^ly_j4$c{7i{PP1G5TJE*@T zM`oaGOHMwrFmp%V-g11E^djx)*Qf{$7+=3N4|^)=(Q@RV)ZkUVWBaTxdb^DcvrbN* zS7Ou84tKqSKHjLF=`)a1sUt5iCIqPv?sVVla3hBF=(zbKc=SD9JQ3^q{%abmJpf z)s<&j?=_O1$L_du+=bIc-u62J6=9Y26fO{77{C6&;Lvqo+=DXMneX75L4}{eD=XEP z_bbpgJ!i!TM0*ZQE~cs$?it{abHUa1J~};N_IaSXoX+*@weuK(G-%n1y>phbw17nR zt)=R#G!Nr~oyhJ4JvTja4~u4%lC8*yCV~{UmX6)4IkPFQK_geW?kr2sh-J8E*nMg2 zR{Y+XRqJ}av*yhtIWtLzN~(#77iBaZ=LKV)a=umRPX7J5!Rcd++{fL0iI>w3ynbk; zYj>H_4i1Pql=btp&m#KRD$M#hoK2<(@S)r!R=7dR@UXv&-I{FD`(9qRY?8G$gpc)j znOVLm+#L%$F=bduP!~cjAm|H&8weVD1PWK_;xq*$Vu)|jn8;u*eaJZf%pwGw(ILdz zqq$7;%u6*C;o=cJ>?JbvJY`qvnrBL|QmT}7!ZUfTU0B@Ore+z^2E25bt3E~#cuuY{-F?L`Tb4R4HsI-8<^0&6tK%i8-R zpft-p_EM2sx66^{aho_m48}x60)Bg&ZRP@SKS7@l%P{VhBJ(I?Or2*lk5~-{c)haX z%6x8tT?*?x5GMxH6ypHucv~GQKE8r)U9zV&L7aZJRVxJ;q_3!dFQ4cnjts``prj4}oV#GRIJGm~lwNLc&D> zs_k$l=c0(AgHYm0j9@%olV)gY98j5yWx$^+v&%3~allty#C@!5Tl}EN{BuiTFI!~? z-f0v?^ctjY*#Geu4yfh9Z;li9e=VVfKO>@oh9|K%alrOFQ~_o_?BcbCK;D*}UiezI z)n?%3NoUmMHfR=SeY<)^lpPZ@p%rV!GC;v7q-2T%!V&PbEgZmw1CDh2d{SCv{H6R{ zM0Ok3o+}vZ_=^%nhE;?XiS?~S7TM^&Vxq6Vf&-)$`m|GAJH7NwDQ8sY1Aa@2IECDdSU4Z^GQ?IQq-P^R-i69H_C&F&DW@4(lmyrv zdo#1d_<}0c))jiR##kry-(VynWVLvt5-V@rj;$iLW8OKa7r1dTnra+zvt^+@-L!>v zHEHRt_M+LDvK~ZRayw4iDOiJw9+Q`ZB5>0X3-yHmuQXJ+|5L$HKdW-gM4*)Berq4> z?r(VOXUDocIsMM?B-S9VFU1eqPQ#MxLZsMg`+%gUt(A{iK$GP~_K7|e8`!eXfj>hV zOxLz==`>dvmfDKbBIWAZv<~>@(Y02*kKJqCU5J%_Hw2Y~7v?UdM2FGL=WE{YqYgq? zR2FNgP=zaq$AEEIZwU^l*<{B*@jKFCQEJooyEU2b3^lKJ6mJPsl8gYiKC;4u<49Yj zhgqIO2pZlGX~ll^#*jw^cw+AO)u&69bGR7ma$m5zQrDjha5}e&;DGwR3Usr{1rMnx zk>t-LQ}Z~$u0ps*DP%kgGQc7jlD)K?H5ke)=Y8ksDp3{f`(nSmlwFm2mPj{^oqEA& z%2w-;LDNZi74H*~RN>6}nOfPS^5x)rl5?npk`c;A6hc|v;W7Hi*t8l41m`u(&Sq*Z z#ulUm*68Da)>i>l6_1Kw9|(zymg@1o z=BLR#W58M}8*d=iT*yuR!SU#`N>Pdj#hq40E)9m(HH3&7hxi)AU8|`?@sV)x6{3ub zzui9Q79)G#V7zMb6tu5n1&Of8I!r1sekdUwaiCHaD%xM4tYhv`ot8vso*~A!D&T$D z7p-n381%6BnytP6O}k)q_{V3ZvgW?8VwDtUyxCP$8NO_sCMCblGty*hivE9(ASyLD-EBA3QB^nah0dXv|`KLAhA{f|H$P_z*F%8?l=-dsrl) z=84vcR@T?mNCoRn+U@b;(Nei;TQ@E;^`ypHPDWNDT?!OUKet5)i_uxeom{!cR$C_? zyBnRV*Bp=D?EBp1{#f`CK2sEu-=IT(J7V0I`D=y*|e*NP1D zBtb-6DtL-%N?M5Cjt_K<&?$Ug&A|W>xONthuRtZDNjaph9h@{Y7OdFjf&e(#t}dFi zJQvB2S?-C|f2tvTX-6HZ;*5-8yImPdMNqlpLcdVxG^u4W)Z`d+eRcgB(zvIwirspf z;h?^@fFFJDso;oXzF%|?DyKssxNHQF%?#@29wK z=~f-BV4xK|0%|P)XGO$877Z`u_S7clTqXKQ>v1u;WX->~Yq@X1#VjSkL^9BX?eW04 zMV(*2UBnzrOMUJe@p{(^oJ%fLK{%M|mWbNI2%!vWm$0VIm3H)jLOvTq?}l@v#dD)eOCn3Z%%qMx3VS?#wiR;*SydLC2RL;#W~%Urf?Qr6;&7^d+vrQ(N0g*(*YY> zbi7ij_-#?G@sROoRE%Ky$RSH@gzI&ixE+%VJyWchnL3!O;&A^r!OUJh*Ip^~V-|kN zGIUi7Tt{>sOvYsa;hW!7rk4Gl^+_cw3XYVTir1k$_S$pN6(I$i^~=nL z6~|Oy+H;@})9tctl|VW@S#4WW9o#EaWBhiS*Hv&;)&LzO_eyagzENtni~NFPW|UC^ z4NFZeG??V9#?D881x(>B3W%N!hN|vq4K-rdus2bGW{+`z_)Piw8L1BH4=rEe2{2O#LU&VpEq-Ra7+3Ct7R%LtAZ9JXN z?v%D>03a%305s|qotS}Iy$kQ~nl8nAPrAl@t%;}hM42~w5~pI{LEmwgo>#h}4^s}J z@JHe555L+Jly>`Ggw(`#p1pN~uDG*%X8en2^4jmou>Emb7Fscr($nkGRskAa zD&eSj)4sYMwF8#W-C&*XxA=Kj>$?5Lw~Wqi95yw^4e+KWsdXoNJL_3$@U#L~d7`cP zdxXRvsC(R4X(;w4i5Ihd;om5)`;wSj0U-R=1`*2roSW&p`xWi$e|EI)`L5b=z1~Rk zl_$F9!`GT+n{Ty#yWGY)!H#s5ZQ_GfE@=_mfpp<8R7man?>EC?^O-S@nd6odrCq`g zmZs1-`-Nb(tOxBJLn!l>T`4P0OcU(=eFLBHg$wz!pIY|RQAkEPnqaAL)^ewi27z2J zDdOfwYsc_?7@8wxu4P~gotutoZeOAtsh$4j&N0ufTeb_IYX{&9Ak7@qDzj(Hg~ssD zM?3dQCDD2Xtf)BeM{*PyaT1~8B!9D>$?w+l@}Fc`Vyar5s5Lb*>z7KraNzu;S#J~? z*V16#uxx2s*-#_CP%9uq?ilqhM{PCKfkzjVf#$3L6P0s-`7)^R8$_v9$KwX!4F31WWlItO(BY!dx)XK}P^=VRdeRPtWKE@BO` z#eDvWC-3R)%Q_Y};Da%|!L(NBjAL1-OtEs-1KYNqe`Fy?6w zruh(SX=J=!Gsw{K*tV$2G*iuxn*XelteF7D8|VM7XCOy`SGh?Nd2{?aVTki}5<8X{ z8;Lh%fO!HEF-4^6mj9G&>aJ|Zp3w}{WHVOo7E_gzunv3fs(D+A#WGQ)Wbmx-w&#u| z+a0J4m7RNs;Q&=$ zTYGhZoAM`CQ7cS95rLaWX0gg>7YJJ9wOUo3OzKqJ4cvwBVH zb}YAF%u0kGanK88J)Cwh4t)m^U-MG)Xs}Z#5UA^w4Kb%u#sL@9E#$MZ?Q8w24at4A zuo$uqR9BLeReueCy>&otbgB?W+}Q4PLtI2eTRext zC?q~5FTdQ!$PetjpgOi<=pGE0<_hl43^(nj0HzgC45jIC;uAd^I$yHrcIgAtTi;}# zeQLg#fPjEsFU4517H^u@*4CQMaKDzrf3GZ#X{eiR%(AYLI3g)>hy2 zOaE|G2VZ*=XoYd`;6hY}Z)to?daZfIlDGXs_8dq2Gqtw01aJj}%L+Stb_;^TA0PANv;e_m?{g@)}vd_p>5n?I71>;evM~C*TXh?x`cxPL(TEw#h zX1uqhF?*BIpS8^yCc+-6C~-;_Ea{cZLPk0Y-1k6JI+ti zGEKpzTS+QCq<$ZNJ%Kr~7YC#iJjl-}M4Jn?$$NzzlRskSOd5u^ zG%NHjm3DF_G2RiK0ksp53`;{R*t#F)uu5*gvya|dCClCka~&KK>juAu6f6krPA}kZ z+t1Old!?yT6Q|CntRHT_Ih_ACo?L!CD!|D2%@LAEGsiIOW4={*S3R5#e_Ook$-dd;_}Pl=0fY&>%B3c*njk(CtR~dBFIFZlwqj*j zu_xr$Zn&XrJkWEWdo6LL$p1w~Sc>aCuY$pNOJg%y3bfa$3xcdd+z_G*{3c? zoYKEgdL3~Oz;`|NHN&%JitisK51)H9xSt;^WYt3hspa-5ozt{Um97dWRnXVB4ezOL z7!DTsPp(FVdZXdJDeL*GF^>0XVvjXPCIp)JX5lw=9Mzsjhhc9l;($_hOyQ3n`0^ab zDJr`!Tj$mk|C>l+{P7H6_}vY6>E{8BK9#O7ihIYLM0(-eG3EP8vva}4`}zIf+mdNt z(MMB}s||ES@I*XtBPhE+UaQ$x?kQ~>LyGBHisGb><0K457~87I1T4l6GZnMm_qOrH zmI(XT1l@S@g*el}fj;H_D|^h0Z)9#_M4#k}zlcO{8<9R`h8>}aeS9I*AoU4^N9b-F zH1RAkP8@Jim<>fJKdKe>D*sJrjv=lF?wgSBrg70_rWV)>37*gpTjC66{BSkKtrCpjFSdVbF-YCA4y_!{1|t$Lz$qy}G051NN!1dIeVbesnUC{^Zq9)7t3Wr+Lm zGMwHS0d;D?pOk{*&u4eo1D%uddGqlTSs>QA(fh~p0i=NG-PLrPac6>ldbeb^zWFU4 zS*9lnsxt{h@LwN}|ET3&Ml%yLqnmm1~9G zP-Sr7ihd2Pa{k5djlBLa`470(+kSsj%0yjzf}q&M9$7Lsikh*!bw&|1|LR zvUlKoU~_;ZI?-{2{1wx(Gkj;$hA2lQ*S_6Wb1sPzyRjxj&BSAM)5^iYEdjYs^+9FX z@yZjx>l;MgR^EhY27y1CC3d=O9vI~(sC&2z(d_d1{}vX>7Tq>vd-MubglV#gqOdKO=G^dKu}P~;dR)L7K0Ls$3j%8d-F?VBL!X!HV<;_N(tY?u`D7gXyjhY}JT8ct~RVIdD2u?D=u$ zer7ic2^Dldj^c;SK%}KN(4}@A`i}!j`l?rUI*XDN7`c%e2Ft;v zQ#ak;%||CQaqUw>8V!jQ7T85K6xqZz<}%CZ8;>45-WvaOHD#=NDJ84_P}XTQePEP3 zw)gBei9tEULSbqaupF$bHtZjrRbQgvm@iQ%Tek5$eQ2=dBhgjRdB1g(Tm3;+1AC!tlaLy2UsQWQwKw%}gm2g2zKkuwy z{oxA-8iRlM9p3)xj;Ih0jpToAp-g`dbl*4t2YkvYENR98i|Qd3Ll^n-E$l01jl22N zv?ZmHRs8)P$+9Y4bt7CCi)(jlbuZUziW`mVn;&;<*nX{e1w={jZHtESN5oRMN|4xuD z-xO^Jbs^j+WhizMJ#kB*{+2L$^b`lk$gQ6TW$L_%qHrFbwr&hrOyzygDE?M_ct1(E zmlZI8afZDF=UlhRzpN}U&*zR+Jo*N|6dDOrSqVzcE^V4?Xihff(avzBe0+&{(O8V% zGM}kF_F-u7cZM*CIoc@#S!FIdb&z|AeWV>JB$$l(*&4fNV9U^ZE#=_aHPtQ5miWo0 zv-}owj)7OOp261`-(Dg^v5CiPISY2zEh9Cg=q67qlsI-4`d4R+l4cNu;?|`;06G=o z%0|t}uA=Ph`#X(7WnPvbeOf&n5LW2=ljG>mx;OI~^!R^oWiuaXA{Wo%pbOO-$a$I2 zzh3a7U_QIRO-q$O?RtM26iK(^6r(nzz*&ybhu(NT{4gT&O1?Q9_w~Q)e+T~uOP@jy2cH=m^bXZWZei@K2%y zfB`Iy6d?Xh55nhv;Sae000j8VuQC>g!~LlQ0DSge@;}G|=lHSy^4~A~5+b}KfB77O z2MHdec#z>ijt2!Elz33#L5&A~3IH^C(BeUd2R$APcrfDe@9q8B>c6i4T`iyoxZ*#a z05_lpxZqPb;D`6#e_j{?qQ9;AzwHfwQN5Dtu`bucDbVlxg#;i4NCTF@1Hcxr2d)Cv zfEd0k4M^Zi68MrFAP(5zKYt}c00HQC+y2$>e%BM?3tD`?YyNBb|J(lmYrXx)+W(dQ zf3N$m{QrLzV8%};Fdh>BwjL5J+d31NRQ`Iw{m1F|FU|j83;dP;anra(;DQ!R69#}l z|F*H?(7+9V5DX>+6G8|HA*2u@2q`%!UdX8^ehC%L9|^_3C4UzF`TDC75Fs%!1qlTs z1qCBL6%`fzuL~9ZpVesoQ;oC%G$cSK2mpgF0t7T5FbxRT32@l#CqzgPIHYXaNQj5Q2$_2=P$>6omgCAfzFp+GBLBT@?GK=5EQy9B`qT>Cx7Fn8cbb7Q|q3-fuWJHiK(sK1AB*u zj*mP%y}W&V{rtn9L_|hCeHNXR{5&N!Ej=UiRbGC<>%uoh#c$tL*VNY4H#C0e=Fw(upP2mkX=?iO%+i--%*yK8*Y%C>d;32Q4v&5wpZwzWi|4<~pL6Y>c+uc_5fJ|J z%P(Fa0-s;RX$XmU#EEHDbs^U7bQdMUNa(L8=2o?nLM8RSG1$Pz$QXIAF7bW;MePq} z|2bla|0iaDBldS*GXMn`gm)g822ci0IeR*eh__9gormI|OB2V5v~Hxa@Z4@{p6g7~ zK#$Ue8O6nTl2~q?%Occep`6W+*CwqF78e6Qni+qp$r2ZVPVi{zCW)Y*qY!QjVh>1b z{Q8WBeId+p`@RdE3H#^BEpj5Z2gsbF<8CGtcp6h_z*gcPivv3ReD>|{-okSIkhUKy zf4(ZBpl#j6EC(Ts^H^C9L&ZNvt~uXPdip^XV{ClYp?syCo$Ds|O4WMUrp_Ig@6RPK z7ID*x`5rDV$GZqFpk*xQEPHW4>;rE{I|F&XUMr$VR0n%jf!}U-_hNR`8xGZ-^{aAI zY?nP(0g4q3-sRPvUX{M#*|kuRBE}f|xe>d8RX=<9x6G=woqWfQI?qcd-9uc8B%?B% znBx5(z1!$ZYll?HI6x^OWFa31kma4f^E&@{7XNeXZ<)aly)EbA_%BEDxsKMAKg4fw z@MD9xaX_mkmVs=;hs!2&&3+w9SS+woDH)bTtfQI)DJnO#WcvAP_96~=P`WcvpT1&X zaQuF47-pg$=WAp&JtKZAV}1sk<69cnaSGAI0XZ7VyW=4dT+{M8XD6ySAUOFmq6qpm~OYYl4}3t~uR1wck7~Ip+Fa=&f+^=pRTZS9<0g{|LvP z^Zzv9DY-9m6M`iO=}tQ}Ji_|LpJMQ4Wgom8lk;0&0@(KPkhO8@(;qoY`f+8x@-K0~ zd!3)-IN;Gdp13#;2+aAOml2WZ@t31jd~}l7h~NvoDvGuXR#lCoqBhS-i-W1Qv-GH{ zOH%1O-~g+2<^6TY`H9ZAyx*I7sH-kX4pshL^$&Kq9xaz{!h!?-V!WpGx_B3j{Ki22 zAFMI@D$bq}7V;0e-z;PpLGK~2x(90Iu7{0Mt$yK zi4hv2b{C1G*0KvQAmQV=C2FrMC!`_AUjdDO)WU9~t}n;J?XYR##lXjDO;kE>b8%)v z#aUE)kx8ftku}(&K_*5$NYXu5P_0}&tu$dB5;l1(>5s7=$8q58c0)96wljSpHE1=l!j zO@pF5+I!a$-0H3D(d!p_6~7$Gx*u^GF3T#$bvlESH2QY#T=Wf=#b`1HR6H-@9_$pq z58E~W;kpY7?_nsRMz~nl(~%!%cqAd=h3M??xNr{NE~gM{{5rV?Sy5qNGLgU2Dt70h zn+IzoU&be~yp%PO`Zeae+S()(mMjWs1{1rQ$fc;H7B?zl-gaKGHprB0d*QsVp;@gV zlZ1L0k_X^yfm2sJ_GDoG_5|T7YjJCe&*y=TTsO%gRU1tYhaiZrJm1Sg>r&GA2IEt4 zqZERkr1~`~xZ7aEmhV^9@)(ixm9y59gZT3Z{-d51^+Woc1+EmHg_E<8dwQCO@-R0a zb~`KE_uASzw*z0I5)+Y$Ht)7d`Kk$B2x& zY(EK9h{v88xz|2CkPUndikyByL3UcDpveJe&Du3-euYN`rDkD&;Q?+5apnUX^%XYH$ zeaLPxfPPh_)Ke4^hyxb%gW~nD$M`Mf4cH~R^OUpTd>;n{=^kFYb-IQy$l%9CI(Yy52j^OqzQZtf{CkB~`a@CX@lKSb6B2ttKlZ znWOck<_gWDgwV%iw?m#;9J+@i*<}=}P)H(3QCs=M-P+R!rM1WCRi4|+va{kSca+1Y z<{s5=UDy*9Qgu{ z(XKre*SB#%%z;9H=fiBG#x@c5@dyt262O;ogIMJnDZ`_IZcaP0DWALfJqjsydJum0 zqh%JQmI!yO+)oRJl_br}=tVevQD_rEQ?F3bDqVt(kYpV34H|R#GuC&g^KrJzz$qPE zyaUN&k#AM5t*R^$*~?ibPtRK+SpR;u3@f8fsrB*8HnX7US-(=F$yPwr8Q-Uc{Zp>< z!|IR^7S1?8xeC90oXn{^EF<3j4AEnqPaPwLQlzI6KgrreD1B)FfFKEv83<^xSfUfT{KgJ1LX;6|C4pybtwmXGf@nJvGinT3pOg&fU{;Q&&vx-)DK zejS#%taS#bhM=B1{E?)L^#2M7z}F^h+8JF+?RUd6-VV3eGUf+-aVnY|szNI4NUrB~ z_eMb(Hs3kRMYV2KqOB4(aDccRGZ6{+^(~Is3&6c3BYrHyq<5OU7ivP2cO#!z0|$7& zu;s~mW{v$4-nTD745lf?0n~~1`ZE0dg*)8}C$%Bm0ru4^g=c6#vA{ll=Z_~oPIoLm zy;v{%SX#b0_cN_iT!Gv!QlELoR4+eHf@H=GrX#29!_6^m8s0T81VmOpefvhvEG%*{ ziAjiRD}vd%ByxBkK|FOPoQSui94)bZkj&}{C84$Z0<2WA#RTXxhkK*4zVx&;o1fGe+U;s72TaA?r)o7N^D zC==i!y4$?=OvOw;P>d)#yb4hw-oFxE^1$E)Gkt>~4v<;w*GqHl{1ig(`x0K+rjkIQ zxSaHY^fJ|`Wb30)_1oD|+%aAE1#Bo1RPs>q%KR+L5PQk6-t{CU7b?H_pQ_a@x$n^> zDS*R~4+~qIALy;dSCwAf3HB+YS7(xu3c9>9$#1o8#a9zMux#%)2wh`BQcc2dv@UjJ zTC~!xrhK`hw`6&$W(d)f-b#>t9I8!4f0mzuA#l?cM|dj#pDa|g_shUBznXH&f@7}F z-|QIb8EASP;K05-HS@;gXS{Jje_8;vgN7~7g-Er{{ys@>dmBHCkPcgH&QBvKHn??< z3x5x7JX6=PssFy(q}*PD7Ohy{uDj2_a9n50=kH$U?m~S14@XcrdY|2)lR z9J3$B23xA5!W6B*{Q>QNqWn-JGEJFOmw6=OE-nyl8gdcjqGwF z38ZbZBW%wg1Wm=my78ZV&d6heJkM?iG-S$Da=DlpT)bc_SU->oa67k&;(&(!s^j>&h;qR;KaD@4__#iarHX}honwrDr) z?FL~aWt&~tkj0d8HQy7_bdjuv**b;8%H`0z(({<4vQf%r3|vjg(f|0+%%TPdgyuKR z&1LB<#TTXp*Baq~wiiLwRoz2xx_F-!b`B@i-o27chDp%i^Cl1v^>HKB%Q(((dL_?U z5addcuu1o0me+Wxql5w(`_dCi=(XX|Ef8Z#C#ZI+lysM_DMKBiC@}4I%es$uKV?Q^ z-gVa8H8nw+xf!yAt@Q0finS4I5a-fU>lOES2q>QS1}0L!!m2kUapX6EdIXeBK13`!*N(ing_-0Hbx$8hPE}hs0NqB8pK_ zQ0J%aPu=X#tI;ZU8?;-KrDNraHTG^iWSS|>b=-{XLV7Hr#9hma|g^-q?2`RdoiHhYL=z@~ySVjf;@ zTZ;U44AKC?Cf)8RZ*$SP;{e*Pa>F6xBg~2+1EO$cXg9TK9yIq%;7m9Nfde{YtMAy7 zojpksm5>RYW}cS4Oz*%CI)dvLJ*(kjfCybZ4JuHf64jv`*3=748J-ALZFhkK+#FYy z%v+y{7Q`+0#v4Uxi?D8MLSfG6IF4Iy5mW?kw_WHLiylwunh&=)g-ES_y^1#LZLa3D z+hW*ns4EmWz8fVx>S80NDyw4Ovi;-ogl2_FjFt8TCU;nKhLjeRI7+kL zK57WH4??t)Om*6|!);{MW7O&g6*Qm}Lw6;XB8Nk%#2s!iCEfhS@)I3hu zlbR*{-W^9hT8teE_1O0aPyNAu_WsLTftXHrlNSoQKF(h9BHj9?QM0jC-A6RfT`wby za?Kkbxc9CtN2%}If^|N6bW6Om-C-x@I{~E}$IVUm@X}2O^TA z+oDoG4EhQLb;dW1CKWc)I!Xy&EG`ZE;+FO{47Q)g!1T_Kk_ zEY*r=UE+)3U!5Ir{cwfXHWYuh@3dp5>t@W0*NtN!n}-erzQpd(YO)MiMK1Nq3h%i` zti2%$h#Xz{OxYD#Tu92AN{5V?dHD_kU70D}nhhnd>fYGo{+9JbMtuI}gm9kg%mZ)2 zMSui84N%2Y+o9I@RqY5gIIf2xFdkBL2SO0rUoM zQc+%iK|z5qjwCtudAoeG6fP8B6L-`SGpCx z41L^UJo>|LF1e2h*V`RA^k{vMMW0FC8>GIec*}xJ33RM8m z-nszqzb2$Sa@M+Znk8gd^TWK1zr1MQ*(J7)?TS~^g5L$xe6Vp=Dru^7p68%A-8Yor z2rp%e5rSQC_-xC=L_Y3Ch_|?t@28$2>XcaKt-V8LY#@^9e09r?E3HsU%bCv9mr$@+ zzV*8%=BDvC7_g*%nT^|}|IJ)%`WAtG2w+FC`N|HpJvsZW4ZNiw@xERYi3l)`cLH z6M5mSmF{^H5>29B%G1Fj3fQ0kB&Oow7l3%N!yG$yTN7}%15_v=idqQ(61NC9FTB{PTdA*(_JC`67^t78m zT0*kM1I3m3tcLk1nW851T@@=vg2CWp7WS0{t`rpoHzNQ}QQ+wM3VqdxW<9g~z}t(* zPBCw%SLi1RCRKGW4=ND>q%i(KJ5%4Cq$R4JyuNL}8bjA$>oDt7#v?XpyvL_?$Rz<8u(0AWSnvGlyt?j#Lo*yD%*9#XT zoqN>JY4!8A-}x=^kJ9xxEw=)kV&qS(|CNSPU9$ zm`h^c`8+DvUoN4&Xbes)`9i{-qoY%8GUQ#t<0^FVMtI}^fvF;f7Pu^7OyN){baFo# zDr-S~m(N(5oZ)`+cIWgk_yWYD3l2`aZI3_nNMS!Ux*=03n(|Le{nxArw~sS4KPt@+AxVaaZ+YL~> z3|UhgGpIVOSJ>ieFu}L2{!6DkFl&@+qSlVW(+}^NlHd^V%P*nwvLf5tQ%59ksFelU zl(McBn^xG`5@)!i))vz;cQg3OvW)0yZUkh$8{%OxDwE$Z3{xz4nnpDo;u{R(fkLu1 zs5;prkjM*~W=S~i62mjU%9ZPM9;V*2fHY2sx@sZ? zeW`)KPC;UgJ(yVnDN$NB3=rJ;j@<~0%inAmB>{a&f@ zeU&G#(lX`p!CX5zxy1(lI*q}RZ$2f`u|UoOI&gq_^6|a(gpi(Q<%2%u6s0#QmAY#5 z6!=8~2syd7{`~V{j-c3O8J+%yRw}9XT9k#wdBIPs0k%tBP%vUoQk>@*PZ|m+nfwtu zu~*7L#gc~zk&u1W3&xOuxY<)bC&uOY+Ie&fvw30PZ%4Vbv|5VfjM&_UltYoMvts7%T=u5z3YzV}(kzP#dr) zr6HGzuoH=&w<|KIi$K?jv?*FyN!>&GKIJAV9au(P4z>GnO^0PTD9A~WKjde~SViv# z#|8YWET=umGOsLA(zEW51u1uHZG&Fu0DFc~HuM+ZWecnPi565jCDR)bU8oqI+b-R{ zy}iRK?NF4yp{)^J$ZM&FC~QVaIy7W#lZWxT@vRWTxcOqrCeRFh;oo;IhEwTqBZw>~yv{GpGCHg6fVa`BpgoM8tqsorb^1=-ryhFXp5yE;(!6}#hu=sd0tzVA97umWr?FX z2j}ME+XgOMnHw7UCU#G6qN8&G<3 zxPmPzES$eFYB=8IOFGZnLdc3-&sbF?M>{mG#x$!)>O*OWgYPKQU91&9d@aSCCJL&c z**kJKK)U)V#s4;_81ntano-8D8A}p%CyuP1&t>H{Z0}vGk8@EG?EIPF2;B%GCVP)M zeyNXjI-N!`FXfLVvF8OJiux?-xumJ*A14oMtE(EDnH`=7o&>*K_6c4Hejg-#oa{78 z{(^bgS$TWo0a31K-op-io%s|>?E2beYGz*B8@7&)Zb|5`RPSKRPJ&MW?;VJey^=Z6 zEF5&KpWNlLv2R+Cr0L;)nP!(i@Md@dbBe-^2X0gl?u2@N6V_yB7*#KIdI+9vd>rO$=gj)*JhT9u#hsOb(-cehuPnKa&^VXqh-x(T8mb zHpc-q$vyWw!ha@CMGsEq*Ri%B;fmRgjuh^%rR`vC%{g5Wdc9)ayPmV8Ge%l4f+hNF z9oLcdT@-lKfkF7>G_m^des;)^=+W8b<_hoqwU4`bEsRy4HNLZ4XSpG8H$wk7T`_?r zgA7?ITpwE~T$PEBDsMV(kNrwR>7)iXYsK$BBC#J2ocOC)!tO^g0&=qu zS=sgDa)(YM|Ddw|nw9OYk`xuji)d}*<Qz9LKTKq z+Z`c3tXfKvI=sGIZ2>#$U&+vzZ&*|!-TM&AAWPwaXoL5N6|AOjxW8FIrZV&FQA3(d zh*TCi#k5s9B(&$VD(IUJ@B42~ez=l0QS&7&d*DFf@mS{I*v0t1)0>h*itxpv^lV@` z)Ieh-5SiUjrtMT9S)@?0{w#B7@(b;(Y2D}GvA4H(XY=~DTPale>jsjMCyVR&z?)e= z(|Ull4=!<{?1$~C@cUw5+M&6_AD1C}(ytcRKS3#=bj&6)KGWavrDqN@c4JW>^4V!qvQ zUq%1zA#CYK`6toP7MTjN7&%+baN6#hqWM;f)>@nen%w1X{`N&7T`I;nAm5aT+xAF; zogIbWUR2S{M;vlxtO9O2t@HLD@jcC4s!MsICCXy@IIs(3z&}mfNnNCDnl>Cib^K9F zs6k8QcIBFAJxh{pyX=Gq`oQSXV8yZcTmjY*XUrhO^QpORlkZsG;%aIKMt3 z6Y-D!Yq^UKQZ~`rGIUcXRoA(;7Y9~nO;cv!gc5e;zQA!h#Fc}Zn-iwy?Dq$aA~im? z5F=Vc91vdQ`itY(ueLV|7z_pe=w+h-ZLXNe=4b#l9L#;5H1M@Bws0Y*&`noeAVX>( k1B#~GejKMUtioM+W(2+VY~)d7v|xdiGVb&L%s+wsFVZpy4FCWD diff --git a/current/DD-Core/Install-WindowsService/DEFAULT/Install-WindowsService_Settings.ini b/current/DD-Core/Install-WindowsService/DEFAULT/Install-WindowsService_Settings.ini index c5748c6..ce495b4 100644 --- a/current/DD-Core/Install-WindowsService/DEFAULT/Install-WindowsService_Settings.ini +++ b/current/DD-Core/Install-WindowsService/DEFAULT/Install-WindowsService_Settings.ini @@ -120,4 +120,4 @@ LogFileKeepTime = 30 #InstallServiceProfile = Digital Data JobRunner ; D:\ProgramFiles\Digital Data\DDJobRunner\SERVICE\DigitalData.Services.JobRunner.exe ; ; Manual ; InstallOnly ; Executes defined and configured jobs to synchronize master and transaction data. #InstallServiceProfile = Digital Data Email-Service ; D:\ProgramFiles\Digital Data\DDEmailService\SERVICE\DDEmailService.exe ; ; Manual ; InstallOnly ; Sends emails from the Digital Data email pool. #InstallServiceProfile = Digital Data WM-ResultHandler ; D:\ProgramFiles\Digital Data\DDResultHandler\SERVICE\DDWDResultHandler.exe ; ; Manual ; InstallOnly ; Executes windream searches and processes the results according to profile specifications. -#InstallServiceProfile = Digital Data EDMI-Service ; ; ; Manual ; InstallOnly ; Proxy Service for Digital Data Applications. \ No newline at end of file +#InstallServiceProfile = Digital Data EDMI-Service ; D:\ProgramFiles\Digital Data\DDEDMI\SERVICE\EDMIService.exe ; ; Manual ; InstallOnly ; Proxy Service for Digital Data Applications. \ No newline at end of file diff --git a/current/DD-Internal/Remove-AzureArcSetup/Remove-AzureArcSetup.ps1 b/current/DD-Internal/Remove-AzureArcSetup/Remove-AzureArcSetup.ps1 new file mode 100644 index 0000000..afc1fc3 --- /dev/null +++ b/current/DD-Internal/Remove-AzureArcSetup/Remove-AzureArcSetup.ps1 @@ -0,0 +1,30 @@ +# Remove-AzureArcSetup +# ---------------------------------------------------------------------------- +# This Script uninstalles the Azure Arc Setup (the installed Agent!), +# if it´s installed in Windows Server 2025. +# +# Returns: - +# ---------------------------------------------------------------------------- +# Copyright (c) 2026 by Digital Data GmbH +# +# Digital Data GmbH • Ludwig-Rinn-Strasse 16 • D-35452 Heuchelheim +# Tel.: 0641/202360 • E-Mail: info-flow@digitaldata.works +# ---------------------------------------------------------------------------- +# Creation Date / Author: 09.04.2026 / MK +# Version Date / Editor: 09.04.2026 / MK +# Version Number: 1.0.0.0 + +#-----------------------------------------------------------------------------------------------------# +############################################# main part ############################################### +#-----------------------------------------------------------------------------------------------------# + +$AzureArcSetup = Get-WindowsCapability -Online -Name "AzureArcSetup~~~~" +if ($AzureArcSetup.State -eq "Installed") { + Remove-WindowsCapability -Online -Name "AzureArcSetup~~~~" +} + +#-----------------------------------------------------------------------------------------------------# +########################################### finishing part ############################################ +#-----------------------------------------------------------------------------------------------------# + +Remove-Variable -Name AzureArcSetup -Force -ErrorAction SilentlyContinue \ No newline at end of file diff --git a/current/Import-FileContentToDB/Import-FileContentToDB.ps1 b/current/Import-FileContentToDB/Import-FileContentToDB.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..1fdb3ccd57f242ef994c5293204822123664731b GIT binary patch literal 162784 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 z zvl1LbOSBSKTbGznhx)Z`{qQQ6%5CY_hBb z-?=2yS|Y9g&#&Q7I2uZh<=1lFQY;U}&@#+rR4n%wXOqol-l+_ORu&=0h;8fMon@0? zb;yR|%d_E6&JI7Z+?pm9mcr;VOR0SxzGMo+@DeM=*Rsg1q34~GSo4rtRILrSZ+V&y zWNs-_$%{8jH4pN0Uto-Dm$kxP`$mM-;$H0=R!-_pmlraY?#aycO2(RwtH?uZSNA|4 z$_VU&HkdS@&Zi#*R_)eq`_`tj>%GevT5BlD3~z?B!Y7`z8h8kQ1s-BW&dLna2>IDr zyKSNIG(LWIW>@m0&k9}UZS1o$yHpb|BVDRCh%3b3ipF^_I|6hc>#kHQaTWhmC*P0= zi|(-xcb@gtYp#*|-Z`W`?)&W7Xk*#lsqxj<;6`i?$bJuEc4SM_MT z=Q!MTrtpUrN7p@Osu9@-Mt{{@)rnDv?<^@((%I{{F{}P0>tYKXj-!s+$5T&;n%(ml znYBE7YoxRCE+_08<18Dsm$5)Y&f)5?kHVHvJ$%Sj7pwhsr87Y4&ryEy?ko4DV&JXt zHUD$9k6iD((pN^AWbJ$3FGtJ$r#@8QS*gU^mo?M#x4h<@{#DxDB;3d8J9M=V!-lLl ze$+KtBl>$jkh2nYgl-`L=WunGCWQ73Faz7!{C6dfg99jM|?0STYPe>sIyb z8?smQ-sqdm?*@x?3F(WaIj%Hn+%ZSKe zte*Tmx^A{gL^5=}c=aABDqVHtFXS3lc&l2qm5OuX9treMjA08g0wi5dcw&UOuEC$| z6w!6G)I*;HqHV!R>I+XYPJL#YBba2YyoWc*NMJY2So9l1DYic^IT!Z7ciFrCO&*in zsdlg+QI$VqZc?4vEO+1wq>OeHX_r!y!+JVa!RT{+++713v(!UEajxCuo*mM$dEap=BieNuMP575@#RB~-cYnrUb{&9r{(2ATr*_!}LOChP?p3)w=TixocwE(RIbnl6fW=;A*A?Vp6^b zFVCRoDAoXb_V6XnEqNo%WLm$(i`zuB(|wS-c^$Eiz&n9jVD#B~{? zYyX&(_pKjUJa%eP(V_2>^cLhiD~GV}Ohen;tp1dHd{*#D*?x%OwY#j7pu-qz!7vZI zmGG^N0rzWHRe1i9WFx~47JByFX2qL|^%#=wquvw=av;5=haMe1hIbBXBfFk({KT@k zOXsV2zK%7OYo29}Jw%lab(#)mA9n{aX|hsv44e;ra|Uh+H(mVgJcXC%*i7T4`|4Dl z^JBv<3%!46RhUv*NoBJJ^it1woBT*#Be)5d3<%|m@Um!{k^h$4l!LCqZ{V) z{Zb6q^OO#s%>>)|`8CsV?w)Sg%&m(@QQh8E{LYV(f0f|2t|=yiJl0lQqR)wl>iHx_ zm-YE`8oHkZ0xpKJb-F!$65guMVRCv%JJA@g&5s&>JrOmu!QF)x;xXn)2l109p@DdW zc>T3PRcmhRyybpmt{cz%*Z()k`VYf>&9iKlxJ~!QmsaJCZo`yz6J9q~jXg>Gy5W8VnmEg>sqKJhc5_&5dmE=6>rAGj>tDN|xmv0`Ai2 z27BrE?(ml~%R@k)AKPHh|JogLJdik(ork$EU8mz3yy^FCkhXE*L!le%k7GPwT|_7%E^xgzm=dWtz>>AU60aObu4!uCB#+k+=j5K2AJs?N~Vll5$8&{ovNCI zbKR*I_Pj9bV^Q(CeOih+5*4>hRQ;~duXU@W`#oTc%v?#=4a)! zZdysC^xxO6jI%$C(RTzrYf4XD`A3zNJQ7Tjmjpv$6|2_0@vBjVS8GurhX<7AV{%da zpXI7F*BjDp|2a&L1wCnnx;{N!gIUfF8@kq$tkxsR_`H;A(>ImmXV)N7%=gkYLRIkD6^X;6=G_zms@IW*65pgZRiVs5YnRD3+Amf~%Dgzy$78TY2_-r6x%l(B zJw`@{eWm5}lE!txs?=pcJH7*W`uRFDR3P7}rHEE%RSk1EMR@7fY%~$oz-mF1MCj!l_gv9Gsj= zW)Uf)ib>XOneh#5it|{uPSSNWhfy@iG#yvN44=g;d1XheTfT6g_x9?dBg4J)%Q=?je*?cghA7tno)%gH>(pa@sP9z zXur~Y*zTKIty|KGTpxG14=qrAK3dc3&-`~gH<)_CvS!t@9`OuxAB|fkFU00j&w=by z+N(r&_;9-NzUYA0at0=T6cwm`)-v_ZSgmSbb2cQA1wYYHeNLi5&t$(8HXtW9zLa}j z$(4GY*UvtcUrkrBmlYq#&c}RNtwp+4E18p?zYL(gR#*#-`s8FZPpCh|X+kUKL+`9q z-50M~xdM;1)g7jGW@i7<^EHW0G~w}{S$ zS``l!dCU5schKHYyPh=|o{`FToQ;cyqS{*}1$SW)BNxI^@%7%xb^PTrH4ZzO4!`q( zz;jEUa#NmT+^gR89|O-cw)&ti_fKM3vn`MTi^hNaIqEkPL&Hv-#t+B<J(MxL&rUwFJp`4}?Esz5^L7Q| zqlyZz3EiQ|`9=3kU`aRW{zpQk%)6~;kIgT9U9W5sw~L&&Z67~AlKSfEN2rBbS_9=X zA0?FxTcU%pQofhD;%i`qA*txF(iGj-*uMAd*pwBrJ%o5pDTJ4*=sOj| zPb+WghCsm>b-99O`gJx^?|AI1`=C>7%$!Au?}g4=9eq_%^7CqKu@*hb=lC@V{FPW+ zWQ*|>)F!QGj~w2d9?^W-Tfss%YmZ3Ip~%*k@>I3?^qV&VHCAZd_9GjB2H%m{vA33W z^O@u=V$ae{Zwr&(!I~}6E|xxiDj6(1H}_yStNUVjI!ySLw{kmtT~exM^&&sEXt$VG4&9g z{=#>Yj$F@0_Mc-3gLoBg7m`Qi%F@;8`rWQL@wBa-LOt}l#iK6Inpqr3sV}aNGiuiQ zDX*k#j>0HS_tgYV9%g@kRrwqX$2;$64MMjW=IT?s-5F+-N_=8H5qxKDx3Q5#p|)Qe z{Y&hHe~I7EUJu|hYXe~xVTOP~z)LY{@DQ)(lhb_5ZV-;x4 z3uCA*H0aOz{`4}gh=|S(_VRPK9v+3pf6H@xdBT$bX8ziLjrt$mBi}*Rj zpJJR6sZc)vp4k(g*{v*+{RZz>xvxG)jd8?J*pk%=XL?b_jbU1=y6%C2t>hQ3HZNvDXjaJS+)qNBsX!i4$OTn8!^V4>+5}>T;h~tGRbl!`Jlmy2Rz`@*VN@mOUWn<{g|v9cb^l zueq|*uH-dOIm*Q;O?}#EAII=ES0#oJp#Mxeqq}poxFudP5g+3E;b~@5(Xe?}^mMVi)G7U>*j2222C_Be3sXi!Y%x&dM{9YPA#-rlziNHeF zKrnD9oTG9GE()t;boa7)n@D`F|8_*azd09{^Q&@mH!b2`R_-c=&gF$s0C&k@#d8^lv1Q%e6KJCt<+HBvmf_nFK06xQ=12oFTIBuEi(3C+ z@{^pP+VEV5RQ#u8=*lBMk&Mhev2E}Rux-iPAa&I`bzk6QCsynQfGY_GNDu zUQ77Y%ksJ8$(ROuQlzqPMPjtcj68jM?|G;eJN}-$vP+{(6GQWRY72xoYQrZqMbM)z2n2cu6`Dqd!K2&TED&iqKRuw0F|884LALY(%Y@ z3MF7(f~|;^On!lCX0FIz6>C*8Dfv?!eJ%A}d|y+Q%Wbhr$p2c^L@u5kTfWvg8Y{tf zJmq({G{+s9`V{z#`pUefx{JPJ>8vK*VPY0Zer?9%gM#SN5qWb1ao$=wIX0r0M#Prr8g4%_1udT~gXR;Cdr=50%<) zD^DJ~Bg|jr=&4Q%+(k}{+zgVIJqGIC<#MU$+R%#QlY4LZ`T<*6d$k$(tJaB~S4rNH zJk4#vaC4UByh@TYI`e;NRhva!)eo^M*t1t9sn{rU7{B+m@`-17P3C#6q*qaU=Bh+r zo+HsZ>9AI^%UUhAVp63%w#Tk$ne&QCU9pgV`o-jlXoQ@kRmNwrViL-^F8{h(qDZWg z)T(ff(NyY>O2(3jk;Hzwb@zAQm0w>Y?^YymQ^e7g|$edRjaUb zCET}HTJw-!)BHv*3vpfz+Qf~0u{rx{(2|T%j}4!QnlFnMw)xJn?__s{F~(tQNQdU; zE>gv#YL@3$Z_ewk>%5!uBIBsU>^QjF3hT;#C>4pzQejk*x*p?$+H8*t9l9-|%ML5w z^H1$P-5&DQLa}zYPrk1#N1aC7XjZzn@nnPJqMZ49`DAxNxW}?i`E6RO*-OvUuEEx1 zCD}E3_&*i++v|7Yn6>V)XsX(&+geS!ptQzFT=tkQa(ySm&FQ8IXqtJqRdvNwaYXdsOFDgwyv=Gg~`+ zonLL1_1|c!(drwKuu9VUZd8rOY8Nri+_62uU=bfd_Z`p=f_iDH%}RBkePL3sot_u$ z06Kd}zt(yKk3{~YnWl&Vm0uC z%PZ;pV+hDhDdtw?=|@!`@&l>sAwNg|?eB_mU11_hlJ*k`p$*^94)S|a@$q&3X;_nUks1H|snHc^jT`_sq|l zMu%^URYGr(mtr9uoY)zu9=FqL^IAWahpu_a%Btpd-J6?n|7x+})>mzw)H2Uu#c`5a z=eestEDOC2183Pv&(A&PiR)rLEz(BF!{`(}Yim9K{1`_rH}FhmW3lJph@oJmmep$S z2mQ3RLs!ckiJq70+K<;eeb2@|&tXNonJ$l~oQH9?{O5Lh{^>E@_vgO8Hdzje7>4P1 z4_m97zdT#Wr{%jYHhY=pz=CsJ-JU^;_xrUQs3`nq37_BN<`=P z(`%)du;X$ywbV;@d|1|c7c87*i@iMmx;|Q@)n10vDSXzJdl`lpS1wOxXT6tTi6NQJ zis*NSL|;py{|u(JCQgeLU&2hPw^-c|ktf}n?~1AZ965VxUZyB~36EuIGA%E5vFw|z z_q?C|A=~_=RXp8x|6Q^8vG=XFrRD!qy&uNqOPEL{sLO@ZYx(E#m zgR^Y&mu6p=_KUPGN>Dmw&)VKEK@j7~WytKT{X8Tw9LsF$_l192>!QsH$lDI{iP7hA zk!q$z+x8_WXUlzV*_WOl(|mv4>ucBN;fSG_j`N_^*~IGm!ag0>O~!MR+?B&vo}>G& z_HeZn^;((yYMgG{oElp?mvyU_$zvdue9qIS*CtQ#;!-oU#?vd$?eIHt7EOq+vs=?% zU;DaVS)>JChtJn#*0y*3*)eWhO3cpcPGN{4xGs8oS*v5ZLq46(CxhM|$xH3(dL}-v zz0><~eh}HRfc0^!!`)x*m`IAvUz{GR@)5_;S*^ zb0V5yjC|6{m~@IJ3t>NQD3o)Ltse%vFAWmA zF8|EC<5|!rgWVBv-|wd9#~r!XPVm9m&+%SRC{=qaH0><@V!XEZ1doS;SGB+M{ljfe zwl}rQ{IwTR4hto@o}N58>F0j*H_iE2{hqXTV%?`)SLdy;?-r6BdOI5L^PV-|(X#-q zFLR!CdUMEDtDXl(0l!VUdg*=iZybh8Z=c}N=s8E7E2Fc?qxIQ0b7(&suf)@#)yw<7 z984<0gWZGFhuEtxH zPF3|&r7p-*;dOqsbNUV9KSCt;xADPs@EZ@_inv=JH+U(D1VFni6%Sfd( zPkAPzqoaQq&jyXC7N~Y%*_Q9IC-#bXi@l9HH}>@!x=~@Bb_{oD(t0-{|5fLuxPK~h zrOylU0?dmI=;F&qS20@zPN#};2UtV zU#&iT_D1mWT4+P9$W{3rP2sc{u5=84QzWN;CF9sw>m#+t;bT4j1bFEDc_dV*)*)QQ z2~rLR%%2knNE93s?_ePI}YVI`N8TtxMcjkR4e{TPKyFR(> zb#;4s`TiJ!>w@_WIWIWH8C+J%{HW~eerNo|+&bAR$24WVs+_Lk-|6%3zdf!_@!pn| z*Yj@hqf^Tm8{g0MRvUXyeDjhe?blm3Po4)9X+~FPQ0Lbdg2!@aHP@$o?^F#M&kw$W zztEWIO`Z*ZJrA@_-{*J-fNuKDbh6>e?Ur;k`$A&4>U-a&Xpv?9Q~#mwtbAQe)~l|; zTA}L`o%~;m4lr$be4_RHK53b82W*Nz=nXkzaS1=YtI3Nu&jbEfeEBz=#-+UbCmENW zX*=>6-`uY*U*UJ(6rRNLGtZv8ABi@`M&ZO~`<@x_ukZRy$``*JE%)DKe4!GN&Qruu z>}(~qz%@>Gty;g_3cx$q@f)&Quf#jKCjP*E@kJhpcH9w(|4`QIhJ3y)HsoZ`c}Fq&EY!iXZdK2|A-=}F(Ki81_PfDi61OkiEcfdFGT`g=rIz3QM z8U9bBwe+|-4txNQZVmrL9TBN@_SQ&e#fcp5MIs+G{%+b9JL{Qn@xJ`2Cf57#YVbk% z#J^ZKsUJiiBJ)o-PxJs)2X*a`#^KsNcRx!~bsYT~nHd%@@0km+f@xqkU8?><3F1XT zsx!q#b}Oj_W9j>4g56dQ-Gx8h_O~e5&5F{93^^=4)2j{M@b~3`{YopIL%4arJg{Fq z#jt;NYGB_MZp1H1>7dW&MbV7GPGn)yzeU0R7r{EQMm=-6ehN~T`78={^DA%39O&o# zUi^-IdEW(QyJpd_?+Coec!Q_U>!M&ci{&)J9!6RF;5xi^QFzC8@wjY%dw@AC3ide8 z7Gkse`{jVW9_Q*ZgT=yb9NPub`Zdb|`()a6QLs~w@m#o7vl?}rcKK!*V4n=@i<2`U z-tSj6cGMwJJ+UVd1LP-FZ+k&yTzw^$0q@u}FT|#Sg5Gw9d^zy`)#y)>C%9WhbBOm~ z-*9S8n-p3GyaW5^63NC+I1RAJxy?E)cll;Wy!VZSamvV!&<3Y#cY#%F7=}HEtWVUj zd@4!|y+-pE2dCCbV=*?Ld1Lq-7Sg^{02RkwEzP%!vD)-$NGk3_5uRgKoUe4GW1Y*e zc<%%EwnRXQy@!4NyTiUHY}YBpb_F!iM*Q2NV9)RCh+%8{v?$o&$FS0=JEho+hJ?JY zdJb~6|q1!7ubV$hiU>(hQD1WwBtQ*8!wLDO> z!-onFc0zUkTNK8Tj&H>`qwe-tu-F}9y>d}-6WL-@=dmc*b8^wo<86nVD;5VkJ6*}P9F1cXP|qv*V|M~J8J{c%Ow^*DAy^*R zu_SjZKSQG|?<f5N~r|vT4lwsXJ#*WiVqyG;}{2zM& literal 0 HcmV?d00001 diff --git a/current/Import-FileContentToDB/Import-FileContentToDB_History.txt b/current/Import-FileContentToDB/Import-FileContentToDB_History.txt new file mode 100644 index 0000000..84db7d9 --- /dev/null +++ b/current/Import-FileContentToDB/Import-FileContentToDB_History.txt @@ -0,0 +1,87 @@ +------------------------------------------------------------------------------- + +Version 2.2.0.1 - 21.10.2024 +NEW: - +FIX: - Fixed issues with data Seperator +CHG: - +REM: - + +------------------------------------------------------------------------------- + +Version 2.2.0.0 - 14.10.2024 +NEW: - Multiple Replace cmds in PreparingFile +FIX: - Fixed XLSX and CSV import issues +CHG: - +REM: - + +------------------------------------------------------------------------------- + +Version 2.1.0.0 - 11.10.2024 +NEW: - Parameter call (-pProfileID) +FIX: - Fixed CSV import issue, if inverted commas in data - other case +CHG: - " will be removed bevor inserting data, Code improvement +REM: - + +------------------------------------------------------------------------------- + +Version 2.0.1.0 - 10.06.2024 +NEW: - +FIX: - Fixed CSV import issue, if inverted commas in data +CHG: - +REM: - + +------------------------------------------------------------------------------- + +Version 2.0.0.2 - 07.05.2024 +NEW: - +FIX: - +CHG: - For ExcelImport Value Seperator removed +REM: - + +------------------------------------------------------------------------------- + +Version 2.0.0.1 - 20.03.2024 +NEW: - +FIX: - +CHG: - Code improvement, clean up variables +REM: - + +------------------------------------------------------------------------------- + +Version 2.0.0.0 - 18.03.2024 +NEW: - +FIX: - +CHG: - New working Version with Hash tables instead of arrays +REM: - + +------------------------------------------------------------------------------- + +Version 1.2.0.0 - 06.12.2023 +NEW: - Excel Import Methode implemented +FIX: - +CHG: - Rename - old: Import-FileContent2Database, new: Import-FileContentToDB +REM: - + +------------------------------------------------------------------------------- + +Version 1.1.0.0 - 18.04.2019 +NEW: - +FIX: - +CHG: - Rename - old: Import-CSV2DB, new: Import-FileContent2Database +REM: - + + +------------------------------------------------------------------------------- + +Version 1.0.0.0 - 15.10.2018 +NEW: - +FIX: - +CHG: - +REM: - + +-------------------------------------legend------------------------------------ +NEW: = Added a new functionality +FIX: = Fixed a Issue with existing functionality +CHG: = Changed a existing functionality +REM: = Removed a functionality +------------------------------------------------------------------------------- \ No newline at end of file diff --git a/current/MoveOrCopy-Files/MoveOrCopy-Files.ps1 b/current/MoveOrCopy-Files/MoveOrCopy-Files.ps1 new file mode 100644 index 0000000000000000000000000000000000000000..e38349a7b97bbbe58c9996487c11d211846b8b4b GIT binary patch literal 189308 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 literal 0 HcmV?d00001 diff --git a/current/MoveOrCopy-Files/MoveOrCopy-Files_History.txt b/current/MoveOrCopy-Files/MoveOrCopy-Files_History.txt new file mode 100644 index 0000000..92b25b1 --- /dev/null +++ b/current/MoveOrCopy-Files/MoveOrCopy-Files_History.txt @@ -0,0 +1,127 @@ +Version 1.5.0.0 - 21.02.2024 +NEW: - Es können nun Netzlaufwerke per "MountProfile" eingebunden werden +FIX: - +CHG: - Der aktuelle Module Loader wurde implementiert +REM: - + +----------------------------------------------------------- + +Version 1.3.3.0 - 12.12.2023 +NEW: - Man kann nun den Parameter %not% als negatives Suchkriterium verwenden +FIX: - +CHG: - +REM: - + +----------------------------------------------------------- + +Version 1.3.2.0 - 08.07.2021 +NEW: - +FIX: - Fehler beim L�schen von Logs behoben. +CHG: - +REM: - + +----------------------------------------------------------- + +Version 1.3.1.0 - 30.04.2021 +NEW: - +FIX: - Fehler in File Collector Funktion behoben. + - Fehler in Zielpfadbestimmung behoben, wenn Datei Attribute ausgelesen wurden. +CHG: - File Collector listet nun vorab nicht mehr alle Dateien auf (machte das Skript zu langsam und die Logs zu gro�). +REM: - + +----------------------------------------------------------- + +Version 1.3.0.0 - 22.04.2021 +NEW: - Neuer Parameter f�r Profile, es muss nun bestimmt werden, ob auch Unterverzeichnisse durchsucht werden (ReclusiveSwitch). + - Neuer Parameter f�r Profile, es muss nun bestimmt werden, wie eine Datei vor der Verarbeitung gepr�ft wird (filechecktyp). +FIX: - +CHG: - +REM: - + +----------------------------------------------------------- + +Version 1.2.0.0 - 20.04.2021 +NEW: - Diverse Datumsplatzhalter f�r den Zielpfad eingef�gt (z.b.: %CreationTimeYear%, ...) +FIX: - +CHG: - +REM: - + +----------------------------------------------------------- + +Version 1.1.4.0 - 15.03.2019 +NEW: - +FIX: - Schleifen Fehler bei %ProcessOnlyLastProfileFiles behoben +CHG: - +REM: - + +----------------------------------------------------------- + +Version 1.1.3.0 - 13.03.2019 +NEW: - +FIX: - +CHG: - Log Dateien entschlackt +REM: - + +----------------------------------------------------------- + +Version 1.1.2.0 - 28.02.2019 +NEW: - %date% Variable hinzugef�gt +FIX: - +CHG: - +REM: - + +----------------------------------------------------------- + +Version 1.1.1.0 - 24.02.2017 +NEW: - +FIX: - Fehler in Schleifenz�hler korrigiert. +CHG: - +REM: - + +----------------------------------------------------------- + +Version 1.1.0.1 - 01.08.2016 +NEW: - +FIX: - Variablen Bereinigung vervollst�ndigt. +CHG: - +REM: - + +----------------------------------------------------------- + +Version 1.1.0.0 - 29.07.2016 +NEW: - Neue optionale Parameter verf�gbar: %RegExGroup and %Replace. +FIX: - +CHG: - Optionale Parameter folgen nun keiner spezifischen Reihenfolge mehr. +REM: - + +----------------------------------------------------------- + + +Version 1.0.1.2 - 07.02.2016 +NEW: - Aufrufparameter nun verf�gbar. +FIX: - +CHG: - +REM: - + +----------------------------------------------------------- + +Version 1.0.1.0 - 30.09.2015 +NEW: - Funktion "Func-File-check-state" nun eingebaut. +FIX: - +CHG: - Umbennung von "Simply_copy_or_move_Files" zu "MoveOrCopyFiles". +REM: - + +----------------------------------------------------------- + +Version 1.0.0.0 - 08.12.2014 - Erste funktionierende Version! +NEW: - +FIX: - +CHG: - +REM: - + +--------------------------Legende-------------------------- +NEW: = Hinzuf�gen einer neuen Funktion +FIX: = Korrektur einer vorhandenen Funktion +CHG: = �nderung oder Erweiterung einer vorhandenen Funktion +REM: = Entfernen einer Funktion +----------------------------------------------------------- diff --git a/current/Set-FolderAttributes/Set-FolderAttributes_Caller.cmd b/current/Set-FolderAttributes/Set-FolderAttributes_Caller.cmd new file mode 100644 index 0000000..7fbce11 --- /dev/null +++ b/current/Set-FolderAttributes/Set-FolderAttributes_Caller.cmd @@ -0,0 +1,45 @@ +@ECHO OFF +TITLE DIGITAL DATA - Run all files in directory with current permissions +ECHO - +ECHO Batch Script +ECHO Run all files in directory with current permissions +ECHO - +ECHO Digital Data +ECHO Ludwig-Rinn-Strasse 16 +ECHO 35452 Heuchelheim +ECHO Tel.: 0641 / 202360 +ECHO E-Mail: info@didalog.de +ECHO - +ECHO Version 1.0.0.0 +ECHO Date: 13.08.2015 +ECHO - +ECHO Program Startup %date% at %time:~0,8% oclock, on %computername%. + +REM -------------------------------------------------------------- +REM ------------------------set variables------------------------- +REM -------------------------------------------------------------- + +setlocal enableextensions + +SET DIRECTORY="%cd%" +SET FILEEXTENSION=*.ps1 +SET COUNT=0 + +REM -------------------------------------------------------------- +REM ---------------------Program 1 / Script 1--------------------- +REM -------------------------------------------------------------- + +FOR /F "tokens=*" %%f in ('dir /S /b %FILEEXTENSION%') do (ECHO %%f && set /a count+=1) +ECHO - +ECHO Found %count% File(s) with File Extension %FILEEXTENSION% in Directory: +ECHO %DIRECTORY%. + +ECHO - +ECHO Running this/them now, with your permissions! +FOR /F "tokens=*" %%f in ('dir /S /b %FILEEXTENSION%') do (PowerShell.exe -Command "& {Start-Process PowerShell.exe -WindowStyle hidden '-ExecutionPolicy Bypass -File "%%f"'}") + +ECHO - +ECHO This Window will close in: +#timeout /T 10 +endlocal +exit \ No newline at end of file diff --git a/current/Set-FolderAttributes/Set-FolderAttributes_History.txt b/current/Set-FolderAttributes/Set-FolderAttributes_History.txt new file mode 100644 index 0000000..2c17611 --- /dev/null +++ b/current/Set-FolderAttributes/Set-FolderAttributes_History.txt @@ -0,0 +1,24 @@ + +------------------------------------------------------------------------------- + +Version 1.1.0.0 - 18.04.2019 +NEW: - +FIX: - +CHG: - +REM: - + + +------------------------------------------------------------------------------- + +Version 1.0.0.0 - 07.03.2016 +NEW: - +FIX: - +CHG: - +REM: - + +-------------------------------------legend------------------------------------ +NEW: = Added a new functionality +FIX: = Fixed a Issue with existing functionality +CHG: = Changed a existing functionality +REM: = Removed a functionality +------------------------------------------------------------------------------- \ No newline at end of file diff --git a/current/[DD_ECM]-Database/ReC/[PRREC_DELETE_OBJECT].sql b/current/[DD_ECM]-Database/ReC/[PRREC_DELETE_OBJECT].sql new file mode 100644 index 0000000..923dfaa --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[PRREC_DELETE_OBJECT].sql @@ -0,0 +1,245 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +-- [PRREC_DELETE_OBJECT] +-- ================================================================= +-- Deletes one or more data in a given Entity +-- +-- Returns: INT Value - 0 = Everything worked well +-- ================================================================= +-- Copyright (c) 2025 by Digital Data GmbH +-- +-- Digital Data GmbH • Ludwig-Rinn-Strasse 16 • D-35452 Heuchelheim +-- Tel.: 0641/202360 • E-Mail: info-flow@digitaldata.works +-- ================================================================= +-- Creation Date / Author: 22.12.2025 / MK +-- Version Date / Editor: 22.12.2025 / MK +-- Version Number: 1.0.0.0 +-- ================================================================= +-- History: +-- 22.12.2025 / MK - First Version + +CREATE OR ALTER PROCEDURE [dbo].[PRREC_DELETE_OBJECT] ( + @pENTITY NVARCHAR(25) = 'RESULT', -- Target entity: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT + @pSTART NVARCHAR(25) = '0', -- Start GUID/ID (inclusive), numeric text + @pEND NVARCHAR(25) = '0', -- End GUID/ID (inclusive), numeric text + @pFORCE BIT = 0 -- 1 = delete even if dependent data exists +) +AS +BEGIN + + SET NOCOUNT ON; + SET XACT_ABORT ON; + + -- declare new vars because of parameter sniffing + DECLARE @ENTITY NVARCHAR(25) = UPPER(LTRIM(RTRIM(ISNULL(@pENTITY, 'RESULT')))), + @START_VAL NVARCHAR(25) = LTRIM(RTRIM(ISNULL(@pSTART, '0'))), + @END_VAL NVARCHAR(25) = LTRIM(RTRIM(ISNULL(@pEND, '0'))), + @FORCE BIT = ISNULL(@pFORCE, 0); + + -- declare runtime vars + DECLARE @MY_PROCEDURE_NAME NVARCHAR(128) = OBJECT_NAME(@@PROCID); + DECLARE @START_ID BIGINT = TRY_CAST(@START_VAL AS BIGINT), + @END_ID BIGINT = TRY_CAST(@END_VAL AS BIGINT), + @END_ID_TMP BIGINT = 0, + @RETURN_STATUS INT = 0, + @RETURN_STATUS_TEXT NVARCHAR(MAX) = 'START PROCEDURE [' + @MY_PROCEDURE_NAME + '] @ ' + CONVERT(VARCHAR(50), GETDATE(), 120); + ---------------------------------------------------------------------------------------------------------------------------- + + --=================================================-- Output parameters --================================================-- + PRINT '===================================================================================================='; + PRINT @RETURN_STATUS_TEXT; + PRINT ''; + PRINT 'PARAMETER01 - @ENTITY: ' + ISNULL(CONVERT(NVARCHAR(25), @ENTITY), 'NULL'); + PRINT 'PARAMETER02 - @START: ' + ISNULL(CONVERT(NVARCHAR(25), @START_VAL), 'NULL'); + PRINT 'PARAMETER03 - @END: ' + ISNULL(CONVERT(NVARCHAR(25), @END_VAL), 'NULL'); + PRINT 'PARAMETER04 - @FORCE: ' + ISNULL(CONVERT(NVARCHAR(1), @FORCE), 'NULL'); + PRINT ''; + ----------------------------------------------------------------------------------------------------------------------------- + + --================================================-- Validation --=======================================================-- + IF (@ENTITY NOT IN ('ACTION', 'ENDPOINT', 'ENDPOINT_AUTH', 'ENDPOINT_PARAMS', 'PROFILE', 'RESULT')) BEGIN + SET @RETURN_STATUS = 50301; + SET @RETURN_STATUS_TEXT = 'ERROR: Unknown entity "' + @ENTITY + '". Allowed: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT.'; + RAISERROR(@RETURN_STATUS_TEXT,16,1); + RETURN @RETURN_STATUS; + END; + + IF (@START_ID IS NULL OR @END_ID IS NULL) BEGIN + SET @RETURN_STATUS = 50302; + SET @RETURN_STATUS_TEXT = 'ERROR: @START and @END must be convertible to BIGINT.'; + RAISERROR(@RETURN_STATUS_TEXT,16,1); + RETURN @RETURN_STATUS; + END; + + -- normalize range + IF (@END_ID = 0) BEGIN + SET @END_ID = @START_ID; + END; + + IF (@START_ID = 0) BEGIN + SET @START_ID = @END_ID; + END; + + IF (@START_ID > @END_ID) BEGIN + SET @END_ID_TMP = @START_ID; + SET @START_ID = @END_ID; + SET @END_ID = @END_ID_TMP; + END; + + PRINT 'INFO: Normalized deletion range from ' + CONVERT(NVARCHAR(25), @START_ID) + ' to ' + CONVERT(NVARCHAR(25), @END_ID); + ----------------------------------------------------------------------------------------------------------------------------- + + --===============================================-- Main Processing --===================================================-- + BEGIN TRY + + BEGIN TRANSACTION; + + -- Delete selected entities respecting dependencies + IF (@ENTITY = 'ACTION' AND @RETURN_STATUS = 0) BEGIN + PRINT 'INFO: Deleting ACTION records...'; + + IF (@FORCE = 0 AND EXISTS (SELECT 1 FROM [dbo].[TBREC_OUT_RESULT] WHERE [ACTION_ID] BETWEEN @START_ID AND @END_ID)) BEGIN + SET @RETURN_STATUS = 50303; + SET @RETURN_STATUS_TEXT = 'ERROR: Dependent results exist for ACTION. Set @pFORCE=1 to delete anyway.'; + RAISERROR(@RETURN_STATUS_TEXT,16,1); + RETURN @RETURN_STATUS; + END; ELSE BEGIN + DELETE FROM [dbo].[TBREC_OUT_RESULT] WHERE [ACTION_ID] BETWEEN @START_ID AND @END_ID; + DELETE FROM [dbo].[TBREC_CFG_ACTION] WHERE [GUID] BETWEEN @START_ID AND @END_ID; + SET @RETURN_STATUS_TEXT = 'INFO: ACTION and related RESULT records deleted.'; + PRINT @RETURN_STATUS_TEXT; + END; + END; + ELSE IF (@ENTITY = 'ENDPOINT' AND @RETURN_STATUS = 0) BEGIN + PRINT 'INFO: Deleting ENDPOINT records...'; + + IF (@FORCE = 0 AND EXISTS (SELECT 1 FROM [dbo].[TBREC_CFG_ACTION] WHERE [ENDPOINT_ID] BETWEEN @START_ID AND @END_ID)) BEGIN + SET @RETURN_STATUS = 50304; + SET @RETURN_STATUS_TEXT = 'ERROR: ENDPOINT is used by ACTION. Set @pFORCE=1 to delete anyway.'; + RAISERROR(@RETURN_STATUS_TEXT,16,1); + RETURN @RETURN_STATUS; + END; ELSE BEGIN + DECLARE @ActionIdsForEndpoint TABLE (GUID BIGINT PRIMARY KEY); + INSERT INTO @ActionIdsForEndpoint(GUID) + SELECT [GUID] FROM [dbo].[TBREC_CFG_ACTION] WHERE [ENDPOINT_ID] BETWEEN @START_ID AND @END_ID; + + DELETE FROM [dbo].[TBREC_OUT_RESULT] WHERE [ACTION_ID] IN (SELECT GUID FROM @ActionIdsForEndpoint); + DELETE FROM [dbo].[TBREC_CFG_ACTION] WHERE [GUID] IN (SELECT GUID FROM @ActionIdsForEndpoint); + DELETE FROM [dbo].[TBREC_CFG_ENDPOINT] WHERE [GUID] BETWEEN @START_ID AND @END_ID; + + SET @RETURN_STATUS_TEXT = 'INFO: ENDPOINT, related ACTION and RESULT records deleted.'; + PRINT @RETURN_STATUS_TEXT; + END; + END; + ELSE IF (@ENTITY = 'ENDPOINT_AUTH' AND @RETURN_STATUS = 0) BEGIN + PRINT 'INFO: Deleting ENDPOINT_AUTH records...'; + + IF (@FORCE = 0 AND EXISTS (SELECT 1 FROM [dbo].[TBREC_CFG_ACTION] WHERE [ENDPOINT_AUTH_ID] BETWEEN @START_ID AND @END_ID)) BEGIN + SET @RETURN_STATUS = 50305; + SET @RETURN_STATUS_TEXT = 'ERROR: ENDPOINT_AUTH is used by ACTION. Set @pFORCE=1 to delete anyway.'; + RAISERROR(@RETURN_STATUS_TEXT,16,1); + RETURN @RETURN_STATUS; + END; ELSE BEGIN + DECLARE @ActionIdsForAuth TABLE (GUID BIGINT PRIMARY KEY); + INSERT INTO @ActionIdsForAuth(GUID) + SELECT [GUID] FROM [dbo].[TBREC_CFG_ACTION] WHERE [ENDPOINT_AUTH_ID] BETWEEN @START_ID AND @END_ID; + + DELETE FROM [dbo].[TBREC_OUT_RESULT] WHERE [ACTION_ID] IN (SELECT GUID FROM @ActionIdsForAuth); + DELETE FROM [dbo].[TBREC_CFG_ACTION] WHERE [GUID] IN (SELECT GUID FROM @ActionIdsForAuth); + DELETE FROM [dbo].[TBREC_CFG_ENDPOINT_AUTH] WHERE [GUID] BETWEEN @START_ID AND @END_ID; + + SET @RETURN_STATUS_TEXT = 'INFO: ENDPOINT_AUTH, related ACTION and RESULT records deleted.'; + PRINT @RETURN_STATUS_TEXT; + END; + END; + ELSE IF (@ENTITY = 'ENDPOINT_PARAMS' AND @RETURN_STATUS = 0) BEGIN + PRINT 'INFO: Deleting ENDPOINT_PARAMS records...'; + + IF (@FORCE = 0 AND EXISTS (SELECT 1 FROM [dbo].[TBREC_CFG_ACTION] WHERE [ENDPOINT_PARAMS_ID] BETWEEN @START_ID AND @END_ID)) BEGIN + SET @RETURN_STATUS = 50306; + SET @RETURN_STATUS_TEXT = 'ERROR: ENDPOINT_PARAMS is used by ACTION. Set @pFORCE=1 to delete anyway.'; + RAISERROR(@RETURN_STATUS_TEXT,16,1); + RETURN @RETURN_STATUS; + END; ELSE BEGIN + DECLARE @ActionIdsForParams TABLE (GUID BIGINT PRIMARY KEY); + INSERT INTO @ActionIdsForParams(GUID) + SELECT [GUID] FROM [dbo].[TBREC_CFG_ACTION] WHERE [ENDPOINT_PARAMS_ID] BETWEEN @START_ID AND @END_ID; + + DELETE FROM [dbo].[TBREC_OUT_RESULT] WHERE [ACTION_ID] IN (SELECT GUID FROM @ActionIdsForParams); + DELETE FROM [dbo].[TBREC_CFG_ACTION] WHERE [GUID] IN (SELECT GUID FROM @ActionIdsForParams); + DELETE FROM [dbo].[TBREC_CFG_ENDPOINT_PARAMS] WHERE [GUID] BETWEEN @START_ID AND @END_ID; + + SET @RETURN_STATUS_TEXT = 'INFO: ENDPOINT_PARAMS, related ACTION and RESULT records deleted.'; + PRINT @RETURN_STATUS_TEXT; + END; + END; + ELSE IF (@ENTITY = 'PROFILE' AND @RETURN_STATUS = 0) BEGIN + PRINT 'INFO: Deleting PROFILE records...'; + + IF (@FORCE = 0 AND EXISTS (SELECT 1 FROM [dbo].[TBREC_CFG_ACTION] WHERE [PROFILE_ID] BETWEEN @START_ID AND @END_ID)) BEGIN + SET @RETURN_STATUS = 50307; + SET @RETURN_STATUS_TEXT = 'ERROR: PROFILE is used by ACTION. Set @pFORCE=1 to delete anyway.'; + RAISERROR(@RETURN_STATUS_TEXT,16,1); + RETURN @RETURN_STATUS; + END; ELSE BEGIN + DECLARE @ActionIdsForProfile TABLE (GUID BIGINT PRIMARY KEY); + INSERT INTO @ActionIdsForProfile(GUID) + SELECT [GUID] FROM [dbo].[TBREC_CFG_ACTION] WHERE [PROFILE_ID] BETWEEN @START_ID AND @END_ID; + + DELETE FROM [dbo].[TBREC_OUT_RESULT] WHERE [ACTION_ID] IN (SELECT GUID FROM @ActionIdsForProfile); + DELETE FROM [dbo].[TBREC_CFG_ACTION] WHERE [GUID] IN (SELECT GUID FROM @ActionIdsForProfile); + DELETE FROM [dbo].[TBREC_RUN_PROFILE] WHERE [PROFILE_ID] BETWEEN @START_ID AND @END_ID; + DELETE FROM [dbo].[TBREC_CFG_PROFILE] WHERE [GUID] BETWEEN @START_ID AND @END_ID; + + SET @RETURN_STATUS_TEXT = 'INFO: PROFILE, related ACTION, RESULT and RUN records deleted.'; + PRINT @RETURN_STATUS_TEXT; + END; + END; + ELSE IF (@ENTITY = 'RESULT' AND @RETURN_STATUS = 0) BEGIN + PRINT 'INFO: Deleting RESULT records...'; + DELETE FROM [dbo].[TBREC_OUT_RESULT] WHERE [GUID] BETWEEN @START_ID AND @END_ID; + SET @RETURN_STATUS_TEXT = 'INFO: RESULT records deleted.'; + PRINT @RETURN_STATUS_TEXT; + END; + + IF (@RETURN_STATUS > 0) BEGIN + IF (XACT_STATE() <> 0) ROLLBACK TRANSACTION; + END; ELSE BEGIN + COMMIT TRANSACTION; + END; + + --======================================================-- Output result --======================================================-- + SET @RETURN_STATUS_TEXT = 'END PROCEDURE [' + @MY_PROCEDURE_NAME + '] @ ' + CONVERT(VARCHAR(50), GETDATE(), 120); + + PRINT ''; + PRINT @RETURN_STATUS_TEXT; + PRINT '===================================================================================================='; + ----------------------------------------------------------------------------------------------------------------------------------- + + RETURN @RETURN_STATUS; + + END TRY BEGIN CATCH + + IF (XACT_STATE() <> 0) ROLLBACK TRANSACTION; + + --======================================================-- Output result --======================================================-- + SET @RETURN_STATUS_TEXT = 'ERROR: ' + ERROR_MESSAGE(); + RAISERROR(@RETURN_STATUS_TEXT,16,1); + + SET @RETURN_STATUS_TEXT = 'END PROCEDURE [' + @MY_PROCEDURE_NAME + '] @ ' + CONVERT(VARCHAR(50), GETDATE(), 120); + + PRINT ''; + PRINT @RETURN_STATUS_TEXT; + PRINT '===================================================================================================='; + ----------------------------------------------------------------------------------------------------------------------------------- + + RETURN @RETURN_STATUS; + + END CATCH; + ----------------------------------------------------------------------------------------------------------------------------- + +END; +GO \ No newline at end of file diff --git a/current/[DD_ECM]-Database/ReC/[PRREC_INSERT_OBJECT].sql b/current/[DD_ECM]-Database/ReC/[PRREC_INSERT_OBJECT].sql new file mode 100644 index 0000000..b748725 --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[PRREC_INSERT_OBJECT].sql @@ -0,0 +1,460 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +-- [PRREC_INSERT_OBJECT] +-- ================================================================= +-- Inserts one record into a given Entity +-- +-- Returns: INT Value - 0 = Everything worked well +-- BIGINT - Output parameter @oGUID returns the inserted GUID +-- ================================================================= +-- Copyright (c) 2025 by Digital Data GmbH +-- +-- Digital Data GmbH • Ludwig-Rinn-Strasse 16 • D-35452 Heuchelheim +-- Tel.: 0641/202360 • E-Mail: info-flow@digitaldata.works +-- ================================================================= +-- Creation Date / Author: 22.12.2025 / MK +-- Version Date / Editor: 22.12.2025 / MK +-- Version Number: 1.0.0.0 +-- ================================================================= +-- History: +-- 22.12.2025 / MK - First Version + +CREATE OR ALTER PROCEDURE [dbo].[PRREC_INSERT_OBJECT] ( + @pENTITY NVARCHAR(25) = 'ACTION', -- Target entity: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT + @pADDED_WHO NVARCHAR(50) = NULL, -- User or function of the Insert + @pADDED_WHEN DATETIME = NULL, -- Datetime of the Insert + @pACTION_PROFILE_ID BIGINT = NULL, -- ACTION: Profile GUID (required) + @pACTION_ACTIVE BIT = 1, -- ACTION: Active flag + @pACTION_SEQUENCE TINYINT = 0, -- ACTION: Sequence/order + @pACTION_ENDPOINT_ID BIGINT = NULL, -- ACTION: Endpoint GUID (required) + @pACTION_ENDPOINT_AUTH_ID BIGINT = NULL, -- ACTION: Endpoint auth GUID + @pACTION_ENDPOINT_PARAMS_ID SMALLINT = NULL, -- ACTION: Endpoint params group GUID + @pACTION_SQL_CONNECTION_ID SMALLINT = NULL, -- ACTION: SQL connection GUID + @pACTION_TYPE_ID TINYINT = 1, -- ACTION: HTTP method id (0..9) + @pACTION_PRE_SQL NVARCHAR(MAX) = NULL, -- ACTION: SQL to run before request + @pACTION_HEADER_SQL NVARCHAR(MAX) = NULL, -- ACTION: SQL to build headers + @pACTION_BODY_SQL NVARCHAR(MAX) = NULL, -- ACTION: SQL to build body + @pACTION_POST_SQL NVARCHAR(MAX) = NULL, -- ACTION: SQL to run after request + @pACTION_ERROR_ACTION_ID TINYINT = 0, -- ACTION: Error behavior (0=STOP,1=CONTINUE) + @pENDPOINT_ACTIVE BIT = 1, -- ENDPOINT: Active flag + @pENDPOINT_DESCRIPTION NVARCHAR(250) = NULL, -- ENDPOINT: Description + @pENDPOINT_URI NVARCHAR(2000) = NULL, -- ENDPOINT: Target URI (required) + @pENDPOINT_AUTH_ACTIVE BIT = 1, -- ENDPOINT_AUTH: Active flag + @pENDPOINT_AUTH_DESCRIPTION NVARCHAR(250) = NULL, -- ENDPOINT_AUTH: Description + @pENDPOINT_AUTH_TYPE_ID TINYINT = 0, -- ENDPOINT_AUTH_ID: Auth type id (0..9) + @pENDPOINT_AUTH_API_KEY NVARCHAR(150) = NULL, -- ENDPOINT_AUTH: API key name/header + @pENDPOINT_AUTH_API_VALUE NVARCHAR(150) = NULL, -- ENDPOINT_AUTH: API key value + @pENDPOINT_AUTH_API_KEY_ADD_TO_ID BIT = NULL, -- ENDPOINT_AUTH: API key placement (0=HEADER,1=QUERY) + @pENDPOINT_AUTH_TOKEN NVARCHAR(150) = NULL, -- ENDPOINT_AUTH: Bearer/JWT token + @pENDPOINT_AUTH_USERNAME NVARCHAR(100) = NULL, -- ENDPOINT_AUTH: Username + @pENDPOINT_AUTH_PASSWORD NVARCHAR(100) = NULL, -- ENDPOINT_AUTH: Password + @pENDPOINT_AUTH_DOMAIN NVARCHAR(50) = NULL, -- ENDPOINT_AUTH: Domain (NTLM) + @pENDPOINT_AUTH_WORKSTATION NVARCHAR(50) = NULL, -- ENDPOINT_AUTH: Workstation (NTLM) + @pPROFILE_ACTIVE BIT = 1, -- PROFILE: Active flag + @pPROFILE_TYPE_ID TINYINT = 1, -- PROFILE: Protocol type id (1=HTTP,2=HTTPS) + @pPROFILE_MANDANTOR NVARCHAR(50) = 'DEFAULT', -- PROFILE: Tenant/mandator + @pPROFILE_NAME NVARCHAR(50) = NULL, -- PROFILE: Profile name (required) + @pPROFILE_DESCRIPTION NVARCHAR(250) = NULL, -- PROFILE: Description + @pPROFILE_LOG_LEVEL_ID TINYINT = 4, -- PROFILE: Log level id (0..6) + @pPROFILE_LANGUAGE_ID SMALLINT = 1031, -- PROFILE: Language id (1031/1033) + @pRESULT_ACTION_ID BIGINT = NULL, -- RESULT: Action GUID (required) + @pRESULT_STATUS_ID SMALLINT = NULL, -- RESULT: HTTP status code (required) + @pRESULT_TYPE_ID TINYINT = NULL, -- RESULT: 1 = Pre; 2 = Main; 3 = Post + @pRESULT_HEADER NVARCHAR(MAX) = NULL, -- RESULT: Response header + @pRESULT_BODY NVARCHAR(MAX) = NULL, -- RESULT: Response body + @pRESULT_INFO NVARCHAR(MAX) = NULL, -- RESULT: Optional Response info text + @pRESULT_ERROR NVARCHAR(MAX) = NULL, -- RESULT: Optional Response error text + @pENDPOINT_PARAMS_ACTIVE BIT = 1, -- ENDPOINT_PARAMS: Active flag + @pENDPOINT_PARAMS_DESCRIPTION NVARCHAR(250) = NULL, -- ENDPOINT_PARAMS: Description + @pENDPOINT_PARAMS_GROUP_ID SMALLINT = NULL, -- ENDPOINT_PARAMS: Parameter group id (required) + @pENDPOINT_PARAMS_SEQUENCE TINYINT = NULL, -- ENDPOINT_PARAMS: Sequence/order + @pENDPOINT_PARAMS_KEY NVARCHAR(150) = NULL, -- ENDPOINT_PARAMS: Parameter key/name + @pENDPOINT_PARAMS_VALUE NVARCHAR(150) = NULL, -- ENDPOINT_PARAMS: Parameter value + @oGUID BIGINT = NULL OUTPUT -- Output: inserted GUID +) +AS +BEGIN + + SET NOCOUNT ON; + SET XACT_ABORT ON; + + -- declare new vars because of parameter sniffing + DECLARE @ENTITY NVARCHAR(25) = UPPER(LTRIM(RTRIM(ISNULL(@pENTITY, 'ACTION')))), + @ADDED_WHO NVARCHAR(50) = ISNULL(@pADDED_WHO, OBJECT_NAME(@@PROCID)), + @ADDED_WHEN DATETIME = ISNULL(@pADDED_WHEN,GetDate()), + @ACTION_PROFILE_ID BIGINT = @pACTION_PROFILE_ID, + @ACTION_ACTIVE BIT = @pACTION_ACTIVE, + @ACTION_SEQUENCE TINYINT = @pACTION_SEQUENCE, + @ACTION_ENDPOINT_ID BIGINT = @pACTION_ENDPOINT_ID, + @ACTION_ENDPOINT_AUTH_ID BIGINT = @pACTION_ENDPOINT_AUTH_ID, + @ACTION_ENDPOINT_PARAMS_ID SMALLINT = @pACTION_ENDPOINT_PARAMS_ID, + @ACTION_SQL_CONNECTION_ID SMALLINT = @pACTION_SQL_CONNECTION_ID, + @ACTION_TYPE_ID TINYINT = @pACTION_TYPE_ID, + @ACTION_PRE_SQL NVARCHAR(MAX) = @pACTION_PRE_SQL, + @ACTION_HEADER_SQL NVARCHAR(MAX) = @pACTION_HEADER_SQL, + @ACTION_BODY_SQL NVARCHAR(MAX) = @pACTION_BODY_SQL, + @ACTION_POST_SQL NVARCHAR(MAX) = @pACTION_POST_SQL, + @ACTION_ERROR_ACTION_ID TINYINT = @pACTION_ERROR_ACTION_ID, + @ENDPOINT_ACTIVE BIT = @pENDPOINT_ACTIVE, + @ENDPOINT_DESCRIPTION NVARCHAR(250) = @pENDPOINT_DESCRIPTION, + @ENDPOINT_URI NVARCHAR(2000) = @pENDPOINT_URI, + @ENDPOINT_AUTH_ACTIVE BIT = @pENDPOINT_AUTH_ACTIVE, + @ENDPOINT_AUTH_DESCRIPTION NVARCHAR(250) = @pENDPOINT_AUTH_DESCRIPTION, + @ENDPOINT_AUTH_TYPE_ID TINYINT = @pENDPOINT_AUTH_TYPE_ID, + @ENDPOINT_AUTH_API_KEY NVARCHAR(150) = @pENDPOINT_AUTH_API_KEY, + @ENDPOINT_AUTH_API_VALUE NVARCHAR(150) = @pENDPOINT_AUTH_API_VALUE, + @ENDPOINT_AUTH_API_KEY_ADD_TO_ID BIT = @pENDPOINT_AUTH_API_KEY_ADD_TO_ID, + @ENDPOINT_AUTH_TOKEN NVARCHAR(150) = @pENDPOINT_AUTH_TOKEN, + @ENDPOINT_AUTH_USERNAME NVARCHAR(100) = @pENDPOINT_AUTH_USERNAME, + @ENDPOINT_AUTH_PASSWORD NVARCHAR(100) = @pENDPOINT_AUTH_PASSWORD, + @ENDPOINT_AUTH_DOMAIN NVARCHAR(50) = @pENDPOINT_AUTH_DOMAIN, + @ENDPOINT_AUTH_WORKSTATION NVARCHAR(50) = @pENDPOINT_AUTH_WORKSTATION, + @PROFILE_ACTIVE BIT = @pPROFILE_ACTIVE, + @PROFILE_TYPE_ID TINYINT = @pPROFILE_TYPE_ID, + @PROFILE_MANDANTOR NVARCHAR(50) = @pPROFILE_MANDANTOR, + @PROFILE_NAME NVARCHAR(50) = @pPROFILE_NAME, + @PROFILE_DESCRIPTION NVARCHAR(250) = @pPROFILE_DESCRIPTION, + @PROFILE_LOG_LEVEL_ID TINYINT = @pPROFILE_LOG_LEVEL_ID, + @PROFILE_LANGUAGE_ID SMALLINT = @pPROFILE_LANGUAGE_ID, + @RESULT_ACTION_ID BIGINT = @pRESULT_ACTION_ID, + @RESULT_STATUS_ID SMALLINT = @pRESULT_STATUS_ID, + @RESULT_TYPE_ID TINYINT = @pRESULT_TYPE_ID, + @RESULT_HEADER NVARCHAR(MAX) = @pRESULT_HEADER, + @RESULT_BODY NVARCHAR(MAX) = @pRESULT_BODY, + @RESULT_INFO NVARCHAR(MAX) = @pRESULT_INFO, + @RESULT_ERROR NVARCHAR(MAX) = @pRESULT_ERROR, + @ENDPOINT_PARAMS_ACTIVE BIT = @pENDPOINT_PARAMS_ACTIVE, + @ENDPOINT_PARAMS_DESCRIPTION NVARCHAR(250) = @pENDPOINT_PARAMS_DESCRIPTION, + @ENDPOINT_PARAMS_GROUP_ID SMALLINT = @pENDPOINT_PARAMS_GROUP_ID, + @ENDPOINT_PARAMS_SEQUENCE TINYINT = @pENDPOINT_PARAMS_SEQUENCE, + @ENDPOINT_PARAMS_KEY NVARCHAR(150) = @pENDPOINT_PARAMS_KEY, + @ENDPOINT_PARAMS_VALUE NVARCHAR(150) = @pENDPOINT_PARAMS_VALUE; + + -- declare runtime vars + DECLARE @MY_PROCEDURE_NAME NVARCHAR(128) = OBJECT_NAME(@@PROCID); + DECLARE @RETURN_STATUS INT = 0, + @RETURN_STATUS_TEXT NVARCHAR(MAX) = 'START PROCEDURE [' + @MY_PROCEDURE_NAME + '] @ ' + CONVERT(VARCHAR(50), GETDATE(), 120); + ---------------------------------------------------------------------------------------------------------------------------- + + --=================================================-- Output parameters --================================================-- + PRINT '===================================================================================================='; + PRINT @RETURN_STATUS_TEXT; + PRINT ''; + PRINT 'PARAMETER01 - @ENTITY: ' + ISNULL(CONVERT(NVARCHAR(25), @ENTITY), 'NULL'); + PRINT 'PARAMETER02 - @ADDED_WHO: ' + ISNULL(CONVERT(NVARCHAR(50), @ADDED_WHO), 'NULL'); + PRINT 'PARAMETER03 - @ADDED_WHEN: ' + ISNULL(CONVERT(NVARCHAR(30), @ADDED_WHEN), 'NULL'); + PRINT 'PARAMETER04 - @ACTION_PROFILE_ID: ' + ISNULL(CONVERT(NVARCHAR(30), @ACTION_PROFILE_ID), 'NULL'); + PRINT 'PARAMETER05 - @ACTION_ACTIVE: ' + ISNULL(CONVERT(NVARCHAR(1), @ACTION_ACTIVE), 'NULL'); + PRINT 'PARAMETER06 - @ACTION_SEQUENCE: ' + ISNULL(CONVERT(NVARCHAR(3), @ACTION_SEQUENCE), 'NULL'); + PRINT 'PARAMETER07 - @ACTION_ENDPOINT_ID: ' + ISNULL(CONVERT(NVARCHAR(30), @ACTION_ENDPOINT_ID), 'NULL'); + PRINT 'PARAMETER08 - @ACTION_ENDPOINT_AUTH_ID: ' + ISNULL(CONVERT(NVARCHAR(30), @ACTION_ENDPOINT_AUTH_ID), 'NULL'); + PRINT 'PARAMETER09 - @ACTION_ENDPOINT_PARAMS_ID: ' + ISNULL(CONVERT(NVARCHAR(30), @ACTION_ENDPOINT_PARAMS_ID), 'NULL'); + PRINT 'PARAMETER10 - @ACTION_SQL_CONNECTION_ID: ' + ISNULL(CONVERT(NVARCHAR(30), @ACTION_SQL_CONNECTION_ID), 'NULL'); + PRINT 'PARAMETER11 - @ACTION_TYPE_ID: ' + ISNULL(CONVERT(NVARCHAR(5), @ACTION_TYPE_ID), 'NULL'); + PRINT 'PARAMETER12 - @ACTION_PRE_SQL: ' + ISNULL(CONVERT(NVARCHAR(100), @ACTION_PRE_SQL), 'NULL'); + PRINT 'PARAMETER13 - @ACTION_HEADER_SQL: ' + ISNULL(CONVERT(NVARCHAR(100), @ACTION_HEADER_SQL), 'NULL'); + PRINT 'PARAMETER14 - @ACTION_BODY_SQL: ' + ISNULL(CONVERT(NVARCHAR(100), @ACTION_BODY_SQL), 'NULL'); + PRINT 'PARAMETER15 - @ACTION_POST_SQL: ' + ISNULL(CONVERT(NVARCHAR(100), @ACTION_POST_SQL), 'NULL'); + PRINT 'PARAMETER16 - @ACTION_ERROR_ACTION_ID: ' + ISNULL(CONVERT(NVARCHAR(5), @ACTION_ERROR_ACTION_ID), 'NULL'); + PRINT 'PARAMETER17 - @ENDPOINT_ACTIVE: ' + ISNULL(CONVERT(NVARCHAR(1), @ENDPOINT_ACTIVE), 'NULL'); + PRINT 'PARAMETER18 - @ENDPOINT_DESCRIPTION: ' + ISNULL(CONVERT(NVARCHAR(250), @ENDPOINT_DESCRIPTION), 'NULL'); + PRINT 'PARAMETER19 - @ENDPOINT_URI: ' + ISNULL(CONVERT(NVARCHAR(2000), @ENDPOINT_URI), 'NULL'); + PRINT 'PARAMETER20 - @ENDPOINT_AUTH_ACTIVE: ' + ISNULL(CONVERT(NVARCHAR(1), @ENDPOINT_AUTH_ACTIVE), 'NULL'); + PRINT 'PARAMETER21 - @ENDPOINT_AUTH_DESCRIPTION: ' + ISNULL(CONVERT(NVARCHAR(250), @ENDPOINT_AUTH_DESCRIPTION), 'NULL'); + PRINT 'PARAMETER22 - @ENDPOINT_AUTH_TYPE_ID: ' + ISNULL(CONVERT(NVARCHAR(5), @ENDPOINT_AUTH_TYPE_ID), 'NULL'); + PRINT 'PARAMETER23 - @ENDPOINT_AUTH_API_KEY: ' + ISNULL(CONVERT(NVARCHAR(150), @ENDPOINT_AUTH_API_KEY), 'NULL'); + PRINT 'PARAMETER24 - @ENDPOINT_AUTH_API_VALUE: ' + ISNULL(CONVERT(NVARCHAR(150), @ENDPOINT_AUTH_API_VALUE), 'NULL'); + PRINT 'PARAMETER25 - @ENDPOINT_AUTH_API_KEY_ADD_TO_ID: ' + ISNULL(CONVERT(NVARCHAR(1), @ENDPOINT_AUTH_API_KEY_ADD_TO_ID), 'NULL'); + PRINT 'PARAMETER26 - @ENDPOINT_AUTH_TOKEN: ' + ISNULL(CONVERT(NVARCHAR(150), @ENDPOINT_AUTH_TOKEN), 'NULL'); + PRINT 'PARAMETER27 - @ENDPOINT_AUTH_USERNAME: ' + ISNULL(CONVERT(NVARCHAR(100), @ENDPOINT_AUTH_USERNAME), 'NULL'); + PRINT 'PARAMETER28 - @ENDPOINT_AUTH_PASSWORD: ' + ISNULL(CONVERT(NVARCHAR(100), @ENDPOINT_AUTH_PASSWORD), 'NULL'); + PRINT 'PARAMETER29 - @ENDPOINT_AUTH_DOMAIN: ' + ISNULL(CONVERT(NVARCHAR(50), @ENDPOINT_AUTH_DOMAIN), 'NULL'); + PRINT 'PARAMETER30 - @ENDPOINT_AUTH_WORKSTATION: ' + ISNULL(CONVERT(NVARCHAR(50), @ENDPOINT_AUTH_WORKSTATION), 'NULL'); + PRINT 'PARAMETER31 - @PROFILE_ACTIVE: ' + ISNULL(CONVERT(NVARCHAR(1), @PROFILE_ACTIVE), 'NULL'); + PRINT 'PARAMETER32 - @PROFILE_TYPE_ID: ' + ISNULL(CONVERT(NVARCHAR(5), @PROFILE_TYPE_ID), 'NULL'); + PRINT 'PARAMETER33 - @PROFILE_MANDANTOR: ' + ISNULL(CONVERT(NVARCHAR(50), @PROFILE_MANDANTOR), 'NULL'); + PRINT 'PARAMETER34 - @PROFILE_NAME: ' + ISNULL(CONVERT(NVARCHAR(50), @PROFILE_NAME), 'NULL'); + PRINT 'PARAMETER35 - @PROFILE_DESCRIPTION: ' + ISNULL(CONVERT(NVARCHAR(250), @PROFILE_DESCRIPTION), 'NULL'); + PRINT 'PARAMETER36 - @PROFILE_LOG_LEVEL_ID: ' + ISNULL(CONVERT(NVARCHAR(5), @PROFILE_LOG_LEVEL_ID), 'NULL'); + PRINT 'PARAMETER37 - @PROFILE_LANGUAGE_ID: ' + ISNULL(CONVERT(NVARCHAR(10), @PROFILE_LANGUAGE_ID), 'NULL'); + PRINT 'PARAMETER38 - @RESULT_ACTION_ID: ' + ISNULL(CONVERT(NVARCHAR(30), @RESULT_ACTION_ID), 'NULL'); + PRINT 'PARAMETER39 - @RESULT_STATUS_ID: ' + ISNULL(CONVERT(NVARCHAR(10), @RESULT_STATUS_ID), 'NULL'); + PRINT 'PARAMETER40 - @RESULT_TYPE_ID: ' + ISNULL(CONVERT(NVARCHAR(1), @RESULT_TYPE_ID), 'NULL'); + PRINT 'PARAMETER41 - @RESULT_HEADER: ' + ISNULL(CONVERT(NVARCHAR(100), @RESULT_HEADER), 'NULL'); + PRINT 'PARAMETER42 - @RESULT_BODY: ' + ISNULL(CONVERT(NVARCHAR(100), @RESULT_BODY), 'NULL'); + PRINT 'PARAMETER43 - @RESULT_INFO: ' + ISNULL(CONVERT(NVARCHAR(100), @RESULT_INFO), 'NULL'); + PRINT 'PARAMETER44 - @RESULT_ERROR: ' + ISNULL(CONVERT(NVARCHAR(100), @RESULT_ERROR), 'NULL'); + PRINT 'PARAMETER45 - @ENDPOINT_PARAMS_ACTIVE: ' + ISNULL(CONVERT(NVARCHAR(1), @ENDPOINT_PARAMS_ACTIVE), 'NULL'); + PRINT 'PARAMETER46 - @ENDPOINT_PARAMS_DESCRIPTION: ' + ISNULL(CONVERT(NVARCHAR(250), @ENDPOINT_PARAMS_DESCRIPTION), 'NULL'); + PRINT 'PARAMETER47 - @ENDPOINT_PARAMS_GROUP_ID: ' + ISNULL(CONVERT(NVARCHAR(10), @ENDPOINT_PARAMS_GROUP_ID), 'NULL'); + PRINT 'PARAMETER48 - @ENDPOINT_PARAMS_SEQUENCE: ' + ISNULL(CONVERT(NVARCHAR(5), @ENDPOINT_PARAMS_SEQUENCE), 'NULL'); + PRINT 'PARAMETER49 - @ENDPOINT_PARAMS_KEY: ' + ISNULL(CONVERT(NVARCHAR(150), @ENDPOINT_PARAMS_KEY), 'NULL'); + PRINT 'PARAMETER50 - @ENDPOINT_PARAMS_VALUE: ' + ISNULL(CONVERT(NVARCHAR(150), @ENDPOINT_PARAMS_VALUE), 'NULL'); + PRINT 'PARAMETER51 - @oGUID (OUT): ' + ISNULL(CONVERT(NVARCHAR(30), @oGUID), 'NULL'); + PRINT ''; + ----------------------------------------------------------------------------------------------------------------------------- + + --================================================-- Validation --=======================================================-- + IF (@ENTITY NOT IN ('ACTION', 'ENDPOINT', 'ENDPOINT_AUTH', 'ENDPOINT_PARAMS', 'PROFILE', 'RESULT')) BEGIN + SET @RETURN_STATUS = 50101; + SET @RETURN_STATUS_TEXT = 'ERROR: Unknown entity "' + @ENTITY + '". Allowed: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT.'; + RAISERROR(@RETURN_STATUS_TEXT,16,1); + RETURN @RETURN_STATUS; + END; + ----------------------------------------------------------------------------------------------------------------------------- + + --===============================================-- Main Processing --===================================================-- + BEGIN TRY + + BEGIN TRANSACTION; + + IF (@ENTITY = 'ACTION') BEGIN + + IF (@ACTION_PROFILE_ID IS NULL OR @ACTION_ENDPOINT_ID IS NULL) BEGIN + SET @RETURN_STATUS = 50102; + SET @RETURN_STATUS_TEXT = 'ERROR: ACTION requires @pACTION_PROFILE_ID and @pACTION_ENDPOINT_ID.'; + END; ELSE BEGIN + INSERT INTO [dbo].[TBREC_CFG_ACTION] ( + [PROFILE_ID], + [ACTIVE], + [SEQUENCE], + [ENDPOINT_ID], + [ENDPOINT_AUTH_ID], + [ENDPOINT_PARAMS_ID], + [SQL_CONNECTION_ID], + [TYPE_ID], + [PREPROCESSING_QUERY], + [HEADER_QUERY], + [BODY_QUERY], + [POSTPROCESSING_QUERY], + [ERROR_ACTION_ID], + [ADDED_WHO], + [ADDED_WHEN] + ) VALUES ( + @ACTION_PROFILE_ID, + ISNULL(@ACTION_ACTIVE,1), + ISNULL(@ACTION_SEQUENCE,0), + @ACTION_ENDPOINT_ID, + @ACTION_ENDPOINT_AUTH_ID, + @ACTION_ENDPOINT_PARAMS_ID, + @ACTION_SQL_CONNECTION_ID, + ISNULL(@ACTION_TYPE_ID,1), + @ACTION_PRE_SQL, + @ACTION_HEADER_SQL, + @ACTION_BODY_SQL, + @ACTION_POST_SQL, + ISNULL(@ACTION_ERROR_ACTION_ID,0), + @ADDED_WHO, + @ADDED_WHEN + ); + + SET @oGUID = SCOPE_IDENTITY(); + SET @RETURN_STATUS_TEXT = 'INFO: Inserted ACTION with GUID=' + CONVERT(NVARCHAR(30), @oGUID); + PRINT @RETURN_STATUS_TEXT; + END; + + END; ELSE IF (@ENTITY = 'ENDPOINT') BEGIN + + IF (@ENDPOINT_URI IS NULL) BEGIN + SET @RETURN_STATUS = 50103; + SET @RETURN_STATUS_TEXT = 'ERROR: ENDPOINT requires @pENDPOINT_URI.'; + END; ELSE BEGIN + INSERT INTO [dbo].[TBREC_CFG_ENDPOINT] ( + [ACTIVE], + [DESCRIPTION], + [URI], + [ADDED_WHO], + [ADDED_WHEN] + ) VALUES ( + ISNULL(@ENDPOINT_ACTIVE,1), + @ENDPOINT_DESCRIPTION, + @ENDPOINT_URI, + @ADDED_WHO, + @ADDED_WHEN + ); + + SET @oGUID = SCOPE_IDENTITY(); + SET @RETURN_STATUS_TEXT = 'INFO: Inserted ENDPOINT with GUID=' + CONVERT(NVARCHAR(30), @oGUID); + PRINT @RETURN_STATUS_TEXT; + END; + + END; ELSE IF (@ENTITY = 'ENDPOINT_AUTH') BEGIN + + INSERT INTO [dbo].[TBREC_CFG_ENDPOINT_AUTH] ( + [ACTIVE], + [DESCRIPTION], + [TYPE_ID], + [API_KEY], + [API_VALUE], + [API_KEY_ADD_TO_ID], + [TOKEN], + [USERNAME], + [PASSWORD], + [DOMAIN], + [WORKSTATION], + [ADDED_WHO], + [ADDED_WHEN] + ) VALUES ( + ISNULL(@ENDPOINT_AUTH_ACTIVE,1), + @ENDPOINT_AUTH_DESCRIPTION, + ISNULL(@ENDPOINT_AUTH_TYPE_ID,0), + @ENDPOINT_AUTH_API_KEY, + @ENDPOINT_AUTH_API_VALUE, + @ENDPOINT_AUTH_API_KEY_ADD_TO_ID, + @ENDPOINT_AUTH_TOKEN, + @ENDPOINT_AUTH_USERNAME, + @ENDPOINT_AUTH_PASSWORD, + @ENDPOINT_AUTH_DOMAIN, + @ENDPOINT_AUTH_WORKSTATION, + @ADDED_WHO, + @ADDED_WHEN + ); + + SET @oGUID = SCOPE_IDENTITY(); + SET @RETURN_STATUS_TEXT = 'INFO: Inserted ENDPOINT_AUTH with GUID=' + CONVERT(NVARCHAR(30), @oGUID); + PRINT @RETURN_STATUS_TEXT; + + END; ELSE IF (@ENTITY = 'PROFILE') BEGIN + + IF (@PROFILE_NAME IS NULL) BEGIN + SET @RETURN_STATUS = 50104; + SET @RETURN_STATUS_TEXT = 'ERROR: PROFILE requires @pPROFILE_NAME.'; + END; ELSE BEGIN + INSERT INTO [dbo].[TBREC_CFG_PROFILE] ( + [ACTIVE], + [TYPE_ID], + [MANDANTOR], + [PROFILE_NAME], + [DESCRIPTION], + [LOG_LEVEL_ID], + [LANGUAGE_ID], + [ADDED_WHO], + [ADDED_WHEN] + ) VALUES ( + ISNULL(@PROFILE_ACTIVE,1), + ISNULL(@PROFILE_TYPE_ID,1), + ISNULL(@PROFILE_MANDANTOR,'DEFAULT'), + @PROFILE_NAME, + @PROFILE_DESCRIPTION, + ISNULL(@PROFILE_LOG_LEVEL_ID,4), + ISNULL(@PROFILE_LANGUAGE_ID,1031), + @ADDED_WHO, + @ADDED_WHEN + ); + + SET @oGUID = SCOPE_IDENTITY(); + IF NOT EXISTS (SELECT 1 FROM [dbo].[TBREC_RUN_PROFILE] WHERE [PROFILE_ID] = @oGUID) BEGIN + INSERT INTO [dbo].[TBREC_RUN_PROFILE] ([PROFILE_ID]) + VALUES (@oGUID); + END; + + SET @RETURN_STATUS_TEXT = 'INFO: Inserted PROFILE with GUID=' + CONVERT(NVARCHAR(30), @oGUID); + PRINT @RETURN_STATUS_TEXT; + END; + + END; ELSE IF (@ENTITY = 'RESULT') BEGIN + + IF (@RESULT_ACTION_ID IS NULL OR @RESULT_STATUS_ID IS NULL OR @RESULT_TYPE_ID IS NULL) BEGIN + SET @RETURN_STATUS = 50105; + SET @RETURN_STATUS_TEXT = 'ERROR: RESULT requires @pRESULT_ACTION_ID, @pRESULT_STATUS_ID and @pRESULT_TYPE_ID.'; + END; ELSE BEGIN + INSERT INTO [dbo].[TBREC_OUT_RESULT] ( + [ACTION_ID], + [STATUS_ID], + [RESULT_TYPE_ID], + [RESULT_HEADER], + [RESULT_BODY], + [RESULT_INFO], + [RESULT_ERROR], + [ADDED_WHO], + [ADDED_WHEN] + ) VALUES ( + @RESULT_ACTION_ID, + @RESULT_STATUS_ID, + @RESULT_TYPE_ID, + @RESULT_HEADER, + @RESULT_BODY, + @RESULT_INFO, + @RESULT_ERROR, + @ADDED_WHO, + @ADDED_WHEN + ); + + SET @oGUID = SCOPE_IDENTITY(); + SET @RETURN_STATUS_TEXT = 'INFO: Inserted RESULT with GUID=' + CONVERT(NVARCHAR(30), @oGUID); + PRINT @RETURN_STATUS_TEXT; + END; + + END; ELSE IF (@ENTITY = 'ENDPOINT_PARAMS') BEGIN + + IF (@ENDPOINT_PARAMS_GROUP_ID IS NULL) BEGIN + SET @RETURN_STATUS = 50106; + SET @RETURN_STATUS_TEXT = 'ERROR: ENDPOINT_PARAMS requires @pENDPOINT_PARAMS_GROUP_ID.'; + END; ELSE BEGIN + INSERT INTO [dbo].[TBREC_CFG_ENDPOINT_PARAMS] ( + [ACTIVE], + [DESCRIPTION], + [GROUP_ID], + [SEQUENCE], + [KEY], + [VALUE], + [ADDED_WHO], + [ADDED_WHEN] + ) VALUES ( + ISNULL(@ENDPOINT_PARAMS_ACTIVE,1), + @ENDPOINT_PARAMS_DESCRIPTION, + @ENDPOINT_PARAMS_GROUP_ID, + @ENDPOINT_PARAMS_SEQUENCE, + @ENDPOINT_PARAMS_KEY, + @ENDPOINT_PARAMS_VALUE, + @ADDED_WHO, + @ADDED_WHEN + ); + + SET @oGUID = SCOPE_IDENTITY(); + SET @RETURN_STATUS_TEXT = 'INFO: Inserted ENDPOINT_PARAMS with GUID=' + CONVERT(NVARCHAR(30), @oGUID); + PRINT @RETURN_STATUS_TEXT; + END; + + END; + + IF (@RETURN_STATUS > 0) BEGIN + IF (XACT_STATE() <> 0) ROLLBACK TRANSACTION; + END; ELSE BEGIN + COMMIT TRANSACTION; + END; + + --======================================================-- Output result --======================================================-- + SET @RETURN_STATUS_TEXT = 'END PROCEDURE [' + @MY_PROCEDURE_NAME + '] @ ' + CONVERT(VARCHAR(50), GETDATE(), 120); + + PRINT ''; + PRINT @RETURN_STATUS_TEXT; + PRINT '===================================================================================================='; + ----------------------------------------------------------------------------------------------------------------------------------- + + RETURN @RETURN_STATUS; + + END TRY BEGIN CATCH + + IF (XACT_STATE() <> 0) ROLLBACK TRANSACTION; + + --======================================================-- Output result --======================================================-- + SET @RETURN_STATUS_TEXT = 'ERROR: ' + ERROR_MESSAGE(); + RAISERROR(@RETURN_STATUS_TEXT,16,1); + + SET @RETURN_STATUS_TEXT = 'END PROCEDURE [' + @MY_PROCEDURE_NAME + '] @ ' + CONVERT(VARCHAR(50), GETDATE(), 120); + + PRINT ''; + PRINT @RETURN_STATUS_TEXT; + PRINT '===================================================================================================='; + ----------------------------------------------------------------------------------------------------------------------------------- + + RETURN @RETURN_STATUS; + + END CATCH; + ----------------------------------------------------------------------------------------------------------------------------- + +END; diff --git a/current/[DD_ECM]-Database/ReC/[PRREC_UPDATE_OBJECT].sql b/current/[DD_ECM]-Database/ReC/[PRREC_UPDATE_OBJECT].sql new file mode 100644 index 0000000..12ab882 --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[PRREC_UPDATE_OBJECT].sql @@ -0,0 +1,453 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +-- [PRREC_UPDATE_OBJECT] +-- ================================================================= +-- Updates one record in a given Entity with validation of allowed values +-- Setting a parameter with NULL = keeps the current value +-- +-- Returns: INT Value - 0 = Everything worked well +-- ================================================================= +-- Copyright (c) 2025 by Digital Data GmbH +-- +-- Digital Data GmbH • Ludwig-Rinn-Strasse 16 • D-35452 Heuchelheim +-- Tel.: 0641/202360 • E-Mail: info-flow@digitaldata.works +-- ================================================================= +-- Creation Date / Author: 22.12.2025 / MK +-- Version Date / Editor: 22.12.2025 / MK +-- Version Number: 1.0.0.0 +-- ================================================================= +-- History: +-- 22.12.2025 / MK - First Version + +CREATE OR ALTER PROCEDURE [dbo].[PRREC_UPDATE_OBJECT] ( + @pENTITY NVARCHAR(25) = 'ACTION', -- Target entity: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT + @pGUID BIGINT = NULL, -- Target GUID to update (required) + @pCHANGED_WHO NVARCHAR(50) = NULL, -- User or function of the Update + @pCHANGED_WHEN DATETIME = NULL, -- Datetime of the Update + @pACTION_PROFILE_ID BIGINT = NULL, -- ACTION: New profile GUID + @pACTION_ACTIVE BIT = NULL, -- ACTION: New active flag + @pACTION_SEQUENCE TINYINT = NULL, -- ACTION: New sequence/order + @pACTION_ENDPOINT_ID BIGINT = NULL, -- ACTION: New endpoint GUID + @pACTION_ENDPOINT_AUTH_ID BIGINT = NULL, -- ACTION: New endpoint auth GUID + @pACTION_ENDPOINT_PARAMS_ID SMALLINT = NULL, -- ACTION: New endpoint params group GUID + @pACTION_SQL_CONNECTION_ID SMALLINT = NULL, -- ACTION: New SQL connection GUID + @pACTION_TYPE_ID TINYINT = NULL, -- ACTION: New HTTP method id (0..9) + @pACTION_PRE_SQL NVARCHAR(MAX) = NULL, -- ACTION: New SQL before request + @pACTION_HEADER_SQL NVARCHAR(MAX) = NULL, -- ACTION: New SQL for headers + @pACTION_BODY_SQL NVARCHAR(MAX) = NULL, -- ACTION: New SQL for body + @pACTION_POST_SQL NVARCHAR(MAX) = NULL, -- ACTION: New SQL after request + @pACTION_ERROR_ACTION_ID TINYINT = NULL, -- ACTION: New error behavior (0=STOP,1=CONTINUE) + @pENDPOINT_ACTIVE BIT = NULL, -- ENDPOINT: New active flag + @pENDPOINT_DESCRIPTION NVARCHAR(250) = NULL, -- ENDPOINT: New description + @pENDPOINT_URI NVARCHAR(2000) = NULL, -- ENDPOINT: New target URI + @pENDPOINT_AUTH_ACTIVE BIT = NULL, -- ENDPOINT_AUTH: New active flag + @pENDPOINT_AUTH_DESCRIPTION NVARCHAR(250) = NULL, -- ENDPOINT_AUTH: New description + @pENDPOINT_AUTH_TYPE_ID TINYINT = NULL, -- ENDPOINT_AUTH: New auth type id (0..9) + @pENDPOINT_AUTH_API_KEY NVARCHAR(150) = NULL, -- ENDPOINT_AUTH: New API key name/header + @pENDPOINT_AUTH_API_VALUE NVARCHAR(150) = NULL, -- ENDPOINT_AUTH: New API key value + @pENDPOINT_AUTH_API_KEY_ADD_TO_ID BIT = NULL, -- ENDPOINT_AUTH: New API key placement (0=HEADER,1=QUERY) + @pENDPOINT_AUTH_TOKEN NVARCHAR(150) = NULL, -- ENDPOINT_AUTH: New bearer/JWT token + @pENDPOINT_AUTH_USERNAME NVARCHAR(100) = NULL, -- ENDPOINT_AUTH: New username + @pENDPOINT_AUTH_PASSWORD NVARCHAR(100) = NULL, -- ENDPOINT_AUTH: New password + @pENDPOINT_AUTH_DOMAIN NVARCHAR(50) = NULL, -- ENDPOINT_AUTH: New domain (NTLM) + @pENDPOINT_AUTH_WORKSTATION NVARCHAR(50) = NULL, -- ENDPOINT_AUTH: New workstation (NTLM) + @pENDPOINT_PARAMS_ACTIVE BIT = NULL, -- ENDPOINT_PARAMS: New active flag + @pENDPOINT_PARAMS_DESCRIPTION NVARCHAR(250) = NULL, -- ENDPOINT_PARAMS: New description + @pENDPOINT_PARAMS_GROUP_ID SMALLINT = NULL, -- ENDPOINT_PARAMS: New parameter group id + @pENDPOINT_PARAMS_SEQUENCE TINYINT = NULL, -- ENDPOINT_PARAMS: New sequence/order + @pENDPOINT_PARAMS_KEY NVARCHAR(150) = NULL, -- ENDPOINT_PARAMS: New parameter key/name + @pENDPOINT_PARAMS_VALUE NVARCHAR(150) = NULL, -- ENDPOINT_PARAMS: New parameter value + @pPROFILE_ACTIVE BIT = NULL, -- PROFILE: New active flag + @pPROFILE_TYPE_ID TINYINT = NULL, -- PROFILE: New protocol type id (1=HTTP,2=HTTPS) + @pPROFILE_MANDANTOR NVARCHAR(50) = NULL, -- PROFILE: New tenant/mandator + @pPROFILE_NAME NVARCHAR(50) = NULL, -- PROFILE: New profile name + @pPROFILE_DESCRIPTION NVARCHAR(250) = NULL, -- PROFILE: New description + @pPROFILE_LOG_LEVEL_ID TINYINT = NULL, -- PROFILE: New log level id (0..6) + @pPROFILE_LANGUAGE_ID SMALLINT = NULL, -- PROFILE: New language id (1031/1033) + @pPROFILE_FIRST_RUN DATETIME = NULL, -- PROFILE: New first run timestamp (RUN_PROFILE) + @pPROFILE_LAST_RUN DATETIME = NULL, -- PROFILE: New last run timestamp (RUN_PROFILE) + @pPROFILE_LAST_RESULT NVARCHAR(250) = NULL, -- PROFILE: New last result text (RUN_PROFILE) + @pRESULT_ACTION_ID BIGINT = NULL, -- RESULT: New action GUID + @pRESULT_STATUS_ID SMALLINT = NULL, -- RESULT: New HTTP status code + @pRESULT_TYPE_ID TINYINT = NULL, -- RESULT: 1 = Pre; 2 = Main; 3 = Post + @pRESULT_HEADER NVARCHAR(MAX) = NULL, -- RESULT: New response header + @pRESULT_BODY NVARCHAR(MAX) = NULL, -- RESULT: New response body + @pRESULT_INFO NVARCHAR(MAX) = NULL, -- RESULT: Optional Response info text + @pRESULT_ERROR NVARCHAR(MAX) = NULL -- RESULT: Optional Response error text +) +AS +BEGIN + + SET NOCOUNT ON; + SET XACT_ABORT ON; + + -- declare new vars because of parameter sniffing + DECLARE @ENTITY NVARCHAR(25) = UPPER(LTRIM(RTRIM(ISNULL(@pENTITY, 'ACTION')))), + @GUID BIGINT = @pGUID, + @CHANGED_WHO NVARCHAR(50) = ISNULL(@pCHANGED_WHO, OBJECT_NAME(@@PROCID)), + @CHANGED_WHEN DATETIME = ISNULL(@pCHANGED_WHEN,GetDate()), + @ACTION_PROFILE_ID BIGINT = @pACTION_PROFILE_ID, + @ACTION_ACTIVE BIT = @pACTION_ACTIVE, + @ACTION_SEQUENCE TINYINT = @pACTION_SEQUENCE, + @ACTION_ENDPOINT_ID BIGINT = @pACTION_ENDPOINT_ID, + @ACTION_ENDPOINT_AUTH_ID BIGINT = @pACTION_ENDPOINT_AUTH_ID, + @ACTION_ENDPOINT_PARAMS_ID SMALLINT = @pACTION_ENDPOINT_PARAMS_ID, + @ACTION_SQL_CONNECTION_ID SMALLINT = @pACTION_SQL_CONNECTION_ID, + @ACTION_TYPE_ID TINYINT = @pACTION_TYPE_ID, + @ACTION_PRE_SQL NVARCHAR(MAX) = @pACTION_PRE_SQL, + @ACTION_HEADER_SQL NVARCHAR(MAX) = @pACTION_HEADER_SQL, + @ACTION_BODY_SQL NVARCHAR(MAX) = @pACTION_BODY_SQL, + @ACTION_POST_SQL NVARCHAR(MAX) = @pACTION_POST_SQL, + @ACTION_ERROR_ACTION_ID TINYINT = @pACTION_ERROR_ACTION_ID, + @ENDPOINT_ACTIVE BIT = @pENDPOINT_ACTIVE, + @ENDPOINT_DESCRIPTION NVARCHAR(250) = @pENDPOINT_DESCRIPTION, + @ENDPOINT_URI NVARCHAR(2000) = @pENDPOINT_URI, + @ENDPOINT_AUTH_ACTIVE BIT = @pENDPOINT_AUTH_ACTIVE, + @ENDPOINT_AUTH_DESCRIPTION NVARCHAR(250) = @pENDPOINT_AUTH_DESCRIPTION, + @ENDPOINT_AUTH_TYPE_ID TINYINT = @pENDPOINT_AUTH_TYPE_ID, + @ENDPOINT_AUTH_API_KEY NVARCHAR(150) = @pENDPOINT_AUTH_API_KEY, + @ENDPOINT_AUTH_API_VALUE NVARCHAR(150) = @pENDPOINT_AUTH_API_VALUE, + @ENDPOINT_AUTH_API_KEY_ADD_TO_ID BIT = @pENDPOINT_AUTH_API_KEY_ADD_TO_ID, + @ENDPOINT_AUTH_TOKEN NVARCHAR(150) = @pENDPOINT_AUTH_TOKEN, + @ENDPOINT_AUTH_USERNAME NVARCHAR(100) = @pENDPOINT_AUTH_USERNAME, + @ENDPOINT_AUTH_PASSWORD NVARCHAR(100) = @pENDPOINT_AUTH_PASSWORD, + @ENDPOINT_AUTH_DOMAIN NVARCHAR(50) = @pENDPOINT_AUTH_DOMAIN, + @ENDPOINT_AUTH_WORKSTATION NVARCHAR(50) = @pENDPOINT_AUTH_WORKSTATION, + @ENDPOINT_PARAMS_ACTIVE BIT = @pENDPOINT_PARAMS_ACTIVE, + @ENDPOINT_PARAMS_DESCRIPTION NVARCHAR(250) = @pENDPOINT_PARAMS_DESCRIPTION, + @ENDPOINT_PARAMS_GROUP_ID SMALLINT = @pENDPOINT_PARAMS_GROUP_ID, + @ENDPOINT_PARAMS_SEQUENCE TINYINT = @pENDPOINT_PARAMS_SEQUENCE, + @ENDPOINT_PARAMS_KEY NVARCHAR(150) = @pENDPOINT_PARAMS_KEY, + @ENDPOINT_PARAMS_VALUE NVARCHAR(150) = @pENDPOINT_PARAMS_VALUE, + @PROFILE_ACTIVE BIT = @pPROFILE_ACTIVE, + @PROFILE_TYPE_ID TINYINT = @pPROFILE_TYPE_ID, + @PROFILE_MANDANTOR NVARCHAR(50) = @pPROFILE_MANDANTOR, + @PROFILE_NAME NVARCHAR(50) = @pPROFILE_NAME, + @PROFILE_DESCRIPTION NVARCHAR(250) = @pPROFILE_DESCRIPTION, + @PROFILE_LOG_LEVEL_ID TINYINT = @pPROFILE_LOG_LEVEL_ID, + @PROFILE_LANGUAGE_ID SMALLINT = @pPROFILE_LANGUAGE_ID, + @PROFILE_FIRST_RUN DATETIME = @pPROFILE_FIRST_RUN, + @PROFILE_LAST_RUN DATETIME = @pPROFILE_LAST_RUN, + @PROFILE_LAST_RESULT NVARCHAR(250) = @pPROFILE_LAST_RESULT, + @RESULT_ACTION_ID BIGINT = @pRESULT_ACTION_ID, + @RESULT_STATUS_ID SMALLINT = @pRESULT_STATUS_ID, + @RESULT_TYPE_ID TINYINT = @pRESULT_TYPE_ID, + @RESULT_HEADER NVARCHAR(MAX) = @pRESULT_HEADER, + @RESULT_BODY NVARCHAR(MAX) = @pRESULT_BODY, + @RESULT_INFO NVARCHAR(MAX) = @pRESULT_INFO, + @RESULT_ERROR NVARCHAR(MAX) = @pRESULT_ERROR; + + -- declare runtime vars + DECLARE @MY_PROCEDURE_NAME NVARCHAR(128) = OBJECT_NAME(@@PROCID); + DECLARE @RETURN_STATUS INT = 0, + @RETURN_STATUS_TEXT NVARCHAR(MAX) = 'START PROCEDURE [' + @MY_PROCEDURE_NAME + '] @ ' + CONVERT(VARCHAR(50), GETDATE(), 120); + ---------------------------------------------------------------------------------------------------------------------------- + + --=================================================-- Output parameters --================================================-- + PRINT '===================================================================================================='; + PRINT @RETURN_STATUS_TEXT; + PRINT ''; + PRINT 'PARAMETER01 - @ENTITY: ' + ISNULL(CONVERT(NVARCHAR(25), @ENTITY), 'NULL'); + PRINT 'PARAMETER02 - @GUID: ' + ISNULL(CONVERT(NVARCHAR(30), @GUID), 'NULL'); + PRINT 'PARAMETER03 - @CHANGED_WHO: ' + ISNULL(CONVERT(NVARCHAR(50), @CHANGED_WHO), 'NULL'); + PRINT 'PARAMETER04 - @CHANGED_WHEN: ' + ISNULL(CONVERT(NVARCHAR(50), @CHANGED_WHEN), 'NULL'); + PRINT 'PARAMETER05 - @ACTION_PROFILE_ID: ' + ISNULL(CONVERT(NVARCHAR(30), @ACTION_PROFILE_ID), 'NULL'); + PRINT 'PARAMETER06 - @ACTION_ACTIVE: ' + ISNULL(CONVERT(NVARCHAR(1), @ACTION_ACTIVE), 'NULL'); + PRINT 'PARAMETER07 - @ACTION_SEQUENCE: ' + ISNULL(CONVERT(NVARCHAR(3), @ACTION_SEQUENCE), 'NULL'); + PRINT 'PARAMETER08 - @ACTION_ENDPOINT_ID: ' + ISNULL(CONVERT(NVARCHAR(30), @ACTION_ENDPOINT_ID), 'NULL'); + PRINT 'PARAMETER09 - @ACTION_ENDPOINT_AUTH_ID: ' + ISNULL(CONVERT(NVARCHAR(30), @ACTION_ENDPOINT_AUTH_ID), 'NULL'); + PRINT 'PARAMETER10 - @ACTION_ENDPOINT_PARAMS_ID: ' + ISNULL(CONVERT(NVARCHAR(30), @ACTION_ENDPOINT_PARAMS_ID), 'NULL'); + PRINT 'PARAMETER11 - @ACTION_SQL_CONNECTION_ID: ' + ISNULL(CONVERT(NVARCHAR(30), @ACTION_SQL_CONNECTION_ID), 'NULL'); + PRINT 'PARAMETER12 - @ACTION_TYPE_ID: ' + ISNULL(CONVERT(NVARCHAR(5), @ACTION_TYPE_ID), 'NULL'); + PRINT 'PARAMETER13 - @ACTION_PRE_SQL: ' + ISNULL(CONVERT(NVARCHAR(4000), @ACTION_PRE_SQL), 'NULL'); + PRINT 'PARAMETER14 - @ACTION_HEADER_SQL: ' + ISNULL(CONVERT(NVARCHAR(4000), @ACTION_HEADER_SQL), 'NULL'); + PRINT 'PARAMETER15 - @ACTION_BODY_SQL: ' + ISNULL(CONVERT(NVARCHAR(4000), @ACTION_BODY_SQL), 'NULL'); + PRINT 'PARAMETER16 - @ACTION_POST_SQL: ' + ISNULL(CONVERT(NVARCHAR(4000), @ACTION_POST_SQL), 'NULL'); + PRINT 'PARAMETER17 - @ACTION_ERROR_ACTION_ID: ' + ISNULL(CONVERT(NVARCHAR(5), @ACTION_ERROR_ACTION_ID), 'NULL'); + PRINT 'PARAMETER18 - @ENDPOINT_ACTIVE: ' + ISNULL(CONVERT(NVARCHAR(1), @ENDPOINT_ACTIVE), 'NULL'); + PRINT 'PARAMETER19 - @ENDPOINT_DESCRIPTION: ' + ISNULL(CONVERT(NVARCHAR(250), @ENDPOINT_DESCRIPTION), 'NULL'); + PRINT 'PARAMETER20 - @ENDPOINT_URI: ' + ISNULL(CONVERT(NVARCHAR(2000), @ENDPOINT_URI), 'NULL'); + PRINT 'PARAMETER21 - @ENDPOINT_AUTH_ACTIVE: ' + ISNULL(CONVERT(NVARCHAR(1), @ENDPOINT_AUTH_ACTIVE), 'NULL'); + PRINT 'PARAMETER22 - @ENDPOINT_AUTH_DESCRIPTION: ' + ISNULL(CONVERT(NVARCHAR(250), @ENDPOINT_AUTH_DESCRIPTION), 'NULL'); + PRINT 'PARAMETER23 - @ENDPOINT_AUTH_TYPE_ID: ' + ISNULL(CONVERT(NVARCHAR(5), @ENDPOINT_AUTH_TYPE_ID), 'NULL'); + PRINT 'PARAMETER24 - @ENDPOINT_AUTH_API_KEY: ' + ISNULL(CONVERT(NVARCHAR(150), @ENDPOINT_AUTH_API_KEY), 'NULL'); + PRINT 'PARAMETER25 - @ENDPOINT_AUTH_API_VALUE: ' + ISNULL(CONVERT(NVARCHAR(150), @ENDPOINT_AUTH_API_VALUE), 'NULL'); + PRINT 'PARAMETER26 - @ENDPOINT_AUTH_API_KEY_ADD_TO_ID: ' + ISNULL(CONVERT(NVARCHAR(1), @ENDPOINT_AUTH_API_KEY_ADD_TO_ID), 'NULL'); + PRINT 'PARAMETER27 - @ENDPOINT_AUTH_TOKEN: ' + ISNULL(CONVERT(NVARCHAR(150), @ENDPOINT_AUTH_TOKEN), 'NULL'); + PRINT 'PARAMETER28 - @ENDPOINT_AUTH_USERNAME: ' + ISNULL(CONVERT(NVARCHAR(100), @ENDPOINT_AUTH_USERNAME), 'NULL'); + PRINT 'PARAMETER29 - @ENDPOINT_AUTH_PASSWORD: ' + ISNULL(CONVERT(NVARCHAR(100), @ENDPOINT_AUTH_PASSWORD), 'NULL'); + PRINT 'PARAMETER30 - @ENDPOINT_AUTH_DOMAIN: ' + ISNULL(CONVERT(NVARCHAR(50), @ENDPOINT_AUTH_DOMAIN), 'NULL'); + PRINT 'PARAMETER31 - @ENDPOINT_AUTH_WORKSTATION: ' + ISNULL(CONVERT(NVARCHAR(50), @ENDPOINT_AUTH_WORKSTATION), 'NULL'); + PRINT 'PARAMETER32 - @ENDPOINT_PARAMS_ACTIVE: ' + ISNULL(CONVERT(NVARCHAR(1), @ENDPOINT_PARAMS_ACTIVE), 'NULL'); + PRINT 'PARAMETER33 - @ENDPOINT_PARAMS_DESCRIPTION: ' + ISNULL(CONVERT(NVARCHAR(250), @ENDPOINT_PARAMS_DESCRIPTION), 'NULL'); + PRINT 'PARAMETER34 - @ENDPOINT_PARAMS_GROUP_ID: ' + ISNULL(CONVERT(NVARCHAR(10), @ENDPOINT_PARAMS_GROUP_ID), 'NULL'); + PRINT 'PARAMETER35 - @ENDPOINT_PARAMS_SEQUENCE: ' + ISNULL(CONVERT(NVARCHAR(5), @ENDPOINT_PARAMS_SEQUENCE), 'NULL'); + PRINT 'PARAMETER36 - @ENDPOINT_PARAMS_KEY: ' + ISNULL(CONVERT(NVARCHAR(150), @ENDPOINT_PARAMS_KEY), 'NULL'); + PRINT 'PARAMETER37 - @ENDPOINT_PARAMS_VALUE: ' + ISNULL(CONVERT(NVARCHAR(150), @ENDPOINT_PARAMS_VALUE), 'NULL'); + PRINT 'PARAMETER38 - @PROFILE_ACTIVE: ' + ISNULL(CONVERT(NVARCHAR(1), @PROFILE_ACTIVE), 'NULL'); + PRINT 'PARAMETER39 - @PROFILE_TYPE_ID: ' + ISNULL(CONVERT(NVARCHAR(5), @PROFILE_TYPE_ID), 'NULL'); + PRINT 'PARAMETER40 - @PROFILE_MANDANTOR: ' + ISNULL(CONVERT(NVARCHAR(50), @PROFILE_MANDANTOR), 'NULL'); + PRINT 'PARAMETER41 - @PROFILE_NAME: ' + ISNULL(CONVERT(NVARCHAR(50), @PROFILE_NAME), 'NULL'); + PRINT 'PARAMETER42 - @PROFILE_DESCRIPTION: ' + ISNULL(CONVERT(NVARCHAR(250), @PROFILE_DESCRIPTION), 'NULL'); + PRINT 'PARAMETER43 - @PROFILE_LOG_LEVEL_ID: ' + ISNULL(CONVERT(NVARCHAR(5), @PROFILE_LOG_LEVEL_ID), 'NULL'); + PRINT 'PARAMETER44 - @PROFILE_LANGUAGE_ID: ' + ISNULL(CONVERT(NVARCHAR(10), @PROFILE_LANGUAGE_ID), 'NULL'); + PRINT 'PARAMETER45 - @PROFILE_FIRST_RUN: ' + ISNULL(CONVERT(NVARCHAR(50), @PROFILE_FIRST_RUN), 'NULL'); + PRINT 'PARAMETER46 - @PROFILE_LAST_RUN: ' + ISNULL(CONVERT(NVARCHAR(50), @PROFILE_LAST_RUN), 'NULL'); + PRINT 'PARAMETER47 - @PROFILE_LAST_RESULT: ' + ISNULL(CONVERT(NVARCHAR(250), @PROFILE_LAST_RESULT), 'NULL'); + PRINT 'PARAMETER48 - @RESULT_ACTION_ID: ' + ISNULL(CONVERT(NVARCHAR(30), @RESULT_ACTION_ID), 'NULL'); + PRINT 'PARAMETER49 - @RESULT_STATUS_ID: ' + ISNULL(CONVERT(NVARCHAR(10), @RESULT_STATUS_ID), 'NULL'); + PRINT 'PARAMETER50 - @RESULT_TYPE_ID: ' + ISNULL(CONVERT(NVARCHAR(1), @RESULT_TYPE_ID), 'NULL'); + PRINT 'PARAMETER51 - @RESULT_HEADER: ' + ISNULL(CONVERT(NVARCHAR(100), @RESULT_HEADER), 'NULL'); + PRINT 'PARAMETER52 - @RESULT_BODY: ' + ISNULL(CONVERT(NVARCHAR(100), @RESULT_BODY), 'NULL'); + PRINT 'PARAMETER53 - @RESULT_INFO: ' + ISNULL(CONVERT(NVARCHAR(100), @RESULT_INFO), 'NULL'); + PRINT 'PARAMETER54 - @RESULT_ERROR: ' + ISNULL(CONVERT(NVARCHAR(100), @RESULT_ERROR), 'NULL'); + PRINT ''; + ----------------------------------------------------------------------------------------------------------------------------- + + --================================================-- Validation --=======================================================-- + IF (@ENTITY NOT IN ('ACTION', 'ENDPOINT', 'ENDPOINT_AUTH', 'ENDPOINT_PARAMS', 'PROFILE', 'RESULT')) BEGIN + SET @RETURN_STATUS = 50201; + SET @RETURN_STATUS_TEXT = 'ERROR: Unknown entity "' + @ENTITY + '". Allowed: ACTION, ENDPOINT, ENDPOINT_AUTH, ENDPOINT_PARAMS, PROFILE, RESULT.'; + RAISERROR(@RETURN_STATUS_TEXT,16,1); + RETURN @RETURN_STATUS; + END; + + IF (@GUID IS NULL) BEGIN + SET @RETURN_STATUS = 50202; + SET @RETURN_STATUS_TEXT = 'ERROR: @pGUID is required.'; + RAISERROR(@RETURN_STATUS_TEXT,16,1); + RETURN @RETURN_STATUS; + END; + + -- value validations from views + IF (@ENTITY = 'ACTION') BEGIN + IF (@ACTION_TYPE_ID IS NOT NULL AND @ACTION_TYPE_ID NOT IN (0,1,2,3,4,5,6,7,8,9)) BEGIN + SET @RETURN_STATUS = 50203; + SET @RETURN_STATUS_TEXT = 'ERROR: ACTION.TYPE_ID must be one of (0..9).'; + END; ELSE IF (@ACTION_ERROR_ACTION_ID IS NOT NULL AND @ACTION_ERROR_ACTION_ID NOT IN (0,1)) BEGIN + SET @RETURN_STATUS = 50204; + SET @RETURN_STATUS_TEXT = 'ERROR: ACTION.ERROR_ACTION_ID must be 0 or 1.'; + END; + END; ELSE IF (@ENTITY = 'ENDPOINT_AUTH') BEGIN + IF (@ENDPOINT_AUTH_TYPE_ID IS NOT NULL AND @ENDPOINT_AUTH_TYPE_ID NOT IN (0,1,2,3,4,5,6,7,8,9)) BEGIN + SET @RETURN_STATUS = 50205; + SET @RETURN_STATUS_TEXT = 'ERROR: ENDPOINT_AUTH.TYPE_ID must be one of (0..9).'; + END; ELSE IF (@ENDPOINT_AUTH_API_KEY_ADD_TO_ID IS NOT NULL AND @ENDPOINT_AUTH_API_KEY_ADD_TO_ID NOT IN (0,1)) BEGIN + SET @RETURN_STATUS = 50206; + SET @RETURN_STATUS_TEXT = 'ERROR: ENDPOINT_AUTH.API_KEY_ADD_TO must be 0 (HEADER) or 1 (QUERY).'; + END; + END; ELSE IF (@ENTITY = 'PROFILE') BEGIN + IF (@PROFILE_TYPE_ID IS NOT NULL AND @PROFILE_TYPE_ID NOT IN (1,2)) BEGIN + SET @RETURN_STATUS = 50207; + SET @RETURN_STATUS_TEXT = 'ERROR: PROFILE.TYPE_ID must be 1 or 2.'; + END; ELSE IF (@PROFILE_LOG_LEVEL_ID IS NOT NULL AND @PROFILE_LOG_LEVEL_ID NOT IN (0,1,2,3,4,5,6)) BEGIN + SET @RETURN_STATUS = 50208; + SET @RETURN_STATUS_TEXT = 'ERROR: PROFILE.LOG_LEVEL_ID must be between 0 and 6.'; + END; ELSE IF (@PROFILE_LANGUAGE_ID IS NOT NULL AND @PROFILE_LANGUAGE_ID NOT IN (1031,1033)) BEGIN + SET @RETURN_STATUS = 50209; + SET @RETURN_STATUS_TEXT = 'ERROR: PROFILE.LANGUAGE_ID must be 1031 or 1033.'; + END; + END; ELSE IF (@ENTITY = 'RESULT') BEGIN + IF (@RESULT_STATUS_ID IS NOT NULL AND @RESULT_STATUS_ID NOT IN (100,101,103,200,201,202,204,206,301,302,304,307,308,400,401,403,404,405,408,429,451,500,501,502,503,504,511)) BEGIN + SET @RETURN_STATUS = 50210; + SET @RETURN_STATUS_TEXT = 'ERROR: RESULT.STATUS_ID not in allowed HTTP status list.'; + END; + END; + + IF (@RETURN_STATUS > 0) BEGIN + RAISERROR(@RETURN_STATUS_TEXT,16,1); + RETURN @RETURN_STATUS; + END; + ----------------------------------------------------------------------------------------------------------------------------- + + --===============================================-- Main Processing --===================================================-- + BEGIN TRY + + BEGIN TRANSACTION; + + IF (@ENTITY = 'ACTION') BEGIN + IF NOT EXISTS (SELECT 1 FROM [dbo].[TBREC_CFG_ACTION] WHERE [GUID] = @GUID) BEGIN + SET @RETURN_STATUS = 50211; + SET @RETURN_STATUS_TEXT = 'ERROR: ACTION with GUID=' + CONVERT(NVARCHAR(30), @GUID) + ' not found.'; + END; ELSE BEGIN + UPDATE [CFG_ACTION] SET + [PROFILE_ID] = COALESCE(@ACTION_PROFILE_ID, [CFG_ACTION].[PROFILE_ID]), + [ACTIVE] = COALESCE(@ACTION_ACTIVE, [CFG_ACTION].[ACTIVE]), + [SEQUENCE] = COALESCE(@ACTION_SEQUENCE, [CFG_ACTION].[SEQUENCE]), + [ENDPOINT_ID] = COALESCE(@ACTION_ENDPOINT_ID, [CFG_ACTION].[ENDPOINT_ID]), + [ENDPOINT_AUTH_ID] = COALESCE(@ACTION_ENDPOINT_AUTH_ID, [CFG_ACTION].[ENDPOINT_AUTH_ID]), + [ENDPOINT_PARAMS_ID] = COALESCE(@ACTION_ENDPOINT_PARAMS_ID,[CFG_ACTION].[ENDPOINT_PARAMS_ID]), + [SQL_CONNECTION_ID] = COALESCE(@ACTION_SQL_CONNECTION_ID, [CFG_ACTION].[SQL_CONNECTION_ID]), + [TYPE_ID] = COALESCE(@ACTION_TYPE_ID, [CFG_ACTION].[TYPE_ID]), + [PREPROCESSING_QUERY] = COALESCE(@ACTION_PRE_SQL, [CFG_ACTION].[PREPROCESSING_QUERY]), + [HEADER_QUERY] = COALESCE(@ACTION_HEADER_SQL, [CFG_ACTION].[HEADER_QUERY]), + [BODY_QUERY] = COALESCE(@ACTION_BODY_SQL, [CFG_ACTION].[BODY_QUERY]), + [POSTPROCESSING_QUERY] = COALESCE(@ACTION_POST_SQL, [CFG_ACTION].[POSTPROCESSING_QUERY]), + [ERROR_ACTION_ID] = COALESCE(@ACTION_ERROR_ACTION_ID, [CFG_ACTION].[ERROR_ACTION_ID]), + [CHANGED_WHO] = COALESCE(@CHANGED_WHO, [CFG_ACTION].[CHANGED_WHO]), + [CHANGED_WHEN] = COALESCE(@CHANGED_WHEN, [CFG_ACTION].[CHANGED_WHEN]) + FROM [dbo].[TBREC_CFG_ACTION] as [CFG_ACTION] + WHERE [CFG_ACTION].[GUID] = @GUID; + + SET @RETURN_STATUS_TEXT = 'INFO: Updated ACTION GUID=' + CONVERT(NVARCHAR(30), @GUID); + END; + + END; ELSE IF (@ENTITY = 'ENDPOINT') BEGIN + IF NOT EXISTS (SELECT 1 FROM [dbo].[TBREC_CFG_ENDPOINT] WHERE [GUID] = @GUID) BEGIN + SET @RETURN_STATUS = 50212; + SET @RETURN_STATUS_TEXT = 'ERROR: ENDPOINT with GUID=' + CONVERT(NVARCHAR(30), @GUID) + ' not found.'; + END; ELSE BEGIN + UPDATE [CFG_ENDPOINT] SET + [ACTIVE] = COALESCE(@ENDPOINT_ACTIVE, [CFG_ENDPOINT].[ACTIVE]), + [DESCRIPTION] = COALESCE(@ENDPOINT_DESCRIPTION, [CFG_ENDPOINT].[DESCRIPTION]), + [URI] = COALESCE(@ENDPOINT_URI, [CFG_ENDPOINT].[URI]), + [CHANGED_WHO] = COALESCE(@CHANGED_WHO, [CFG_ENDPOINT].[CHANGED_WHO]), + [CHANGED_WHEN] = COALESCE(@CHANGED_WHEN, [CFG_ENDPOINT].[CHANGED_WHEN]) + FROM [dbo].[TBREC_CFG_ENDPOINT] as [CFG_ENDPOINT] + WHERE [CFG_ENDPOINT].[GUID] = @GUID; + + SET @RETURN_STATUS_TEXT = 'INFO: Updated ENDPOINT GUID=' + CONVERT(NVARCHAR(30), @GUID); + END; + + END; ELSE IF (@ENTITY = 'ENDPOINT_AUTH') BEGIN + IF NOT EXISTS (SELECT 1 FROM [dbo].[TBREC_CFG_ENDPOINT_AUTH] WHERE [GUID] = @GUID) BEGIN + SET @RETURN_STATUS = 50213; + SET @RETURN_STATUS_TEXT = 'ERROR: ENDPOINT_AUTH with GUID=' + CONVERT(NVARCHAR(30), @GUID) + ' not found.'; + END; ELSE BEGIN + UPDATE [CFG_ENDPOINT_AUTH] SET + [ACTIVE] = COALESCE(@ENDPOINT_AUTH_ACTIVE, [CFG_ENDPOINT_AUTH].[ACTIVE]), + [DESCRIPTION] = COALESCE(@ENDPOINT_AUTH_DESCRIPTION, [CFG_ENDPOINT_AUTH].[DESCRIPTION]), + [TYPE_ID] = COALESCE(@ENDPOINT_AUTH_TYPE_ID, [CFG_ENDPOINT_AUTH].[TYPE_ID]), + [API_KEY] = COALESCE(@ENDPOINT_AUTH_API_KEY, [CFG_ENDPOINT_AUTH].[API_KEY]), + [API_VALUE] = COALESCE(@ENDPOINT_AUTH_API_VALUE, [CFG_ENDPOINT_AUTH].[API_VALUE]), + [API_KEY_ADD_TO_ID] = COALESCE(@ENDPOINT_AUTH_API_KEY_ADD_TO_ID,[CFG_ENDPOINT_AUTH].[API_KEY_ADD_TO_ID]), + [TOKEN] = COALESCE(@ENDPOINT_AUTH_TOKEN, [CFG_ENDPOINT_AUTH].[TOKEN]), + [USERNAME] = COALESCE(@ENDPOINT_AUTH_USERNAME, [CFG_ENDPOINT_AUTH].[USERNAME]), + [PASSWORD] = COALESCE(@ENDPOINT_AUTH_PASSWORD, [CFG_ENDPOINT_AUTH].[PASSWORD]), + [DOMAIN] = COALESCE(@ENDPOINT_AUTH_DOMAIN, [CFG_ENDPOINT_AUTH].[DOMAIN]), + [WORKSTATION] = COALESCE(@ENDPOINT_AUTH_WORKSTATION, [CFG_ENDPOINT_AUTH].[WORKSTATION]), + [CHANGED_WHO] = COALESCE(@CHANGED_WHO, [CFG_ENDPOINT_AUTH].[CHANGED_WHO]), + [CHANGED_WHEN] = COALESCE(@CHANGED_WHEN, [CFG_ENDPOINT_AUTH].[CHANGED_WHEN]) + FROM [dbo].[TBREC_CFG_ENDPOINT_AUTH] as [CFG_ENDPOINT_AUTH] + WHERE [CFG_ENDPOINT_AUTH].[GUID] = @GUID; + + SET @RETURN_STATUS_TEXT = 'INFO: Updated ENDPOINT_AUTH GUID=' + CONVERT(NVARCHAR(30), @GUID); + END; + + END; ELSE IF (@ENTITY = 'PROFILE') BEGIN + IF NOT EXISTS (SELECT 1 FROM [dbo].[TBREC_CFG_PROFILE] WHERE [GUID] = @GUID) BEGIN + SET @RETURN_STATUS = 50214; + SET @RETURN_STATUS_TEXT = 'ERROR: PROFILE with GUID=' + CONVERT(NVARCHAR(30), @GUID) + ' not found.'; + END; ELSE BEGIN + UPDATE [CFG_PROFILE] SET + [ACTIVE] = COALESCE(@PROFILE_ACTIVE, [CFG_PROFILE].[ACTIVE]), + [TYPE_ID] = COALESCE(@PROFILE_TYPE_ID, [CFG_PROFILE].[TYPE_ID]), + [MANDANTOR] = COALESCE(@PROFILE_MANDANTOR, [CFG_PROFILE].[MANDANTOR]), + [PROFILE_NAME] = COALESCE(@PROFILE_NAME, [CFG_PROFILE].[PROFILE_NAME]), + [DESCRIPTION] = COALESCE(@PROFILE_DESCRIPTION, [CFG_PROFILE].[DESCRIPTION]), + [LOG_LEVEL_ID] = COALESCE(@PROFILE_LOG_LEVEL_ID, [CFG_PROFILE].[LOG_LEVEL_ID]), + [LANGUAGE_ID] = COALESCE(@PROFILE_LANGUAGE_ID, [CFG_PROFILE].[LANGUAGE_ID]), + [CHANGED_WHO] = COALESCE(@CHANGED_WHO, [CFG_PROFILE].[CHANGED_WHO]), + [CHANGED_WHEN] = COALESCE(@CHANGED_WHEN, [CFG_PROFILE].[CHANGED_WHEN]) + FROM [dbo].[TBREC_CFG_PROFILE] as [CFG_PROFILE] + WHERE [CFG_PROFILE].[GUID] = @GUID; + + IF EXISTS (SELECT 1 FROM [dbo].[TBREC_RUN_PROFILE] WHERE [PROFILE_ID] = @GUID) BEGIN + UPDATE [RUN_PROFILE] SET + [FIRST_RUN] = COALESCE(@PROFILE_FIRST_RUN, [RUN_PROFILE].[FIRST_RUN]), + [LAST_RUN] = COALESCE(@PROFILE_LAST_RUN, [RUN_PROFILE].[LAST_RUN]), + [LAST_RESULT] = COALESCE(@PROFILE_LAST_RESULT, [RUN_PROFILE].[LAST_RESULT]) + FROM [dbo].[TBREC_RUN_PROFILE] as [RUN_PROFILE] + WHERE [RUN_PROFILE].[PROFILE_ID] = @GUID; + END; ELSE BEGIN + INSERT INTO [dbo].[TBREC_RUN_PROFILE] ([PROFILE_ID],[FIRST_RUN],[LAST_RUN],[LAST_RESULT]) + VALUES (@GUID, @PROFILE_FIRST_RUN, @PROFILE_LAST_RUN, @PROFILE_LAST_RESULT); + END; + + SET @RETURN_STATUS_TEXT = 'INFO: Updated PROFILE and RUN_PROFILE for GUID=' + CONVERT(NVARCHAR(30), @GUID); + END; + + END; ELSE IF (@ENTITY = 'ENDPOINT_PARAMS') BEGIN + IF NOT EXISTS (SELECT 1 FROM [dbo].[TBREC_CFG_ENDPOINT_PARAMS] WHERE [GUID] = @GUID) BEGIN + SET @RETURN_STATUS = 50215; + SET @RETURN_STATUS_TEXT = 'ERROR: ENDPOINT_PARAMS with GUID=' + CONVERT(NVARCHAR(30), @GUID) + ' not found.'; + END; ELSE BEGIN + UPDATE [CFG_ENDPOINT_PARAMS] SET + [ACTIVE] = COALESCE(@ENDPOINT_PARAMS_ACTIVE, [CFG_ENDPOINT_PARAMS].[ACTIVE]), + [DESCRIPTION] = COALESCE(@ENDPOINT_PARAMS_DESCRIPTION, [CFG_ENDPOINT_PARAMS].[DESCRIPTION]), + [GROUP_ID] = COALESCE(@ENDPOINT_PARAMS_GROUP_ID, [CFG_ENDPOINT_PARAMS].[GROUP_ID]), + [SEQUENCE] = COALESCE(@ENDPOINT_PARAMS_SEQUENCE, [CFG_ENDPOINT_PARAMS].[SEQUENCE]), + [KEY] = COALESCE(@ENDPOINT_PARAMS_KEY, [CFG_ENDPOINT_PARAMS].[KEY]), + [VALUE] = COALESCE(@ENDPOINT_PARAMS_VALUE, [CFG_ENDPOINT_PARAMS].[VALUE]), + [CHANGED_WHO] = COALESCE(@CHANGED_WHO, [CFG_ENDPOINT_PARAMS].[CHANGED_WHO]), + [CHANGED_WHEN] = COALESCE(@CHANGED_WHEN, [CFG_ENDPOINT_PARAMS].[CHANGED_WHEN]) + FROM [dbo].[TBREC_CFG_ENDPOINT_PARAMS] as [CFG_ENDPOINT_PARAMS] + WHERE [CFG_ENDPOINT_PARAMS].[GUID] = @GUID; + + SET @RETURN_STATUS_TEXT = 'INFO: Updated ENDPOINT_PARAMS GUID=' + CONVERT(NVARCHAR(30), @GUID); + END; + + END; ELSE IF (@ENTITY = 'RESULT') BEGIN + IF NOT EXISTS (SELECT 1 FROM [dbo].[TBREC_OUT_RESULT] WHERE [GUID] = @GUID) BEGIN + SET @RETURN_STATUS = 50216; + SET @RETURN_STATUS_TEXT = 'ERROR: RESULT with GUID=' + CONVERT(NVARCHAR(30), @GUID) + ' not found.'; + END; ELSE BEGIN + UPDATE [OUT_RESULT] SET + [ACTION_ID] = COALESCE(@RESULT_ACTION_ID, [OUT_RESULT].[ACTION_ID]), + [STATUS_ID] = COALESCE(@RESULT_STATUS_ID, [OUT_RESULT].[STATUS_ID]), + [RESULT_TYPE_ID] = COALESCE(@RESULT_STATUS_ID, [OUT_RESULT].[RESULT_TYPE_ID]), + [RESULT_HEADER] = COALESCE(@RESULT_HEADER, [OUT_RESULT].[RESULT_HEADER]), + [RESULT_BODY] = COALESCE(@RESULT_BODY, [OUT_RESULT].[RESULT_BODY]), + [RESULT_INFO] = COALESCE(@RESULT_INFO, [OUT_RESULT].[RESULT_INFO]), + [RESULT_ERROR] = COALESCE(@RESULT_ERROR, [OUT_RESULT].[RESULT_ERROR]), + [CHANGED_WHO] = COALESCE(@CHANGED_WHO, [OUT_RESULT].[CHANGED_WHO]), + [CHANGED_WHEN] = COALESCE(@CHANGED_WHEN, [OUT_RESULT].[CHANGED_WHEN]) + FROM [dbo].[TBREC_OUT_RESULT] as [OUT_RESULT] + WHERE [OUT_RESULT].[GUID] = @GUID; + + SET @RETURN_STATUS_TEXT = 'INFO: Updated RESULT GUID=' + CONVERT(NVARCHAR(30), @GUID); + END; + + END; + + IF (@RETURN_STATUS > 0) BEGIN + IF (XACT_STATE() <> 0) ROLLBACK TRANSACTION; + END; ELSE BEGIN + COMMIT TRANSACTION; + END; + + --======================================================-- Output result --======================================================-- + SET @RETURN_STATUS_TEXT = 'END PROCEDURE [' + @MY_PROCEDURE_NAME + '] @ ' + CONVERT(VARCHAR(50), GETDATE(), 120); + + PRINT ''; + PRINT @RETURN_STATUS_TEXT; + PRINT '===================================================================================================='; + ----------------------------------------------------------------------------------------------------------------------------------- + + RETURN @RETURN_STATUS; + + END TRY BEGIN CATCH + + IF (XACT_STATE() <> 0) ROLLBACK TRANSACTION; + + --======================================================-- Output result --======================================================-- + SET @RETURN_STATUS_TEXT = 'ERROR: ' + ERROR_MESSAGE(); + RAISERROR(@RETURN_STATUS_TEXT,16,1); + + SET @RETURN_STATUS_TEXT = 'END PROCEDURE [' + @MY_PROCEDURE_NAME + '] @ ' + CONVERT(VARCHAR(50), GETDATE(), 120); + + PRINT ''; + PRINT @RETURN_STATUS_TEXT; + PRINT '===================================================================================================='; + ----------------------------------------------------------------------------------------------------------------------------------- + + RETURN @RETURN_STATUS; + + END CATCH; + ----------------------------------------------------------------------------------------------------------------------------- + +END; +GO \ No newline at end of file diff --git a/current/[DD_ECM]-Database/ReC/[TBREC_CFG_ACTION].sql b/current/[DD_ECM]-Database/ReC/[TBREC_CFG_ACTION].sql new file mode 100644 index 0000000..5f59352 --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[TBREC_CFG_ACTION].sql @@ -0,0 +1,137 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +CREATE TABLE [dbo].[TBREC_CFG_ACTION]( + [GUID] [bigint] IDENTITY(1,1) NOT NULL, + [PROFILE_ID] [bigint] NOT NULL, + [ACTIVE] [bit] NOT NULL, + [SEQUENCE] [tinyint] NOT NULL, + [ENDPOINT_ID] [bigint] NOT NULL, + [ENDPOINT_AUTH_ID] [bigint] NULL, + [ENDPOINT_PARAMS_ID] [smallint] NULL, + [SQL_CONNECTION_ID] [smallint] NULL, + [TYPE_ID] [tinyint] NOT NULL, + [PREPROCESSING_QUERY] [nvarchar](max) NULL, + [HEADER_QUERY] [nvarchar](max) NULL, + [BODY_QUERY] [nvarchar](max) NULL, + [POSTPROCESSING_QUERY] [nvarchar](max) NULL, + [ERROR_ACTION_ID] [tinyint] NOT NULL, + [ADDED_WHO] [nvarchar](50) NOT NULL, + [ADDED_WHEN] [datetime] NOT NULL, + [CHANGED_WHO] [nvarchar](50) NULL, + [CHANGED_WHEN] [datetime] NULL, + CONSTRAINT [PK_TBREC_CFG_ACTION_GUID] PRIMARY KEY CLUSTERED +( + [GUID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] ADD CONSTRAINT [DF_TBREC_CFG_ACTION_ACTIVE] DEFAULT ((0)) FOR [ACTIVE] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] ADD CONSTRAINT [DF_TBREC_CFG_ACTION_SEQUENCE] DEFAULT ((0)) FOR [SEQUENCE] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] ADD CONSTRAINT [DF_TBREC_CFG_ACTION_TYPE_ID] DEFAULT ((1)) FOR [TYPE_ID] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] ADD CONSTRAINT [DF_TBREC_CFG_ACTION_ERROR_ACTION_ID] DEFAULT ((0)) FOR [ERROR_ACTION_ID] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] ADD CONSTRAINT [DF_TBREC_CFG_ACTION_ADDED_WHO] DEFAULT (suser_sname()) FOR [ADDED_WHO] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] ADD CONSTRAINT [DF_TBREC_CFG_ACTION_ADDED_WHEN] DEFAULT (sysdatetime()) FOR [ADDED_WHEN] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] WITH CHECK ADD CONSTRAINT [FK_TBREC_CFG_ACTION_TBDD_CONNECTION] FOREIGN KEY([SQL_CONNECTION_ID]) +REFERENCES [dbo].[TBDD_CONNECTION] ([GUID]) +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] CHECK CONSTRAINT [FK_TBREC_CFG_ACTION_TBDD_CONNECTION] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] WITH CHECK ADD CONSTRAINT [FK_TBREC_CFG_ACTION_TBREC_CFG_ENDPOINT] FOREIGN KEY([ENDPOINT_ID]) +REFERENCES [dbo].[TBREC_CFG_ENDPOINT] ([GUID]) +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] CHECK CONSTRAINT [FK_TBREC_CFG_ACTION_TBREC_CFG_ENDPOINT] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] WITH CHECK ADD CONSTRAINT [FK_TBREC_CFG_ACTION_TBREC_CFG_ENDPOINT_AUTH] FOREIGN KEY([ENDPOINT_AUTH_ID]) +REFERENCES [dbo].[TBREC_CFG_ENDPOINT_AUTH] ([GUID]) +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] CHECK CONSTRAINT [FK_TBREC_CFG_ACTION_TBREC_CFG_ENDPOINT_AUTH] +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Primärschlüssel' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'GUID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Profil-Referenz' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'PROFILE_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Ein-/Ausschalter' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'ACTIVE' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Reihenfolge im Profil' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'SEQUENCE' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Endpoint-Referenz' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'ENDPOINT_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Auth-Referenz' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'ENDPOINT_AUTH_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Parameterguppe' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'ENDPOINT_PARAMS_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'SQL-Verbindungs-Referenz' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'SQL_CONNECTION_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'HTTP-Methode (0 = NONE; 1 = GET; 2 = POST; 3 = PUT; 4 = PATCH; 5 = DELETE; 6 = HEAD; 7 = OPTIONS; 8 = CONNECT; 9 = TRACE)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'TYPE_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'SQL vor Request' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'PREPROCESSING_QUERY' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'SQL fuer Header-Erzeugung' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'HEADER_QUERY' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'SQL fuer Body-Erzeugung' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'BODY_QUERY' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'SQL nach Request' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'POSTPROCESSING_QUERY' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Fehlerbehandlung (0 = STOP; 1 = CONTINUE)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'ERROR_ACTION_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Angelegt von' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'ADDED_WHO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Angelegt am' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'ADDED_WHEN' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Geaendert von' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'CHANGED_WHO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Geaendert am' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ACTION', @level2type=N'COLUMN',@level2name=N'CHANGED_WHEN' +GO + +-------------------------------------------------------------------------------------- + +CREATE OR ALTER TRIGGER [dbo].[TBREC_CFG_ACTION_AFT_UPD] ON [dbo].[TBREC_CFG_ACTION] +FOR UPDATE +AS + UPDATE [TBREC_CFG_ACTION] + SET [CHANGED_WHEN] = (SYSDATETIME()) + FROM [INSERTED] + WHERE [TBREC_CFG_ACTION].[GUID] = [INSERTED].[GUID] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ACTION] ENABLE TRIGGER [TBREC_CFG_ACTION_AFT_UPD] +GO \ No newline at end of file diff --git a/current/[DD_ECM]-Database/ReC/[TBREC_CFG_ENDPOINT].sql b/current/[DD_ECM]-Database/ReC/[TBREC_CFG_ENDPOINT].sql new file mode 100644 index 0000000..a1a467b --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[TBREC_CFG_ENDPOINT].sql @@ -0,0 +1,64 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +CREATE TABLE [dbo].[TBREC_CFG_ENDPOINT]( + [GUID] [bigint] IDENTITY(1,1) NOT NULL, + [ACTIVE] [bit] NOT NULL, + [DESCRIPTION] [nvarchar](250) NULL, + [URI] [nvarchar](2000) NOT NULL, + [ADDED_WHO] [nvarchar](50) NOT NULL, + [ADDED_WHEN] [datetime] NOT NULL, + [CHANGED_WHO] [nvarchar](50) NULL, + [CHANGED_WHEN] [datetime] NULL, + CONSTRAINT [PK_TBREC_CFG_ENDPOINT] PRIMARY KEY CLUSTERED +( + [GUID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ENDPOINT] ADD CONSTRAINT [DF_TBREC_CFG_ENDPOINT_ADDED_WHO] DEFAULT (SUSER_SNAME()) FOR [ADDED_WHO] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ENDPOINT] ADD CONSTRAINT [DF_TBREC_CFG_ENDPOINT_ADDED_WHEN] DEFAULT (sysdatetime()) FOR [ADDED_WHEN] +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Primärschlüssel' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT', @level2type=N'COLUMN',@level2name=N'GUID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Ein-/Ausschalter' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT', @level2type=N'COLUMN',@level2name=N'ACTIVE' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Beschreibung' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT', @level2type=N'COLUMN',@level2name=N'DESCRIPTION' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Ziel-URI' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT', @level2type=N'COLUMN',@level2name=N'URI' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Angelegt von' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT', @level2type=N'COLUMN',@level2name=N'ADDED_WHO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Angelegt am' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT', @level2type=N'COLUMN',@level2name=N'ADDED_WHEN' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Geaendert von' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT', @level2type=N'COLUMN',@level2name=N'CHANGED_WHO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Geaendert am' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT', @level2type=N'COLUMN',@level2name=N'CHANGED_WHEN' +GO + +-------------------------------------------------------------------------------------- + +CREATE OR ALTER TRIGGER [dbo].[TBREC_CFG_ENDPOINT_AFT_UPD] ON [dbo].[TBREC_CFG_ENDPOINT] +FOR UPDATE +AS + UPDATE [TBREC_CFG_ENDPOINT] + SET [CHANGED_WHEN] = (SYSDATETIME()) + FROM [INSERTED] + WHERE [TBREC_CFG_ENDPOINT].[GUID] = [INSERTED].[GUID] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ENDPOINT] ENABLE TRIGGER [TBREC_CFG_ENDPOINT_AFT_UPD] +GO \ No newline at end of file diff --git a/current/[DD_ECM]-Database/ReC/[TBREC_CFG_ENDPOINT_AUTH].sql b/current/[DD_ECM]-Database/ReC/[TBREC_CFG_ENDPOINT_AUTH].sql new file mode 100644 index 0000000..34cd493 --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[TBREC_CFG_ENDPOINT_AUTH].sql @@ -0,0 +1,102 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +CREATE TABLE [dbo].[TBREC_CFG_ENDPOINT_AUTH]( + [GUID] [bigint] IDENTITY(1,1) NOT NULL, + [ACTIVE] [bit] NOT NULL, + [DESCRIPTION] [nvarchar](250) NULL, + [TYPE_ID] [tinyint] NOT NULL, + [API_KEY] [nvarchar](150) NULL, + [API_VALUE] [nvarchar](150) NULL, + [API_KEY_ADD_TO_ID] [bit] NULL, + [TOKEN] [nvarchar](150) NULL, + [USERNAME] [nvarchar](100) NULL, + [PASSWORD] [nvarchar](100) NULL, + [DOMAIN] [nvarchar](50) NULL, + [WORKSTATION] [nvarchar](50) NULL, + [ADDED_WHO] [nvarchar](50) NOT NULL, + [ADDED_WHEN] [datetime] NOT NULL, + [CHANGED_WHO] [nvarchar](50) NULL, + [CHANGED_WHEN] [datetime] NULL, + CONSTRAINT [PK_TBREC_CFG_ENDPOINT_AUTH_GUID] PRIMARY KEY CLUSTERED +( + [GUID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ENDPOINT_AUTH] ADD CONSTRAINT [DF_TBREC_CFG_ENDPOINT_AUTH_ACTIVE] DEFAULT ((1)) FOR [ACTIVE] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ENDPOINT_AUTH] ADD CONSTRAINT [DF_TBREC_CFG_ENDPOINT_AUTH_TYPE_ID] DEFAULT ((0)) FOR [TYPE_ID] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ENDPOINT_AUTH] ADD CONSTRAINT [DF_TBREC_CFG_ENDPOINT_AUTH_ADDED_WHO] DEFAULT (suser_sname()) FOR [ADDED_WHO] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ENDPOINT_AUTH] ADD CONSTRAINT [DF_TBREC_CFG_ENDPOINT_AUTH_ADDED_WHEN] DEFAULT (sysdatetime()) FOR [ADDED_WHEN] +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Primärschlüssel' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'GUID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Ein-/Ausschalter' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'ACTIVE' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Beschreibung' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'DESCRIPTION' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Auth-Typ ("0 = No Auth", "1 = API Key", "2 = Bearer Token", "3 = JWT Bearer", "4 = Basic Auth", "5 = Digest Auth", "6 = OAuth 1.0", "7 = OAuth 2.0", "8 = AWS Signature", "9 = NTLM Auth")' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'TYPE_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'API-Key-Name/-Header' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'API_KEY' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'API-Key-Wert' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'API_VALUE' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Platzierung (0 = HEADER; 1 = QUERY)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'API_KEY_ADD_TO_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Bearer/JWT-Token' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'TOKEN' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Username Basic/Digest/NTLM' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'USERNAME' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Passwort Basic/Digest/NTLM' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'PASSWORD' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Domain fuer NTLM' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'DOMAIN' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Workstation fuer NTLM' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'WORKSTATION' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Angelegt von' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'ADDED_WHO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Angelegt am' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'ADDED_WHEN' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Geaendert von' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'CHANGED_WHO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Geaendert am' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_AUTH', @level2type=N'COLUMN',@level2name=N'CHANGED_WHEN' +GO + +-------------------------------------------------------------------------------------- + +CREATE OR ALTER TRIGGER [dbo].[TBREC_CFG_ENDPOINT_AUTH_AFT_UPD] ON [dbo].[TBREC_CFG_ENDPOINT_AUTH] +FOR UPDATE +AS + UPDATE [TBREC_CFG_ENDPOINT_AUTH] + SET [CHANGED_WHEN] = (SYSDATETIME()) + FROM [INSERTED] + WHERE [TBREC_CFG_ENDPOINT_AUTH].[GUID] = [INSERTED].[GUID] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ENDPOINT_AUTH] ENABLE TRIGGER [TBREC_CFG_ENDPOINT_AUTH_AFT_UPD] +GO \ No newline at end of file diff --git a/current/[DD_ECM]-Database/ReC/[TBREC_CFG_ENDPOINT_PARAMS].sql b/current/[DD_ECM]-Database/ReC/[TBREC_CFG_ENDPOINT_PARAMS].sql new file mode 100644 index 0000000..2c2e255 --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[TBREC_CFG_ENDPOINT_PARAMS].sql @@ -0,0 +1,79 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +CREATE TABLE [dbo].[TBREC_CFG_ENDPOINT_PARAMS]( + [GUID] [bigint] IDENTITY(1,1) NOT NULL, + [ACTIVE] [bit] NOT NULL, + [DESCRIPTION] [nvarchar](250) NULL, + [GROUP_ID] [smallint] NOT NULL, + [SEQUENCE] [tinyint] NULL, + [KEY] [nvarchar](150) NULL, + [VALUE] [nvarchar](150) NULL, + [ADDED_WHO] [nvarchar](50) NOT NULL, + [ADDED_WHEN] [datetime] NOT NULL, + [CHANGED_WHO] [nvarchar](50) NULL, + [CHANGED_WHEN] [datetime] NULL, + CONSTRAINT [PK_TBREC_CFG_ENDPOINT_PARAMS_GUID] PRIMARY KEY CLUSTERED +( + [GUID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ENDPOINT_PARAMS] ADD CONSTRAINT [DF_TBREC_CFG_ENDPOINT_PARAMS_ACTIVE] DEFAULT ((1)) FOR [ACTIVE] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ENDPOINT_PARAMS] ADD CONSTRAINT [DF_TBREC_CFG_ENDPOINT_PARAMS_ADDED_WHO] DEFAULT (suser_sname()) FOR [ADDED_WHO] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ENDPOINT_PARAMS] ADD CONSTRAINT [DF_TBREC_CFG_ENDPOINT_PARAMS_ADDED_WHEN] DEFAULT (sysdatetime()) FOR [ADDED_WHEN] +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Primärschlüssel' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_PARAMS', @level2type=N'COLUMN',@level2name=N'GUID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Ein-/Ausschalter' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_PARAMS', @level2type=N'COLUMN',@level2name=N'ACTIVE' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Beschreibung' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_PARAMS', @level2type=N'COLUMN',@level2name=N'DESCRIPTION' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Parameterguppe' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_PARAMS', @level2type=N'COLUMN',@level2name=N'GROUP_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Reihenfolge' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_PARAMS', @level2type=N'COLUMN',@level2name=N'SEQUENCE' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Parameter-Name' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_PARAMS', @level2type=N'COLUMN',@level2name=N'KEY' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Parameter-Wert' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_PARAMS', @level2type=N'COLUMN',@level2name=N'VALUE' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Angelegt von' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_PARAMS', @level2type=N'COLUMN',@level2name=N'ADDED_WHO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Angelegt am' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_PARAMS', @level2type=N'COLUMN',@level2name=N'ADDED_WHEN' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Geaendert von' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_PARAMS', @level2type=N'COLUMN',@level2name=N'CHANGED_WHO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Geaendert am' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_ENDPOINT_PARAMS', @level2type=N'COLUMN',@level2name=N'CHANGED_WHEN' +GO + +-------------------------------------------------------------------------------------- + +CREATE OR ALTER TRIGGER [dbo].[TBREC_CFG_ENDPOINT_PARAMS_AFT_UPD] ON [dbo].[TBREC_CFG_ENDPOINT_PARAMS] +FOR UPDATE +AS + UPDATE [TBREC_CFG_ENDPOINT_PARAMS] + SET [CHANGED_WHEN] = (SYSDATETIME()) + FROM [INSERTED] + WHERE [TBREC_CFG_ENDPOINT_PARAMS].[GUID] = [INSERTED].[GUID] +GO + +ALTER TABLE [dbo].[TBREC_CFG_ENDPOINT_PARAMS] ENABLE TRIGGER [TBREC_CFG_ENDPOINT_PARAMS_AFT_UPD] +GO \ No newline at end of file diff --git a/current/[DD_ECM]-Database/ReC/[TBREC_CFG_PROFILE].sql b/current/[DD_ECM]-Database/ReC/[TBREC_CFG_PROFILE].sql new file mode 100644 index 0000000..6e2ae94 --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[TBREC_CFG_PROFILE].sql @@ -0,0 +1,96 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +CREATE TABLE [dbo].[TBREC_CFG_PROFILE]( + [GUID] [bigint] IDENTITY(1,1) NOT NULL, + [ACTIVE] [bit] NOT NULL, + [TYPE_ID] [tinyint] NOT NULL, + [MANDANTOR] [nvarchar](50) NOT NULL, + [PROFILE_NAME] [nvarchar](50) NOT NULL, + [DESCRIPTION] [nvarchar](250) NULL, + [LOG_LEVEL_ID] [tinyint] NOT NULL, + [LANGUAGE_ID] [smallint] NOT NULL, + [ADDED_WHO] [nvarchar](50) NOT NULL, + [ADDED_WHEN] [datetime] NOT NULL, + [CHANGED_WHO] [nvarchar](50) NULL, + [CHANGED_WHEN] [datetime] NULL, + CONSTRAINT [PK_TBREC_CFG_PROFILE_GUID] PRIMARY KEY CLUSTERED +( + [GUID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = ON, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[TBREC_CFG_PROFILE] ADD CONSTRAINT [DF_TBREC_CFG_PROFILE_ACTIVE] DEFAULT ((0)) FOR [ACTIVE] +GO + +ALTER TABLE [dbo].[TBREC_CFG_PROFILE] ADD CONSTRAINT [DF_TBREC_CFG_PROFILE_TYPE_ID] DEFAULT ((1)) FOR [TYPE_ID] +GO + +ALTER TABLE [dbo].[TBREC_CFG_PROFILE] ADD CONSTRAINT [DF_TBREC_CFG_PROFILE_MANDANTOR] DEFAULT ('DEFAULT') FOR [MANDANTOR] +GO + +ALTER TABLE [dbo].[TBREC_CFG_PROFILE] ADD CONSTRAINT [DF_TBREC_CFG_PROFILE_LOG_LEVEL_ID] DEFAULT ((4)) FOR [LOG_LEVEL_ID] +GO + +ALTER TABLE [dbo].[TBREC_CFG_PROFILE] ADD CONSTRAINT [DF_TBREC_CFG_PROFILE_LANGUAGE_ID] DEFAULT ((1031)) FOR [LANGUAGE_ID] +GO + +ALTER TABLE [dbo].[TBREC_CFG_PROFILE] ADD CONSTRAINT [DF_TBREC_CFG_PROFILE_ADDED_WHO] DEFAULT (suser_sname()) FOR [ADDED_WHO] +GO + +ALTER TABLE [dbo].[TBREC_CFG_PROFILE] ADD CONSTRAINT [DF_TBREC_CFG_PROFILE_ADDED_WHEN] DEFAULT (sysdatetime()) FOR [ADDED_WHEN] +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Primärschlüssel' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_PROFILE', @level2type=N'COLUMN',@level2name=N'GUID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Ein-/Ausschalter' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_PROFILE', @level2type=N'COLUMN',@level2name=N'ACTIVE' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Profiltyp (1 = HTTP; 2 = HTTPS)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_PROFILE', @level2type=N'COLUMN',@level2name=N'TYPE_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Mandant/Kunde' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_PROFILE', @level2type=N'COLUMN',@level2name=N'MANDANTOR' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Profilname' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_PROFILE', @level2type=N'COLUMN',@level2name=N'PROFILE_NAME' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Beschreibung' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_PROFILE', @level2type=N'COLUMN',@level2name=N'DESCRIPTION' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Protokollstufe (0 = TRACE , 1 = DEBUG, 2 = INFO, 3 = WARN, 4 = ERROR, 5 = CRITICAL und 6 = NONE)' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_PROFILE', @level2type=N'COLUMN',@level2name=N'LOG_LEVEL_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Sprache nach LCID (Dec) Standard' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_PROFILE', @level2type=N'COLUMN',@level2name=N'LANGUAGE_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Angelegt von' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_PROFILE', @level2type=N'COLUMN',@level2name=N'ADDED_WHO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Angelegt am' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_PROFILE', @level2type=N'COLUMN',@level2name=N'ADDED_WHEN' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Geaendert von' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_PROFILE', @level2type=N'COLUMN',@level2name=N'CHANGED_WHO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Geaendert am' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_CFG_PROFILE', @level2type=N'COLUMN',@level2name=N'CHANGED_WHEN' +GO + +-------------------------------------------------------------------------------------- + +CREATE OR ALTER TRIGGER [dbo].[TBREC_CFG_PROFILE_AFT_UPD] ON [dbo].[TBREC_CFG_PROFILE] +FOR UPDATE +AS + + UPDATE [TBREC_CFG_PROFILE] + SET [CHANGED_WHEN] = (SYSDATETIME()) + FROM [INSERTED] + WHERE [TBREC_CFG_PROFILE].[GUID] = [INSERTED].[GUID]; +GO + +ALTER TABLE [dbo].[TBREC_CFG_PROFILE] ENABLE TRIGGER [TBREC_CFG_PROFILE_AFT_UPD] +GO \ No newline at end of file diff --git a/current/[DD_ECM]-Database/ReC/[TBREC_OUT_RESULT].sql b/current/[DD_ECM]-Database/ReC/[TBREC_OUT_RESULT].sql new file mode 100644 index 0000000..de9c87f --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[TBREC_OUT_RESULT].sql @@ -0,0 +1,66 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +CREATE TABLE [dbo].[TBREC_OUT_RESULT]( + [GUID] [bigint] IDENTITY(1,1) NOT NULL, + [ACTION_ID] [bigint] NOT NULL, + [STATUS_ID] [smallint] NOT NULL, + [RESULT_TYPE_ID] [tinyint] NOT NULL, + [RESULT_HEADER] [nvarchar](max) NULL, + [RESULT_BODY] [nvarchar](max) NULL, + [RESULT_INFO] [nvarchar](max) NULL, + [RESULT_ERROR] [nvarchar](max) NULL, + [ADDED_WHO] [nvarchar](50) NOT NULL, + [ADDED_WHEN] [datetime] NOT NULL, + [CHANGED_WHO] [nvarchar](50) NULL, + [CHANGED_WHEN] [datetime] NULL, + CONSTRAINT [PK_TBREC_OUT_RESULT_GUID] PRIMARY KEY CLUSTERED +( + [GUID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] +GO + +ALTER TABLE [dbo].[TBREC_OUT_RESULT] ADD CONSTRAINT [DF_TBREC_OUT_RESULT_ADDED_WHO] DEFAULT (suser_sname()) FOR [ADDED_WHO] +GO + +ALTER TABLE [dbo].[TBREC_OUT_RESULT] ADD CONSTRAINT [DF_TBREC_OUT_RESULT_ADDED_WHEN] DEFAULT (sysdatetime()) FOR [ADDED_WHEN] +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Primärschlüssel' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_OUT_RESULT', @level2type=N'COLUMN',@level2name=N'GUID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Action-Referenz' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_OUT_RESULT', @level2type=N'COLUMN',@level2name=N'ACTION_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Antwort-Code' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_OUT_RESULT', @level2type=N'COLUMN',@level2name=N'STATUS_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Antwort von Schritt 1=Pre; 2=Main; 3=Post' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_OUT_RESULT', @level2type=N'COLUMN',@level2name=N'RESULT_TYPE_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Antwort-Header' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_OUT_RESULT', @level2type=N'COLUMN',@level2name=N'RESULT_HEADER' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Antwort-Body' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_OUT_RESULT', @level2type=N'COLUMN',@level2name=N'RESULT_BODY' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Optionaler Antwort Infotext' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_OUT_RESULT', @level2type=N'COLUMN',@level2name=N'RESULT_INFO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Optionaler Antwort Fehlertext' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_OUT_RESULT', @level2type=N'COLUMN',@level2name=N'RESULT_ERROR' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Angelegt von' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_OUT_RESULT', @level2type=N'COLUMN',@level2name=N'ADDED_WHO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Angelegt am' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_OUT_RESULT', @level2type=N'COLUMN',@level2name=N'ADDED_WHEN' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Geaendert von' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_OUT_RESULT', @level2type=N'COLUMN',@level2name=N'CHANGED_WHO' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Geaendert am' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_OUT_RESULT', @level2type=N'COLUMN',@level2name=N'CHANGED_WHEN' +GO diff --git a/current/[DD_ECM]-Database/ReC/[TBREC_RUN_PROFILE].sql b/current/[DD_ECM]-Database/ReC/[TBREC_RUN_PROFILE].sql new file mode 100644 index 0000000..41058e2 --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[TBREC_RUN_PROFILE].sql @@ -0,0 +1,32 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +CREATE TABLE [dbo].[TBREC_RUN_PROFILE]( + [GUID] [bigint] IDENTITY(1,1) NOT NULL, + [PROFILE_ID] [bigint] NOT NULL, + [FIRST_RUN] [datetime] NULL, + [LAST_RUN] [datetime] NULL, + [LAST_RESULT] [nvarchar](250) NULL, + CONSTRAINT [PK_TBREC_RUN_PROFILE_GUID] PRIMARY KEY CLUSTERED +( + [GUID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = ON, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Primärschlüssel' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_RUN_PROFILE', @level2type=N'COLUMN',@level2name=N'GUID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Profil-Referenz' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_RUN_PROFILE', @level2type=N'COLUMN',@level2name=N'PROFILE_ID' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Erste Ausfuehrung' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_RUN_PROFILE', @level2type=N'COLUMN',@level2name=N'FIRST_RUN' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Letzte Ausfuehrung' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_RUN_PROFILE', @level2type=N'COLUMN',@level2name=N'LAST_RUN' +GO + +EXEC sys.sp_addextendedproperty @name=N'MS_Description', @value=N'Letztes Ergebnis' , @level0type=N'SCHEMA',@level0name=N'dbo', @level1type=N'TABLE',@level1name=N'TBREC_RUN_PROFILE', @level2type=N'COLUMN',@level2name=N'LAST_RESULT' +GO \ No newline at end of file diff --git a/current/[DD_ECM]-Database/ReC/[VWREC_ACTION].sql b/current/[DD_ECM]-Database/ReC/[VWREC_ACTION].sql new file mode 100644 index 0000000..76e8d8d --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[VWREC_ACTION].sql @@ -0,0 +1,131 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +CREATE OR ALTER VIEW [dbo].[VWREC_ACTION] +AS +SELECT TOP (100) PERCENT + [CFG_ACTION].[GUID] as 'ACTION_GUID', + [CFG_ACTION].[PROFILE_ID] as 'PROFILE_ID', + [CFG_PROFILE].[PROFILE_NAME] as 'PROFILE_NAME', + [CFG_PROFILE].[TYPE_ID] as 'PROFILE_TYPE_ID', + CASE + WHEN [CFG_PROFILE].[TYPE_ID] = 1 THEN 'HTTP' + WHEN [CFG_PROFILE].[TYPE_ID] = 2 THEN 'HTTPS' + ELSE 'INVALID' + END as 'PROFILE_TYPE', + [CFG_ACTION].[SEQUENCE] as 'SEQUENCE', + [CFG_ACTION].[ENDPOINT_ID] as 'ENDPOINT_ID', + [CFG_ENDPOINT].[URI] as 'ENDPOINT_URI', + [CFG_ACTION].[ENDPOINT_AUTH_ID] as 'ENDPOINT_AUTH_ID', + [CFG_ENDPOINT_AUTH].[TYPE_ID] as 'ENDPOINT_AUTH_TYPE_ID', + CASE + WHEN [CFG_ENDPOINT_AUTH].[TYPE_ID] = 0 THEN 'No Auth' + WHEN [CFG_ENDPOINT_AUTH].[TYPE_ID] = 1 THEN 'API Key' + WHEN [CFG_ENDPOINT_AUTH].[TYPE_ID] = 2 THEN 'Bearer Token' + WHEN [CFG_ENDPOINT_AUTH].[TYPE_ID] = 3 THEN 'JWT Bearer' + WHEN [CFG_ENDPOINT_AUTH].[TYPE_ID] = 4 THEN 'Basic Auth' + WHEN [CFG_ENDPOINT_AUTH].[TYPE_ID] = 5 THEN 'Digest Auth' + WHEN [CFG_ENDPOINT_AUTH].[TYPE_ID] = 6 THEN 'OAuth 1.0' + WHEN [CFG_ENDPOINT_AUTH].[TYPE_ID] = 7 THEN 'OAuth 2.0' + WHEN [CFG_ENDPOINT_AUTH].[TYPE_ID] = 8 THEN 'AWS Signature' + WHEN [CFG_ENDPOINT_AUTH].[TYPE_ID] = 9 THEN 'NTLM Auth' + ELSE 'INVALID' + END as 'ENDPOINT_AUTH_TYPE', + [CFG_ENDPOINT_AUTH].[API_KEY] as 'ENDPOINT_AUTH_API_KEY', + [CFG_ENDPOINT_AUTH].[API_VALUE] as 'ENDPOINT_AUTH_API_VALUE', + [CFG_ENDPOINT_AUTH].[API_KEY_ADD_TO_ID] as 'ENDPOINT_AUTH_API_KEY_ADD_TO_ID', + CASE + WHEN [CFG_ENDPOINT_AUTH].[API_KEY_ADD_TO_ID] = 0 THEN 'HEADER' + WHEN [CFG_ENDPOINT_AUTH].[API_KEY_ADD_TO_ID] = 1 THEN 'QUERY' + ELSE NULL + END as 'ENDPOINT_AUTH_API_KEY_ADD_TO', + [CFG_ENDPOINT_AUTH].[TOKEN] as 'ENDPOINT_AUTH_TOKEN', + [CFG_ENDPOINT_AUTH].[USERNAME] as 'ENDPOINT_AUTH_USERNAME', + [CFG_ENDPOINT_AUTH].[PASSWORD] as 'ENDPOINT_AUTH_PASSWORD', + [CFG_ENDPOINT_AUTH].[DOMAIN] as 'ENDPOINT_AUTH_DOMAIN', + [CFG_ENDPOINT_AUTH].[WORKSTATION] as 'ENDPOINT_AUTH_WORKSTATION', + [CFG_ACTION].[ENDPOINT_PARAMS_ID] as 'ENDPOINT_PARAMS_ID', + [CFG_ACTION].[SQL_CONNECTION_ID] as 'SQL_CONNECTION_ID', + [CFG_SQL_CONNECTION].[SERVER] as 'SQL_CONNECTION_SERVER', + [CFG_SQL_CONNECTION].[DATENBANK] as 'SQL_CONNECTION_DB', + [CFG_SQL_CONNECTION].[USERNAME] as 'SQL_CONNECTION_USERNAME', + [CFG_SQL_CONNECTION].[PASSWORD] as 'SQL_CONNECTION_PASSWORD', + [CFG_ACTION].[TYPE_ID] as 'REST_TYPE_ID', + CASE + WHEN [CFG_ACTION].[TYPE_ID] = 0 THEN 'NONE' + WHEN [CFG_ACTION].[TYPE_ID] = 1 THEN 'GET' + WHEN [CFG_ACTION].[TYPE_ID] = 2 THEN 'POST' + WHEN [CFG_ACTION].[TYPE_ID] = 3 THEN 'PUT' + WHEN [CFG_ACTION].[TYPE_ID] = 4 THEN 'PATCH' + WHEN [CFG_ACTION].[TYPE_ID] = 5 THEN 'DELETE' + WHEN [CFG_ACTION].[TYPE_ID] = 6 THEN 'HEAD' + WHEN [CFG_ACTION].[TYPE_ID] = 7 THEN 'OPTIONS' + WHEN [CFG_ACTION].[TYPE_ID] = 8 THEN 'CONNECT' + WHEN [CFG_ACTION].[TYPE_ID] = 9 THEN 'TRACE' + ELSE 'INVALID' + END as 'REST_TYPE', + [CFG_ACTION].[PREPROCESSING_QUERY] as 'PREPROCESSING_QUERY', + [CFG_ACTION].[HEADER_QUERY] as 'HEADER_QUERY', + [CFG_ACTION].[BODY_QUERY] as 'BODY_QUERY', + [CFG_ACTION].[POSTPROCESSING_QUERY] as 'POSTPROCESSING_QUERY', + [CFG_ACTION].[ERROR_ACTION_ID] as 'ERROR_ACTION_ID', + CASE + WHEN [CFG_ACTION].[ERROR_ACTION_ID] = 0 THEN 'STOP' + WHEN [CFG_ACTION].[ERROR_ACTION_ID] = 1 THEN 'CONTINUE' + ELSE 'INVALID' + END as 'ERROR_ACTION' + + FROM [TBREC_CFG_ACTION] as [CFG_ACTION] WITH (NOLOCK) + INNER JOIN [TBREC_CFG_PROFILE] as [CFG_PROFILE] WITH (NOLOCK) ON [CFG_ACTION].[PROFILE_ID] = [CFG_PROFILE].[GUID] + INNER JOIN [TBREC_CFG_ENDPOINT] as [CFG_ENDPOINT] WITH (NOLOCK) ON [CFG_ACTION].[ENDPOINT_ID] = [CFG_ENDPOINT].[GUID] + LEFT JOIN [TBREC_CFG_ENDPOINT_AUTH] as [CFG_ENDPOINT_AUTH] WITH (NOLOCK) ON [CFG_ACTION].[ENDPOINT_AUTH_ID] = [CFG_ENDPOINT_AUTH].[GUID] + LEFT JOIN [TBDD_CONNECTION] as [CFG_SQL_CONNECTION] WITH (NOLOCK) ON [CFG_ACTION].[SQL_CONNECTION_ID] = [CFG_SQL_CONNECTION].[GUID] + + WHERE [CFG_ACTION].[ACTIVE] = 1 + AND [CFG_PROFILE].[ACTIVE] = 1 + AND [CFG_ENDPOINT].[ACTIVE] = 1 + AND ([CFG_ACTION].[ENDPOINT_AUTH_ID] IS NULL OR [CFG_ENDPOINT_AUTH].[ACTIVE] = 1) + +ORDER BY [CFG_ACTION].[PROFILE_ID] ASC, [CFG_ACTION].[SEQUENCE] ASC, [CFG_ACTION].[GUID] ASC; + +GO + +-------------------------------------------------------------------------------------- + +CREATE OR ALTER TRIGGER [dbo].[VWREC_ACTION_IO_INS] +ON [dbo].[VWREC_ACTION] +INSTEAD OF INSERT +AS +BEGIN + SET NOCOUNT ON; + THROW 51000, 'DML is not allowed on view [dbo].[VWREC_ACTION]. Use these Procedure instead: [PRREC_INSERT_OBJECT]', 1; +END; +GO + +-------------------------------------------------------------------------------------- + +CREATE OR ALTER TRIGGER [dbo].[VWREC_ACTION_IO_UPD] +ON [dbo].[VWREC_ACTION] +INSTEAD OF UPDATE +AS +BEGIN + SET NOCOUNT ON; + THROW 52000, 'DML is not allowed on view [dbo].[VWREC_ACTION]. Use these Procedure instead: [PRREC_UPDATE_OBJECT]', 1; +END; +GO + +-------------------------------------------------------------------------------------- + +CREATE OR ALTER TRIGGER [dbo].[VWREC_ACTION_IO_DEL] +ON [dbo].[VWREC_ACTION] +INSTEAD OF DELETE +AS +BEGIN + SET NOCOUNT ON; + THROW 53000, 'DML is not allowed on view [dbo].[VWREC_ACTION]. Use these Procedure instead: [PRREC_DELETE_OBJECT]', 1; +END; +GO + +-------------------------------------------------------------------------------------- \ No newline at end of file diff --git a/current/[DD_ECM]-Database/ReC/[VWREC_PROFILE].sql b/current/[DD_ECM]-Database/ReC/[VWREC_PROFILE].sql new file mode 100644 index 0000000..8081fc5 --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[VWREC_PROFILE].sql @@ -0,0 +1,86 @@ +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +CREATE OR ALTER VIEW [dbo].[VWREC_PROFILE] +AS +SELECT TOP (100) PERCENT + [CFG_PROFILE].[GUID] as 'PROFILE_GUID', + [CFG_PROFILE].[ACTIVE] as 'ACTIVE', + [CFG_PROFILE].[TYPE_ID] as 'TYPE_ID', + CASE + WHEN [CFG_PROFILE].[TYPE_ID] = 1 THEN 'HTTP' + WHEN [CFG_PROFILE].[TYPE_ID] = 2 THEN 'HTTPS' + ELSE 'INVALID' + END as 'TYPE', + [CFG_PROFILE].[MANDANTOR] as 'MANDANTOR', + [CFG_PROFILE].[PROFILE_NAME] as 'PROFILE_NAME', + [CFG_PROFILE].[DESCRIPTION] as 'DESCRIPTION', + [CFG_PROFILE].[LOG_LEVEL_ID] as 'LOG_LEVEL_ID', + CASE + WHEN [CFG_PROFILE].[LOG_LEVEL_ID] = 0 THEN 'TRACE' + WHEN [CFG_PROFILE].[LOG_LEVEL_ID] = 1 THEN 'DEBUG' + WHEN [CFG_PROFILE].[LOG_LEVEL_ID] = 2 THEN 'INFO' + WHEN [CFG_PROFILE].[LOG_LEVEL_ID] = 3 THEN 'WARN' + WHEN [CFG_PROFILE].[LOG_LEVEL_ID] = 4 THEN 'ERROR' + WHEN [CFG_PROFILE].[LOG_LEVEL_ID] = 5 THEN 'CRITICAL' + WHEN [CFG_PROFILE].[LOG_LEVEL_ID] = 6 THEN 'NONE' + ELSE 'INVALID' + END as 'LOG_LEVEL', + [CFG_PROFILE].[LANGUAGE_ID] as 'LANGUAGE_ID', + CASE + WHEN [CFG_PROFILE].[LANGUAGE_ID] = 1031 THEN 'de-de' + WHEN [CFG_PROFILE].[LANGUAGE_ID] = 1033 THEN 'en-us' + ELSE 'INVALID' + END as 'LANGUAGE', + [CFG_PROFILE].[ADDED_WHO] as 'ADDED_WHO', + [CFG_PROFILE].[ADDED_WHEN] as 'ADDED_WHEN', + [CFG_PROFILE].[CHANGED_WHO] as 'CHANGED_WHO', + [CFG_PROFILE].[CHANGED_WHEN] as 'CHANGED_WHEN', + [RUN_PROFILE].[FIRST_RUN] as 'FIRST_RUN', + [RUN_PROFILE].[LAST_RUN] as 'LAST_RUN', + [RUN_PROFILE].[LAST_RESULT] as 'LAST_RESULT' + +FROM [TBREC_CFG_PROFILE] as [CFG_PROFILE] WITH (NOLOCK) +LEFT JOIN [TBREC_RUN_PROFILE] as [RUN_PROFILE] WITH (NOLOCK) ON [CFG_PROFILE].[GUID] = [RUN_PROFILE].[PROFILE_ID] + +ORDER BY [CFG_PROFILE].[GUID] ASC; + +GO + +-------------------------------------------------------------------------------------- + +CREATE OR ALTER TRIGGER [dbo].[TRREC_VWREC_PROFILE_IO_INS] +ON [dbo].[VWREC_PROFILE] +INSTEAD OF INSERT +AS +BEGIN + SET NOCOUNT ON; + THROW 51000, 'DML is not allowed on view [dbo].[VWREC_PROFILE]. Use these Procedure instead: [PRREC_INSERT_OBJECT]', 1; +END; +GO + +-------------------------------------------------------------------------------------- + +CREATE OR ALTER TRIGGER [dbo].[TRREC_VWREC_PROFILE_IO_UPD] +ON [dbo].[VWREC_PROFILE] +INSTEAD OF UPDATE +AS +BEGIN + SET NOCOUNT ON; + THROW 52000, 'DML is not allowed on view [dbo].[VWREC_PROFILE]. Use these Procedure instead: [PRREC_UPDATE_OBJECT]', 1; +END; +GO + +-------------------------------------------------------------------------------------- + +CREATE OR ALTER TRIGGER [dbo].[TRREC_VWREC_PROFILE_IO_DEL] +ON [dbo].[VWREC_PROFILE] +INSTEAD OF DELETE +AS +BEGIN + SET NOCOUNT ON; + THROW 53000, 'DML is not allowed on view [dbo].[VWREC_PROFILE]. Use these Procedure instead: [PRREC_DELETE_OBJECT]', 1; +END; +GO \ No newline at end of file diff --git a/current/[DD_ECM]-Database/ReC/[VWREC_RESULT].sql b/current/[DD_ECM]-Database/ReC/[VWREC_RESULT].sql new file mode 100644 index 0000000..495468f --- /dev/null +++ b/current/[DD_ECM]-Database/ReC/[VWREC_RESULT].sql @@ -0,0 +1,77 @@ +USE [DD_ECM] +GO + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +CREATE OR ALTER VIEW [dbo].[VWREC_RESULT] +AS +SELECT TOP (100) PERCENT + [OUT_RESULT].[GUID] as 'RESULT_GUID', + [OUT_RESULT].[ACTION_ID] as 'ACTION_ID', + [CFG_ACTION].[PROFILE_ID] as 'PROFILE_ID', + [CFG_PROFILE].[PROFILE_NAME] as 'PROFILE_NAME', + [OUT_RESULT].[STATUS_ID] as 'STATUS_ID', + CASE + -- None HTTP codes + WHEN [OUT_RESULT].[STATUS_ID] = 0 THEN 'OK' + WHEN [OUT_RESULT].[STATUS_ID] = 999 THEN 'Error' + -- 1xx Informational + WHEN [OUT_RESULT].[STATUS_ID] = 100 THEN 'Continue' + WHEN [OUT_RESULT].[STATUS_ID] = 101 THEN 'Switching Protocols' + WHEN [OUT_RESULT].[STATUS_ID] = 103 THEN 'Early Hints' + -- 2xx Success + WHEN [OUT_RESULT].[STATUS_ID] = 200 THEN 'OK' + WHEN [OUT_RESULT].[STATUS_ID] = 201 THEN 'Created' + WHEN [OUT_RESULT].[STATUS_ID] = 202 THEN 'Accepted' + WHEN [OUT_RESULT].[STATUS_ID] = 204 THEN 'No Content' + WHEN [OUT_RESULT].[STATUS_ID] = 206 THEN 'Partial Content' + -- 3xx Redirection + WHEN [OUT_RESULT].[STATUS_ID] = 301 THEN 'Moved Permanently' + WHEN [OUT_RESULT].[STATUS_ID] = 302 THEN 'Found' + WHEN [OUT_RESULT].[STATUS_ID] = 304 THEN 'Not Modified' + WHEN [OUT_RESULT].[STATUS_ID] = 307 THEN 'Temporary Redirect' + WHEN [OUT_RESULT].[STATUS_ID] = 308 THEN 'Permanent Redirect' + -- 4xx Client Error + WHEN [OUT_RESULT].[STATUS_ID] = 400 THEN 'Bad Request' + WHEN [OUT_RESULT].[STATUS_ID] = 401 THEN 'Unauthorized' + WHEN [OUT_RESULT].[STATUS_ID] = 403 THEN 'Forbidden' + WHEN [OUT_RESULT].[STATUS_ID] = 404 THEN 'Not Found' + WHEN [OUT_RESULT].[STATUS_ID] = 405 THEN 'Method Not Allowed' + WHEN [OUT_RESULT].[STATUS_ID] = 408 THEN 'Request Timeout' + WHEN [OUT_RESULT].[STATUS_ID] = 429 THEN 'Too Many Requests' + WHEN [OUT_RESULT].[STATUS_ID] = 451 THEN 'Unavailable For Legal Reasons' + -- 5xx Server Error + WHEN [OUT_RESULT].[STATUS_ID] = 500 THEN 'Internal Server Error' + WHEN [OUT_RESULT].[STATUS_ID] = 501 THEN 'Not Implemented' + WHEN [OUT_RESULT].[STATUS_ID] = 502 THEN 'Bad Gateway' + WHEN [OUT_RESULT].[STATUS_ID] = 503 THEN 'Service Unavailable' + WHEN [OUT_RESULT].[STATUS_ID] = 504 THEN 'Gateway Timeout' + WHEN [OUT_RESULT].[STATUS_ID] = 511 THEN 'Network Authentication Required' + ELSE 'UNKNOWN STATUS' + END as 'STATUS', + [OUT_RESULT].[RESULT_TYPE_ID] as 'RESULT_TYPE_ID', + CASE + WHEN [OUT_RESULT].[RESULT_TYPE_ID] = 1 THEN 'PRE' + WHEN [OUT_RESULT].[RESULT_TYPE_ID] = 2 THEN 'MAIN' + WHEN [OUT_RESULT].[RESULT_TYPE_ID] = 3 THEN 'POST' + ELSE 'INVALID' + END as 'RESULT_TYPE', + [OUT_RESULT].[RESULT_HEADER] as 'RESULT_HEADER', + [OUT_RESULT].[RESULT_BODY] as 'RESULT_BODY', + [OUT_RESULT].[RESULT_INFO] as 'RESULT_INFO', + [OUT_RESULT].[RESULT_ERROR] as 'RESULT_ERROR', + [OUT_RESULT].[ADDED_WHO] as 'ADDED_WHO', + [OUT_RESULT].[ADDED_WHEN] as 'ADDED_WHEN', + [OUT_RESULT].[CHANGED_WHO] as 'CHANGED_WHO', + [OUT_RESULT].[CHANGED_WHEN] as 'CHANGED_WHEN' + +FROM [dbo].[TBREC_OUT_RESULT] as [OUT_RESULT] WITH (NOLOCK) +LEFT JOIN [dbo].[TBREC_CFG_ACTION] as [CFG_ACTION] WITH (NOLOCK) ON [OUT_RESULT].[ACTION_ID] = [CFG_ACTION].[GUID] +LEFT JOIN [dbo].[TBREC_CFG_PROFILE] as [CFG_PROFILE] WITH (NOLOCK) ON [CFG_ACTION].[PROFILE_ID] = [CFG_PROFILE].[GUID] + +ORDER BY [OUT_RESULT].[GUID]; + +GO \ No newline at end of file diff --git a/current/[DD_ECM]-Database/[FNCUST_GET_EDMI_ITEM_VALUE]/[FNCUST_GET_EDMI_ITEM_VALUE].sql b/current/[DD_ECM]-Database/[FNCUST_GET_EDMI_ITEM_VALUE]/[FNCUST_GET_EDMI_ITEM_VALUE].sql new file mode 100644 index 0000000..e3d998e --- /dev/null +++ b/current/[DD_ECM]-Database/[FNCUST_GET_EDMI_ITEM_VALUE]/[FNCUST_GET_EDMI_ITEM_VALUE].sql @@ -0,0 +1,190 @@ +USE [DD_ECM] +GO + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +-- [FNCUST_GET_EDMI_ITEM_VALUE] +-- ================================================================= +-- Returns item values from [TBEDMI_ITEM_VALUE] with optional filters, +-- fallback handling and EB normalization for INVOICE_REFERENCE specs. +-- +-- Returns: Table (max. 10.000 rows) +-- ================================================================= + +CREATE OR ALTER FUNCTION [dbo].[FNCUST_GET_EDMI_ITEM_VALUE] +( + @REFERENCE_GUID NVARCHAR(250) = NULL, + @SPEC_NAME NVARCHAR(100) = NULL +) +RETURNS TABLE +AS +RETURN +( + --====================================-- SPEC fallback configuration --====================================-- + -- FALLBACK_ITEM_VALUE: value used when EB is invalid/missing + -- ALLOW_FALLBACK: 1 = use fallback, 0 = keep original ITEM_VALUE + WITH [CFG_INVOICE_REFERENCE_SPEC] AS + ( + SELECT N'INVOICE_REFERENCE' AS [SPEC_NAME], CAST(N'EB9999999' AS NVARCHAR(100)) AS [FALLBACK_ITEM_VALUE], CAST(1 AS BIT) AS [ALLOW_FALLBACK] + UNION ALL SELECT N'INVOICE_REFERENCE2', CAST(NULL AS NVARCHAR(100)), CAST(0 AS BIT) + UNION ALL SELECT N'INVOICE_REFERENCE3', N'', CAST(0 AS BIT) + ), + + --=======================================-- Source data (filtered) --=======================================-- + [SRC_FILTERED_DATA] AS + ( + SELECT + [GUID], + [REFERENCE_GUID], + [ITEM_DESCRIPTION], + [ITEM_VALUE], + [CREATEDWHEN], + [CREATEDWHO], + [CHANGEDWHEN], + [GROUP_COUNTER], + [SPEC_NAME], + [IS_REQUIRED], + [CHANGEDWHO], + [COMMENT] + FROM [dbo].[TBEDMI_ITEM_VALUE] + WHERE (@REFERENCE_GUID IS NULL OR [REFERENCE_GUID] = @REFERENCE_GUID) + AND (@SPEC_NAME IS NULL OR [SPEC_NAME] = @SPEC_NAME) + ) + + --========================================-- Final output resultset --========================================-- + SELECT TOP (10000) + [GUID], + [REFERENCE_GUID], + [ITEM_DESCRIPTION], + CASE + -- Normalize ITEM_VALUE for configured INVOICE_REFERENCE specs only + WHEN [CHK_SPEC].[IS_INVOICE_REFERENCE_SPEC] = 1 + THEN [NORM_EB].[NORMALIZED_EB_VALUE] + ELSE [OUT_RESULT_DATA].[ITEM_VALUE] + END AS [ITEM_VALUE], + [OUT_RESULT_DATA].[CREATEDWHEN], + [OUT_RESULT_DATA].[CREATEDWHO], + [OUT_RESULT_DATA].[CHANGEDWHEN], + [OUT_RESULT_DATA].[GROUP_COUNTER], + [OUT_RESULT_DATA].[SPEC_NAME], + [OUT_RESULT_DATA].[IS_REQUIRED], + [OUT_RESULT_DATA].[CHANGEDWHO], + [OUT_RESULT_DATA].[COMMENT], + [OUT_RESULT_DATA].[IS_FALLBACK], + CASE + -- Flag rows where configured EB fallback was actually applied + WHEN [CHK_SPEC].[IS_INVOICE_REFERENCE_SPEC] = 1 + AND + [CHK_SPEC].[ALLOW_FALLBACK] = 1 + AND + ( + ([CHK_SPEC].[CONFIGURED_FALLBACK_ITEM_VALUE] IS NULL AND [NORM_EB].[NORMALIZED_EB_VALUE] IS NULL) + OR [NORM_EB].[NORMALIZED_EB_VALUE] = [CHK_SPEC].[CONFIGURED_FALLBACK_ITEM_VALUE] + ) + THEN CAST(1 AS BIT) + ELSE CAST(0 AS BIT) + END AS [IS_EB_FALLBACK] + FROM + ( + -- Real rows from source table + SELECT + [GUID], + [REFERENCE_GUID], + [ITEM_DESCRIPTION], + [ITEM_VALUE], + [CREATEDWHEN], + [CREATEDWHO], + [CHANGEDWHEN], + [GROUP_COUNTER], + [SPEC_NAME], + [IS_REQUIRED], + [CHANGEDWHO], + [COMMENT], + CAST(0 AS BIT) AS [IS_FALLBACK] + FROM [SRC_FILTERED_DATA] + + UNION ALL + + -- Failsafe row if source query returns no row + SELECT + CAST(0 AS BIGINT) AS [GUID], + ISNULL(@REFERENCE_GUID, N'FAILSAFE') AS [REFERENCE_GUID], + N'NO_DATA_FOUND' AS [ITEM_DESCRIPTION], + N'' AS [ITEM_VALUE], + GETDATE() AS [CREATEDWHEN], + N'SYSTEM' AS [CREATEDWHO], + NULL AS [CHANGEDWHEN], + CAST(0 AS INT) AS [GROUP_COUNTER], + ISNULL(@SPEC_NAME, N'FAILSAFE') AS [SPEC_NAME], + CAST(0 AS BIT) AS [IS_REQUIRED], + 'SYSTEM' AS [CHANGEDWHO], + 'FAILSAFE_ROW_RETURNED' AS [COMMENT], + CAST(1 AS BIT) AS [IS_FALLBACK] + WHERE NOT EXISTS (SELECT 1 FROM [SRC_FILTERED_DATA]) + ) AS [OUT_RESULT_DATA] + + --===================================-- Resolve spec configuration --===================================-- + OUTER APPLY ( + SELECT TOP (1) + v.[SPEC_NAME] AS [MATCHED_SPEC_NAME], + v.[FALLBACK_ITEM_VALUE] AS [CONFIGURED_FALLBACK_ITEM_VALUE], + v.[ALLOW_FALLBACK] AS [ALLOW_FALLBACK] + FROM [CFG_INVOICE_REFERENCE_SPEC] v + WHERE v.[SPEC_NAME] = UPPER(CONVERT(NVARCHAR(200), ISNULL([OUT_RESULT_DATA].[SPEC_NAME], N''))) + ) AS [CFG_SPEC] + + --=============================-- Derived check flags and fallback value --=============================-- + CROSS APPLY ( + SELECT + CASE + WHEN [CFG_SPEC].[MATCHED_SPEC_NAME] IS NULL THEN CAST(0 AS BIT) + ELSE CAST(1 AS BIT) + END AS [IS_INVOICE_REFERENCE_SPEC], + [CFG_SPEC].[CONFIGURED_FALLBACK_ITEM_VALUE] AS [CONFIGURED_FALLBACK_ITEM_VALUE], + ISNULL([CFG_SPEC].[ALLOW_FALLBACK], CAST(0 AS BIT)) AS [ALLOW_FALLBACK] + ) AS [CHK_SPEC] + + --=============================-- Preprocessing for EB pattern matching --=============================-- + CROSS APPLY ( + SELECT LTRIM(RTRIM(ISNULL([OUT_RESULT_DATA].[ITEM_VALUE], N''))) AS [CLEAN_ITEM_VALUE] + ) AS [VAL_CLEAN] + + CROSS APPLY ( + SELECT N' ' + [VAL_CLEAN].[CLEAN_ITEM_VALUE] + N' ' AS [PADDED_ITEM_VALUE] + ) AS [VAL_PADDED] + + CROSS APPLY ( + -- Match EB + 8 digits with non-digit boundaries left and right + SELECT PATINDEX( + N'%[^0-9]EB[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][^0-9]%', + [VAL_PADDED].[PADDED_ITEM_VALUE] + ) AS [EB_PATTERN_POS] + ) AS [PAT_EB] + + --====================================-- Normalize EB output value --====================================-- + CROSS APPLY ( + SELECT + CASE + -- Exact EB value + WHEN [VAL_CLEAN].[CLEAN_ITEM_VALUE] LIKE N'EB[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]' + THEN [VAL_CLEAN].[CLEAN_ITEM_VALUE] + + -- Extract EB value from a longer free-text string + WHEN [PAT_EB].[EB_PATTERN_POS] > 0 + THEN SUBSTRING([VAL_PADDED].[PADDED_ITEM_VALUE], [PAT_EB].[EB_PATTERN_POS] + 1, 10) + + -- No valid EB found: fallback if allowed, otherwise keep original value + ELSE CASE + WHEN [CHK_SPEC].[ALLOW_FALLBACK] = 1 THEN [CHK_SPEC].[CONFIGURED_FALLBACK_ITEM_VALUE] + ELSE [OUT_RESULT_DATA].[ITEM_VALUE] + END + END AS [NORMALIZED_EB_VALUE] + ) AS [NORM_EB] + + --=========================================-- Default result ordering --=========================================-- + ORDER BY [GROUP_COUNTER] ASC +); +GO diff --git a/current/[DD_ECM]-Database/[FNCUST_GET_EDMI_ITEM_VALUE]/[PRDD_TEST_PERFORMANCE].sql b/current/[DD_ECM]-Database/[FNCUST_GET_EDMI_ITEM_VALUE]/[PRDD_TEST_PERFORMANCE].sql new file mode 100644 index 0000000..b81b3e9 --- /dev/null +++ b/current/[DD_ECM]-Database/[FNCUST_GET_EDMI_ITEM_VALUE]/[PRDD_TEST_PERFORMANCE].sql @@ -0,0 +1,374 @@ +USE [DD_SYS] +GO + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +-- [PRDD_TEST_PERFORMANCE] +-- ================================================================= +-- Runs a configurable performance smoke test: creates a table, inserts data and queries it. +-- Minimum requirement: MS SQL Server 2016 +-- +-- Returns: INT Value - 0 = Everything worked well +-- ================================================================= +-- Copyright (c) 2025 by Digital Data GmbH +-- +-- Digital Data GmbH Ludwig-Rinn-Strasse 16 D-35452 Heuchelheim +-- Tel.: 0641/202360 E-Mail: info-flow@digitaldata.works +-- ================================================================= +-- Creation Date / Author: 15.12.2025 / MK +-- Version Date / Editor: 23.12.2025 / MK +-- Version Number: 1.1.0.1 +-- ================================================================= +-- History: +-- 15.12.2025 / MK - First Version +-- 23.12.2025 / MK - Add DATA_COMPRESSION = PAGE to log table PK, fix minor formatting, add pRANDOMDATA parameter + +CREATE OR ALTER PROCEDURE [dbo].[PRDD_TEST_PERFORMANCE] ( + @pTARGETDB NVARCHAR(128) = NULL, -- Database to run the test against (defaults to current database) + @pSCHEMA NVARCHAR(128) = 'dbo', -- Schema of the test table + @pTABLENAME NVARCHAR(128) = 'TBDD_TEST_PERFORMANCE', -- Name of the test table to create/use + @pROWCOUNT BIGINT = 1000000, -- Number of rows to insert + @pBATCHSIZE BIGINT = 100000, -- Rows per batch; controls transaction size/log impact + @pPADLENGTH INT = 100, -- Length of the CHAR padding column + @pRANDOMDATA BIT = 0, -- 1 = insert randomized Payload/Pad values + @pDROPANDRECREATE BIT = 1, -- Set to 1 to drop/recreate the table before inserting, otherwise reuse existing table + @pLOGLEVEL NVARCHAR(25) = 'INFO' -- Set to 'INFO','WARN' or 'ERROR' (or NULL to disable) logging to table: [TBDD_TEST_PERFORMANCE_LOG] +) +AS +BEGIN + + --================================================-- Set session options --===============================================-- + SET NOCOUNT ON; + ---------------------------------------------------------------------------------------------------------------------------- + + --=========================================-- Parameter copies (avoid sniffing) --========================================-- + DECLARE @TARGETDB NVARCHAR(128) = LTRIM(RTRIM(ISNULL(@pTARGETDB,DB_NAME()))), + @SCHEMA NVARCHAR(128) = LTRIM(RTRIM(ISNULL(@pSCHEMA,'dbo'))), + @TABLENAME NVARCHAR(128) = LTRIM(RTRIM(ISNULL(@pTABLENAME,'TBDD_TEST_PERFORMANCE'))), + @ROWCOUNT BIGINT = ISNULL(@pROWCOUNT,1000000), + @BATCHSIZE BIGINT = ISNULL(@pBATCHSIZE,100000), + @PADLENGTH INT = ISNULL(@pPADLENGTH,100), + @RANDOMDATA BIT = ISNULL(@pRANDOMDATA,0), + @DROPANDRECREATE BIT = ISNULL(@pDROPANDRECREATE,1), + @LOGLEVEL NVARCHAR(25) = UPPER(LTRIM(RTRIM(ISNULL(@pLOGLEVEL,'INFO')))); + ---------------------------------------------------------------------------------------------------------------------------- + + --=================================================-- Declare runtime variables --========================================-- + DECLARE @MY_PROCEDURE_NAME NVARCHAR(128) = OBJECT_NAME(@@PROCID); + DECLARE @QualifiedTable NVARCHAR(300) = QUOTENAME(@SCHEMA) + '.' + QUOTENAME(@TABLENAME), + @FullTable NVARCHAR(400) = QUOTENAME(@TARGETDB) + '.' + QUOTENAME(@SCHEMA) + '.' + QUOTENAME(@TABLENAME), + @ProductVersion sql_variant, + @ProductMainVersion INT, + @ProductLevel sql_variant, + @ProductEdition sql_variant, + @SQLCommand NVARCHAR(MAX) = NULL, + @RowsRemaining BIGINT = 0, + @RowsInserted BIGINT = 0, + @BatchStart BIGINT = 1, + @BatchNumber INT = 0, + @InsertStart DATETIME2(3) = NULL, + @InsertEnd DATETIME2(3) = NULL, + @return_status INT = 0, + @return_status_text NVARCHAR(MAX) = 'START PROCEDURE [' + @MY_PROCEDURE_NAME + '] @ ' + CONVERT(varchar(50),GETDATE(),120), + @return_error_text NVARCHAR(MAX) = ''; + ---------------------------------------------------------------------------------------------------------------------------- + + --=================================================-- Failsafe settings --=================================================-- + IF (@ROWCOUNT < 0) SET @ROWCOUNT = 0; + IF (@BATCHSIZE <= 0) SET @BATCHSIZE = @ROWCOUNT; + IF (@PADLENGTH < 1) SET @PADLENGTH = 1; + IF (@LOGLEVEL NOT IN ('INFO','WARN','ERROR')) SET @LOGLEVEL = 'ERROR'; + ----------------------------------------------------------------------------------------------------------------------------- + + --=================================================-- Output parameters --================================================-- + PRINT '===================================================================================================='; + PRINT @return_status_text; + PRINT ''; + PRINT 'PARAMETER01 - @TARGETDB: ' + CONVERT(NVARCHAR(128),@TARGETDB); + PRINT 'PARAMETER02 - @SCHEMA: ' + CONVERT(NVARCHAR(128),@SCHEMA); + PRINT 'PARAMETER03 - @TABLENAME: ' + CONVERT(NVARCHAR(128),@TABLENAME); + PRINT 'PARAMETER04 - @ROWCOUNT: ' + CONVERT(NVARCHAR(100),@ROWCOUNT); + PRINT 'PARAMETER05 - @BATCHSIZE: ' + CONVERT(NVARCHAR(100),@BATCHSIZE); + PRINT 'PARAMETER06 - @PADLENGTH: ' + CONVERT(NVARCHAR(100),@PADLENGTH); + PRINT 'PARAMETER07 - @RANDOMDATA: ' + CONVERT(NVARCHAR(1),@RANDOMDATA); + PRINT 'PARAMETER08 - @DROPANDRECREATE: ' + CONVERT(NVARCHAR(1),@DROPANDRECREATE); + PRINT 'PARAMETER09 - @LOGLEVEL: ' + CONVERT(NVARCHAR(25),@LOGLEVEL); + PRINT ''; + ----------------------------------------------------------------------------------------------------------------------------- + + --=================================================-- Get server infos --==================================================-- + SELECT @ProductVersion = SERVERPROPERTY('productversion'), @ProductLevel = SERVERPROPERTY ('productlevel'), @ProductEdition = SERVERPROPERTY ('edition'); + SET @ProductMainVersion = ISNULL(LEFT(convert(NVARCHAR(100),@ProductVersion), CHARINDEX('.', convert(NVARCHAR(100),@ProductVersion)) - 1),0); + + PRINT 'Informations about this Server:'; + PRINT '@MySessionID: ' + CONVERT(NVARCHAR(100),@@SPID); + PRINT '@ProductVersion: ' + CONVERT(NVARCHAR(100),@ProductVersion); + PRINT '@ProductMainVersion: ' + CONVERT(NVARCHAR(100),@ProductMainVersion); + PRINT '@ProductLevel: ' + CONVERT(NVARCHAR(100),@ProductLevel); + PRINT '@ProductEdition: ' + CONVERT(NVARCHAR(100),@ProductEdition); + ----------------------------------------------------------------------------------------------------------------------------- + + --==============================================-- Prepare the log table --================================================-- + IF (@LOGLEVEL is not NULL) BEGIN + PRINT ''; + IF EXISTS (SELECT * FROM [INFORMATION_SCHEMA].[TABLES] WHERE [TABLE_NAME] = N'TBDD_TEST_PERFORMANCE_LOG') BEGIN + PRINT 'INFO: Log table already exists'; + END; ELSE BEGIN + PRINT 'INFO: Log table does not exist, trying to create...'; + + CREATE TABLE [dbo].[TBDD_TEST_PERFORMANCE_LOG]( + [GUID] [bigint] IDENTITY(1,1) NOT NULL, + [LOG_LEVEL] [NVARCHAR](25) NOT NULL, + [MESSAGE1] [NVARCHAR](max) NOT NULL, + [MESSAGE2] [NVARCHAR](max) NULL, + [MESSAGE3] [NVARCHAR](max) NULL, + [MESSAGE4] [NVARCHAR](max) NULL, + [MESSAGE5] [NVARCHAR](max) NULL, + [COMMENT] [NVARCHAR](max) NULL, + [ADDED_WHO] [NVARCHAR](50) NOT NULL, + [ADDED_WHEN] [datetime] NOT NULL, + CONSTRAINT [PK_TBDD_TEST_PERFORMANCE_LOG_GUID] PRIMARY KEY CLUSTERED + ( + [GUID] ASC + )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, DATA_COMPRESSION = PAGE) ON [PRIMARY] + ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]; + + ALTER TABLE [dbo].[TBDD_TEST_PERFORMANCE_LOG] ADD CONSTRAINT [DF_TBDD_TEST_PERFORMANCE_LOG_ADDED_WHO] DEFAULT (suser_sname()) FOR [ADDED_WHO]; + ALTER TABLE [dbo].[TBDD_TEST_PERFORMANCE_LOG] ADD CONSTRAINT [DF_TBDD_TEST_PERFORMANCE_LOG_ADDED_WHEN] DEFAULT (sysdatetime()) FOR [ADDED_WHEN]; + + END; + END; ELSE BEGIN + PRINT ''; + PRINT 'WARN: Skipping Logging to log table!'; + END; + ----------------------------------------------------------------------------------------------------------------------------- + + + --===============================================-- Check for log table --================================================-- + IF NOT EXISTS (SELECT * FROM [INFORMATION_SCHEMA].[TABLES] WHERE [TABLE_NAME] = N'TBDD_TEST_PERFORMANCE_LOG') BEGIN + SET @LOGLEVEL = 'NONE'; + PRINT 'ERROR: Because the log table [TBDD_TEST_PERFORMANCE_LOG] does not exist, logging is disabled for this run!'; + END; + ----------------------------------------------------------------------------------------------------------------------------- + + + --===============================================-- Log start to table --=================================================-- + IF ((@LOGLEVEL in ('INFO')) and (@return_status is not null) and (@return_status_text is not null)) BEGIN + INSERT INTO [TBDD_TEST_PERFORMANCE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [MESSAGE4], [ADDED_WHO], [ADDED_WHEN]) + VALUES (@LOGLEVEL,'preparing', 'procedure', @return_status, @return_status_text, @MY_PROCEDURE_NAME, GetDate()); + END; + ----------------------------------------------------------------------------------------------------------------------------- + + --===============================================-- Validate target database --============================================-- + IF NOT EXISTS (SELECT 1 FROM [sys].[databases] WHERE [name] = @TARGETDB) BEGIN + SET @return_status = 10; + SET @return_status_text = 'ERROR: Target database [' + @TARGETDB + '] does not exist!'; + PRINT @return_status_text; + + IF ((@LOGLEVEL in ('INFO','WARN','ERROR')) and (@return_status is not null) and (@return_status_text is not null)) BEGIN + INSERT INTO [TBDD_TEST_PERFORMANCE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [MESSAGE4], [ADDED_WHO], [ADDED_WHEN]) + VALUES ('ERROR', 'validation', 'database', @return_status, @return_status_text, @MY_PROCEDURE_NAME, GetDate()); + END; + + RETURN @return_status; + END; + ----------------------------------------------------------------------------------------------------------------------------- + + BEGIN TRY + + --======================================-- Drop and recreate or ensure table --==========================================-- + IF (@DROPANDRECREATE = 1) BEGIN + + SET @return_status_text = 'INFO: Dropping and recreating table ' + @FullTable; + PRINT @return_status_text; + + SET @SQLCommand = N'USE ' + QUOTENAME(@TARGETDB) + N'; + IF OBJECT_ID(''' + @QualifiedTable + ''',''U'') IS NOT NULL + DROP TABLE ' + @QualifiedTable + N'; + + CREATE TABLE ' + @QualifiedTable + N'( + [Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY, + [Payload] BIGINT NOT NULL, + [CreatedAt] DATETIME2(3) NOT NULL DEFAULT SYSUTCDATETIME(), + [Pad] CHAR(' + CONVERT(NVARCHAR(10),@PADLENGTH) + N') NOT NULL DEFAULT REPLICATE(''X'',' + CONVERT(NVARCHAR(10),@PADLENGTH) + N') + );'; + + END; ELSE BEGIN + + SET @return_status_text = 'INFO: Ensuring table ' + @FullTable + ' exists (DROPANDRECREATE = 0)'; + PRINT @return_status_text; + + SET @SQLCommand = N'USE ' + QUOTENAME(@TARGETDB) + N'; + IF NOT EXISTS (SELECT 1 FROM sys.tables WHERE [name] = N''' + @TABLENAME + N''' AND [schema_id] = SCHEMA_ID(N''' + @SCHEMA + N''')) + BEGIN + CREATE TABLE ' + @QualifiedTable + N'( + [Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY, + [Payload] BIGINT NOT NULL, + [CreatedAt] DATETIME2(3) NOT NULL DEFAULT SYSUTCDATETIME(), + [Pad] CHAR(' + CONVERT(NVARCHAR(10),@PADLENGTH) + N') NOT NULL DEFAULT REPLICATE(''X'',' + CONVERT(NVARCHAR(10),@PADLENGTH) + N') + ); + END;'; + + END; + + EXEC @return_status = sp_executesql @SQLCommand; + + IF (@LOGLEVEL in ('INFO','WARN','ERROR')) BEGIN + INSERT INTO [TBDD_TEST_PERFORMANCE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [MESSAGE4], [ADDED_WHO], [ADDED_WHEN]) + VALUES (@LOGLEVEL, 'table', @FullTable, @return_status, @return_status_text, @MY_PROCEDURE_NAME, GetDate()); + END; + ----------------------------------------------------------------------------------------------------------------------------- + + --================================================-- Insert test data --=================================================-- + IF (@ROWCOUNT > 0) and (@return_status = 0) BEGIN + + SET @RowsRemaining = @ROWCOUNT; + SET @RowsInserted = 0; + SET @BatchStart = 1; + SET @BatchNumber = 0; + SET @InsertStart = SYSUTCDATETIME(); + + WHILE (@RowsRemaining > 0) AND (@return_status = 0) BEGIN + + DECLARE @CurrentBatch BIGINT = CASE WHEN @RowsRemaining > @BATCHSIZE THEN @BATCHSIZE ELSE @RowsRemaining END; + + SET @BatchNumber = @BatchNumber + 1; + + SET @SQLCommand = N'USE ' + QUOTENAME(@TARGETDB) + N'; + SET NOCOUNT ON; + ;WITH Numbers AS ( + SELECT TOP (@BatchSize) + ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n + FROM sys.all_objects a + CROSS JOIN sys.all_objects b + CROSS JOIN sys.all_objects c + ) + INSERT INTO ' + @QualifiedTable + N' ([Payload],[CreatedAt],[Pad]) + SELECT + CASE WHEN @RandomData = 1 THEN ABS(CAST(CHECKSUM(NEWID()) AS BIGINT)) ELSE @BatchStart + n - 1 END, + DATEADD(SECOND, @BatchStart + n - 1, SYSUTCDATETIME()), + CASE WHEN @RandomData = 1 + THEN LEFT(REPLICATE(REPLACE(CONVERT(VARCHAR(36), NEWID()), ''-'', ''''), CAST(CEILING(@PadLength / 32.0) AS INT)), @PadLength) + ELSE REPLICATE(''X'', @PadLength) + END + FROM Numbers;'; + + EXEC @return_status = sp_executesql @SQLCommand, + N'@BatchSize BIGINT, @PadLength INT, @BatchStart BIGINT, @RandomData BIT', + @BatchSize = @CurrentBatch, + @PadLength = @PADLENGTH, + @BatchStart = @BatchStart, + @RandomData = @RANDOMDATA; + + IF (@return_status = 0) BEGIN + SET @RowsRemaining = @RowsRemaining - @CurrentBatch; + SET @BatchStart = @BatchStart + @CurrentBatch; + SET @RowsInserted = @RowsInserted + @CurrentBatch; + + SET @return_status_text = 'INFO: Batch ' + CONVERT(NVARCHAR(20),@BatchNumber) + ' inserted ' + CONVERT(NVARCHAR(20),@CurrentBatch) + ' rows (total ' + CONVERT(NVARCHAR(20),@RowsInserted) + ').'; + PRINT @return_status_text; + + IF (@LOGLEVEL in ('INFO','WARN')) BEGIN + INSERT INTO [TBDD_TEST_PERFORMANCE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [MESSAGE4], [ADDED_WHO], [ADDED_WHEN]) + VALUES ('INFO', 'insert_batch', @FullTable, @RowsInserted, @return_status_text, @MY_PROCEDURE_NAME, GetDate()); + END; + + END; ELSE BEGIN + + SET @return_error_text = 'ERROR: Insert batch ' + CONVERT(NVARCHAR(20),@BatchNumber) + ' failed!'; + PRINT @return_error_text; + + IF (@LOGLEVEL in ('INFO','WARN','ERROR')) BEGIN + INSERT INTO [TBDD_TEST_PERFORMANCE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [ADDED_WHO], [ADDED_WHEN]) + VALUES ('ERROR', 'insert_batch', @FullTable, @return_error_text, @MY_PROCEDURE_NAME, GetDate()); + END; + + END; + + END; + + SET @InsertEnd = SYSUTCDATETIME(); + + IF (@return_status = 0) BEGIN + SET @return_status_text = 'INFO: Inserted ' + CONVERT(NVARCHAR(50),@RowsInserted) + ' rows in ' + CONVERT(NVARCHAR(50),CAST(DATEDIFF(MILLISECOND,@InsertStart,@InsertEnd)/1000.0 AS DECIMAL(18,2))) + ' seconds.'; + PRINT @return_status_text; + + IF (@LOGLEVEL in ('INFO','WARN')) BEGIN + INSERT INTO [TBDD_TEST_PERFORMANCE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [MESSAGE4], [ADDED_WHO], [ADDED_WHEN]) + VALUES ('INFO', 'insert_total', @FullTable, @return_status, @return_status_text, @MY_PROCEDURE_NAME, GetDate()); + END; + END; + + END; ELSE BEGIN + + SET @return_status_text = 'WARN: ROWCOUNT was 0, skipping insert!'; + PRINT @return_status_text; + + IF (@LOGLEVEL in ('INFO','WARN')) BEGIN + INSERT INTO [TBDD_TEST_PERFORMANCE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [MESSAGE4], [ADDED_WHO], [ADDED_WHEN]) + VALUES ('WARN', 'insert_total', @FullTable, @return_status, @return_status_text, @MY_PROCEDURE_NAME, GetDate()); + END; + + END; + ----------------------------------------------------------------------------------------------------------------------------- + + --================================================-- Query the test data --================================================-- + IF (@return_status = 0) BEGIN + + SET @return_status_text = 'INFO: Running query phase for table ' + @FullTable; + PRINT @return_status_text; + + SET @SQLCommand = N'USE ' + QUOTENAME(@TARGETDB) + N'; + SELECT COUNT(*) AS TotalRows, MIN(Id) AS MinId, MAX(Id) AS MaxId FROM ' + @QualifiedTable + N'; + SELECT TOP (10) * FROM ' + @QualifiedTable + N' ORDER BY Id DESC; + SELECT AVG(CONVERT(FLOAT, [Payload])) AS AvgPayload FROM ' + @QualifiedTable + N';'; + + EXEC @return_status = sp_executesql @SQLCommand; + + IF (@LOGLEVEL in ('INFO','WARN','ERROR')) BEGIN + INSERT INTO [TBDD_TEST_PERFORMANCE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [MESSAGE4], [ADDED_WHO], [ADDED_WHEN]) + VALUES (@LOGLEVEL, 'query', @FullTable, @return_status, @return_status_text, @MY_PROCEDURE_NAME, GetDate()); + END; + + END; + ----------------------------------------------------------------------------------------------------------------------------- + + END TRY BEGIN CATCH + + -- Handle any errors that occur during the process. + SELECT @return_status = ERROR_NUMBER(), @return_error_text = ERROR_MESSAGE(); + + SET @return_status_text = 'ERROR: ' + @return_error_text; + PRINT @return_status_text; + + IF ((@LOGLEVEL in ('INFO','WARN','ERROR')) and (@return_status is not null) and (@return_status_text is not null)) BEGIN + INSERT INTO [TBDD_TEST_PERFORMANCE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [MESSAGE4], [ADDED_WHO], [ADDED_WHEN]) + VALUES ('ERROR', 'catch', @FullTable, @return_status, @return_status_text, @MY_PROCEDURE_NAME, GetDate()); + END; + + END CATCH; + ----------------------------------------------------------------------------------------------------------------------------- + + SET @return_status_text = 'END PROCEDURE [' + @MY_PROCEDURE_NAME + '] @ ' + CONVERT(varchar(50),GETDATE(),120); + + --================================================-- Log end to table --===================================================-- + IF ((@LOGLEVEL in ('INFO')) and (@return_status is not null) and (@return_status_text is not null)) BEGIN + INSERT INTO [TBDD_TEST_PERFORMANCE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [MESSAGE4], [ADDED_WHO], [ADDED_WHEN]) + VALUES (@LOGLEVEL, 'closing', 'procedure', @return_status, @return_status_text, @MY_PROCEDURE_NAME, GetDate()); + END; + ----------------------------------------------------------------------------------------------------------------------------- + + PRINT ''; + PRINT @return_status_text; + PRINT '===================================================================================================='; + + Return @return_status; + +END; +GO + +-- Example execution: +-- EXEC dbo.PRDD_TEST_PERFORMANCE @pTARGETDB = 'DD_ECM', @pROWCOUNT = 1000000, @pBATCHSIZE = 100000, @pDROPANDRECREATE = 1; diff --git a/current/[DD_ECM]-Database/[FNCUST_GET_EDMI_ITEM_VALUE]/[TBEDMI_ITEM_VALUE].sql b/current/[DD_ECM]-Database/[FNCUST_GET_EDMI_ITEM_VALUE]/[TBEDMI_ITEM_VALUE].sql new file mode 100644 index 0000000..0532b03 --- /dev/null +++ b/current/[DD_ECM]-Database/[FNCUST_GET_EDMI_ITEM_VALUE]/[TBEDMI_ITEM_VALUE].sql @@ -0,0 +1,35 @@ +USE [DD_ECM] +GO + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +CREATE TABLE [dbo].[TBEDMI_ITEM_VALUE]( + [GUID] [bigint] IDENTITY(1,1) NOT NULL, + [REFERENCE_GUID] [nvarchar](250) NULL, + [ITEM_DESCRIPTION] [nvarchar](250) NULL, + [ITEM_VALUE] [nvarchar](4000) NULL, + [CREATEDWHEN] [datetime] NOT NULL, + [CREATEDWHO] [nvarchar](100) NULL, + [CHANGEDWHEN] [datetime] NULL, + [GROUP_COUNTER] [int] NULL, + [SPEC_NAME] [nvarchar](100) NULL, + [IS_REQUIRED] [bit] NOT NULL, + [CHANGEDWHO] [varchar](100) NULL, + [COMMENT] [varchar](3000) NULL, + CONSTRAINT [PK_TBEDMI_ITEM_VALUE] PRIMARY KEY CLUSTERED +( + [GUID] ASC +)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 80, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY] +) ON [PRIMARY] +GO + +ALTER TABLE [dbo].[TBEDMI_ITEM_VALUE] ADD CONSTRAINT [DF__TBEDMI_IT__CREAT__04EFA97D] DEFAULT (getdate()) FOR [CREATEDWHEN] +GO + +ALTER TABLE [dbo].[TBEDMI_ITEM_VALUE] ADD CONSTRAINT [DF__TBEDMI_IT__IS_RE__05E3CDB6] DEFAULT ((0)) FOR [IS_REQUIRED] +GO + + diff --git a/current/[DD_IIM]-Database/[MASTER_DEPLOY].sql b/current/[DD_IIM]-Database/[MASTER_DEPLOY].sql new file mode 100644 index 0000000..c3dd45e --- /dev/null +++ b/current/[DD_IIM]-Database/[MASTER_DEPLOY].sql @@ -0,0 +1,36 @@ +/* ============================================================================ + MASTER DEPLOY + Führt die getrennten Deploy-Skripte in korrekter Reihenfolge aus. + + WICHTIG: + - Dieses Skript benötigt SQLCMD-Modus (SSMS/ADS). + - Ausführung im gleichen Verzeichnis wie die referenzierten Dateien. + ============================================================================ */ + +:on error exit + +PRINT 'Starte Deploy: Schema'; +:r "[SCHEMA_META].sql" + +PRINT 'Starte Deploy: Tabelle'; +:r "[TBDD_CFG_SYSTEM_INFO].sql" + +PRINT 'Starte Deploy: Prozeduren'; +:r "[TBDD_CFG_SYSTEM_INFO_PROCEDURES].sql" + +PRINT 'Starte Deploy: Trigger'; +:r "[TBDD_CFG_SYSTEM_INFO_TRIGGER].sql" + +PRINT 'Starte Deploy: Tabelle FUNCTION_MODULE'; +:r "[TBDD_CFG_FUNCTION_MODULE].sql" + +PRINT 'Starte Deploy: Prozeduren FUNCTION_MODULE'; +:r "[TBDD_CFG_FUNCTION_MODULE_PROCEDURES].sql" + +PRINT 'Starte Deploy: Trigger FUNCTION_MODULE'; +:r "[TBDD_CFG_FUNCTION_MODULE_TRIGGER].sql" + +PRINT 'Starte Deploy: Security Baseline'; +:r "[SECURITY_META_CFG].sql" + +PRINT 'Deploy abgeschlossen.'; diff --git a/current/[DD_IIM]-Database/[SCHEMA_META].sql b/current/[DD_IIM]-Database/[SCHEMA_META].sql new file mode 100644 index 0000000..6eaa387 --- /dev/null +++ b/current/[DD_IIM]-Database/[SCHEMA_META].sql @@ -0,0 +1,12 @@ +/* ============================================================================ + META – SCHEMA-SKRIPT + ============================================================================ */ + +USE [DD_IIM]; +GO + +IF SCHEMA_ID(N'_meta') IS NULL +BEGIN + EXEC(N'CREATE SCHEMA [_meta] AUTHORIZATION [dbo];'); +END; +GO diff --git a/current/[DD_IIM]-Database/[SECURITY_META_CFG].sql b/current/[DD_IIM]-Database/[SECURITY_META_CFG].sql new file mode 100644 index 0000000..da55559 --- /dev/null +++ b/current/[DD_IIM]-Database/[SECURITY_META_CFG].sql @@ -0,0 +1,28 @@ +/* ============================================================================ + META – SECURITY BASELINE + Ziel: Direkte DML auf Konfigurationstabellen unterbinden, + Zugriff über freigegebene Prozeduren steuern. + ============================================================================ */ + +USE [DD_IIM]; +GO + +IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name = N'RL_META_CFG_EXEC') +BEGIN + CREATE ROLE [RL_META_CFG_EXEC] AUTHORIZATION [dbo]; +END; +GO + +DENY INSERT, UPDATE, DELETE ON OBJECT::[_meta].[TBDD_CFG_SYSTEM_INFO] TO [public]; +DENY INSERT, UPDATE, DELETE ON OBJECT::[_meta].[TBDD_CFG_FUNCTION_MODULE] TO [public]; +GO + +GRANT EXECUTE ON OBJECT::[_meta].[PRDD_UPSERT_SYSTEM_INFO] TO [RL_META_CFG_EXEC]; +GRANT EXECUTE ON OBJECT::[_meta].[PRDD_DELETE_SYSTEM_INFO] TO [RL_META_CFG_EXEC]; +GRANT EXECUTE ON OBJECT::[_meta].[PRDD_UPSERT_FUNCTION_MODULE] TO [RL_META_CFG_EXEC]; +GRANT EXECUTE ON OBJECT::[_meta].[PRDD_DELETE_FUNCTION_MODULE] TO [RL_META_CFG_EXEC]; +GO + +/* Mitgliedschaften projektspezifisch vergeben, z. B.: +ALTER ROLE [RL_META_CFG_EXEC] ADD MEMBER []; +*/ diff --git a/current/[DD_IIM]-Database/[TBDD_CFG_FUNCTION_MODULE].sql b/current/[DD_IIM]-Database/[TBDD_CFG_FUNCTION_MODULE].sql new file mode 100644 index 0000000..59284d5 --- /dev/null +++ b/current/[DD_IIM]-Database/[TBDD_CFG_FUNCTION_MODULE].sql @@ -0,0 +1,83 @@ +USE [DD_IIM] +GO + +SET ANSI_NULLS ON +GO + +SET QUOTED_IDENTIFIER ON +GO + +IF OBJECT_ID(N'_meta.TBDD_CFG_FUNCTION_MODULE', N'U') IS NULL +BEGIN + CREATE TABLE [_meta].[TBDD_CFG_FUNCTION_MODULE] + ( + [PK_CFG_FUNCTION_MODULE_ID] [bigint] IDENTITY(1,1) NOT NULL, + [ACTIVE] [bit] NOT NULL, + [INTERNAL] [bit] NOT NULL, + [FUNCTION_NAME] [nvarchar](50) COLLATE Latin1_General_CI_AS NOT NULL, + [FUNCTION_TYPE] [nvarchar](10) COLLATE Latin1_General_CI_AS NOT NULL, + [FUNCTION_DEFINITION] [nvarchar](max) COLLATE Latin1_General_CI_AS NOT NULL, + [COMMENT] [nvarchar](500) COLLATE Latin1_General_CI_AS NULL, + [VERSION] [smallint] NOT NULL, + [CREATED_WHO] [bigint] NOT NULL, + [CREATED_WHEN] [datetime2](0) NOT NULL, + [CHANGED_WHO] [bigint] NULL, + [CHANGED_WHEN] [datetime2](0) NULL, + + CONSTRAINT [TBDD_CFG_FUNCTION_MODULE_primaryKey] PRIMARY KEY NONCLUSTERED HASH + ( + [PK_CFG_FUNCTION_MODULE_ID] + )WITH ( BUCKET_COUNT = 65536) + )WITH ( MEMORY_OPTIMIZED = ON , DURABILITY = SCHEMA_AND_DATA ); +END; +GO + +IF NOT EXISTS +( + SELECT 1 + FROM sys.default_constraints dc + JOIN sys.columns c + ON c.object_id = dc.parent_object_id + AND c.column_id = dc.parent_column_id + WHERE dc.parent_object_id = OBJECT_ID(N'_meta.TBDD_CFG_FUNCTION_MODULE', N'U') + AND c.name = N'ACTIVE' +) +BEGIN + ALTER TABLE [_meta].[TBDD_CFG_FUNCTION_MODULE] + ADD CONSTRAINT [DF_TBDD_CFG_FUNCTION_MODULE_ACTIVE] DEFAULT ((1)) FOR [ACTIVE]; +END; +GO + +IF NOT EXISTS +( + SELECT 1 + FROM sys.default_constraints dc + JOIN sys.columns c + ON c.object_id = dc.parent_object_id + AND c.column_id = dc.parent_column_id + WHERE dc.parent_object_id = OBJECT_ID(N'_meta.TBDD_CFG_FUNCTION_MODULE', N'U') + AND c.name = N'INTERNAL' +) +BEGIN + ALTER TABLE [_meta].[TBDD_CFG_FUNCTION_MODULE] + ADD CONSTRAINT [DF_TBDD_CFG_FUNCTION_MODULE_INTERNAL] DEFAULT ((0)) FOR [INTERNAL]; +END; +GO + +IF NOT EXISTS +( + SELECT 1 + FROM sys.default_constraints dc + JOIN sys.columns c + ON c.object_id = dc.parent_object_id + AND c.column_id = dc.parent_column_id + WHERE dc.parent_object_id = OBJECT_ID(N'_meta.TBDD_CFG_FUNCTION_MODULE', N'U') + AND c.name = N'VERSION' +) +BEGIN + ALTER TABLE [_meta].[TBDD_CFG_FUNCTION_MODULE] + ADD CONSTRAINT [DF_TBDD_CFG_FUNCTION_MODULE_VERSION] DEFAULT ((1)) FOR [VERSION]; +END; +GO + + diff --git a/current/[DD_IIM]-Database/[TBDD_CFG_FUNCTION_MODULE_PROCEDURES].sql b/current/[DD_IIM]-Database/[TBDD_CFG_FUNCTION_MODULE_PROCEDURES].sql new file mode 100644 index 0000000..dfbdb07 --- /dev/null +++ b/current/[DD_IIM]-Database/[TBDD_CFG_FUNCTION_MODULE_PROCEDURES].sql @@ -0,0 +1,207 @@ +/* ============================================================================ + FUNCTION_MODULE – PROZEDUREN + Voraussetzung: Tabelle [_meta].[TBDD_CFG_FUNCTION_MODULE] existiert + ============================================================================ */ + +USE [DD_IIM]; +GO + +CREATE OR ALTER PROCEDURE [_meta].[PRDD_UPSERT_FUNCTION_MODULE] + @PK_CFG_FUNCTION_MODULE_ID BIGINT = NULL, + @ACTIVE BIT, + @INTERNAL BIT, + @FUNCTION_NAME NVARCHAR(50), + @FUNCTION_TYPE NVARCHAR(10), + @FUNCTION_DEFINITION NVARCHAR(MAX), + @COMMENT NVARCHAR(500) = NULL, + @VERSION SMALLINT = 1, + @CREATED_WHO BIGINT, + @CREATED_WHEN DATETIME2(0), + @CHANGED_WHO BIGINT = NULL, + @CHANGED_WHEN DATETIME2(0) = NULL, + @OUT_PK_CFG_FUNCTION_MODULE_ID BIGINT OUTPUT +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @identity_insert_enabled BIT = 0; + DECLARE @next_insert_id BIGINT; + DECLARE @app_lock_result INT; + + BEGIN TRY + SET CONTEXT_INFO 0x544244445F46554E4354494F4E5F4D4F44554C45; + + IF @PK_CFG_FUNCTION_MODULE_ID IS NOT NULL + BEGIN + UPDATE [_meta].[TBDD_CFG_FUNCTION_MODULE] + SET [ACTIVE] = @ACTIVE, + [INTERNAL] = @INTERNAL, + [FUNCTION_NAME] = @FUNCTION_NAME, + [FUNCTION_TYPE] = @FUNCTION_TYPE, + [FUNCTION_DEFINITION] = @FUNCTION_DEFINITION, + [COMMENT] = @COMMENT, + [VERSION] = @VERSION, + [CHANGED_WHO] = @CHANGED_WHO, + [CHANGED_WHEN] = @CHANGED_WHEN + WHERE [PK_CFG_FUNCTION_MODULE_ID] = @PK_CFG_FUNCTION_MODULE_ID; + + IF @@ROWCOUNT = 1 + BEGIN + SET @OUT_PK_CFG_FUNCTION_MODULE_ID = @PK_CFG_FUNCTION_MODULE_ID; + END + ELSE + BEGIN + IF @PK_CFG_FUNCTION_MODULE_ID < 100001 + BEGIN + THROW 52011, 'Explizite PK_CFG_FUNCTION_MODULE_ID muss >= 100001 sein.', 1; + END; + + SET @identity_insert_enabled = 1; + SET IDENTITY_INSERT [_meta].[TBDD_CFG_FUNCTION_MODULE] ON; + + INSERT INTO [_meta].[TBDD_CFG_FUNCTION_MODULE] + ( + [PK_CFG_FUNCTION_MODULE_ID], + [ACTIVE], + [INTERNAL], + [FUNCTION_NAME], + [FUNCTION_TYPE], + [FUNCTION_DEFINITION], + [COMMENT], + [VERSION], + [CREATED_WHO], + [CREATED_WHEN], + [CHANGED_WHO], + [CHANGED_WHEN] + ) + VALUES + ( + @PK_CFG_FUNCTION_MODULE_ID, + @ACTIVE, + 0, + @FUNCTION_NAME, + @FUNCTION_TYPE, + @FUNCTION_DEFINITION, + @COMMENT, + @VERSION, + @CREATED_WHO, + @CREATED_WHEN, + @CHANGED_WHO, + @CHANGED_WHEN + ); + + SET IDENTITY_INSERT [_meta].[TBDD_CFG_FUNCTION_MODULE] OFF; + SET @identity_insert_enabled = 0; + + SET @OUT_PK_CFG_FUNCTION_MODULE_ID = @PK_CFG_FUNCTION_MODULE_ID; + END; + END + ELSE + BEGIN + EXEC @app_lock_result = sys.sp_getapplock + @Resource = N'_meta.PRDD_UPSERT_FUNCTION_MODULE.IDENTITY_RANGE', + @LockMode = N'Exclusive', + @LockOwner = N'Session', + @LockTimeout = 10000; + + IF @app_lock_result < 0 + BEGIN + THROW 52010, 'Konnte keine exklusive ID-Sperre für [_meta].[TBDD_CFG_FUNCTION_MODULE] erhalten.', 1; + END; + + SELECT @next_insert_id = CASE + WHEN MAX([PK_CFG_FUNCTION_MODULE_ID]) IS NULL OR MAX([PK_CFG_FUNCTION_MODULE_ID]) < 100000 THEN 100001 + ELSE MAX([PK_CFG_FUNCTION_MODULE_ID]) + 1 + END + FROM [_meta].[TBDD_CFG_FUNCTION_MODULE]; + + SET @identity_insert_enabled = 1; + SET IDENTITY_INSERT [_meta].[TBDD_CFG_FUNCTION_MODULE] ON; + + INSERT INTO [_meta].[TBDD_CFG_FUNCTION_MODULE] + ( + [PK_CFG_FUNCTION_MODULE_ID], + [ACTIVE], + [INTERNAL], + [FUNCTION_NAME], + [FUNCTION_TYPE], + [FUNCTION_DEFINITION], + [COMMENT], + [VERSION], + [CREATED_WHO], + [CREATED_WHEN], + [CHANGED_WHO], + [CHANGED_WHEN] + ) + VALUES + ( + @next_insert_id, + @ACTIVE, + 0, + @FUNCTION_NAME, + @FUNCTION_TYPE, + @FUNCTION_DEFINITION, + @COMMENT, + @VERSION, + @CREATED_WHO, + @CREATED_WHEN, + @CHANGED_WHO, + @CHANGED_WHEN + ); + + SET IDENTITY_INSERT [_meta].[TBDD_CFG_FUNCTION_MODULE] OFF; + SET @identity_insert_enabled = 0; + + EXEC sys.sp_releaseapplock + @Resource = N'_meta.PRDD_UPSERT_FUNCTION_MODULE.IDENTITY_RANGE', + @LockOwner = N'Session'; + + SET @OUT_PK_CFG_FUNCTION_MODULE_ID = @next_insert_id; + END; + + SET CONTEXT_INFO 0x00; + END TRY + BEGIN CATCH + IF @identity_insert_enabled = 1 + BEGIN + BEGIN TRY + SET IDENTITY_INSERT [_meta].[TBDD_CFG_FUNCTION_MODULE] OFF; + END TRY + BEGIN CATCH + END CATCH + END; + + BEGIN TRY + EXEC sys.sp_releaseapplock + @Resource = N'_meta.PRDD_UPSERT_FUNCTION_MODULE.IDENTITY_RANGE', + @LockOwner = N'Session'; + END TRY + BEGIN CATCH + END CATCH + + SET CONTEXT_INFO 0x00; + THROW; + END CATCH +END; +GO + +CREATE OR ALTER PROCEDURE [_meta].[PRDD_DELETE_FUNCTION_MODULE] + @PK_CFG_FUNCTION_MODULE_ID BIGINT +AS +BEGIN + SET NOCOUNT ON; + + BEGIN TRY + SET CONTEXT_INFO 0x544244445F46554E4354494F4E5F4D4F44554C45; + + DELETE FROM [_meta].[TBDD_CFG_FUNCTION_MODULE] + WHERE [PK_CFG_FUNCTION_MODULE_ID] = @PK_CFG_FUNCTION_MODULE_ID; + + SET CONTEXT_INFO 0x00; + END TRY + BEGIN CATCH + SET CONTEXT_INFO 0x00; + THROW; + END CATCH +END; +GO diff --git a/current/[DD_IIM]-Database/[TBDD_CFG_FUNCTION_MODULE_TRIGGER].sql b/current/[DD_IIM]-Database/[TBDD_CFG_FUNCTION_MODULE_TRIGGER].sql new file mode 100644 index 0000000..34aa915 --- /dev/null +++ b/current/[DD_IIM]-Database/[TBDD_CFG_FUNCTION_MODULE_TRIGGER].sql @@ -0,0 +1,58 @@ +/* ============================================================================ + FUNCTION_MODULE – TRIGGER + Voraussetzung: Tabelle [_meta].[TBDD_CFG_FUNCTION_MODULE] und Prozeduren existieren + ============================================================================ */ + +USE [DD_IIM]; +GO + +CREATE OR ALTER TRIGGER [_meta].[TBDD_CFG_FUNCTION_MODULE_IO_INS] +ON [_meta].[TBDD_CFG_FUNCTION_MODULE] +WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER +AFTER INSERT +AS +BEGIN ATOMIC WITH +( + TRANSACTION ISOLATION LEVEL = SNAPSHOT, + LANGUAGE = N'us_english' +) + IF CONTEXT_INFO() IS NULL OR CONTEXT_INFO() <> 0x544244445F46554E4354494F4E5F4D4F44554C45 + BEGIN + THROW 51101, 'Direktes INSERT auf [_meta].[TBDD_CFG_FUNCTION_MODULE] ist nicht erlaubt. Bitte Prozedur [_meta].[PRDD_UPSERT_FUNCTION_MODULE] verwenden.', 1; + END; +END; +GO + +CREATE OR ALTER TRIGGER [_meta].[TBDD_CFG_FUNCTION_MODULE_IO_UPD] +ON [_meta].[TBDD_CFG_FUNCTION_MODULE] +WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER +AFTER UPDATE +AS +BEGIN ATOMIC WITH +( + TRANSACTION ISOLATION LEVEL = SNAPSHOT, + LANGUAGE = N'us_english' +) + IF CONTEXT_INFO() IS NULL OR CONTEXT_INFO() <> 0x544244445F46554E4354494F4E5F4D4F44554C45 + BEGIN + THROW 51102, 'Direktes UPDATE auf [_meta].[TBDD_CFG_FUNCTION_MODULE] ist nicht erlaubt. Bitte Prozedur [_meta].[PRDD_UPSERT_FUNCTION_MODULE] verwenden.', 1; + END; +END; +GO + +CREATE OR ALTER TRIGGER [_meta].[TBDD_CFG_FUNCTION_MODULE_IO_DEL] +ON [_meta].[TBDD_CFG_FUNCTION_MODULE] +WITH NATIVE_COMPILATION, SCHEMABINDING, EXECUTE AS OWNER +AFTER DELETE +AS +BEGIN ATOMIC WITH +( + TRANSACTION ISOLATION LEVEL = SNAPSHOT, + LANGUAGE = N'us_english' +) + IF CONTEXT_INFO() IS NULL OR CONTEXT_INFO() <> 0x544244445F46554E4354494F4E5F4D4F44554C45 + BEGIN + THROW 51103, 'Direktes DELETE auf [_meta].[TBDD_CFG_FUNCTION_MODULE] ist nicht erlaubt. Bitte Prozedur [_meta].[PRDD_DELETE_FUNCTION_MODULE] verwenden.', 1; + END; +END; +GO diff --git a/current/[DD_IIM]-Database/[TBDD_CFG_SYSTEM_INFO].sql b/current/[DD_IIM]-Database/[TBDD_CFG_SYSTEM_INFO].sql new file mode 100644 index 0000000..caf498e --- /dev/null +++ b/current/[DD_IIM]-Database/[TBDD_CFG_SYSTEM_INFO].sql @@ -0,0 +1,74 @@ +/* ============================================================================ + SYSTEM_INFO – TABELLEN-SKRIPT + Voraussetzung: Schema [_meta] existiert (siehe [SCHEMA_META].sql) + ============================================================================ */ + +USE [DD_IIM]; +GO + +SET NOCOUNT ON; +SET XACT_ABORT ON; + +BEGIN TRY + BEGIN TRAN; + + IF OBJECT_ID(N'_meta.TBDD_CFG_SYSTEM_INFO', N'U') IS NULL + BEGIN + CREATE TABLE [_meta].[TBDD_CFG_SYSTEM_INFO] + ( + [PK_CFG_SYSTEM_INFO_ID] BIGINT IDENTITY(1,1) NOT NULL, + [SYSTEM_VERSION] NVARCHAR(50) NOT NULL, + [COMMENT] NVARCHAR(4000) NULL, + [CREATED_WHO] BIGINT NOT NULL, + [CREATED_WHEN] DATETIME2(0) NOT NULL, + [CHANGED_WHO] BIGINT NULL, + [CHANGED_WHEN] DATETIME2(0) NULL + ); + END; + + IF NOT EXISTS + ( + SELECT 1 + FROM sys.key_constraints kc + JOIN sys.tables t ON t.object_id = kc.parent_object_id + JOIN sys.schemas s ON s.schema_id = t.schema_id + WHERE s.name = N'_meta' + AND t.name = N'TBDD_CFG_SYSTEM_INFO' + AND kc.type = N'PK' + ) + BEGIN + ALTER TABLE [_meta].[TBDD_CFG_SYSTEM_INFO] + ADD CONSTRAINT [PK_CFG_SYSTEM_INFO_ID] + PRIMARY KEY CLUSTERED ([PK_CFG_SYSTEM_INFO_ID]); + END; + + IF NOT EXISTS (SELECT 1 FROM [_meta].[TBDD_CFG_SYSTEM_INFO] WITH (HOLDLOCK, UPDLOCK)) + BEGIN + INSERT INTO [_meta].[TBDD_CFG_SYSTEM_INFO] + ( + [SYSTEM_VERSION], + [COMMENT], + [CREATED_WHO], + [CREATED_WHEN] + ) + VALUES + ( + N'1.0.0.0', + N'Initiale Anlage', + 1, + GETDATE() + ); + END; + + COMMIT TRAN; +END TRY +BEGIN CATCH + IF @@TRANCOUNT > 0 ROLLBACK TRAN; + + DECLARE @msg NVARCHAR(4000) = ERROR_MESSAGE(); + DECLARE @num INT = ERROR_NUMBER(); + DECLARE @sev INT = ERROR_SEVERITY(); + DECLARE @stt INT = ERROR_STATE(); + RAISERROR(N'Fehler %d: %s', @sev, @stt, @num, @msg); +END CATCH; +GO diff --git a/current/[DD_IIM]-Database/[TBDD_CFG_SYSTEM_INFO_PROCEDURES].sql b/current/[DD_IIM]-Database/[TBDD_CFG_SYSTEM_INFO_PROCEDURES].sql new file mode 100644 index 0000000..d66a72d --- /dev/null +++ b/current/[DD_IIM]-Database/[TBDD_CFG_SYSTEM_INFO_PROCEDURES].sql @@ -0,0 +1,139 @@ +/* ============================================================================ + SYSTEM_INFO – PROZEDUREN + Voraussetzung: Tabelle [_meta].[TBDD_CFG_SYSTEM_INFO] existiert + ============================================================================ */ + +USE [DD_IIM]; +GO + +DROP PROCEDURE IF EXISTS [_meta].[PRDD_INSERT_SYSTEM_INFO]; +DROP PROCEDURE IF EXISTS [_meta].[PRDD_UPDATE_SYSTEM_INFO]; +GO + +CREATE OR ALTER PROCEDURE [_meta].[PRDD_UPSERT_SYSTEM_INFO] + @PK_CFG_SYSTEM_INFO_ID BIGINT = NULL, + @SYSTEM_VERSION NVARCHAR(50), + @COMMENT NVARCHAR(4000) = NULL, + @CREATED_WHO BIGINT, + @CREATED_WHEN DATETIME2(0), + @CHANGED_WHO BIGINT = NULL, + @CHANGED_WHEN DATETIME2(0) = NULL, + @OUT_PK_CFG_SYSTEM_INFO_ID BIGINT OUTPUT +AS +BEGIN + SET NOCOUNT ON; + + DECLARE @identity_insert_enabled BIT = 0; + + BEGIN TRY + EXEC sys.sp_set_session_context @key = N'_meta_allow_tbdd_system_info_dml', @value = 1; + + IF @PK_CFG_SYSTEM_INFO_ID IS NULL + BEGIN + EXEC sys.sp_set_session_context @key = N'_meta_tbdd_system_info_use_input_pk', @value = 0; + + INSERT INTO [_meta].[TBDD_CFG_SYSTEM_INFO] + ( + [SYSTEM_VERSION], + [COMMENT], + [CREATED_WHO], + [CREATED_WHEN], + [CHANGED_WHO], + [CHANGED_WHEN] + ) + VALUES + ( + @SYSTEM_VERSION, + @COMMENT, + @CREATED_WHO, + @CREATED_WHEN, + @CHANGED_WHO, + @CHANGED_WHEN + ); + + SET @OUT_PK_CFG_SYSTEM_INFO_ID = CAST(@@IDENTITY AS BIGINT); + END + ELSE + BEGIN + UPDATE [_meta].[TBDD_CFG_SYSTEM_INFO] + SET [SYSTEM_VERSION] = @SYSTEM_VERSION, + [COMMENT] = @COMMENT, + [CHANGED_WHO] = @CHANGED_WHO, + [CHANGED_WHEN] = @CHANGED_WHEN + WHERE [PK_CFG_SYSTEM_INFO_ID] = @PK_CFG_SYSTEM_INFO_ID; + + IF @@ROWCOUNT = 0 + BEGIN + SET @identity_insert_enabled = 1; + EXEC sys.sp_set_session_context @key = N'_meta_tbdd_system_info_use_input_pk', @value = 1; + SET IDENTITY_INSERT [_meta].[TBDD_CFG_SYSTEM_INFO] ON; + + INSERT INTO [_meta].[TBDD_CFG_SYSTEM_INFO] + ( + [PK_CFG_SYSTEM_INFO_ID], + [SYSTEM_VERSION], + [COMMENT], + [CREATED_WHO], + [CREATED_WHEN], + [CHANGED_WHO], + [CHANGED_WHEN] + ) + VALUES + ( + @PK_CFG_SYSTEM_INFO_ID, + @SYSTEM_VERSION, + @COMMENT, + @CREATED_WHO, + @CREATED_WHEN, + @CHANGED_WHO, + @CHANGED_WHEN + ); + + SET IDENTITY_INSERT [_meta].[TBDD_CFG_SYSTEM_INFO] OFF; + SET @identity_insert_enabled = 0; + EXEC sys.sp_set_session_context @key = N'_meta_tbdd_system_info_use_input_pk', @value = 0; + END; + + SET @OUT_PK_CFG_SYSTEM_INFO_ID = @PK_CFG_SYSTEM_INFO_ID; + END; + + EXEC sys.sp_set_session_context @key = N'_meta_tbdd_system_info_use_input_pk', @value = NULL; + EXEC sys.sp_set_session_context @key = N'_meta_allow_tbdd_system_info_dml', @value = NULL; + END TRY + BEGIN CATCH + IF @identity_insert_enabled = 1 + BEGIN + BEGIN TRY + SET IDENTITY_INSERT [_meta].[TBDD_CFG_SYSTEM_INFO] OFF; + END TRY + BEGIN CATCH + END CATCH + END; + + EXEC sys.sp_set_session_context @key = N'_meta_tbdd_system_info_use_input_pk', @value = NULL; + EXEC sys.sp_set_session_context @key = N'_meta_allow_tbdd_system_info_dml', @value = NULL; + THROW; + END CATCH +END; +GO + +CREATE OR ALTER PROCEDURE [_meta].[PRDD_DELETE_SYSTEM_INFO] + @PK_CFG_SYSTEM_INFO_ID BIGINT +AS +BEGIN + SET NOCOUNT ON; + + BEGIN TRY + EXEC sys.sp_set_session_context @key = N'_meta_allow_tbdd_system_info_dml', @value = 1; + + DELETE FROM [_meta].[TBDD_CFG_SYSTEM_INFO] + WHERE [PK_CFG_SYSTEM_INFO_ID] = @PK_CFG_SYSTEM_INFO_ID; + + EXEC sys.sp_set_session_context @key = N'_meta_allow_tbdd_system_info_dml', @value = NULL; + END TRY + BEGIN CATCH + EXEC sys.sp_set_session_context @key = N'_meta_allow_tbdd_system_info_dml', @value = NULL; + THROW; + END CATCH +END; +GO diff --git a/current/[DD_IIM]-Database/[TBDD_CFG_SYSTEM_INFO_TRIGGER].sql b/current/[DD_IIM]-Database/[TBDD_CFG_SYSTEM_INFO_TRIGGER].sql new file mode 100644 index 0000000..cfd2f14 --- /dev/null +++ b/current/[DD_IIM]-Database/[TBDD_CFG_SYSTEM_INFO_TRIGGER].sql @@ -0,0 +1,114 @@ +/* ============================================================================ + SYSTEM_INFO – TRIGGER + Voraussetzung: Tabelle [_meta].[TBDD_CFG_SYSTEM_INFO] und Prozeduren existieren + ============================================================================ */ + +USE [DD_IIM]; +GO + +CREATE OR ALTER TRIGGER [_meta].[TBDD_CFG_SYSTEM_INFO_IO_INS] +ON [_meta].[TBDD_CFG_SYSTEM_INFO] +INSTEAD OF INSERT +AS +BEGIN + SET NOCOUNT ON; + + IF TRY_CAST(SESSION_CONTEXT(N'_meta_allow_tbdd_system_info_dml') AS bit) = 1 + BEGIN + IF TRY_CAST(SESSION_CONTEXT(N'_meta_tbdd_system_info_use_input_pk') AS bit) = 1 + BEGIN + INSERT INTO [_meta].[TBDD_CFG_SYSTEM_INFO] + ( + [PK_CFG_SYSTEM_INFO_ID], + [SYSTEM_VERSION], + [COMMENT], + [CREATED_WHO], + [CREATED_WHEN], + [CHANGED_WHO], + [CHANGED_WHEN] + ) + SELECT + i.[PK_CFG_SYSTEM_INFO_ID], + i.[SYSTEM_VERSION], + i.[COMMENT], + i.[CREATED_WHO], + i.[CREATED_WHEN], + i.[CHANGED_WHO], + i.[CHANGED_WHEN] + FROM inserted i; + END + ELSE + BEGIN + INSERT INTO [_meta].[TBDD_CFG_SYSTEM_INFO] + ( + [SYSTEM_VERSION], + [COMMENT], + [CREATED_WHO], + [CREATED_WHEN], + [CHANGED_WHO], + [CHANGED_WHEN] + ) + SELECT + i.[SYSTEM_VERSION], + i.[COMMENT], + i.[CREATED_WHO], + i.[CREATED_WHEN], + i.[CHANGED_WHO], + i.[CHANGED_WHEN] + FROM inserted i; + END; + + RETURN; + END; + + THROW 51001, 'Direktes INSERT auf [_meta].[TBDD_CFG_SYSTEM_INFO] ist nicht erlaubt. Bitte Prozedur [_meta].[PRDD_UPSERT_SYSTEM_INFO] verwenden.', 1; +END; +GO + +CREATE OR ALTER TRIGGER [_meta].[TBDD_CFG_SYSTEM_INFO_IO_UPD] +ON [_meta].[TBDD_CFG_SYSTEM_INFO] +INSTEAD OF UPDATE +AS +BEGIN + SET NOCOUNT ON; + + IF TRY_CAST(SESSION_CONTEXT(N'_meta_allow_tbdd_system_info_dml') AS bit) = 1 + BEGIN + UPDATE t + SET t.[SYSTEM_VERSION] = i.[SYSTEM_VERSION], + t.[COMMENT] = i.[COMMENT], + t.[CREATED_WHO] = i.[CREATED_WHO], + t.[CREATED_WHEN] = i.[CREATED_WHEN], + t.[CHANGED_WHO] = i.[CHANGED_WHO], + t.[CHANGED_WHEN] = i.[CHANGED_WHEN] + FROM [_meta].[TBDD_CFG_SYSTEM_INFO] t + JOIN inserted i + ON i.[PK_CFG_SYSTEM_INFO_ID] = t.[PK_CFG_SYSTEM_INFO_ID]; + + RETURN; + END; + + THROW 51002, 'Direktes UPDATE auf [_meta].[TBDD_CFG_SYSTEM_INFO] ist nicht erlaubt. Bitte Prozedur [_meta].[PRDD_UPSERT_SYSTEM_INFO] verwenden.', 1; +END; +GO + +CREATE OR ALTER TRIGGER [_meta].[TBDD_CFG_SYSTEM_INFO_IO_DEL] +ON [_meta].[TBDD_CFG_SYSTEM_INFO] +INSTEAD OF DELETE +AS +BEGIN + SET NOCOUNT ON; + + IF TRY_CAST(SESSION_CONTEXT(N'_meta_allow_tbdd_system_info_dml') AS bit) = 1 + BEGIN + DELETE t + FROM [_meta].[TBDD_CFG_SYSTEM_INFO] t + JOIN deleted d + ON d.[PK_CFG_SYSTEM_INFO_ID] = t.[PK_CFG_SYSTEM_INFO_ID]; + + RETURN; + END; + + THROW 51003, 'Direktes DELETE auf [_meta].[TBDD_CFG_SYSTEM_INFO] ist nicht erlaubt. Bitte Prozedur [_meta].[PRDD_DELETE_SYSTEM_INFO] verwenden.', 1; +END; +GO diff --git a/current/[DD_SYS]-Database/[PRDD_MIGRATE_DATABASE]/[PRDD_MIGRATE_DATABASE].sql b/current/[DD_SYS]-Database/[PRDD_MIGRATE_DATABASE]/[PRDD_MIGRATE_DATABASE].sql index b8699b3..9b8c8eb 100644 --- a/current/[DD_SYS]-Database/[PRDD_MIGRATE_DATABASE]/[PRDD_MIGRATE_DATABASE].sql +++ b/current/[DD_SYS]-Database/[PRDD_MIGRATE_DATABASE]/[PRDD_MIGRATE_DATABASE].sql @@ -1,14 +1,11 @@ USE [DD_SYS] GO -/****** Object: StoredProcedure [dbo].[PRDD_MIGRATE_DATABASE] Script Date: 24.12.2025 14:51:05 ******/ SET ANSI_NULLS ON GO - SET QUOTED_IDENTIFIER ON GO - -- [PRDD_MIGRATE_DATABASE] -- ================================================================= -- Clone a source database into a new target database with a new collation. @@ -19,17 +16,18 @@ GO -- ================================================================= -- SUPPORTED OBJECTS: -- Schemas, Partition Functions/Schemes, Sequences, User-Defined Types, --- Table Types, Tables (with Collation conversion), Data, Default/Check --- Constraints, Primary/Unique Keys, Indexes, Foreign Keys, Triggers, --- Views, Functions, Stored Procedures, Statistics, Synonyms +-- Table Types (incl. PK/UQ/Indexes), Tables (with Collation + Filegroup), +-- Data, Default/Check Constraints, Primary/Unique Keys, +-- Indexes (Clustered/Nonclustered only), Foreign Keys, Triggers, +-- Views, Functions, Stored Procedures, Statistics, Synonyms, +-- Extended Properties (via sp_addextendedproperty), +-- Memory-optimized tables (migrated as regular disk-based tables), +-- Filestream columns (migrated as regular varbinary(max) columns), +-- Filetables (migrated as regular disk-based tables) -- -- NOT SUPPORTED (must be migrated manually): --- - Memory-optimized tables (In-Memory OLTP) --- - Filestream columns --- - Filetables -- - XML Schema Collections -- - Full-Text Indexes / Full-Text Catalogs --- - Extended Properties -- - Database-level Triggers (DDL Triggers) -- - CLR Assemblies -- - Service Broker objects @@ -45,8 +43,8 @@ GO -- Tel.: 0641/202360 • E-Mail: info-flow@digitaldata.works -- ================================================================= -- Creation Date / Author: 22.12.2025 / MK --- Version Date / Editor: 24.12.2025 / MK --- Version Number: 1.1.4.0 +-- Version Date / Editor: 20.03.2026 / MK +-- Version Number: 1.2.0.0 -- ================================================================= -- History: -- 22.12.2025 / MK - First Version @@ -60,8 +58,37 @@ GO -- external DB references - added IGNORE_DUP_KEY and NOT EXISTS checks -- 24.12.2025 / MK - @pNEWCOLLATION now optional - if NULL, source collation is used -- (allows database cloning without collation change) +-- 19.03.2026 / MK - Bugfix: Memory-optimized table preflight now honors @pEXCLUDEOBJECTS +-- and reports concrete offending tables +-- 19.03.2026 / MK - Feature: Memory-optimized tables are migrated as regular +-- disk-based tables instead of aborting the migration +-- 19.03.2026 / MK - Feature: Filestream columns are migrated as regular +-- varbinary(max) columns instead of aborting the migration +-- 19.03.2026 / MK - Feature: Filetables are migrated as regular disk-based +-- tables instead of aborting the migration +-- 20.03.2026 / MK - Bugfix: Phases 05-09 now check target table existence +-- before adding constraints (prevents errors on missing tables) +-- 20.03.2026 / MK - Bugfix: Synonym base_object_name now replaces SourceDB +-- with TargetDB in target synonyms +-- 20.03.2026 / MK - Bugfix: Index migration limited to type 1/2 (Clustered/ +-- Nonclustered); XML/Spatial/Columnstore/Hash skipped with WARN +-- 20.03.2026 / MK - Bugfix: Source DB locking deferred to execution only +-- (@pEXECUTE=0 no longer locks source database) +-- 20.03.2026 / MK - Feature: MODE=DATA now disables/re-enables FKs around inserts +-- 20.03.2026 / MK - Feature: CREATE TABLE now includes ON [filegroup] clause +-- 20.03.2026 / MK - Bugfix: Disabled indexes preserved as disabled in target +-- 20.03.2026 / MK - Security: SQL injection prevention for DB names and paths +-- 20.03.2026 / MK - Bugfix: FK constraints created WITH NOCHECK + re-checked +-- 20.03.2026 / MK - Feature: DBCC SHRINKFILE target raised to 256 MB +-- 20.03.2026 / MK - Bugfix: Double-dot DB reference replacement added +-- 20.03.2026 / MK - Bugfix: Trigger header replacement uses STUFF approach +-- 20.03.2026 / MK - Feature: Table Types now include PK/UQ constraints +-- 20.03.2026 / MK - Bugfix: Validation trigger name exclusion added +-- 20.03.2026 / MK - Bugfix: Target DB set to MULTI_USER in 99-Finalize +-- 20.03.2026 / MK - Feature: Extended Properties migration (new phase 16) +-- 20.03.2026 / MK - Bugfix: Sequence START WITH uses current_value directly -CREATE OR ALTER PROCEDURE [dbo].[PRDD_MIGRATE_DATABASE] ( +CREATE OR ALTER PROCEDURE [dbo].[PRDD_MIGRATE_DATABASE] ( @pDATABASE NVARCHAR(128) = NULL, -- Source database (unchanged) @pTARGETDATABASE NVARCHAR(128) = NULL, -- Target database to create @pNEWCOLLATION NVARCHAR(128) = NULL, -- New collation for target (e.g. 'Latin1_General_CI_AS'), NULL = use source collation @@ -155,6 +182,7 @@ BEGIN @HAS_CREATE_DATABASE BIT = 0, @HAS_ALTER_ANY_DATABASE BIT = 0, @HAS_VIEW_SERVER_STATE BIT = 0, + @UNSUPPORTED_OBJECT_LIST NVARCHAR(MAX) = NULL, @PERMISSION_SQL NVARCHAR(500) = NULL, @MISSING_PERMISSIONS NVARCHAR(MAX) = N'', @RETURN_STATUS INT = 0, @@ -456,9 +484,20 @@ BEGIN --=================================================-- Basic preflight for unsupported features --=======================-- -- Check for Memory-optimized tables SET @DYNAMICSQL = N' -SELECT TOP (1) 1 -FROM {#SOURCEDB_Q#}.sys.tables -WHERE is_memory_optimized = 1;'; +SELECT @UnsupportedObjects = STUFF(( + SELECT N'', '' + QUOTENAME(sc.name) + N''.'' + QUOTENAME(t.name) + FROM {#SOURCEDB_Q#}.sys.tables AS t + JOIN {#SOURCEDB_Q#}.sys.schemas AS sc ON sc.schema_id = t.schema_id + WHERE t.is_memory_optimized = 1 + AND NOT EXISTS ( + SELECT 1 + FROM #ExcludedObjects AS ex + WHERE (ex.IsWildcard = 1 AND (t.name COLLATE DATABASE_DEFAULT LIKE ex.Pattern OR (sc.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT LIKE ex.Pattern)) + OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (sc.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) + ) + ORDER BY sc.name, t.name + FOR XML PATH(''''), TYPE +).value(''.'', ''nvarchar(max)''), 1, 2, N'''');'; -- Ersetze Platzhalter durch tatsächliche Werte SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), @@ -467,29 +506,40 @@ WHERE is_memory_optimized = 1;'; @PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; - DELETE FROM @tmp; BEGIN TRY - INSERT INTO @tmp(x) EXEC sys.sp_executesql @DYNAMICSQL; + SET @UNSUPPORTED_OBJECT_LIST = NULL; + EXEC sys.sp_executesql @DYNAMICSQL, N'@UnsupportedObjects NVARCHAR(MAX) OUTPUT', @UnsupportedObjects = @UNSUPPORTED_OBJECT_LIST OUTPUT; END TRY BEGIN CATCH PRINT N'ERROR in dynamic SQL:'; PRINT @DYNAMICSQL; THROW; END CATCH; - IF EXISTS (SELECT 1 FROM @tmp) BEGIN + IF @UNSUPPORTED_OBJECT_LIST IS NOT NULL BEGIN + PRINT N'WARN: Memory-optimized tables detected: ' + @UNSUPPORTED_OBJECT_LIST; + PRINT N'WARN: These tables will be migrated as regular disk-based tables without In-Memory OLTP attributes.'; IF (@LOGLEVEL IN ('INFO', 'WARN', 'ERROR')) BEGIN INSERT INTO [dbo].[TBDD_MIGRATE_DATABASE_LOG] ([RUN_ID], [LOG_LEVEL], [SOURCE_DATABASE], [TARGET_DATABASE], [NEW_COLLATION], [MESSAGE], [ERROR_MESSAGE], [ADDED_WHO], [ADDED_WHEN]) - VALUES (@RUN_ID, 'ERROR', @SOURCEDATABASE, @TARGETDATABASE, @NEWCOLLATION, 'Preflight check failed', 'Memory-optimized tables detected. Handle manually.', @MY_PROCEDURE_NAME, GETDATE()); + VALUES (@RUN_ID, 'WARN', @SOURCEDATABASE, @TARGETDATABASE, @NEWCOLLATION, 'Memory-optimized tables detected - migrating as regular disk-based tables', 'Affected tables: ' + @UNSUPPORTED_OBJECT_LIST, @MY_PROCEDURE_NAME, GETDATE()); END; - RAISERROR(N'Unsupported: memory-optimized tables detected. Handle manually.', 16, 1); - RETURN 1; END; -- Check for Filestream columns SET @DYNAMICSQL = N' -SELECT TOP (1) 1 -FROM {#SOURCEDB_Q#}.sys.columns AS c -JOIN {#SOURCEDB_Q#}.sys.tables AS t ON t.object_id = c.object_id -WHERE c.is_filestream = 1;'; +SELECT @UnsupportedObjects = STUFF(( + SELECT N'', '' + QUOTENAME(sc.name) + N''.'' + QUOTENAME(t.name) + N''.'' + QUOTENAME(c.name) + FROM {#SOURCEDB_Q#}.sys.columns AS c + JOIN {#SOURCEDB_Q#}.sys.tables AS t ON t.object_id = c.object_id + JOIN {#SOURCEDB_Q#}.sys.schemas AS sc ON sc.schema_id = t.schema_id + WHERE c.is_filestream = 1 + AND NOT EXISTS ( + SELECT 1 + FROM #ExcludedObjects AS ex + WHERE (ex.IsWildcard = 1 AND (t.name COLLATE DATABASE_DEFAULT LIKE ex.Pattern OR (sc.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT LIKE ex.Pattern)) + OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (sc.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) + ) + ORDER BY sc.name, t.name, c.column_id + FOR XML PATH(''''), TYPE +).value(''.'', ''nvarchar(max)''), 1, 2, N'''');'; -- Ersetze Platzhalter durch tatsächliche Werte SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), @@ -498,28 +548,39 @@ WHERE c.is_filestream = 1;'; @PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; - DELETE FROM @tmp; BEGIN TRY - INSERT INTO @tmp(x) EXEC sys.sp_executesql @DYNAMICSQL; + SET @UNSUPPORTED_OBJECT_LIST = NULL; + EXEC sys.sp_executesql @DYNAMICSQL, N'@UnsupportedObjects NVARCHAR(MAX) OUTPUT', @UnsupportedObjects = @UNSUPPORTED_OBJECT_LIST OUTPUT; END TRY BEGIN CATCH PRINT N'ERROR in dynamic SQL:'; PRINT @DYNAMICSQL; THROW; END CATCH; - IF EXISTS (SELECT 1 FROM @tmp) BEGIN + IF @UNSUPPORTED_OBJECT_LIST IS NOT NULL BEGIN + PRINT N'WARN: Filestream columns detected: ' + @UNSUPPORTED_OBJECT_LIST; + PRINT N'WARN: These columns will be migrated as regular varbinary(max) columns without FILESTREAM attributes.'; IF (@LOGLEVEL IN ('INFO', 'WARN', 'ERROR')) BEGIN INSERT INTO [dbo].[TBDD_MIGRATE_DATABASE_LOG] ([RUN_ID], [LOG_LEVEL], [SOURCE_DATABASE], [TARGET_DATABASE], [NEW_COLLATION], [MESSAGE], [ERROR_MESSAGE], [ADDED_WHO], [ADDED_WHEN]) - VALUES (@RUN_ID, 'ERROR', @SOURCEDATABASE, @TARGETDATABASE, @NEWCOLLATION, 'Preflight check failed', 'Filestream columns detected. Handle manually.', @MY_PROCEDURE_NAME, GETDATE()); + VALUES (@RUN_ID, 'WARN', @SOURCEDATABASE, @TARGETDATABASE, @NEWCOLLATION, 'Filestream columns detected - migrating as regular varbinary(max) columns', 'Affected columns: ' + @UNSUPPORTED_OBJECT_LIST, @MY_PROCEDURE_NAME, GETDATE()); END; - RAISERROR(N'Unsupported: Filestream columns detected. Handle manually.', 16, 1); - RETURN 1; END; -- Check for Filetables SET @DYNAMICSQL = N' -SELECT TOP (1) 1 -FROM {#SOURCEDB_Q#}.sys.tables -WHERE is_filetable = 1;'; +SELECT @UnsupportedObjects = STUFF(( + SELECT N'', '' + QUOTENAME(sc.name) + N''.'' + QUOTENAME(t.name) + FROM {#SOURCEDB_Q#}.sys.tables AS t + JOIN {#SOURCEDB_Q#}.sys.schemas AS sc ON sc.schema_id = t.schema_id + WHERE t.is_filetable = 1 + AND NOT EXISTS ( + SELECT 1 + FROM #ExcludedObjects AS ex + WHERE (ex.IsWildcard = 1 AND (t.name COLLATE DATABASE_DEFAULT LIKE ex.Pattern OR (sc.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT LIKE ex.Pattern)) + OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (sc.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) + ) + ORDER BY sc.name, t.name + FOR XML PATH(''''), TYPE +).value(''.'', ''nvarchar(max)''), 1, 2, N'''');'; -- Ersetze Platzhalter durch tatsächliche Werte SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), @@ -528,21 +589,21 @@ WHERE is_filetable = 1;'; @PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; - DELETE FROM @tmp; BEGIN TRY - INSERT INTO @tmp(x) EXEC sys.sp_executesql @DYNAMICSQL; + SET @UNSUPPORTED_OBJECT_LIST = NULL; + EXEC sys.sp_executesql @DYNAMICSQL, N'@UnsupportedObjects NVARCHAR(MAX) OUTPUT', @UnsupportedObjects = @UNSUPPORTED_OBJECT_LIST OUTPUT; END TRY BEGIN CATCH PRINT N'ERROR in dynamic SQL:'; PRINT @DYNAMICSQL; THROW; END CATCH; - IF EXISTS (SELECT 1 FROM @tmp) BEGIN + IF @UNSUPPORTED_OBJECT_LIST IS NOT NULL BEGIN + PRINT N'WARN: Filetables detected: ' + @UNSUPPORTED_OBJECT_LIST; + PRINT N'WARN: These tables will be migrated as regular disk-based tables without FILETABLE semantics.'; IF (@LOGLEVEL IN ('INFO', 'WARN', 'ERROR')) BEGIN INSERT INTO [dbo].[TBDD_MIGRATE_DATABASE_LOG] ([RUN_ID], [LOG_LEVEL], [SOURCE_DATABASE], [TARGET_DATABASE], [NEW_COLLATION], [MESSAGE], [ERROR_MESSAGE], [ADDED_WHO], [ADDED_WHEN]) - VALUES (@RUN_ID, 'ERROR', @SOURCEDATABASE, @TARGETDATABASE, @NEWCOLLATION, 'Preflight check failed', 'Filetables detected. Handle manually.', @MY_PROCEDURE_NAME, GETDATE()); + VALUES (@RUN_ID, 'WARN', @SOURCEDATABASE, @TARGETDATABASE, @NEWCOLLATION, 'Filetables detected - migrating as regular disk-based tables', 'Affected tables: ' + @UNSUPPORTED_OBJECT_LIST, @MY_PROCEDURE_NAME, GETDATE()); END; - RAISERROR(N'Unsupported: Filetables detected. Handle manually.', 16, 1); - RETURN 1; END; -- Check for Temporal Tables (system-versioned) @@ -612,70 +673,75 @@ WHERE type IN (5, 6);'; -- 5 = Clustered columnstore, 6 = Nonclustered columnst PRINT 'INFO: Source database original user access mode: ' + ISNULL(@SOURCE_USER_ACCESS_ORIGINAL, '(unknown)'); - -- Kill all active connections to source database (except own session) - PRINT 'INFO: Killing active connections to source database...'; - BEGIN TRY - DECLARE kill_cursor CURSOR FAST_FORWARD FOR - SELECT session_id - FROM sys.dm_exec_sessions - WHERE database_id = DB_ID(@SOURCEDATABASE) - AND session_id <> @@SPID; + -- Only lock source database when actually executing (not in script-only mode) + IF @EXECUTECOMMANDS = 1 BEGIN + -- Kill all active connections to source database (except own session) + PRINT 'INFO: Killing active connections to source database...'; + BEGIN TRY + DECLARE kill_cursor CURSOR FAST_FORWARD FOR + SELECT session_id + FROM sys.dm_exec_sessions + WHERE database_id = DB_ID(@SOURCEDATABASE) + AND session_id <> @@SPID; - OPEN kill_cursor; - FETCH NEXT FROM kill_cursor INTO @KILLSESSIONID; - WHILE @@FETCH_STATUS = 0 BEGIN - BEGIN TRY - SET @DYNAMICSQL = N'KILL ' + CONVERT(NVARCHAR(10), @KILLSESSIONID) + N';'; - PRINT 'INFO: Killing session ' + CONVERT(NVARCHAR(10), @KILLSESSIONID); - IF @DEBUG = 1 PRINT @DYNAMICSQL; - EXEC sys.sp_executesql @DYNAMICSQL; - END TRY BEGIN CATCH - PRINT 'WARN: Could not kill session ' + CONVERT(NVARCHAR(10), @KILLSESSIONID) + ': ' + ERROR_MESSAGE(); - END CATCH; + OPEN kill_cursor; FETCH NEXT FROM kill_cursor INTO @KILLSESSIONID; - END; - CLOSE kill_cursor; - DEALLOCATE kill_cursor; - END TRY BEGIN CATCH - -- Ensure cursor is cleaned up even on error - IF CURSOR_STATUS('local', 'kill_cursor') >= 0 BEGIN + WHILE @@FETCH_STATUS = 0 BEGIN + BEGIN TRY + SET @DYNAMICSQL = N'KILL ' + CONVERT(NVARCHAR(10), @KILLSESSIONID) + N';'; + PRINT 'INFO: Killing session ' + CONVERT(NVARCHAR(10), @KILLSESSIONID); + IF @DEBUG = 1 PRINT @DYNAMICSQL; + EXEC sys.sp_executesql @DYNAMICSQL; + END TRY BEGIN CATCH + PRINT 'WARN: Could not kill session ' + CONVERT(NVARCHAR(10), @KILLSESSIONID) + ': ' + ERROR_MESSAGE(); + END CATCH; + FETCH NEXT FROM kill_cursor INTO @KILLSESSIONID; + END; CLOSE kill_cursor; DEALLOCATE kill_cursor; - END; - PRINT 'WARN: Error during connection cleanup: ' + ERROR_MESSAGE(); - END CATCH; - - -- Set source database to RESTRICTED_USER mode - PRINT 'INFO: Setting source database to RESTRICTED_USER mode...'; - BEGIN TRY - SET @DYNAMICSQL = N'ALTER DATABASE {#SOURCEDB_Q#} SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE;'; - -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); - IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; - IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; - BEGIN TRY - EXEC sys.sp_executesql @DYNAMICSQL; END TRY BEGIN CATCH - PRINT N'ERROR in dynamic SQL:'; - PRINT @DYNAMICSQL; - THROW; + -- Ensure cursor is cleaned up even on error + IF CURSOR_STATUS('local', 'kill_cursor') >= 0 BEGIN + CLOSE kill_cursor; + DEALLOCATE kill_cursor; + END; + PRINT 'WARN: Error during connection cleanup: ' + ERROR_MESSAGE(); END CATCH; - PRINT 'INFO: Source database is now in RESTRICTED_USER mode.'; - SET @SOURCE_LOCKED = 1; - END TRY BEGIN CATCH - SET @ERRORMESSAGE = ERROR_MESSAGE(); - PRINT 'ERROR: Could not set source database to RESTRICTED_USER: ' + @ERRORMESSAGE; - IF (@LOGLEVEL IN ('INFO', 'WARN', 'ERROR')) BEGIN - INSERT INTO [dbo].[TBDD_MIGRATE_DATABASE_LOG] ([RUN_ID], [LOG_LEVEL], [SOURCE_DATABASE], [TARGET_DATABASE], [NEW_COLLATION], [MESSAGE], [ERROR_MESSAGE], [ADDED_WHO], [ADDED_WHEN]) - VALUES (@RUN_ID, 'ERROR', @SOURCEDATABASE, @TARGETDATABASE, @NEWCOLLATION, 'Failed to lock source database', @ERRORMESSAGE, @MY_PROCEDURE_NAME, GETDATE()); - END; - RAISERROR(N'Failed to set source database to RESTRICTED_USER mode.', 16, 1); - RETURN 1; - END CATCH; + + -- Set source database to RESTRICTED_USER mode + PRINT 'INFO: Setting source database to RESTRICTED_USER mode...'; + BEGIN TRY + SET @DYNAMICSQL = N'ALTER DATABASE {#SOURCEDB_Q#} SET RESTRICTED_USER WITH ROLLBACK IMMEDIATE;'; + -- Ersetze Platzhalter durch tatsächliche Werte + SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), + @PH_TARGETDB, @TARGETDATABASE); + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; + BEGIN TRY + EXEC sys.sp_executesql @DYNAMICSQL; + END TRY BEGIN CATCH + PRINT N'ERROR in dynamic SQL:'; + PRINT @DYNAMICSQL; + THROW; + END CATCH; + PRINT 'INFO: Source database is now in RESTRICTED_USER mode.'; + SET @SOURCE_LOCKED = 1; + END TRY BEGIN CATCH + SET @ERRORMESSAGE = ERROR_MESSAGE(); + PRINT 'ERROR: Could not set source database to RESTRICTED_USER: ' + @ERRORMESSAGE; + IF (@LOGLEVEL IN ('INFO', 'WARN', 'ERROR')) BEGIN + INSERT INTO [dbo].[TBDD_MIGRATE_DATABASE_LOG] ([RUN_ID], [LOG_LEVEL], [SOURCE_DATABASE], [TARGET_DATABASE], [NEW_COLLATION], [MESSAGE], [ERROR_MESSAGE], [ADDED_WHO], [ADDED_WHEN]) + VALUES (@RUN_ID, 'ERROR', @SOURCEDATABASE, @TARGETDATABASE, @NEWCOLLATION, 'Failed to lock source database', @ERRORMESSAGE, @MY_PROCEDURE_NAME, GETDATE()); + END; + RAISERROR(N'Failed to set source database to RESTRICTED_USER mode.', 16, 1); + RETURN 1; + END CATCH; + END; ELSE BEGIN + PRINT 'INFO: Script-only mode (@pEXECUTE=0) - source database NOT locked.'; + END; PRINT ''; ---------------------------------------------------------------------------------------------------------------------------- @@ -848,16 +914,17 @@ WHERE type IN (5, 6);'; -- 5 = Clustered columnstore, 6 = Nonclustered columnst VALUES (N'01-CreateDb', N'USE [master]; CREATE DATABASE {#TARGETDB_Q#} COLLATE ' + @NEWCOLLATION + N';'); END; ELSE BEGIN - -- Custom paths specified - DECLARE @MDFFILEPATH NVARCHAR(520) = ISNULL(@DATAFILEPATH, N'') + @TARGETDATABASE + N'.mdf'; - DECLARE @LDFFILEPATH NVARCHAR(520) = ISNULL(@LOGFILEPATH, @DATAFILEPATH) + @TARGETDATABASE + N'_log.ldf'; + -- Custom paths specified - escape single quotes for SQL injection prevention + DECLARE @SAFE_TARGETDATABASE NVARCHAR(260) = REPLACE(@TARGETDATABASE, N'''', N''''''); + DECLARE @MDFFILEPATH NVARCHAR(520) = REPLACE(ISNULL(@DATAFILEPATH, N'') + @TARGETDATABASE + N'.mdf', N'''', N''''''); + DECLARE @LDFFILEPATH NVARCHAR(520) = REPLACE(ISNULL(@LOGFILEPATH, @DATAFILEPATH) + @TARGETDATABASE + N'_log.ldf', N'''', N''''''); INSERT INTO #Commands(Phase, Command) VALUES (N'01-CreateDb', N'USE [master]; CREATE DATABASE {#TARGETDB_Q#} - ON PRIMARY (NAME = N''' + @TARGETDATABASE + N''', FILENAME = N''' + @MDFFILEPATH + N''', SIZE = 64MB, FILEGROWTH = 64MB) - LOG ON (NAME = N''' + @TARGETDATABASE + N'_log'', FILENAME = N''' + @LDFFILEPATH + N''', SIZE = 64MB, FILEGROWTH = 64MB) + ON PRIMARY (NAME = N''' + @SAFE_TARGETDATABASE + N''', FILENAME = N''' + @MDFFILEPATH + N''', SIZE = 64MB, FILEGROWTH = 64MB) + LOG ON (NAME = N''' + @SAFE_TARGETDATABASE + N'_log'', FILENAME = N''' + @LDFFILEPATH + N''', SIZE = 64MB, FILEGROWTH = 64MB) COLLATE ' + @NEWCOLLATION + N';'); END; @@ -894,11 +961,11 @@ WHERE s.name NOT IN (N''sys'', N''INFORMATION_SCHEMA'') OR (ex.IsWildcard = 0 AND s.name COLLATE DATABASE_DEFAULT = ex.Pattern) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -955,11 +1022,11 @@ WHERE NOT EXISTS ( OR (ex.IsWildcard = 0 AND pf.name COLLATE DATABASE_DEFAULT = ex.Pattern) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -998,11 +1065,11 @@ WHERE NOT EXISTS ( OR (ex.IsWildcard = 0 AND ps.name COLLATE DATABASE_DEFAULT = ex.Pattern) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1024,18 +1091,10 @@ SELECT N''02c-Sequences'', N''USE {#TARGETDB_Q#}; CREATE SEQUENCE '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(sq.name) + N'' AS '' + ty.name + - -- Use current_value + increment to get next value (handles positive and negative increments) - -- If sequence was never used (current_value = start_value - increment), this still works - -- Added overflow protection: if at boundary, use start_value for cycling or current for non-cycling - N'' START WITH '' + CONVERT(nvarchar(30), - CASE - WHEN sq.is_exhausted = 1 THEN sq.start_value -- Exhausted sequence, restart from beginning - WHEN sq.is_cycling = 0 AND sq.increment > 0 AND CONVERT(bigint, sq.current_value) >= sq.maximum_value THEN CONVERT(bigint, sq.current_value) -- At max, non-cycling - WHEN sq.is_cycling = 0 AND sq.increment < 0 AND CONVERT(bigint, sq.current_value) <= sq.minimum_value THEN CONVERT(bigint, sq.current_value) -- At min, non-cycling - WHEN sq.is_cycling = 1 AND sq.increment > 0 AND CONVERT(bigint, sq.current_value) >= sq.maximum_value THEN sq.minimum_value -- At max, cycling -> wrap to min - WHEN sq.is_cycling = 1 AND sq.increment < 0 AND CONVERT(bigint, sq.current_value) <= sq.minimum_value THEN sq.maximum_value -- At min, cycling -> wrap to max - ELSE CONVERT(bigint, sq.current_value) + CONVERT(bigint, sq.increment) -- Normal: next value - END) + + -- Use current_value directly to preserve exact sequence state + -- SQL Server sets current_value = start_value before first NEXT VALUE FOR + -- so using current_value as START WITH faithfully reproduces the source state + N'' START WITH '' + CONVERT(nvarchar(30), CONVERT(bigint, sq.current_value)) + N'' INCREMENT BY '' + CONVERT(nvarchar(30), sq.increment) + CASE WHEN sq.minimum_value IS NOT NULL THEN N'' MINVALUE '' + CONVERT(nvarchar(30), sq.minimum_value) ELSE N'' NO MINVALUE'' END + CASE WHEN sq.maximum_value IS NOT NULL THEN N'' MAXVALUE '' + CONVERT(nvarchar(30), sq.maximum_value) ELSE N'' NO MAXVALUE'' END + @@ -1053,11 +1112,11 @@ WHERE s.name <> N''sys'' OR (ex.IsWildcard = 0 AND (sq.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (s.name + N''.'' + sq.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1102,11 +1161,11 @@ WHERE t.is_user_defined = 1 OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (s.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1143,9 +1202,39 @@ SELECT WHERE tt2.user_type_id = t.user_type_id ORDER BY c.column_id FOR XML PATH(''''), TYPE - ).value(''.'', ''nvarchar(max)''), 1, 2, N'''') + N'');'' + ).value(''.'', ''nvarchar(max)''), 1, 2, N'''') + + -- Append PK/UQ constraints inline + ISNULL(pk_uq.constraint_defs, N'''') + + N'');'' FROM {#SOURCEDB_Q#}.sys.table_types AS t JOIN {#SOURCEDB_Q#}.sys.schemas AS s ON s.schema_id = t.schema_id +-- Get inline PK/UQ constraints for this table type +OUTER APPLY ( + SELECT STUFF(( + SELECT N'', '' + + CASE WHEN k.[type] = ''PK'' THEN N''PRIMARY KEY '' ELSE N''UNIQUE '' END + + CASE WHEN i.[type] = 1 THEN N''CLUSTERED '' ELSE N''NONCLUSTERED '' END + + N''('' + + STUFF(( + SELECT N'', '' + QUOTENAME(c2.name) + CASE WHEN ic2.is_descending_key = 1 THEN N'' DESC'' ELSE N'' ASC'' END + FROM {#SOURCEDB_Q#}.sys.index_columns AS ic2 + JOIN {#SOURCEDB_Q#}.sys.columns AS c2 ON c2.object_id = ic2.object_id AND c2.column_id = ic2.column_id + WHERE ic2.object_id = i.object_id AND ic2.index_id = i.index_id AND ic2.is_included_column = 0 + ORDER BY ic2.key_ordinal + FOR XML PATH(''''), TYPE + ).value(''.'', ''nvarchar(max)''), 1, 2, N'''') + N'')'' + FROM {#SOURCEDB_Q#}.sys.indexes AS i + LEFT JOIN {#SOURCEDB_Q#}.sys.key_constraints AS k ON k.parent_object_id = i.object_id AND k.unique_index_id = i.index_id + WHERE i.object_id = t.type_table_object_id + AND i.index_id > 0 + AND (i.is_primary_key = 1 OR i.is_unique_constraint = 1) + ORDER BY i.is_primary_key DESC, i.index_id + FOR XML PATH(''''), TYPE + ).value(''.'', ''nvarchar(max)''), 1, 2, N'''') AS constraint_defs_raw +) AS pk_uq_raw +OUTER APPLY ( + SELECT CASE WHEN pk_uq_raw.constraint_defs_raw IS NOT NULL THEN N'', '' + pk_uq_raw.constraint_defs_raw ELSE NULL END AS constraint_defs +) AS pk_uq WHERE s.name <> N''sys'' -- Exclude table types matching patterns in #ExcludedObjects AND NOT EXISTS ( @@ -1154,11 +1243,11 @@ WHERE s.name <> N''sys'' OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (s.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1180,7 +1269,7 @@ SELECT STUFF(( SELECT N'', '' + CASE WHEN c.is_computed = 1 THEN - QUOTENAME(c.name) + N'' AS '' + REPLACE(REPLACE(cc.definition, N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].''), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' ) + CASE WHEN cc.is_persisted = 1 THEN N'' PERSISTED'' ELSE N'''' END + QUOTENAME(c.name) + N'' AS '' + REPLACE(REPLACE(REPLACE(REPLACE(cc.definition, N''[{#SOURCEDB#}]..'', N''[{#TARGETDB#}]..''), N''{#SOURCEDB#}..'', N''{#TARGETDB#}..''), N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].''), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' ) + CASE WHEN cc.is_persisted = 1 THEN N'' PERSISTED'' ELSE N'''' END ELSE QUOTENAME(c.name) + N'' '' + -- Use UDT name if user-defined, otherwise system type with size specs @@ -1206,9 +1295,20 @@ SELECT LEFT JOIN {#SOURCEDB_Q#}.sys.schemas AS tys ON tys.schema_id = ty.schema_id WHERE c.object_id = t.object_id ORDER BY c.column_id - FOR XML PATH(''''), TYPE).value(''.'', ''nvarchar(max)''), 1, 2, N'''') + N'');'' + FOR XML PATH(''''), TYPE).value(''.'', ''nvarchar(max)''), 1, 2, N'''') + N'')'' + + -- ON [filegroup] clause + ISNULL(N'' ON '' + CASE + WHEN ds.[type] = ''PS'' THEN QUOTENAME(ps.name) + N''('' + QUOTENAME(pc.name) + N'')'' + ELSE QUOTENAME(ds.name) + END, N'''') + N'';'' FROM {#SOURCEDB_Q#}.sys.tables AS t JOIN {#SOURCEDB_Q#}.sys.schemas AS sc ON sc.schema_id = t.schema_id +-- Get data space for heap or clustered index (index_id 0=heap, 1=clustered) +LEFT JOIN {#SOURCEDB_Q#}.sys.indexes AS ci ON ci.object_id = t.object_id AND ci.index_id IN (0, 1) +LEFT JOIN {#SOURCEDB_Q#}.sys.data_spaces AS ds ON ds.data_space_id = ci.data_space_id +LEFT JOIN {#SOURCEDB_Q#}.sys.partition_schemes AS ps ON ps.data_space_id = ds.data_space_id +LEFT JOIN {#SOURCEDB_Q#}.sys.index_columns AS icp ON icp.object_id = ci.object_id AND icp.index_id = ci.index_id AND icp.partition_ordinal = 1 +LEFT JOIN {#SOURCEDB_Q#}.sys.columns AS pc ON pc.object_id = icp.object_id AND pc.column_id = icp.column_id WHERE sc.name <> N''sys'' AND t.is_ms_shipped = 0 -- Exclude tables matching patterns in #ExcludedObjects AND NOT EXISTS ( @@ -1217,11 +1317,11 @@ WHERE sc.name <> N''sys'' AND t.is_ms_shipped = 0 OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (sc.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1233,6 +1333,38 @@ WHERE sc.name <> N''sys'' AND t.is_ms_shipped = 0 END CATCH; ---------------------------------------------------------------------------------------------------------------------------- + --=================================================-- 03a: Disable FKs for DATA mode --================================-- + -- When MODE=DATA, FKs already exist in target and must be disabled before inserting data + IF @MODE = 'DATA' BEGIN + IF @DEBUG = 1 PRINT 'DEBUG: Generating 03a-FK-Disable commands for DATA mode...'; + SET @DYNAMICSQL = N' +INSERT INTO #Commands(Phase, Command) +SELECT + N''03a-FK-Disable'', + N''USE {#TARGETDB_Q#}; ALTER TABLE '' + QUOTENAME(spt.name) + N''.'' + QUOTENAME(pt.name) + + N'' NOCHECK CONSTRAINT '' + QUOTENAME(fk.name) + N'';'' +FROM {#TARGETDB_Q#}.sys.foreign_keys AS fk +JOIN {#TARGETDB_Q#}.sys.tables AS pt ON pt.object_id = fk.parent_object_id +JOIN {#TARGETDB_Q#}.sys.schemas AS spt ON spt.schema_id = pt.schema_id +WHERE spt.name <> N''sys'';'; + -- Ersetze Platzhalter durch tatsächliche Werte + SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), + @PH_TARGETDB, @TARGETDATABASE); + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; + BEGIN TRY + EXEC sys.sp_executesql @DYNAMICSQL; + END TRY BEGIN CATCH + PRINT N'ERROR in dynamic SQL:'; + PRINT @DYNAMICSQL; + THROW; + END CATCH; + END; + ---------------------------------------------------------------------------------------------------------------------------- + IF @DEBUG = 1 PRINT 'DEBUG: Generating 04-Data commands...'; --=================================================-- 04: Data copy --==================================================-- -- Using TABLOCK hint for minimal logging in SIMPLE recovery mode @@ -1283,11 +1415,11 @@ WHERE sc.name <> N''sys'' AND t.is_ms_shipped = 0 OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (sc.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1368,12 +1500,12 @@ WHERE sc.name <> N''sys'' AND t.is_ms_shipped = 0 WHERE (ex.IsWildcard = 1 AND (t.name COLLATE DATABASE_DEFAULT LIKE ex.Pattern OR (sc.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT LIKE ex.Pattern)) OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (sc.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; - -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); + -- Ersetze Platzhalter durch tatsächliche Werte +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1461,11 +1593,11 @@ WHERE sc.name <> N''sys'' AND t.is_ms_shipped = 0 OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (sc.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1493,13 +1625,13 @@ IF EXISTS ( AND (SELECT COUNT(*) FROM {#SOURCEDB_Q#}.sys.index_columns AS ic2 WHERE ic2.object_id = i.object_id AND ic2.index_id = i.index_id) = 1 ) ) - INSERT INTO #Commands(Phase, Command) VALUES (N''04a-ShrinkTempdb'', N''USE tempdb; BEGIN TRY DECLARE @f sysname = (SELECT TOP (1) name FROM tempdb.sys.database_files WHERE type_desc = ''''ROWS''''); IF @f IS NOT NULL BEGIN DBCC SHRINKFILE(@f, 1); END END TRY BEGIN CATCH PRINT N''''WARN: DBCC SHRINKFILE skipped: '''' + ERROR_MESSAGE(); END CATCH;'');'; + INSERT INTO #Commands(Phase, Command) VALUES (N''04a-ShrinkTempdb'', N''USE tempdb; BEGIN TRY DECLARE @f sysname = (SELECT TOP (1) name FROM tempdb.sys.database_files WHERE type_desc = ''''ROWS''''); IF @f IS NOT NULL BEGIN DBCC SHRINKFILE(@f, 256); END END TRY BEGIN CATCH PRINT N''''WARN: DBCC SHRINKFILE skipped: '''' + ERROR_MESSAGE(); END CATCH;'');'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1512,14 +1644,57 @@ IF EXISTS ( END; ---------------------------------------------------------------------------------------------------------------------------- + --=================================================-- 04b: Re-enable FKs for DATA mode --==============================-- + -- When MODE=DATA, re-enable FKs after data insert and re-check them to mark as trusted + IF @MODE = 'DATA' BEGIN + IF @DEBUG = 1 PRINT 'DEBUG: Generating 04b-FK-Enable commands for DATA mode...'; + SET @DYNAMICSQL = N' +INSERT INTO #Commands(Phase, Command) +SELECT + N''04b-FK-Enable'', + N''USE {#TARGETDB_Q#}; ALTER TABLE '' + QUOTENAME(spt.name) + N''.'' + QUOTENAME(pt.name) + + CASE WHEN fk.is_disabled = 1 THEN + -- FK was disabled in source - keep it disabled + N'' NOCHECK CONSTRAINT '' + QUOTENAME(fk.name) + N'';'' + ELSE + -- FK was enabled - re-enable with CHECK CHECK to make it trusted + N'' WITH CHECK CHECK CONSTRAINT '' + QUOTENAME(fk.name) + N'';'' + END +FROM {#SOURCEDB_Q#}.sys.foreign_keys AS fk +JOIN {#SOURCEDB_Q#}.sys.tables AS pt ON pt.object_id = fk.parent_object_id +JOIN {#SOURCEDB_Q#}.sys.schemas AS spt ON spt.schema_id = pt.schema_id +WHERE spt.name <> N''sys'' + AND NOT EXISTS ( + SELECT 1 FROM #ExcludedObjects AS ex + WHERE (ex.IsWildcard = 1 AND (pt.name COLLATE DATABASE_DEFAULT LIKE ex.Pattern OR (spt.name + N''.'' + pt.name) COLLATE DATABASE_DEFAULT LIKE ex.Pattern)) + OR (ex.IsWildcard = 0 AND (pt.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (spt.name + N''.'' + pt.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) + );'; + -- Ersetze Platzhalter durch tatsächliche Werte + SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), + @PH_TARGETDB, @TARGETDATABASE); + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; + BEGIN TRY + EXEC sys.sp_executesql @DYNAMICSQL; + END TRY BEGIN CATCH + PRINT N'ERROR in dynamic SQL:'; + PRINT @DYNAMICSQL; + THROW; + END CATCH; + END; + ---------------------------------------------------------------------------------------------------------------------------- + IF @DEBUG = 1 PRINT 'DEBUG: Generating 05-DefaultConstraints commands...'; --=================================================-- 05: Default constraints --========================================-- SET @DYNAMICSQL = N' INSERT INTO #Commands(Phase, Command) SELECT N''05-Defaults'', - N''USE {#TARGETDB_Q#}; ALTER TABLE '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + - N'' ADD CONSTRAINT '' + QUOTENAME(dc.name) + N'' DEFAULT '' + REPLACE(REPLACE(dc.definition, N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].''), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' ) + + N''USE {#TARGETDB_Q#}; IF OBJECT_ID(N'''''' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + N'''''', N''''U'''') IS NOT NULL ALTER TABLE '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + + N'' ADD CONSTRAINT '' + QUOTENAME(dc.name) + N'' DEFAULT '' + REPLACE(REPLACE(REPLACE(REPLACE(dc.definition, N''[{#SOURCEDB#}]..'', N''[{#TARGETDB#}]..''), N''{#SOURCEDB#}..'', N''{#TARGETDB#}..''), N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].''), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' ) + N'' FOR '' + QUOTENAME(c.name) + N'';'' FROM {#SOURCEDB_Q#}.sys.default_constraints AS dc JOIN {#SOURCEDB_Q#}.sys.tables AS t ON t.object_id = dc.parent_object_id @@ -1533,11 +1708,11 @@ WHERE s.name <> N''sys'' OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (s.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1555,8 +1730,8 @@ WHERE s.name <> N''sys'' INSERT INTO #Commands(Phase, Command) SELECT N''06-Checks'', - N''USE {#TARGETDB_Q#}; ALTER TABLE '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + - N'' WITH NOCHECK ADD CONSTRAINT '' + QUOTENAME(cc.name) + N'' CHECK '' + REPLACE(REPLACE(cc.definition, N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].''), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' ) + N'';'' + + N''USE {#TARGETDB_Q#}; IF OBJECT_ID(N'''''' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + N'''''', N''''U'''') IS NOT NULL ALTER TABLE '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + + N'' WITH NOCHECK ADD CONSTRAINT '' + QUOTENAME(cc.name) + N'' CHECK '' + REPLACE(REPLACE(REPLACE(REPLACE(cc.definition, N''[{#SOURCEDB#}]..'', N''[{#TARGETDB#}]..''), N''{#SOURCEDB#}..'', N''{#TARGETDB#}..''), N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].''), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' ) + N'';'' + CASE WHEN cc.is_disabled = 1 THEN N'' ALTER TABLE '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + N'' NOCHECK CONSTRAINT '' + QUOTENAME(cc.name) + N'';'' ELSE N'''' END @@ -1571,11 +1746,11 @@ WHERE s.name <> N''sys'' OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (s.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1593,7 +1768,7 @@ WHERE s.name <> N''sys'' INSERT INTO #Commands(Phase, Command) SELECT N''07-PK_UQ'', - N''USE {#TARGETDB_Q#}; ALTER TABLE '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + + N''USE {#TARGETDB_Q#}; IF OBJECT_ID(N'''''' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + N'''''', N''''U'''') IS NOT NULL ALTER TABLE '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + N'' ADD CONSTRAINT '' + QUOTENAME(k.name) + N'' '' + CASE WHEN k.[type] = ''PK'' THEN N''PRIMARY KEY '' ELSE N''UNIQUE '' END + CASE WHEN i.[type] = 1 THEN N''CLUSTERED '' ELSE N''NONCLUSTERED '' END + @@ -1653,11 +1828,11 @@ WHERE s.name <> N''sys'' OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (s.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1675,14 +1850,14 @@ WHERE s.name <> N''sys'' INSERT INTO #Commands(Phase, Command) SELECT N''08-Indexes'', - N''USE {#TARGETDB_Q#}; CREATE '' + + N''USE {#TARGETDB_Q#}; IF OBJECT_ID(N'''''' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + N'''''', N''''U'''') IS NOT NULL CREATE '' + CASE WHEN i.is_unique = 1 THEN N''UNIQUE '' ELSE N'''' END + CASE WHEN i.[type] = 1 THEN N''CLUSTERED '' ELSE N''NONCLUSTERED '' END + N''INDEX '' + QUOTENAME(i.name) + N'' ON '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + N'' ('' + kc.key_cols + N'')'' + CASE WHEN inc.included_cols IS NULL THEN N'''' ELSE N'' INCLUDE ('' + inc.included_cols + N'')'' END + - CASE WHEN i.has_filter = 1 THEN N'' WHERE '' + REPLACE(REPLACE(i.filter_definition, N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].''), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' ) ELSE N'''' END + + CASE WHEN i.has_filter = 1 THEN N'' WHERE '' + REPLACE(REPLACE(REPLACE(REPLACE(i.filter_definition, N''[{#SOURCEDB#}]..'', N''[{#TARGETDB#}]..''), N''{#SOURCEDB#}..'', N''{#TARGETDB#}..''), N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].''), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' ) ELSE N'''' END + -- Index options (WITH clause) N'' WITH ('' + N''PAD_INDEX = '' + CASE WHEN i.is_padded = 1 THEN N''ON'' ELSE N''OFF'' END + @@ -1693,7 +1868,9 @@ SELECT ISNULL(N'', DATA_COMPRESSION = '' + pc.compression_desc, N'''') + N'')'' + CASE WHEN on_target.on_target IS NULL THEN N'''' ELSE N'' ON '' + on_target.on_target END + - N'';'' + N'';'' + + -- Preserve disabled state: if index was disabled in source, disable it in target too + CASE WHEN i.is_disabled = 1 THEN N'' ALTER INDEX '' + QUOTENAME(i.name) + N'' ON '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + N'' DISABLE;'' ELSE N'''' END FROM {#SOURCEDB_Q#}.sys.indexes AS i JOIN {#SOURCEDB_Q#}.sys.tables AS t ON t.object_id = i.object_id JOIN {#SOURCEDB_Q#}.sys.schemas AS s ON s.schema_id = t.schema_id @@ -1746,6 +1923,7 @@ WHERE s.name <> N''sys'' AND i.index_id > 0 AND i.is_primary_key = 0 AND i.is_unique_constraint = 0 + AND i.[type] IN (1, 2) -- Only Clustered (1) and Nonclustered (2); XML/Spatial/Columnstore/Hash skipped below -- Exclude indexes on tables matching patterns in #ExcludedObjects AND NOT EXISTS ( SELECT 1 FROM #ExcludedObjects AS ex @@ -1753,11 +1931,49 @@ WHERE s.name <> N''sys'' OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (s.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; + BEGIN TRY + EXEC sys.sp_executesql @DYNAMICSQL; + END TRY BEGIN CATCH + PRINT N'ERROR in dynamic SQL:'; + PRINT @DYNAMICSQL; + THROW; + END CATCH; + + -- Generate WARN messages for unsupported index types (XML, Spatial, Columnstore, Hash) + SET @DYNAMICSQL = N' +INSERT INTO #Commands(Phase, Command) +SELECT + N''08-Indexes'', + N''PRINT N''''WARN: Index '' + QUOTENAME(i.name) + N'' on '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + + N'' (type='' + CONVERT(nvarchar(10), i.[type]) + N'' '' + + CASE i.[type] WHEN 3 THEN N''XML'' WHEN 4 THEN N''Spatial'' WHEN 5 THEN N''Clustered Columnstore'' WHEN 6 THEN N''Nonclustered Columnstore'' WHEN 7 THEN N''Hash'' ELSE N''Unknown'' END + + N'') was SKIPPED - unsupported index type, recreate manually.'''''';'' +FROM {#SOURCEDB_Q#}.sys.indexes AS i +JOIN {#SOURCEDB_Q#}.sys.tables AS t ON t.object_id = i.object_id +JOIN {#SOURCEDB_Q#}.sys.schemas AS s ON s.schema_id = t.schema_id +WHERE s.name <> N''sys'' + AND i.index_id > 0 + AND i.is_primary_key = 0 + AND i.is_unique_constraint = 0 + AND i.[type] NOT IN (1, 2) + AND NOT EXISTS ( + SELECT 1 FROM #ExcludedObjects AS ex + WHERE (ex.IsWildcard = 1 AND (t.name COLLATE DATABASE_DEFAULT LIKE ex.Pattern OR (s.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT LIKE ex.Pattern)) + OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (s.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) + );'; + -- Ersetze Platzhalter durch tatsächliche Werte +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1775,15 +1991,22 @@ WHERE s.name <> N''sys'' INSERT INTO #Commands(Phase, Command) SELECT N''09-FK'', - N''USE {#TARGETDB_Q#}; ALTER TABLE '' + QUOTENAME(spt.name) + N''.'' + QUOTENAME(pt.name) + - N'' ADD CONSTRAINT '' + QUOTENAME(fk.name) + + N''USE {#TARGETDB_Q#}; IF OBJECT_ID(N'''''' + QUOTENAME(spt.name) + N''.'' + QUOTENAME(pt.name) + N'''''', N''''U'''') IS NOT NULL AND OBJECT_ID(N'''''' + QUOTENAME(srt.name) + N''.'' + QUOTENAME(rt.name) + N'''''', N''''U'''') IS NOT NULL ALTER TABLE '' + QUOTENAME(spt.name) + N''.'' + QUOTENAME(pt.name) + + N'' WITH NOCHECK ADD CONSTRAINT '' + QUOTENAME(fk.name) + N'' FOREIGN KEY ('' + fkc.parent_cols + N'') REFERENCES '' + QUOTENAME(srt.name) + N''.'' + QUOTENAME(rt.name) + N'' ('' + fkc.ref_cols + N'')'' + CASE WHEN fk.delete_referential_action_desc <> N''NO_ACTION'' THEN N'' ON DELETE '' + fk.delete_referential_action_desc ELSE N'''' END + CASE WHEN fk.update_referential_action_desc <> N''NO_ACTION'' THEN N'' ON UPDATE '' + fk.update_referential_action_desc ELSE N'''' END + CASE WHEN fk.is_not_for_replication = 1 THEN N'' NOT FOR REPLICATION'' ELSE N'''' END + N'';'' + - CASE WHEN fk.is_disabled = 1 THEN N'' ALTER TABLE '' + QUOTENAME(spt.name) + N''.'' + QUOTENAME(pt.name) + N'' NOCHECK CONSTRAINT '' + QUOTENAME(fk.name) + N'';'' ELSE N'''' END + -- Re-check the constraint to mark it as trusted (is_not_trusted = 0) + CASE WHEN fk.is_disabled = 1 THEN + -- FK was disabled in source: NOCHECK to disable it + N'' ALTER TABLE '' + QUOTENAME(spt.name) + N''.'' + QUOTENAME(pt.name) + N'' NOCHECK CONSTRAINT '' + QUOTENAME(fk.name) + N'';'' + ELSE + -- FK was enabled in source: WITH CHECK CHECK to make it trusted + N'' ALTER TABLE '' + QUOTENAME(spt.name) + N''.'' + QUOTENAME(pt.name) + N'' WITH CHECK CHECK CONSTRAINT '' + QUOTENAME(fk.name) + N'';'' + END FROM {#SOURCEDB_Q#}.sys.foreign_keys AS fk JOIN {#SOURCEDB_Q#}.sys.tables AS pt ON pt.object_id = fk.parent_object_id JOIN {#SOURCEDB_Q#}.sys.tables AS rt ON rt.object_id = fk.referenced_object_id @@ -1818,11 +2041,11 @@ WHERE spt.name <> N''sys'' OR (ex.IsWildcard = 0 AND (rt.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (srt.name + N''.'' + rt.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1848,6 +2071,8 @@ SELECT REPLACE( REPLACE( REPLACE( + REPLACE( + REPLACE( -- Only add OR ALTER if not already present CASE WHEN PATINDEX(N''%CREATE[^A-Za-z]%OR[^A-Za-z]%ALTER[^A-Za-z]%TRIGGER[^A-Za-z]%'', m.definition + N'' '') > 0 @@ -1859,6 +2084,10 @@ SELECT 0, -- Delete 0 characters N'' OR ALTER'') -- Insert " OR ALTER" END, + N''[{#SOURCEDB#}]..'', N''[{#TARGETDB#}]..'' -- Replace [SourceDB].. with [TargetDB].. + ), + N''{#SOURCEDB#}..'', N''{#TARGETDB#}..'' -- Replace SourceDB.. with TargetDB.. (unquoted) + ), N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].'' -- Replace [SourceDB]. with [TargetDB]. ), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' -- Replace SourceDB. with TargetDB. (unquoted) @@ -1888,11 +2117,11 @@ WHERE s.name <> N''sys'' AND tr.parent_id IS NOT NULL AND m.definition IS NOT NU OR (ex.IsWildcard = 0 AND (tr.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (s.name + N''.'' + tr.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -1940,9 +2169,15 @@ SELECT REPLACE( REPLACE( REPLACE( + REPLACE( + REPLACE( N''CREATE OR ALTER VIEW '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(v.name) + N'' '' + -- Extract everything after the view name (AS SELECT... or WITH ...) LTRIM(SUBSTRING(m.definition, body_pos.pos, LEN(m.definition))), + N''[{#SOURCEDB#}]..'', N''[{#TARGETDB#}]..'' -- Replace [SourceDB].. with [TargetDB].. + ), + N''{#SOURCEDB#}..'', N''{#TARGETDB#}..'' -- Replace SourceDB.. with TargetDB.. (unquoted) + ), N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].'' -- Replace [SourceDB]. with [TargetDB]. ), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' -- Replace SourceDB. with TargetDB. (unquoted) @@ -1987,11 +2222,11 @@ WHERE s.name <> N''sys'' ORDER BY ISNULL(vml.max_level, 999) OPTION (MAXRECURSION 0);'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -2042,9 +2277,15 @@ SELECT REPLACE( REPLACE( REPLACE( + REPLACE( + REPLACE( N''CREATE OR ALTER FUNCTION '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(o.name) + N'' '' + -- Extract everything after the function name (parameters and body) LTRIM(SUBSTRING(m.definition, body_pos.pos, LEN(m.definition))), + N''[{#SOURCEDB#}]..'', N''[{#TARGETDB#}]..'' -- Replace [SourceDB].. with [TargetDB].. + ), + N''{#SOURCEDB#}..'', N''{#TARGETDB#}..'' -- Replace SourceDB.. with TargetDB.. (unquoted) + ), N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].'' -- Replace [SourceDB]. with [TargetDB]. ), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' -- Replace SourceDB. with TargetDB. (unquoted) @@ -2081,11 +2322,11 @@ WHERE s.name <> N''sys'' AND o.[type] IN (N''FN'',N''TF'',N''IF'',N''FS'',N''FT' ORDER BY ISNULL(fml.max_level, 999) OPTION (MAXRECURSION 0);'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -2113,6 +2354,8 @@ SELECT REPLACE( REPLACE( REPLACE( + REPLACE( + REPLACE( -- Use STUFF to replace from position 1 up to end of procedure name with new header STUFF( m.definition, @@ -2128,6 +2371,10 @@ SELECT -- New header (replaces everything from CREATE to proc name) N''CREATE OR ALTER PROCEDURE '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(p.name) ), + N''[{#SOURCEDB#}]..'', N''[{#TARGETDB#}]..'' + ), + N''{#SOURCEDB#}..'', N''{#TARGETDB#}..'' + ), N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].'' ), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' @@ -2147,11 +2394,11 @@ WHERE s.name <> N''sys'' OR (ex.IsWildcard = 0 AND (p.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (s.name + N''.'' + p.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -2172,7 +2419,7 @@ SELECT N''USE {#TARGETDB_Q#}; CREATE STATISTICS '' + QUOTENAME(st.name) + N'' ON '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(t.name) + N'' ('' + cols.stats_columns + N'')'' + - CASE WHEN st.has_filter = 1 THEN N'' WHERE '' + REPLACE(REPLACE(st.filter_definition, N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].''), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' ) ELSE N'''' END + + CASE WHEN st.has_filter = 1 THEN N'' WHERE '' + REPLACE(REPLACE(REPLACE(REPLACE(st.filter_definition, N''[{#SOURCEDB#}]..'', N''[{#TARGETDB#}]..''), N''{#SOURCEDB#}..'', N''{#TARGETDB#}..''), N''[{#SOURCEDB#}].'', N''[{#TARGETDB#}].''), N''{#SOURCEDB#}.'', N''{#TARGETDB#}.'' ) ELSE N'''' END + CASE WHEN (st.no_recompute = 1 OR st.is_incremental = 1) THEN N'' WITH '' + STUFF( @@ -2207,11 +2454,11 @@ WHERE i.index_id IS NULL -- only user-created stats OR (ex.IsWildcard = 0 AND (t.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (s.name + N''.'' + t.name) COLLATE DATABASE_DEFAULT = ex.Pattern)) );'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -2245,7 +2492,12 @@ OPEN syn_cursor; FETCH NEXT FROM syn_cursor INTO @SYN_SCHEMA, @SYN_NAME, @SYN_TARGET; WHILE @@FETCH_STATUS = 0 BEGIN - -- base_object_name wird direkt verwendet - kein Escaping nötig da EXEC() verwendet wird + -- Replace source DB name with target DB name in base_object_name (covers [DB].. and [DB]. and unquoted) + SET @SYN_TARGET = REPLACE(REPLACE(REPLACE(REPLACE(@SYN_TARGET, + QUOTENAME(N''{#SOURCEDB#}'') + N''..'', QUOTENAME(N''{#TARGETDB#}'') + N''..''), + N''{#SOURCEDB#}..'', N''{#TARGETDB#}..''), + QUOTENAME(N''{#SOURCEDB#}'') + N''.'', QUOTENAME(N''{#TARGETDB#}'') + N''.''), + N''{#SOURCEDB#}.'', N''{#TARGETDB#}.''); INSERT INTO #Commands(Phase, Command) VALUES (N''15-Synonyms'', N''USE {#TARGETDB_Q#}; CREATE SYNONYM '' + QUOTENAME(@SYN_SCHEMA) + N''.'' + QUOTENAME(@SYN_NAME) + N'' FOR '' + @SYN_TARGET + N'';''); FETCH NEXT FROM syn_cursor INTO @SYN_SCHEMA, @SYN_NAME, @SYN_TARGET; @@ -2253,11 +2505,11 @@ END; CLOSE syn_cursor; DEALLOCATE syn_cursor;'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -2289,11 +2541,98 @@ END; CLOSE syn_warn_cursor; DEALLOCATE syn_warn_cursor;'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; + BEGIN TRY + EXEC sys.sp_executesql @DYNAMICSQL; + END TRY BEGIN CATCH + PRINT N'ERROR in dynamic SQL:'; + PRINT @DYNAMICSQL; + THROW; + END CATCH; + ---------------------------------------------------------------------------------------------------------------------------- + + IF @DEBUG = 1 PRINT 'DEBUG: Generating 16-ExtendedProperties commands...'; + --=================================================-- 16: Extended Properties --========================================-- + -- Migrate extended properties for schemas, tables, columns, views, functions, procedures, indexes, constraints + -- Uses sys.extended_properties and sp_addextendedproperty to recreate them in target + SET @DYNAMICSQL = N' +INSERT INTO #Commands(Phase, Command) +SELECT + N''16-ExtendedProperties'', + N''USE {#TARGETDB_Q#}; EXEC sys.sp_addextendedproperty '' + + N''@name = N'''''' + REPLACE(ep.name, N'''''''', N'''''''''''') + N'''''', '' + + N''@value = N'''''' + REPLACE(CONVERT(nvarchar(max), ep.value), N'''''''', N'''''''''''') + N'''''''' + + -- Level 0 (Schema or NULL for database-level) + CASE ep.class + WHEN 0 THEN N'''' -- Database-level: no extra params needed + WHEN 1 THEN -- Object/Column level + CASE + -- Triggers: Level-2 under parent TABLE + WHEN o.[type] = N''TR'' THEN + N'', @level0type = N''''SCHEMA'''', @level0name = N'''''' + REPLACE(ps.name, N'''''''', N'''''''''''') + N'''''''' + + N'', @level1type = N''''TABLE'''', @level1name = N'''''' + REPLACE(po.name, N'''''''', N'''''''''''') + N'''''''' + + N'', @level2type = N''''TRIGGER'''', @level2name = N'''''' + REPLACE(o.name, N'''''''', N'''''''''''') + N'''''''' + -- Constraints: Level-2 under parent TABLE + WHEN o.[type] IN (N''C'',N''D'',N''F'',N''PK'',N''UQ'') THEN + N'', @level0type = N''''SCHEMA'''', @level0name = N'''''' + REPLACE(ps.name, N'''''''', N'''''''''''') + N'''''''' + + N'', @level1type = N''''TABLE'''', @level1name = N'''''' + REPLACE(po.name, N'''''''', N'''''''''''') + N'''''''' + + N'', @level2type = N''''CONSTRAINT'''', @level2name = N'''''' + REPLACE(o.name, N'''''''', N'''''''''''') + N'''''''' + ELSE + -- Regular Level-1 objects (TABLE, VIEW, PROCEDURE, FUNCTION) + N'', @level0type = N''''SCHEMA'''', @level0name = N'''''' + REPLACE(s.name, N'''''''', N'''''''''''') + N'''''''' + + N'', @level1type = N'''''' + + CASE + WHEN o.[type] IN (N''U'') THEN N''TABLE'' + WHEN o.[type] IN (N''V'') THEN N''VIEW'' + WHEN o.[type] IN (N''P'',N''PC'') THEN N''PROCEDURE'' + WHEN o.[type] IN (N''FN'',N''TF'',N''IF'',N''FS'',N''FT'') THEN N''FUNCTION'' + ELSE N''TABLE'' + END + N'''''', @level1name = N'''''' + REPLACE(o.name, N'''''''', N'''''''''''') + N'''''''' + + CASE WHEN ep.minor_id > 0 AND o.[type] = N''U'' THEN + N'', @level2type = N''''COLUMN'''', @level2name = N'''''' + REPLACE(c.name, N'''''''', N'''''''''''') + N'''''''' + WHEN ep.minor_id > 0 AND o.[type] NOT IN (N''U'') THEN + N'', @level2type = N''''PARAMETER'''', @level2name = N'''''' + REPLACE(ISNULL(par.name, N''''), N'''''''', N'''''''''''') + N'''''''' + ELSE N'''' + END + END + WHEN 3 THEN -- Schema-level + N'', @level0type = N''''SCHEMA'''', @level0name = N'''''' + REPLACE(sch.name, N'''''''', N'''''''''''') + N'''''''' + WHEN 7 THEN -- Index level + N'', @level0type = N''''SCHEMA'''', @level0name = N'''''' + REPLACE(s.name, N'''''''', N'''''''''''') + N'''''''' + + N'', @level1type = N''''TABLE'''', @level1name = N'''''' + REPLACE(o.name, N'''''''', N'''''''''''') + N'''''''' + + N'', @level2type = N''''INDEX'''', @level2name = N'''''' + REPLACE(idx.name, N'''''''', N'''''''''''') + N'''''''' + ELSE N'''' + END + N'';'' +FROM {#SOURCEDB_Q#}.sys.extended_properties AS ep +LEFT JOIN {#SOURCEDB_Q#}.sys.objects AS o ON o.object_id = ep.major_id AND ep.class IN (1, 7) +LEFT JOIN {#SOURCEDB_Q#}.sys.schemas AS s ON s.schema_id = o.schema_id +LEFT JOIN {#SOURCEDB_Q#}.sys.objects AS po ON po.object_id = o.parent_object_id AND ep.class = 1 AND o.parent_object_id <> 0 +LEFT JOIN {#SOURCEDB_Q#}.sys.schemas AS ps ON ps.schema_id = po.schema_id +LEFT JOIN {#SOURCEDB_Q#}.sys.columns AS c ON c.object_id = ep.major_id AND c.column_id = ep.minor_id AND ep.class = 1 +LEFT JOIN {#SOURCEDB_Q#}.sys.parameters AS par ON par.object_id = ep.major_id AND par.parameter_id = ep.minor_id AND ep.class = 1 +LEFT JOIN {#SOURCEDB_Q#}.sys.indexes AS idx ON idx.object_id = ep.major_id AND idx.index_id = ep.minor_id AND ep.class = 7 +LEFT JOIN {#SOURCEDB_Q#}.sys.schemas AS sch ON sch.schema_id = ep.major_id AND ep.class = 3 +WHERE ep.class IN (0, 1, 3, 7) -- 0=Database, 1=Object/Column, 3=Schema, 7=Index + AND (ep.class IN (0, 3) OR (o.is_ms_shipped = 0 AND ISNULL(s.name, N''sys'') <> N''sys'')) + -- Exclude properties on excluded objects + AND NOT EXISTS ( + SELECT 1 FROM #ExcludedObjects AS ex + WHERE ep.class IN (1, 7) AND o.name IS NOT NULL + AND ((ex.IsWildcard = 1 AND (o.name COLLATE DATABASE_DEFAULT LIKE ex.Pattern OR (s.name + N''.'' + o.name) COLLATE DATABASE_DEFAULT LIKE ex.Pattern)) + OR (ex.IsWildcard = 0 AND (o.name COLLATE DATABASE_DEFAULT = ex.Pattern OR (s.name + N''.'' + o.name) COLLATE DATABASE_DEFAULT = ex.Pattern))) + );'; + -- Ersetze Platzhalter durch tatsächliche Werte +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -2310,6 +2649,11 @@ DEALLOCATE syn_warn_cursor;'; VALUES (N'99-Finalize', N'USE [master]; ALTER DATABASE {#TARGETDB_Q#} SET RECOVERY FULL;'); + -- Set target database to MULTI_USER mode + INSERT INTO #Commands(Phase, Command) + VALUES + (N'99-Finalize', N'USE [master]; ALTER DATABASE {#TARGETDB_Q#} SET MULTI_USER;'); + -- Restore source database to original user access mode INSERT INTO #Commands(Phase, Command) VALUES @@ -2328,13 +2672,13 @@ DEALLOCATE syn_warn_cursor;'; -- Filter commands based on MODE -- FULL: All phases - -- SCHEMA: All phases except 04-Data and 04a-ShrinkTempdb - -- DATA: Only 04-Data and 04a-ShrinkTempdb (target DB must exist) + -- SCHEMA: All phases except 04-Data, 04a-ShrinkTempdb, 03a-FK-Disable, 04b-FK-Enable + -- DATA: Only 03a-FK-Disable, 04-Data, 04a-ShrinkTempdb, 04b-FK-Enable (target DB must exist) SELECT Step, Phase, Command FROM #Commands WHERE (@MODE = 'FULL') - OR (@MODE = 'SCHEMA' AND Phase NOT IN ('04-Data', '04a-ShrinkTempdb')) - OR (@MODE = 'DATA' AND Phase IN ('04-Data', '04a-ShrinkTempdb')) + OR (@MODE = 'SCHEMA' AND Phase NOT IN ('04-Data', '04a-ShrinkTempdb', '03a-FK-Disable', '04b-FK-Enable')) + OR (@MODE = 'DATA' AND Phase IN ('03a-FK-Disable', '04-Data', '04a-ShrinkTempdb', '04b-FK-Enable')) ORDER BY Step; ---------------------------------------------------------------------------------------------------------------------------- @@ -2370,8 +2714,8 @@ DEALLOCATE syn_warn_cursor;'; SELECT Step, Phase, Command FROM #Commands WHERE (@MODE = 'FULL') - OR (@MODE = 'SCHEMA' AND Phase NOT IN ('04-Data', '04a-ShrinkTempdb')) - OR (@MODE = 'DATA' AND Phase IN ('04-Data', '04a-ShrinkTempdb')) + OR (@MODE = 'SCHEMA' AND Phase NOT IN ('04-Data', '04a-ShrinkTempdb', '03a-FK-Disable', '04b-FK-Enable')) + OR (@MODE = 'DATA' AND Phase IN ('03a-FK-Disable', '04-Data', '04a-ShrinkTempdb', '04b-FK-Enable')) ORDER BY Step; OPEN preval_cur; @@ -2386,14 +2730,20 @@ DEALLOCATE syn_warn_cursor;'; -- - 99-Finalize: ALTER DATABASE statements may fail without proper context -- - 04-Data: INSERT statements may reference tables that don't exist yet -- - 15-Synonyms-WARN: Only PRINT statements, no SQL to validate + -- - 16-ExtendedProperties: EXEC sp_addextendedproperty cannot be validated with PARSEONLY -- - Phases that depend on previous phases having run successfully - IF @PREVAL_PHASE IN (N'00-DropTarget', N'01-CreateDb', N'99-Finalize', N'04-Data', N'04a-ShrinkTempdb', N'15-Synonyms-WARN') BEGIN + IF @PREVAL_PHASE IN (N'00-DropTarget', N'01-CreateDb', N'99-Finalize', N'04-Data', N'04a-ShrinkTempdb', N'03a-FK-Disable', N'04b-FK-Enable', N'15-Synonyms-WARN', N'16-ExtendedProperties') BEGIN SET @PREVAL_SKIPPED = @PREVAL_SKIPPED + 1; IF @DEBUG = 1 PRINT N'DEBUG: Skipping pre-validation for ' + @PREVAL_PHASE + N' (cannot be validated before dependent objects exist)'; END ELSE BEGIN -- Use SET PARSEONLY to check SQL syntax without execution -- PARSEONLY validates T-SQL syntax but doesn't verify object existence + -- LIMITATION: PARSEONLY cannot detect all runtime errors, e.g.: + -- - Missing tables/columns (deferred name resolution) + -- - Incorrect data types in expressions + -- - Permission errors + -- It catches: malformed SQL, wrong keywords, incorrect escaping -- This catches syntax errors like malformed statements, incorrect escaping, etc. BEGIN TRY DECLARE @PREVAL_WRAPPER NVARCHAR(MAX); @@ -2537,8 +2887,8 @@ DEALLOCATE syn_warn_cursor;'; SELECT Step, Phase, Command FROM #Commands WHERE (@MODE = 'FULL') - OR (@MODE = 'SCHEMA' AND Phase NOT IN ('04-Data', '04a-ShrinkTempdb')) - OR (@MODE = 'DATA' AND Phase IN ('04-Data', '04a-ShrinkTempdb')) + OR (@MODE = 'SCHEMA' AND Phase NOT IN ('04-Data', '04a-ShrinkTempdb', '03a-FK-Disable', '04b-FK-Enable')) + OR (@MODE = 'DATA' AND Phase IN ('03a-FK-Disable', '04-Data', '04a-ShrinkTempdb', '04b-FK-Enable')) ORDER BY Step; OPEN cmd_cur; @@ -2552,6 +2902,9 @@ DEALLOCATE syn_warn_cursor;'; PRINT N'Executing step ' + CONVERT(NVARCHAR(20), @CURRENTSTEP) + N' (' + @CURRENTPHASE + N')'; IF @DEBUG = 1 PRINT 'DEBUG: Command length: ' + CONVERT(NVARCHAR(20), LEN(@CURRENTCOMMAND)) + ' chars'; EXEC (@CURRENTCOMMAND); + -- NOTE: @@ROWCOUNT after EXEC() returns the row count of the LAST statement + -- inside the dynamic SQL, not the total rows affected by all statements. + -- For batched data copy (04-Data), the actual row count is handled inside the batch loop. SET @ROWCOUNT_AFFECTED = @@ROWCOUNT; IF @DEBUG = 1 PRINT 'DEBUG: Step completed, rows affected: ' + CONVERT(NVARCHAR(20), @ROWCOUNT_AFFECTED); @@ -2605,20 +2958,20 @@ DEALLOCATE syn_warn_cursor;'; BEGIN TRY SET @DYNAMICSQL = N'ALTER DATABASE {#SOURCEDB_Q#} SET ' + ISNULL(@SOURCE_USER_ACCESS_ORIGINAL, N'MULTI_USER') + N';'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); - IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; - IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; - BEGIN TRY - EXEC sys.sp_executesql @DYNAMICSQL; - END TRY BEGIN CATCH - PRINT N'ERROR in dynamic SQL:'; - PRINT @DYNAMICSQL; - THROW; - END CATCH; +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; + BEGIN TRY + EXEC sys.sp_executesql @DYNAMICSQL; + END TRY BEGIN CATCH + PRINT N'ERROR in dynamic SQL:'; + PRINT @DYNAMICSQL; + THROW; + END CATCH; PRINT 'INFO: Source database restored to ' + ISNULL(@SOURCE_USER_ACCESS_ORIGINAL, 'MULTI_USER') + ' mode.'; END TRY BEGIN CATCH PRINT 'WARN: Could not restore source database to ' + ISNULL(@SOURCE_USER_ACCESS_ORIGINAL, 'MULTI_USER') + ': ' + ERROR_MESSAGE(); @@ -2940,20 +3293,20 @@ DEALLOCATE syn_warn_cursor;'; BEGIN TRY SET @DYNAMICSQL = N'ALTER DATABASE {#TARGETDB_Q#} SET MULTI_USER;'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); - IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; - IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; - BEGIN TRY - EXEC sys.sp_executesql @DYNAMICSQL; - END TRY BEGIN CATCH - PRINT N'ERROR in dynamic SQL:'; - PRINT @DYNAMICSQL; - THROW; - END CATCH; +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; + IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; + BEGIN TRY + EXEC sys.sp_executesql @DYNAMICSQL; + END TRY BEGIN CATCH + PRINT N'ERROR in dynamic SQL:'; + PRINT @DYNAMICSQL; + THROW; + END CATCH; PRINT N'SUCCESS: Target database ' + @TARGETDATABASE + N' is now in MULTI_USER mode.'; IF (@LOGLEVEL IN ('INFO')) BEGIN @@ -2996,11 +3349,11 @@ DEALLOCATE syn_warn_cursor;'; BEGIN TRY SET @DYNAMICSQL = N'ALTER DATABASE {#SOURCEDB_Q#} SET ' + ISNULL(@SOURCE_USER_ACCESS_ORIGINAL, N'MULTI_USER') + N';'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY @@ -3053,11 +3406,11 @@ DEALLOCATE syn_warn_cursor;'; BEGIN TRY SET @DYNAMICSQL = N'ALTER DATABASE {#SOURCEDB_Q#} SET ' + ISNULL(@SOURCE_USER_ACCESS_ORIGINAL, N'MULTI_USER') + N';'; -- Ersetze Platzhalter durch tatsächliche Werte - SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, - @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), - @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), - @PH_SOURCEDB, @SOURCEDATABASE), - @PH_TARGETDB, @TARGETDATABASE); +SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(REPLACE(@DYNAMICSQL, + @PH_SOURCEDB_QUOTED, @SOURCEDATABASE_QUOTED), + @PH_TARGETDB_QUOTED, @TARGETDATABASE_QUOTED), + @PH_SOURCEDB, @SOURCEDATABASE), +@PH_TARGETDB, @TARGETDATABASE); IF @DEBUG = 1 AND LEN(@DYNAMICSQL) <= 4000 PRINT @DYNAMICSQL; IF @DEBUG = 1 AND LEN(@DYNAMICSQL) > 4000 PRINT LEFT(@DYNAMICSQL, 4000) + N'...(truncated)'; BEGIN TRY diff --git a/current/[DD_SYS]-Database/[PRDD_SYNC_DATABASE]/[PRDD_SYNC_DATABASE].sql b/current/[DD_SYS]-Database/[PRDD_SYNC_DATABASE]/[PRDD_SYNC_DATABASE].sql index 553a228..2fbdd3f 100644 --- a/current/[DD_SYS]-Database/[PRDD_SYNC_DATABASE]/[PRDD_SYNC_DATABASE].sql +++ b/current/[DD_SYS]-Database/[PRDD_SYNC_DATABASE]/[PRDD_SYNC_DATABASE].sql @@ -5,10 +5,6 @@ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -SET ANSI_WARNINGS ON -GO -SET ANSI_PADDING ON -GO -- [PRDD_SYNC_DATABASE] -- ================================================================= @@ -33,36 +29,18 @@ GO -- - CLR Assemblies, CLR Functions, CLR Procedures (CREATE ASSEMBLY) -- - Encrypted Objects (WITH ENCRYPTION) -- ================================================================= --- GEPLANTE FEATURES / PLANNED FEATURES (Future): --- - @pBATCHSIZE: Batch-basiertes MERGE für große Tabellen (Parameter validiert, Implementierung ausstehend) --- ================================================================= --- Copyright (c) 2025 by Digital Data GmbH +-- Copyright (c) 2026 by Digital Data GmbH -- -- Digital Data GmbH • Ludwig-Rinn-Strasse 16 • D-35452 Heuchelheim -- Tel.: 0641/202360 • E-Mail: info-flow@digitaldata.works -- ================================================================= -- Creation Date / Author: 24.12.2025 / MK --- Version Date / Editor: 29.12.2025 / MK --- Version Number: 0.6.4 (Final) +-- Version Date / Editor: 19.03.2026 / MK +-- Version Number: 1.1.0.0 -- ================================================================= -- History: --- 29.12.2025 / MK - v0.6.4: Bugfix: Views+Functions+Procedures robust (case-insensitive, whitespace, placeholder) --- 29.12.2025 / MK - v0.6.3: Code Review: 34 Punkte behoben (CRITICAL, HIGH, MEDIUM, LOW) --- 29.12.2025 / MK - v0.6.2: Validation auch bei @EXECUTE=0 (DRY-RUN/Preview) --- 29.12.2025 / MK - v0.6.1: OBJECT DETAILS nur bei @DEBUG=1 (weniger Output) --- 29.12.2025 / MK - v0.6.0: Views/Procedures/Functions use CREATE OR ALTER (no more DROP required) --- 29.12.2025 / MK - v0.5.9: Cycle Detection for Views/Functions Dependency CTEs --- 29.12.2025 / MK - v0.5.8: Code Review Fixes + Bidirectional Mismatch Report --- 29.12.2025 / MK - v0.5.7: Feature: @pDROPEXISTING Parameter zur Steuerung von DROP-Statements --- 29.12.2025 / MK - v0.5.6: Bugfix: DROP Phases sort before CREATE, Comprehensive Collation-Fix --- 29.12.2025 / MK - v0.5.4: Feature: @pUSETRANSACTION Parameter, Transaction Safety-Net --- 29.12.2025 / MK - v0.5.3: Code Review: 23-Punkte-Plan (Security, Performance, Validation) --- 29.12.2025 / MK - v0.5.2: Feature: Collation-Check, Temp-Tables mit Server-Collation --- 29.12.2025 / MK - v0.5.1: Bugfix: Temp-Tabellen dynamisch mit Quell-DB Collation --- 29.12.2025 / MK - v0.5.0: Feature: DROP + CREATE for programmable objects --- 29.12.2025 / MK - v0.4.x: Diverse Bugfixes und Code Reviews --- 28.12.2025 / MK - v0.3.x: Collation-Fixes, Cursors LOCAL, Stats --- 24.12.2025 / MK - v0.2.0: IncludeData-Option, Logging-Tabelle, Hash-Vergleich +-- 13.12.2024 / MK - First Version +-- 19.03.2026 / MK - Collate of source and target will be respected -- ================================================================= CREATE OR ALTER PROCEDURE [dbo].[PRDD_SYNC_DATABASE] ( @pSOURCEDATABASE NVARCHAR(128) = NULL, -- Quell-Datenbank (Referenz). Schema- und Datenvergleich-Basis. Nicht NULL erforderlich. @@ -153,7 +131,7 @@ BEGIN -- BATCHSIZE mit Konstanten validieren (#1, #18) SET @BATCHSIZE = CASE - WHEN @pBATCHSIZE IS NULL OR @pBATCHSIZE < 0 THEN @CONST_DEFAULT_BATCHSIZE + WHEN @pBATCHSIZE IS NULL OR @pBATCHSIZE <= 0 THEN @CONST_DEFAULT_BATCHSIZE WHEN @pBATCHSIZE > 0 AND @pBATCHSIZE < @CONST_MIN_BATCHSIZE THEN @CONST_MIN_BATCHSIZE WHEN @pBATCHSIZE > @CONST_MAX_BATCHSIZE THEN @CONST_MAX_BATCHSIZE ELSE @pBATCHSIZE @@ -170,6 +148,9 @@ BEGIN SET @VALIDATION_MODE = N'NONE'; END; + -- Validate LOGLEVEL early (before first use in log table creation) + IF @LOGLEVEL IS NOT NULL AND UPPER(@LOGLEVEL) NOT IN (N'INFO',N'WARN',N'ERROR') BEGIN RAISERROR('Invalid @pLOGLEVEL',16,1); RETURN 1; END; + --=================================================-- Declare runtime variables --==========================================-- DECLARE @MY_PROCEDURE_NAME NVARCHAR(128) = OBJECT_NAME(@@PROCID); DECLARE @PRODUCTVERSION sql_variant, @@ -258,6 +239,19 @@ BEGIN RETURN 1; END; + -- Validate database parameters early (before collation detection which needs valid DBs) + IF @SOURCEDATABASE IS NULL OR DB_ID(@SOURCEDATABASE) IS NULL BEGIN + RAISERROR('Source database invalid/missing: [%s]',16,1, @pSOURCEDATABASE); RETURN 1; END; + IF @TARGETDATABASE IS NULL OR DB_ID(@TARGETDATABASE) IS NULL BEGIN + RAISERROR('Target database must exist: [%s]',16,1, @pTARGETDATABASE); RETURN 1; END; + IF @SOURCEDATABASE = @TARGETDATABASE BEGIN RAISERROR('Source and target must differ: [%s]=[%s]',16,1, @pSOURCEDATABASE, @pTARGETDATABASE); RETURN 1; END; + + -- Check if databases are online (uses state instead of state_desc for performance) + IF EXISTS (SELECT 1 FROM sys.databases WHERE name = @SOURCEDATABASE AND state <> 0) BEGIN + RAISERROR('Source database is not online (state <> 0)',16,1); RETURN 1; END; + IF EXISTS (SELECT 1 FROM sys.databases WHERE name = @TARGETDATABASE AND state <> 0) BEGIN + RAISERROR('Target database is not online (state <> 0)',16,1); RETURN 1; END; + -- Get Collations: Server, Source and Target (not DD_SYS!) SELECT @SERVERCOLLATION = CONVERT(NVARCHAR(128), SERVERPROPERTY('Collation')); DECLARE @COLLATION_SQL NVARCHAR(1000); SET @COLLATION_SQL = N'USE ' + @SOURCEDATABASEQUOTED + N'; SELECT @col = CONVERT(NVARCHAR(128), DATABASEPROPERTYEX(DB_NAME(), ''Collation''))'; EXEC sys.sp_executesql @COLLATION_SQL, N'@col NVARCHAR(128) OUTPUT', @SOURCECOLLATION OUTPUT; @@ -286,7 +280,7 @@ BEGIN --=================================================-- Logging-Tabelle im aktuellen Kontext sicherstellen --================================================-- IF @LOGLEVEL IS NOT NULL BEGIN - IF EXISTS (SELECT * FROM [INFORMATION_SCHEMA].[TABLES] WHERE [TABLE_NAME] = N'TBDD_SYNC_DATABASE_LOG') BEGIN + IF EXISTS (SELECT * FROM [INFORMATION_SCHEMA].[TABLES] WHERE [TABLE_SCHEMA] = N'dbo' AND [TABLE_NAME] = N'TBDD_SYNC_DATABASE_LOG') BEGIN PRINT '[INFO] Log table already exists'; END ELSE BEGIN @@ -328,7 +322,7 @@ BEGIN N'; SessionID=' + CONVERT(NVARCHAR(100),@MYSESSIONID); --================================================-- Log server info to table --=================================================-- - IF (UPPER(@LOGLEVEL) IN (N'INFO',N'WARN',N'ERROR')) BEGIN + IF @LOGLEVEL = N'INFO' BEGIN INSERT INTO [TBDD_SYNC_DATABASE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [ADDED_WHO], [ADDED_WHEN]) VALUES ('INFO', '00-Server', CONVERT(NVARCHAR(MAX),@SERVERNAME), @SERVERINFOMSG, @MY_PROCEDURE_NAME, GETDATE()); END; @@ -337,19 +331,8 @@ BEGIN ----------------------------------------------------------------------------------------------------------------------------- - IF @SOURCEDATABASE IS NULL OR DB_ID(@SOURCEDATABASE) IS NULL BEGIN - RAISERROR('Source database invalid/missing',16,1); RETURN 1; END; - IF @TARGETDATABASE IS NULL OR DB_ID(@TARGETDATABASE) IS NULL BEGIN - RAISERROR('Target database must exist',16,1); RETURN 1; END; - IF @SOURCEDATABASE = @TARGETDATABASE BEGIN RAISERROR('Source and target must differ',16,1); RETURN 1; END; - - -- Check if databases are online (uses state instead of state_desc for performance) - IF EXISTS (SELECT 1 FROM sys.databases WHERE name = @SOURCEDATABASE AND state <> 0) BEGIN - RAISERROR('Source database is not online (state <> 0)',16,1); RETURN 1; END; - IF EXISTS (SELECT 1 FROM sys.databases WHERE name = @TARGETDATABASE AND state <> 0) BEGIN - RAISERROR('Target database is not online (state <> 0)',16,1); RETURN 1; END; IF @DEBUG = 1 PRINT '[DEBUG] Validating @LOGLEVEL: ' + ISNULL(@LOGLEVEL, ''); - IF @LOGLEVEL IS NOT NULL AND UPPER(@LOGLEVEL) NOT IN (N'INFO',N'WARN',N'ERROR') BEGIN RAISERROR('Invalid @pLOGLEVEL',16,1); RETURN 1; END; + -- LOGLEVEL already validated early (before first use) IF @DEBUG = 1 PRINT '[DEBUG] Validating @VALIDATION_MODE: ' + ISNULL(@VALIDATION_MODE, ''); -- VALIDATION_MODE is already validated in line 101-104 and set to default @@ -385,25 +368,29 @@ BEGIN IF @DEBUG = 1 PRINT '[DEBUG] All validations passed'; -- Security #17: Extended permission check for DDL operations - IF @EXECUTE = 1 BEGIN - IF HAS_PERMS_BY_NAME(@TARGETDATABASE, 'DATABASE', 'ALTER') = 0 BEGIN + IF HAS_PERMS_BY_NAME(@TARGETDATABASE, 'DATABASE', 'ALTER') = 0 BEGIN + IF @EXECUTE = 1 BEGIN RAISERROR('Insufficient permissions: ALTER permission required on target database',16,1); RETURN 1; - END; - IF HAS_PERMS_BY_NAME(@TARGETDATABASE, 'DATABASE', 'CREATE TABLE') = 0 BEGIN + END ELSE PRINT '[WARN] No ALTER permission on target database (dry-run continues)'; + END; + IF HAS_PERMS_BY_NAME(@TARGETDATABASE, 'DATABASE', 'CREATE TABLE') = 0 BEGIN + IF @EXECUTE = 1 BEGIN RAISERROR('Insufficient permissions: CREATE TABLE permission required on target database',16,1); RETURN 1; - END; - IF HAS_PERMS_BY_NAME(@SOURCEDATABASE, 'DATABASE', 'VIEW DEFINITION') = 0 BEGIN + END ELSE PRINT '[WARN] No CREATE TABLE permission on target database (dry-run continues)'; + END; + IF HAS_PERMS_BY_NAME(@SOURCEDATABASE, 'DATABASE', 'VIEW DEFINITION') = 0 BEGIN + IF @EXECUTE = 1 BEGIN RAISERROR('Insufficient permissions: VIEW DEFINITION permission required on source database',16,1); RETURN 1; - END; + END ELSE PRINT '[WARN] No VIEW DEFINITION permission on source database (dry-run continues)'; END; IF @DEBUG = 1 PRINT '[DEBUG] Permissions validated'; --===============================================-- Log result to table --=================================================-- IF @DEBUG = 1 PRINT '[DEBUG] Logging to table...'; - IF UPPER(@LOGLEVEL) IN (N'INFO',N'WARN',N'ERROR') BEGIN + IF @LOGLEVEL = N'INFO' BEGIN INSERT INTO [TBDD_SYNC_DATABASE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [ADDED_WHO], [ADDED_WHEN]) VALUES ('INFO', '01-Validation', 'Parametern validiert', 'Source: '+@SOURCEDATABASE+', Target: '+@TARGETDATABASE, @MY_PROCEDURE_NAME, GETDATE()); END; @@ -440,7 +427,7 @@ BEGIN --===============================================-- Log result to table --=================================================-- IF @DEBUG = 1 PRINT '[DEBUG] Counting excludes...'; DECLARE @EXCLUDECOUNT INT = (SELECT COUNT(*) FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS); - IF (UPPER(@LOGLEVEL) IN (N'INFO',N'WARN',N'ERROR')) BEGIN + IF @LOGLEVEL = N'INFO' BEGIN INSERT INTO [TBDD_SYNC_DATABASE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [ADDED_WHO], [ADDED_WHEN]) VALUES ('INFO', '02-Preparation', 'Temp-Tabellen erstellt', 'Excludes: '+CONVERT(NVARCHAR(10),@EXCLUDECOUNT), @MY_PROCEDURE_NAME, GETDATE()); END; @@ -457,7 +444,7 @@ BEGIN IF @SYNCSECURITY = 1 BEGIN IF @DEBUG = 1 PRINT '[DEBUG] Security sync is enabled'; --===============================================-- Log result to table --=================================================-- - IF (UPPER(@LOGLEVEL) IN (N'INFO',N'WARN',N'ERROR')) BEGIN + IF @LOGLEVEL = N'INFO' BEGIN INSERT INTO [TBDD_SYNC_DATABASE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [ADDED_WHO], [ADDED_WHEN]) VALUES ('INFO', '03-Security', 'Security-Sync aktiviert', 'Sync Rollen, Benutzer, Grants', @MY_PROCEDURE_NAME, GETDATE()); END; @@ -471,7 +458,8 @@ SELECT * FROM ( SELECT N''01-Security-Roles'', N''USE {#TARGETDB_Q#}; IF NOT EXISTS (SELECT 1 FROM sys.database_principals WHERE name=N'''''' + REPLACE(r.name, '''''''', '''''''''''') + N'''''' AND type=''''R'''') CREATE ROLE ''+QUOTENAME(r.name)+N'';'' FROM {#SOURCEDB_Q#}.sys.database_principals r -WHERE r.type=''R'' AND ISNULL(r.is_fixed_role,0)=0 AND r.name{#COLLATION#} NOT IN (N''public'')) AS X(Phase, Command) +WHERE r.type=''R'' AND ISNULL(r.is_fixed_role,0)=0 AND r.name{#COLLATION#} NOT IN (N''public'') + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard=1 AND r.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#}) OR (ex.IsWildcard=0 AND r.name{#COLLATION#}=ex.Pattern{#COLLATION#}))) AS X(Phase, Command) WHERE X.Command IS NOT NULL AND LEN(X.Command)>0;' SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(@DYNAMICSQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); BEGIN TRY @@ -496,7 +484,8 @@ SELECT N''01-Security-Users'', BEGIN CREATE USER ''+QUOTENAME(dp.name)+N'' FOR LOGIN ''+QUOTENAME(dp.name)+N'' WITH DEFAULT_SCHEMA='' + QUOTENAME(ISNULL(dp.default_schema_name,N''dbo'')) + N''; END'' FROM {#SOURCEDB_Q#}.sys.database_principals dp WHERE dp.type IN (''S'',''U'') - AND dp.name{#COLLATION#} NOT IN (N''dbo'',N''guest'',N''INFORMATION_SCHEMA'',N''sys'',N''public'')) AS X(Phase, Command) + AND dp.name{#COLLATION#} NOT IN (N''dbo'',N''guest'',N''INFORMATION_SCHEMA'',N''sys'',N''public'') + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard=1 AND dp.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#}) OR (ex.IsWildcard=0 AND dp.name{#COLLATION#}=ex.Pattern{#COLLATION#}))) AS X(Phase, Command) WHERE X.Command IS NOT NULL AND LEN(X.Command)>0;'; SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(@DYNAMICSQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); BEGIN TRY @@ -525,7 +514,8 @@ FROM {#SOURCEDB_Q#}.sys.database_role_members drm JOIN {#SOURCEDB_Q#}.sys.database_principals r ON r.principal_id=drm.role_principal_id JOIN {#SOURCEDB_Q#}.sys.database_principals m ON m.principal_id=drm.member_principal_id WHERE r.name{#COLLATION#} NOT IN (N''public'') - AND m.name{#COLLATION#} NOT IN (N''dbo'',N''guest'',N''INFORMATION_SCHEMA'',N''sys'',N''public'')) AS X(Phase, Command) + AND m.name{#COLLATION#} NOT IN (N''dbo'',N''guest'',N''INFORMATION_SCHEMA'',N''sys'',N''public'') + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard=1 AND (r.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR m.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard=0 AND (r.name{#COLLATION#}=ex.Pattern{#COLLATION#} OR m.name{#COLLATION#}=ex.Pattern{#COLLATION#})))) AS X(Phase, Command) WHERE X.Command IS NOT NULL AND LEN(X.Command)>0;'; SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(@DYNAMICSQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); BEGIN TRY @@ -575,7 +565,9 @@ LEFT JOIN {#TARGETDB_Q#}.sys.database_permissions tdp ON tdp.grantee_principal_i WHERE pr.name{#COLLATION#} NOT IN (N''dbo'',N''guest'',N''INFORMATION_SCHEMA'',N''sys'',N''public'') AND dp.permission_name NOT IN (N''CONTROL'') AND dp.state_desc IN (''GRANT'',''GRANT_WITH_GRANT_OPTION'',''DENY'') - AND tdp.major_id IS NULL;'; + AND dp.class IN (0, 1, 3, 4) + AND tdp.major_id IS NULL + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard=1 AND pr.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#}) OR (ex.IsWildcard=0 AND pr.name{#COLLATION#}=ex.Pattern{#COLLATION#}));'; SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(@DYNAMICSQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); IF @DEBUG=1 BEGIN DECLARE @DbgPos INT = 1, @DbgChunk INT = 4000; @@ -633,7 +625,7 @@ WHERE s.name{#COLLATION#} NOT IN (N''sys'',N''INFORMATION_SCHEMA'',N''dbo'',N''g SET @DYNAMICSQL = N' INSERT INTO #TBDD_SYNC_DATABASE_COMMANDS(Phase, Command) SELECT N''03-Tables'', - CASE WHEN tgt.object_id IS NULL THEN + CASE WHEN tt.object_id IS NULL THEN N''USE {#TARGETDB_Q#}; CREATE TABLE '' + QUOTENAME(sc.name) + N''.'' + QUOTENAME(t.name) + N''('' + STUFF(( SELECT N'','' + CHAR(10) + N'' '' + @@ -659,15 +651,14 @@ SELECT N''03-Tables'', FOR XML PATH(''''), TYPE).value(''.'', ''nvarchar(max)''),1,2,N'''') + N'' );'' ELSE - N''-- Table structure differs: '' + QUOTENAME(sc.name) + N''.'' + QUOTENAME(t.name) + N'' (manual review required)'' + NULL END FROM {#SOURCEDB_Q#}.sys.tables t JOIN {#SOURCEDB_Q#}.sys.schemas sc ON sc.schema_id=t.schema_id LEFT JOIN {#TARGETDB_Q#}.sys.schemas tsc ON tsc.name{#COLLATION#}=sc.name{#COLLATION#} LEFT JOIN {#TARGETDB_Q#}.sys.tables tt ON tt.name{#COLLATION#}=t.name{#COLLATION#} AND tt.schema_id = tsc.schema_id -LEFT JOIN {#TARGETDB_Q#}.sys.objects tgt ON tgt.object_id = tt.object_id WHERE sc.name{#COLLATION#}<>N''sys''{#COLLATION#} AND t.is_ms_shipped=0 - AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard=1 AND (t.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (sc.name + N''.'' + t.name){#COLLATION#} LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard=0 AND (t.name{#COLLATION#}=ex.Pattern{#COLLATION#} OR (sc.name + N''.'' + t.name){#COLLATION#}=ex.Pattern{#COLLATION#})));'; + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard=1 AND (t.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (sc.name{#COLLATION#}+N''.''{#COLLATION#}+t.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard=0 AND (t.name{#COLLATION#}=ex.Pattern{#COLLATION#} OR (sc.name{#COLLATION#}+N''.''{#COLLATION#}+t.name{#COLLATION#})=ex.Pattern{#COLLATION#})));'; SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(@DYNAMICSQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); SET @DYNAMICSQL = REPLACE(REPLACE(@DYNAMICSQL, @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE); SET @DYNAMICSQL = REPLACE(@DYNAMICSQL, @PLACEHOLDERTARGETCOLLATION, @TARGETCOLLATION); @@ -739,6 +730,49 @@ WHERE sc.name{#COLLATION#}<>N''sys''{#COLLATION#} AND t.is_ms_shipped=0 END CATCH; ----------------------------------------------------------------------------------------------------------------------------- + --=================================================-- Table ALTER: Drop dependent NC indexes before column modification --================================================-- + -- ALTER COLUMN fails if the column is part of an index. Drop NC indexes on columns that will be altered. + SET @DYNAMICSQL = N' +INSERT INTO #TBDD_SYNC_DATABASE_COMMANDS(Phase, Command) +SELECT DISTINCT N''03-Table-AlterCols-DropIdx'', + N''USE {#TARGETDB_Q#}; DROP INDEX ''+QUOTENAME(ti.name)+N'' ON ''+QUOTENAME(tsc.name)+N''.''{#COLLATION#}+QUOTENAME(tt.name)+N'';'' +FROM {#SOURCEDB_Q#}.sys.tables t +JOIN {#SOURCEDB_Q#}.sys.schemas sc ON sc.schema_id=t.schema_id +JOIN {#SOURCEDB_Q#}.sys.columns c ON c.object_id=t.object_id +JOIN {#SOURCEDB_Q#}.sys.types ty ON ty.user_type_id=c.user_type_id +LEFT JOIN {#SOURCEDB_Q#}.sys.identity_columns ic_src ON ic_src.object_id=c.object_id AND ic_src.column_id=c.column_id +LEFT JOIN {#TARGETDB_Q#}.sys.schemas tsc ON tsc.name{#COLLATION#}=sc.name{#COLLATION#} +LEFT JOIN {#TARGETDB_Q#}.sys.tables tt ON tt.name{#COLLATION#}=t.name{#COLLATION#} AND tt.schema_id=tsc.schema_id +LEFT JOIN {#TARGETDB_Q#}.sys.columns tc ON tc.object_id=tt.object_id AND tc.name{#COLLATION#}=c.name{#COLLATION#} +LEFT JOIN {#TARGETDB_Q#}.sys.types tty ON tty.user_type_id=tc.user_type_id +-- Find target NC indexes referencing this column +JOIN {#TARGETDB_Q#}.sys.index_columns tic ON tic.object_id=tt.object_id AND tic.column_id=tc.column_id +JOIN {#TARGETDB_Q#}.sys.indexes ti ON ti.object_id=tic.object_id AND ti.index_id=tic.index_id AND ti.is_primary_key=0 AND ti.is_unique_constraint=0 AND ti.type IN (1,2) +WHERE sc.name{#COLLATION#}<>N''sys''{#COLLATION#} AND t.is_ms_shipped=0 AND c.is_computed=0 AND tc.object_id IS NOT NULL + AND ic_src.object_id IS NULL + AND ( + c.is_nullable<>tc.is_nullable OR c.is_sparse<>tc.is_sparse OR c.max_length<>tc.max_length OR c.precision<>tc.precision OR c.scale<>tc.scale OR ty.name{#COLLATION#}<>tty.name{#COLLATION#} OR ty.is_user_defined<>tty.is_user_defined + OR (ISNULL(c.collation_name,N''''){#COLLATION#}<>ISNULL(tc.collation_name,N''''){#COLLATION#} + AND NOT (c.collation_name{#COLLATION#}=N''{#SOURCECOLLATION_NAME#}''{#COLLATION#} AND tc.collation_name{#COLLATION#}=N''{#TARGETCOLLATION_NAME#}''{#COLLATION#})) + ) + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard=1 AND (t.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (sc.name{#COLLATION#}+N''.''{#COLLATION#}+t.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard=0 AND (t.name{#COLLATION#}=ex.Pattern{#COLLATION#} OR (sc.name{#COLLATION#}+N''.''{#COLLATION#}+t.name{#COLLATION#})=ex.Pattern{#COLLATION#})));'; + SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(@DYNAMICSQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); + SET @DYNAMICSQL = REPLACE(REPLACE(@DYNAMICSQL, @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE); + SET @DYNAMICSQL = REPLACE(@DYNAMICSQL, @PLACEHOLDERTARGETCOLLATION, @TARGETCOLLATION); + SET @DYNAMICSQL = REPLACE(REPLACE(@DYNAMICSQL, @PLACEHOLDERSOURCECOLLATIONNAME, @SOURCECOLLATION), @PLACEHOLDERTARGETCOLLATIONNAME, @TARGETCOLLATION); + BEGIN TRY + EXEC sys.sp_executesql @DYNAMICSQL; + IF @DEBUG = 1 PRINT '[DEBUG] Table-AlterCols-DropIdx commands executed successfully'; + END TRY + BEGIN CATCH + PRINT '[ERROR] Failed to execute Table-AlterCols-DropIdx command!'; + PRINT '[ERROR] Error Message: ' + ERROR_MESSAGE(); + PRINT '[ERROR] Dynamic SQL (first 8000 chars):'; + PRINT SUBSTRING(@DYNAMICSQL, 1, 8000); + THROW; + END CATCH; + ----------------------------------------------------------------------------------------------------------------------------- + --=================================================-- Table ALTER: Modify columns (Type/Nullability/Collation/Sparse) --================================================-- SET @DYNAMICSQL = N' INSERT INTO #TBDD_SYNC_DATABASE_COMMANDS(Phase, Command) @@ -768,11 +802,14 @@ WHERE sc.name{#COLLATION#}<>N''sys''{#COLLATION#} AND t.is_ms_shipped=0 AND c.is AND ic_src.object_id IS NULL AND ( c.is_nullable<>tc.is_nullable OR c.is_sparse<>tc.is_sparse OR c.max_length<>tc.max_length OR c.precision<>tc.precision OR c.scale<>tc.scale OR ty.name{#COLLATION#}<>tty.name{#COLLATION#} OR ty.is_user_defined<>tty.is_user_defined + OR (ISNULL(c.collation_name,N''''){#COLLATION#}<>ISNULL(tc.collation_name,N''''){#COLLATION#} + AND NOT (c.collation_name{#COLLATION#}=N''{#SOURCECOLLATION_NAME#}''{#COLLATION#} AND tc.collation_name{#COLLATION#}=N''{#TARGETCOLLATION_NAME#}''{#COLLATION#})) ) AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard=1 AND (t.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (sc.name{#COLLATION#}+N''.''{#COLLATION#}+t.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard=0 AND (t.name{#COLLATION#}=ex.Pattern{#COLLATION#} OR (sc.name{#COLLATION#}+N''.''{#COLLATION#}+t.name{#COLLATION#})=ex.Pattern{#COLLATION#})));'; SET @DYNAMICSQL = REPLACE(REPLACE(REPLACE(@DYNAMICSQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); SET @DYNAMICSQL = REPLACE(REPLACE(@DYNAMICSQL, @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE); SET @DYNAMICSQL = REPLACE(@DYNAMICSQL, @PLACEHOLDERTARGETCOLLATION, @TARGETCOLLATION); + SET @DYNAMICSQL = REPLACE(REPLACE(@DYNAMICSQL, @PLACEHOLDERSOURCECOLLATIONNAME, @SOURCECOLLATION), @PLACEHOLDERTARGETCOLLATIONNAME, @TARGETCOLLATION); BEGIN TRY EXEC sys.sp_executesql @DYNAMICSQL; IF @DEBUG = 1 PRINT '[DEBUG] Table-AlterColumns commands executed successfully'; @@ -860,7 +897,7 @@ SELECT * FROM ( SELECT N''03-Table-Unique'', N''USE {#TARGETDB_Q#}; '' + CASE WHEN tgtuq.object_id IS NOT NULL THEN N''ALTER TABLE ''+QUOTENAME(sc.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+N'' DROP CONSTRAINT ''+QUOTENAME(tgtuq.name)+N''; '' ELSE N'''' END + N''ALTER TABLE ''+QUOTENAME(sc.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+N'' ADD CONSTRAINT ''+QUOTENAME(uq.name)+N'' UNIQUE '' + CASE WHEN i.type=1 THEN N''CLUSTERED '' ELSE N''NONCLUSTERED '' END + - N''(''+STUFF((SELECT '',''{#COLLATION#}+QUOTENAME(cs.name) + N''(''+STUFF((SELECT '',''{#COLLATION#}+QUOTENAME(cs.name) + CASE WHEN ic.is_descending_key=1 THEN N'' DESC'' ELSE N'''' END FROM {#SOURCEDB_Q#}.sys.index_columns ic JOIN {#SOURCEDB_Q#}.sys.columns cs ON cs.object_id=ic.object_id AND cs.column_id=ic.column_id WHERE ic.object_id=i.object_id AND ic.index_id=i.index_id @@ -875,7 +912,7 @@ LEFT JOIN {#TARGETDB_Q#}.sys.tables tt ON tt.name{#COLLATION#}=t.name{#COLLATION LEFT JOIN {#TARGETDB_Q#}.sys.key_constraints tgtuq ON tgtuq.parent_object_id=tt.object_id AND tgtuq.name{#COLLATION#}=uq.name{#COLLATION#} AND tgtuq.type{#COLLATION#}=''UQ''{#COLLATION#} OUTER APPLY ( SELECT HASHBYTES(''SHA2_256'', - (SELECT cs.name{#COLLATION#}, ic.key_ordinal + (SELECT cs.name{#COLLATION#}, ic.key_ordinal, ic.is_descending_key FROM {#SOURCEDB_Q#}.sys.index_columns ic JOIN {#SOURCEDB_Q#}.sys.columns cs ON cs.object_id=ic.object_id AND cs.column_id=ic.column_id WHERE ic.object_id=i.object_id AND ic.index_id=i.index_id @@ -884,7 +921,7 @@ OUTER APPLY ( ) hsrc OUTER APPLY ( SELECT HASHBYTES(''SHA2_256'', - (SELECT cs.name{#COLLATION#}, ic.key_ordinal + (SELECT cs.name{#COLLATION#}, ic.key_ordinal, ic.is_descending_key FROM {#TARGETDB_Q#}.sys.index_columns ic JOIN {#TARGETDB_Q#}.sys.columns cs ON cs.object_id=ic.object_id AND cs.column_id=ic.column_id WHERE ic.object_id=tgtuq.parent_object_id AND ic.index_id=tgtuq.unique_index_id @@ -913,20 +950,51 @@ WHERE X.Command IS NOT NULL AND LEN(X.Command)>0;'; END ELSE PRINT '[INFO] Skipping Tables (disabled by @pSYNCOBJECTS)'; ----------------------------------------------------------------------------------------------------------------------------- - --=================================================-- Foreign Keys vor PK-Anpassung droppen (Target referenziert PK-Tabellen) --================================================-- + --=================================================-- Foreign Keys vor PK-Anpassung droppen (nur bei PK-Abweichungen) --================================================-- IF @SYNC_TABLES = 1 BEGIN -- FK-Drop for PK belongs to TABLES SET @DYNAMICSQL = N' INSERT INTO #TBDD_SYNC_DATABASE_COMMANDS(Phase, Command) SELECT * FROM ( - SELECT N''04-FK-DropForPK'', - N''USE {#TARGETDB_Q#}; ALTER TABLE ''+QUOTENAME(ts.name)+N''.''{#COLLATION#}+QUOTENAME(tt.name)+N'' DROP CONSTRAINT ''+QUOTENAME(tfk.name)+N'';'' + SELECT DISTINCT N''04-FK-DropForPK'', + N''USE {#TARGETDB_Q#}; IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE object_id='' + CONVERT(NVARCHAR(20), tfk.object_id) + N'') ALTER TABLE ''+QUOTENAME(fkps.name)+N''.''{#COLLATION#}+QUOTENAME(fkpt.name)+N'' DROP CONSTRAINT ''+QUOTENAME(tfk.name)+N'';'' FROM {#SOURCEDB_Q#}.sys.key_constraints pk JOIN {#SOURCEDB_Q#}.sys.tables st ON st.object_id=pk.parent_object_id JOIN {#SOURCEDB_Q#}.sys.schemas ss ON ss.schema_id=st.schema_id + JOIN {#SOURCEDB_Q#}.sys.indexes si ON si.object_id=pk.parent_object_id AND si.index_id=pk.unique_index_id + -- Target PK table JOIN {#TARGETDB_Q#}.sys.schemas ts ON ts.name{#COLLATION#}=ss.name{#COLLATION#} JOIN {#TARGETDB_Q#}.sys.tables tt ON tt.name{#COLLATION#}=st.name{#COLLATION#} AND tt.schema_id=ts.schema_id + -- Target FK referencing this PK table JOIN {#TARGETDB_Q#}.sys.foreign_keys tfk ON tfk.referenced_object_id=tt.object_id + -- FK parent table (the table that OWNS the FK constraint) - this is where DROP must happen + JOIN {#TARGETDB_Q#}.sys.tables fkpt ON fkpt.object_id=tfk.parent_object_id + JOIN {#TARGETDB_Q#}.sys.schemas fkps ON fkps.schema_id=fkpt.schema_id + -- Hash comparison: only drop FKs when the PK actually differs (same logic as Phase 05) + OUTER APPLY ( + SELECT HASHBYTES(''SHA2_256'', + (SELECT cs.name{#COLLATION#}, ic.key_ordinal, ic.is_descending_key + FROM {#SOURCEDB_Q#}.sys.index_columns ic + JOIN {#SOURCEDB_Q#}.sys.columns cs ON cs.object_id=ic.object_id AND cs.column_id=ic.column_id + WHERE ic.object_id=si.object_id AND ic.index_id=si.index_id + ORDER BY ic.key_ordinal + FOR XML PATH(''''), TYPE).value(''.'',''nvarchar(max)''){#COLLATION#}) AS src_hash + ) hsrc + OUTER APPLY ( + SELECT tp.object_id AS tpk_id, tp.unique_index_id AS tpk_idx + FROM {#TARGETDB_Q#}.sys.key_constraints tp + WHERE tp.parent_object_id=tt.object_id AND tp.type{#COLLATION#}=''PK''{#COLLATION#} + ) tpk + OUTER APPLY ( + SELECT HASHBYTES(''SHA2_256'', + (SELECT cs.name{#COLLATION#}, ic.key_ordinal, ic.is_descending_key + FROM {#TARGETDB_Q#}.sys.index_columns ic + JOIN {#TARGETDB_Q#}.sys.columns cs ON cs.object_id=ic.object_id AND cs.column_id=ic.column_id + WHERE ic.object_id=tt.object_id AND ic.index_id=tpk.tpk_idx + ORDER BY ic.key_ordinal + FOR XML PATH(''''), TYPE).value(''.'',''nvarchar(max)''){#COLLATION#}) AS tgt_hash + ) htgt WHERE pk.type{#COLLATION#}=''PK''{#COLLATION#} AND ss.name{#COLLATION#}<>N''sys''{#COLLATION#} + AND (tpk.tpk_id IS NULL OR hsrc.src_hash<>htgt.tgt_hash) AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard=1 AND (st.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (ss.name{#COLLATION#}+N''.''{#COLLATION#}+st.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard=0 AND (st.name{#COLLATION#}=ex.Pattern{#COLLATION#} OR (ss.name{#COLLATION#}+N''.''{#COLLATION#}+st.name{#COLLATION#})=ex.Pattern{#COLLATION#}))) ) AS X(Phase, Command) WHERE X.Command IS NOT NULL AND LEN(X.Command)>0;'; @@ -952,16 +1020,16 @@ WHERE X.Command IS NOT NULL AND LEN(X.Command)>0;'; SELECT * FROM ( SELECT N''05-PrimaryKeys'', N''USE {#TARGETDB_Q#}; '' + - CASE WHEN tp.object_id IS NOT NULL THEN N''ALTER TABLE ''+QUOTENAME(sc.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+'' DROP CONSTRAINT ''+QUOTENAME(tp.name)+''; '' ELSE N'''' END + - N''ALTER TABLE ''+QUOTENAME(sc.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+'' ADD CONSTRAINT ''+QUOTENAME(pk.name)+'' PRIMARY KEY '' + + CASE WHEN tp.object_id IS NOT NULL THEN N''ALTER TABLE ''+QUOTENAME(sc.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+N'' DROP CONSTRAINT ''+QUOTENAME(tp.name)+N''; '' ELSE N'''' END + + N''ALTER TABLE ''+QUOTENAME(sc.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+N'' ADD CONSTRAINT ''+QUOTENAME(pk.name)+N'' PRIMARY KEY '' + CASE WHEN i.type=1 THEN N''CLUSTERED '' ELSE N''NONCLUSTERED '' END + N''('' + - STUFF((SELECT '',''{#COLLATION#}+QUOTENAME(cs.name) + STUFF((SELECT '',''{#COLLATION#}+QUOTENAME(cs.name) + CASE WHEN ic.is_descending_key=1 THEN N'' DESC'' ELSE N'''' END FROM {#SOURCEDB_Q#}.sys.index_columns ic JOIN {#SOURCEDB_Q#}.sys.columns cs ON cs.object_id=ic.object_id AND cs.column_id=ic.column_id WHERE ic.object_id=i.object_id AND ic.index_id=i.index_id ORDER BY ic.key_ordinal - FOR XML PATH(''''), TYPE).value(''.'',''nvarchar(max)''),1,1,N'''') + N'')'' + FOR XML PATH(''''), TYPE).value(''.'',''nvarchar(max)''),1,1,N'''') + N'');'' FROM {#SOURCEDB_Q#}.sys.key_constraints pk JOIN {#SOURCEDB_Q#}.sys.tables t ON t.object_id=pk.parent_object_id JOIN {#SOURCEDB_Q#}.sys.schemas sc ON sc.schema_id=t.schema_id @@ -975,7 +1043,7 @@ WHERE X.Command IS NOT NULL AND LEN(X.Command)>0;'; ) tp OUTER APPLY ( SELECT HASHBYTES(''SHA2_256'', - (SELECT cs.name{#COLLATION#}, ic.key_ordinal + (SELECT cs.name{#COLLATION#}, ic.key_ordinal, ic.is_descending_key FROM {#SOURCEDB_Q#}.sys.index_columns ic JOIN {#SOURCEDB_Q#}.sys.columns cs ON cs.object_id=ic.object_id AND cs.column_id=ic.column_id WHERE ic.object_id=i.object_id AND ic.index_id=i.index_id @@ -984,7 +1052,7 @@ WHERE X.Command IS NOT NULL AND LEN(X.Command)>0;'; ) hsrc OUTER APPLY ( SELECT HASHBYTES(''SHA2_256'', - (SELECT cs.name{#COLLATION#}, ic.key_ordinal + (SELECT cs.name{#COLLATION#}, ic.key_ordinal, ic.is_descending_key FROM {#TARGETDB_Q#}.sys.index_columns ic JOIN {#TARGETDB_Q#}.sys.columns cs ON cs.object_id=ic.object_id AND cs.column_id=ic.column_id WHERE ic.object_id=tp.object_id AND ic.index_id=tp.unique_index_id @@ -1020,8 +1088,10 @@ WHERE X.Command IS NOT NULL AND LEN(X.Command)>0;'; SELECT * FROM ( SELECT N''06-ForeignKeys'', N''USE {#TARGETDB_Q#}; '' + - CASE WHEN tfk.object_id IS NOT NULL THEN N''ALTER TABLE ''+QUOTENAME(ts.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+N'' DROP CONSTRAINT ''+QUOTENAME(tfk.name)+N''; '' ELSE N'''' END + - N''ALTER TABLE ''+QUOTENAME(ts.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+ + -- DROP: Use actual FK parent from target metadata (tfkpt/tfkps), not name-matched tt/tts + CASE WHEN tfk.object_id IS NOT NULL THEN N''IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE object_id='' + CONVERT(NVARCHAR(20), tfk.object_id) + N'') ALTER TABLE ''+QUOTENAME(tfkps.name)+N''.''{#COLLATION#}+QUOTENAME(tfkpt.name)+N'' DROP CONSTRAINT ''+QUOTENAME(tfk.name)+N''; '' ELSE N'''' END + + -- ADD: Always use source parent table name (correct for creating in target) + N''IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name=N'''''' + REPLACE(fk.name, '''''''', '''''''''''') + N'''''' ) ALTER TABLE ''+QUOTENAME(ts.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+ N'' WITH CHECK ADD CONSTRAINT ''+QUOTENAME(fk.name)+N'' FOREIGN KEY (''+ STUFF((SELECT '',''{#COLLATION#}+QUOTENAME(c.name) FROM {#SOURCEDB_Q#}.sys.foreign_key_columns fkc @@ -1046,7 +1116,11 @@ WHERE X.Command IS NOT NULL AND LEN(X.Command)>0;'; JOIN {#SOURCEDB_Q#}.sys.schemas rs ON rs.schema_id=rt.schema_id LEFT JOIN {#TARGETDB_Q#}.sys.schemas tts ON tts.name{#COLLATION#}=ts.name{#COLLATION#} LEFT JOIN {#TARGETDB_Q#}.sys.tables tt ON tt.name{#COLLATION#}=t.name{#COLLATION#} AND tt.schema_id=tts.schema_id - LEFT JOIN {#TARGETDB_Q#}.sys.foreign_keys tfk ON tfk.name{#COLLATION#}=fk.name{#COLLATION#} AND tfk.parent_object_id=ISNULL(tt.object_id, -1) + -- Match target FK by name and parent table (FK names are unique per schema, not per database) + LEFT JOIN {#TARGETDB_Q#}.sys.foreign_keys tfk ON tfk.name{#COLLATION#}=fk.name{#COLLATION#} AND tfk.parent_object_id=tt.object_id + -- Resolve FKs ACTUAL parent table from target metadata (not name-matched) + LEFT JOIN {#TARGETDB_Q#}.sys.tables tfkpt ON tfkpt.object_id=tfk.parent_object_id + LEFT JOIN {#TARGETDB_Q#}.sys.schemas tfkps ON tfkps.schema_id=tfkpt.schema_id OUTER APPLY ( SELECT HASHBYTES(''SHA2_256'', (SELECT fkc.constraint_column_id, pc.name{#COLLATION#}, rc.name{#COLLATION#}, fk.delete_referential_action, fk.update_referential_action, fk.is_not_for_replication @@ -1113,12 +1187,12 @@ WHERE X.Command IS NOT NULL AND LEN(X.Command)>0;'; ORDER BY ic.index_column_id FOR XML PATH(''''), TYPE).value(''.'',''nvarchar(max)''),1,1,N'''')+N'')'' ELSE N'''' END + + CASE WHEN i.has_filter=1 THEN N'' WHERE ''+ISNULL(i.filter_definition,N'''') ELSE N'''' END + N'' WITH (PAD_INDEX = ''+CASE WHEN i.is_padded=1 THEN N''ON'' ELSE N''OFF'' END+ N'', ALLOW_ROW_LOCKS = ''+CASE WHEN i.allow_row_locks=1 THEN N''ON'' ELSE N''OFF'' END+ N'', ALLOW_PAGE_LOCKS = ''+CASE WHEN i.allow_page_locks=1 THEN N''ON'' ELSE N''OFF'' END+ N'', IGNORE_DUP_KEY = ''+CASE WHEN i.ignore_dup_key=1 THEN N''ON'' ELSE N''OFF'' END+ - N'', FILLFACTOR = ''+CONVERT(nvarchar(3), CASE WHEN i.fill_factor=0 THEN 100 ELSE i.fill_factor END)+N'')'' + - CASE WHEN i.has_filter=1 THEN N'' WHERE ''+ISNULL(i.filter_definition,N'''') ELSE N'''' END + N'', FILLFACTOR = ''+CONVERT(nvarchar(3), CASE WHEN i.fill_factor=0 THEN 100 ELSE i.fill_factor END)+N'')''+N'';'' FROM {#SOURCEDB_Q#}.sys.indexes i JOIN {#SOURCEDB_Q#}.sys.tables t ON t.object_id=i.object_id JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id=t.schema_id @@ -1198,10 +1272,20 @@ SELECT N''10B-Triggers'', REPLACE( REPLACE( REPLACE( - -- First normalize spaces (8->1, 4->1, 2->1 twice for 3+ spaces), then replace CREATE/ALTER - REPLACE(REPLACE( - REPLACE(REPLACE(REPLACE(REPLACE(CAST(m.definition AS NVARCHAR(max)){#COLLATION#}, N'' '', N'' ''), N'' '', N'' ''), N'' '', N'' ''), N'' '', N'' ''), - N''ALTER TRIGGER'', N''CREATE TRIGGER''), N''CREATE OR ALTER TRIGGER'', N''CREATE TRIGGER''), + -- Case-insensitive REPLACE chain on normalized definition: + -- 1. CREATE OR ALTER TRIGGER -> placeholder (preserve existing) + -- 2. ALTER TRIGGER -> CREATE OR ALTER TRIGGER + -- 3. CREATE TRIGGER -> CREATE OR ALTER TRIGGER + -- 4. placeholder -> CREATE OR ALTER TRIGGER (restore) + REPLACE( + REPLACE( + REPLACE( + REPLACE( + REPLACE(REPLACE(REPLACE(REPLACE(CAST(m.definition AS NVARCHAR(max)){#COLLATION#}, N'' '', N'' ''), N'' '', N'' ''), N'' '', N'' ''), N'' '', N'' '') COLLATE Latin1_General_CI_AS, + N''CREATE OR ALTER TRIGGER'' COLLATE Latin1_General_CI_AS, N''<#COA_TRIG#>''), + N''ALTER TRIGGER'' COLLATE Latin1_General_CI_AS, N''CREATE OR ALTER TRIGGER''), + N''CREATE TRIGGER'' COLLATE Latin1_General_CI_AS, N''CREATE OR ALTER TRIGGER''), + N''<#COA_TRIG#>'', N''CREATE OR ALTER TRIGGER''), N''[''+ N''{#SOURCEDB#}'' +N'']'', N''[''+ N''{#TARGETDB#}'' +N'']''), N''{#SOURCEDB#}''+N''.'', N''{#TARGETDB#}''+N''.''), CHAR(39), CHAR(39)+CHAR(39)) + @@ -1254,13 +1338,20 @@ WHERE X.Command IS NOT NULL AND LEN(X.Command)>0;'; ;WITH ViewDeps AS ( SELECT v.object_id, 0 dep, CAST(CONCAT(N'','',v.object_id,N'','') AS NVARCHAR(MAX)) AS visited FROM {#SOURCEDB_Q#}.sys.views v - WHERE NOT EXISTS (SELECT 1 FROM {#SOURCEDB_Q#}.sys.sql_expression_dependencies d JOIN {#SOURCEDB_Q#}.sys.views rv ON rv.object_id=d.referenced_id WHERE d.referencing_id=v.object_id) + WHERE NOT EXISTS (SELECT 1 FROM {#SOURCEDB_Q#}.sys.sql_expression_dependencies d + JOIN {#SOURCEDB_Q#}.sys.views rv ON (rv.object_id=d.referenced_id + OR (d.referenced_id IS NULL AND rv.name{#COLLATION#}=d.referenced_entity_name{#COLLATION#} + AND (d.referenced_database_name IS NULL OR d.referenced_database_name{#COLLATION#}=N''{#SOURCEDB#}''{#COLLATION#}))) + WHERE d.referencing_id=v.object_id) UNION ALL SELECT v.object_id, vd.dep+1, CAST(CONCAT(vd.visited,v.object_id,N'','') AS NVARCHAR(MAX)) FROM {#SOURCEDB_Q#}.sys.views v JOIN {#SOURCEDB_Q#}.sys.sql_expression_dependencies d ON d.referencing_id=v.object_id - JOIN ViewDeps vd ON vd.object_id=d.referenced_id - WHERE vd.visited NOT LIKE CONCAT(N''%,'',v.object_id,N'',%'') AND vd.dep < 50 + JOIN {#SOURCEDB_Q#}.sys.views rv2 ON (rv2.object_id=d.referenced_id + OR (d.referenced_id IS NULL AND rv2.name{#COLLATION#}=d.referenced_entity_name{#COLLATION#} + AND (d.referenced_database_name IS NULL OR d.referenced_database_name{#COLLATION#}=N''{#SOURCEDB#}''{#COLLATION#}))) + JOIN ViewDeps vd ON vd.object_id=rv2.object_id + WHERE vd.visited NOT LIKE CONCAT(N''%,'',v.object_id,N'',%'') AND vd.dep < 100 ), MaxLevel AS (SELECT object_id, MAX(dep) dep FROM ViewDeps GROUP BY object_id) INSERT INTO #TBDD_SYNC_DATABASE_COMMANDS(Phase, Command) SELECT X.Phase, X.Command FROM ( @@ -1347,13 +1438,21 @@ OPTION(MAXRECURSION 100);'; ;WITH FuncDeps AS ( SELECT o.object_id, 0 dep, CAST(CONCAT(N'','',o.object_id,N'','') AS NVARCHAR(MAX)) AS visited FROM {#SOURCEDB_Q#}.sys.objects o WHERE o.type IN (N''FN'',N''TF'',N''IF'',N''FS'',N''FT'') - AND NOT EXISTS(SELECT 1 FROM {#SOURCEDB_Q#}.sys.sql_expression_dependencies d JOIN {#SOURCEDB_Q#}.sys.objects ro ON ro.object_id=d.referenced_id AND ro.type IN (N''FN'',N''TF'',N''IF'',N''FS'',N''FT'') WHERE d.referencing_id=o.object_id) + AND NOT EXISTS(SELECT 1 FROM {#SOURCEDB_Q#}.sys.sql_expression_dependencies d + JOIN {#SOURCEDB_Q#}.sys.objects ro ON (ro.object_id=d.referenced_id + OR (d.referenced_id IS NULL AND ro.name{#COLLATION#}=d.referenced_entity_name{#COLLATION#} + AND (d.referenced_database_name IS NULL OR d.referenced_database_name{#COLLATION#}=N''{#SOURCEDB#}''{#COLLATION#}))) + WHERE d.referencing_id=o.object_id AND ro.type IN (N''FN'',N''TF'',N''IF'',N''FS'',N''FT'')) UNION ALL SELECT o.object_id, fd.dep+1, CAST(CONCAT(fd.visited,o.object_id,N'','') AS NVARCHAR(MAX)) FROM {#SOURCEDB_Q#}.sys.objects o JOIN {#SOURCEDB_Q#}.sys.sql_expression_dependencies d ON d.referencing_id=o.object_id - JOIN FuncDeps fd ON fd.object_id=d.referenced_id - WHERE fd.visited NOT LIKE CONCAT(N''%,'',o.object_id,N'',%'') AND fd.dep < 50 + JOIN {#SOURCEDB_Q#}.sys.objects ro2 ON (ro2.object_id=d.referenced_id + OR (d.referenced_id IS NULL AND ro2.name{#COLLATION#}=d.referenced_entity_name{#COLLATION#} + AND (d.referenced_database_name IS NULL OR d.referenced_database_name{#COLLATION#}=N''{#SOURCEDB#}''{#COLLATION#}))) + AND ro2.type IN (N''FN'',N''TF'',N''IF'',N''FS'',N''FT'') + JOIN FuncDeps fd ON fd.object_id=ro2.object_id + WHERE fd.visited NOT LIKE CONCAT(N''%,'',o.object_id,N'',%'') AND fd.dep < 100 ), MaxLevel AS (SELECT object_id, MAX(dep) dep FROM FuncDeps GROUP BY object_id) INSERT INTO #TBDD_SYNC_DATABASE_COMMANDS(Phase, Command) SELECT X.Phase, X.Command FROM ( @@ -1540,6 +1639,8 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} OR seq.minimum_value<>tseq.minimum_value OR seq.maximum_value<>tseq.maximum_value OR seq.is_cycling<>tseq.is_cycling + OR seq.is_cached<>tseq.is_cached + OR ISNULL(seq.cache_size,0)<>ISNULL(tseq.cache_size,0) OR ty.name{#COLLATION#}<>tty.name{#COLLATION#}) AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard=1 AND (seq.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#}+N''.''{#COLLATION#}+seq.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard=0 AND (seq.name{#COLLATION#}=ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#}+N''.''{#COLLATION#}+seq.name{#COLLATION#})=ex.Pattern{#COLLATION#}))) ) AS X(Phase, Command) @@ -1569,7 +1670,7 @@ SELECT * FROM ( SELECT N''15-Synonyms'', N''USE {#TARGETDB_Q#}; '' + CASE WHEN tgt.object_id IS NOT NULL THEN N''DROP SYNONYM '' + QUOTENAME(s.name)+N''.'' + QUOTENAME(sn.name) + N''; '' ELSE N'''' END + - N''CREATE SYNONYM '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(sn.name) + N'' FOR '' + sn.base_object_name + N''CREATE SYNONYM '' + QUOTENAME(s.name) + N''.'' + QUOTENAME(sn.name) + N'' FOR '' + REPLACE(REPLACE(sn.base_object_name, N''['' + N''{#SOURCEDB#}'' + N'']'', N''['' + N''{#TARGETDB#}'' + N'']''), N''{#SOURCEDB#}'' + N''.'', N''{#TARGETDB#}'' + N''.'') + N'';'' FROM {#SOURCEDB_Q#}.sys.synonyms sn JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id=sn.schema_id OUTER APPLY ( @@ -1579,7 +1680,7 @@ OUTER APPLY ( WHERE ts.name{#COLLATION#}=s.name{#COLLATION#} AND tsn.name{#COLLATION#}=sn.name{#COLLATION#} ) tgt WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} - AND (tgt.object_id IS NULL OR ISNULL(tgt.base_object_name{#COLLATION#},N'''')<>ISNULL(sn.base_object_name{#COLLATION#},N'''')) + AND (tgt.object_id IS NULL OR ISNULL(tgt.base_object_name{#COLLATION#},N'''')<>ISNULL(REPLACE(REPLACE(sn.base_object_name, N''['' + N''{#SOURCEDB#}'' + N'']'', N''['' + N''{#TARGETDB#}'' + N'']''), N''{#SOURCEDB#}'' + N''.'', N''{#TARGETDB#}'' + N''.''){#COLLATION#},N'''')) AND (PARSENAME(sn.base_object_name,3) IS NULL OR PARSENAME(sn.base_object_name,3){#COLLATION#}=N''{#SOURCEDB#}''{#COLLATION#}) AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard=1 AND (sn.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#}+N''.''{#COLLATION#}+sn.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard=0 AND (sn.name{#COLLATION#}=ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#}+N''.''{#COLLATION#}+sn.name{#COLLATION#})=ex.Pattern{#COLLATION#}))) ) AS X(Phase, Command) @@ -1604,9 +1705,9 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} --=================================================-- Datenabgleich (optional, Tabellen mit PK) --================================================-- IF @INCLUDEDATA = 1 BEGIN --===============================================-- Log result to table --=================================================-- - IF (UPPER(@LOGLEVEL) IN (N'INFO',N'WARN',N'ERROR')) BEGIN + IF @LOGLEVEL = N'INFO' BEGIN INSERT INTO [TBDD_SYNC_DATABASE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [ADDED_WHO], [ADDED_WHEN]) - VALUES ('INFO', '04-Data', 'Data-Sync aktiviert', 'Hash-basierter Datenabgleich, DeleteMissing: '+CONVERT(NVARCHAR(1),@DELETEMISSING), @MY_PROCEDURE_NAME, GETDATE()); + VALUES ('INFO', '20-Data', 'Data-Sync aktiviert', 'Hash-basierter Datenabgleich, DeleteMissing: '+CONVERT(NVARCHAR(1),@DELETEMISSING), @MY_PROCEDURE_NAME, GETDATE()); END; ----------------------------------------------------------------------------------------------------------------------------- @@ -1624,20 +1725,23 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} IF @rcs<>@rct OR ISNULL(@chks,-1)<>ISNULL(@chkt,-1) BEGIN '' + CASE WHEN idc.object_id IS NOT NULL THEN N''SET IDENTITY_INSERT ''+QUOTENAME(sch.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+'' ON; '' ELSE N'''' END + + N''DISABLE TRIGGER ALL ON ''+QUOTENAME(sch.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+N''; '' + N''MERGE {#TARGETDB_Q#}.''+QUOTENAME(sch.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+'' AS tgt USING {#SOURCEDB_Q#}.''+QUOTENAME(sch.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+'' AS src ON ''+pkhash.JoinCondition+'' '' + CASE WHEN cols.UpdateList IS NOT NULL AND cols.UpdateList<>'''' THEN N''WHEN MATCHED AND BINARY_CHECKSUM(''+pkhash.HashSrcCols+'') <> BINARY_CHECKSUM(''+pkhash.HashTgtCols+'') THEN UPDATE SET ''+cols.UpdateList+'' '' ELSE N'''' END + N''WHEN NOT MATCHED THEN INSERT(''+cols.InsertCols+'') VALUES(''+cols.InsertVals+'')'' + N''@DEL_CLAUSE@'' + N''; + ENABLE TRIGGER ALL ON ''+QUOTENAME(sch.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+N''; '' + CASE WHEN idc.object_id IS NOT NULL THEN N''SET IDENTITY_INSERT ''+QUOTENAME(sch.name)+N''.''{#COLLATION#}+QUOTENAME(t.name)+'' OFF;'' ELSE N'''' END + N'' END;'' FROM {#SOURCEDB_Q#}.sys.tables t JOIN {#SOURCEDB_Q#}.sys.schemas sch ON sch.schema_id=t.schema_id JOIN {#SOURCEDB_Q#}.sys.key_constraints pkc ON pkc.parent_object_id=t.object_id AND pkc.type{#COLLATION#}=''PK''{#COLLATION#} OUTER APPLY ( - SELECT STUFF((SELECT '' AND src.''+QUOTENAME(c.name)+'' = tgt.''+QUOTENAME(c.name) + SELECT STUFF((SELECT '' AND src.''+QUOTENAME(c.name)+CASE WHEN ty.name{#COLLATION#} IN (N''char'',N''varchar'',N''nchar'',N''nvarchar'') THEN N''{#COLLATION#}'' ELSE N'''' END+'' = tgt.''+QUOTENAME(c.name)+CASE WHEN ty.name{#COLLATION#} IN (N''char'',N''varchar'',N''nchar'',N''nvarchar'') THEN N''{#COLLATION#}'' ELSE N'''' END FROM {#SOURCEDB_Q#}.sys.index_columns ic JOIN {#SOURCEDB_Q#}.sys.columns c ON c.object_id=ic.object_id AND c.column_id=ic.column_id + JOIN {#SOURCEDB_Q#}.sys.types ty ON ty.user_type_id=c.user_type_id WHERE ic.object_id=pkc.parent_object_id AND ic.index_id=pkc.unique_index_id ORDER BY ic.key_ordinal FOR XML PATH(''''), TYPE).value(''.'',''nvarchar(max)''),1,5,N'''') AS JoinCondition, @@ -1719,7 +1823,7 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} --=================================================-- Befehle generiert --=================================================-- DECLARE @COMMANDCOUNT INT = (SELECT COUNT(*) FROM #TBDD_SYNC_DATABASE_COMMANDS); --===============================================-- Log result to table --=================================================-- - IF (UPPER(@LOGLEVEL) IN (N'INFO',N'WARN',N'ERROR')) BEGIN + IF @LOGLEVEL = N'INFO' BEGIN INSERT INTO [TBDD_SYNC_DATABASE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [ADDED_WHO], [ADDED_WHEN]) VALUES ('INFO', '05-Planning', 'Befehle generiert', 'Anzahl: '+CONVERT(NVARCHAR(10),@COMMANDCOUNT)+', Execute-Modus: '+CONVERT(NVARCHAR(1),@EXECUTE), @MY_PROCEDURE_NAME, GETDATE()); END; @@ -1772,6 +1876,7 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} WHEN Phase = '02-Schemas' THEN 'Schemas' WHEN Phase = '03-Tables' THEN 'New Tables' WHEN Phase = '03-Table-AddColumns' THEN 'Add Columns' + WHEN Phase = '03-Table-AlterCols-DropIdx' THEN 'Drop Indexes (for ALTER)' WHEN Phase = '03-Table-AlterColumns' THEN 'Alter Columns' WHEN Phase = '03-Table-Defaults' THEN 'Default Constraints' WHEN Phase = '03-Table-Checks' THEN 'Check Constraints' @@ -2003,7 +2108,7 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} ELSE BEGIN --=================================================-- Cursor-Ausfuehrung startet --=================================================-- --===============================================-- Log result to table --=================================================-- - IF (UPPER(@LOGLEVEL) IN (N'INFO',N'WARN',N'ERROR')) BEGIN + IF @LOGLEVEL = N'INFO' BEGIN INSERT INTO [TBDD_SYNC_DATABASE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [ADDED_WHO], [ADDED_WHEN]) VALUES ('INFO', '06-Execution', 'Cursor-Ausfuehrung startet', 'Anzahl Commands: '+CONVERT(NVARCHAR(10),@COMMANDCOUNT), @MY_PROCEDURE_NAME, GETDATE()); END; @@ -2073,10 +2178,23 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} SET @RETURN_STATUS = 1; GOTO CLEANUP_AND_EXIT; END; + -- Bei Transaktions-Modus: Wenn Transaction doomed ist, sofort abbrechen + IF @USETRANSACTION = 1 AND XACT_STATE() = -1 BEGIN + PRINT '[ERROR] Transaction is doomed (XACT_STATE=-1) - aborting execution...'; + IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION SYNC_TRANSACTION; + CLOSE cmd_cur; + DEALLOCATE cmd_cur; + SET @RETURN_STATUS = 1; + GOTO CLEANUP_AND_EXIT; + END; END CATCH; --================================================-- Log execution result to table --=================================================-- - IF (UPPER(@LOGLEVEL) IN (N'INFO',N'WARN',N'ERROR')) BEGIN + IF @LOGLEVEL IS NOT NULL AND XACT_STATE() <> -1 AND ( + @SEVERITY = N'ERROR' + OR (@SEVERITY = N'WARN' AND @LOGLEVEL IN (N'INFO', N'WARN')) + OR (@SEVERITY = N'INFO' AND @LOGLEVEL = N'INFO') + ) BEGIN INSERT INTO [TBDD_SYNC_DATABASE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [ADDED_WHO], [ADDED_WHEN]) VALUES (@SEVERITY, @PHASE, CONVERT(NVARCHAR(256),@STEP), ISNULL(@ERRMSG, N'OK'), @MY_PROCEDURE_NAME, GETDATE()); END; @@ -2122,7 +2240,7 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} CONVERT(NVARCHAR(10), @EXECUTION_ERRORS) + N' errors of ' + CONVERT(NVARCHAR(10), @COMMANDCOUNT) + N' total commands'; --===============================================-- Log result to table --=================================================-- - IF (UPPER(@LOGLEVEL) IN (N'INFO',N'WARN',N'ERROR')) BEGIN + IF @LOGLEVEL = N'INFO' BEGIN INSERT INTO [TBDD_SYNC_DATABASE_LOG]([LOG_LEVEL],[MESSAGE1], [MESSAGE2], [MESSAGE3], [ADDED_WHO], [ADDED_WHEN]) VALUES ('INFO', '07-Complete', 'Cursor-Ausfuehrung abgeschlossen', 'Success: ' + CONVERT(NVARCHAR(10), @EXECUTION_SUCCESS) + ', Errors: ' + CONVERT(NVARCHAR(10), @EXECUTION_ERRORS) + ' of ' + CONVERT(NVARCHAR(10), @COMMANDCOUNT), @@ -2163,7 +2281,30 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} PRINT N''; PRINT N'--- Schema Validation ---'; - -- Validate Tables + IF @SYNC_SCHEMAS = 1 BEGIN -- Validate Schemas + SET @VALIDATION_SQL = N' + SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.schemas s + WHERE s.name{#COLLATION#} NOT IN (N''sys'',N''INFORMATION_SCHEMA'',N''dbo'',N''guest'',N''db_owner'',N''db_accessadmin'',N''db_securityadmin'',N''db_ddladmin'',N''db_backupoperator'',N''db_datareader'',N''db_datawriter'',N''db_denydatareader'',N''db_denydatawriter'') + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND s.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#}) OR (ex.IsWildcard = 0 AND s.name{#COLLATION#} = ex.Pattern{#COLLATION#}));'; + SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); + EXEC sys.sp_executesql @VALIDATION_SQL, N'@src INT OUTPUT', @src = @VALIDATION_SOURCE_COUNT OUTPUT; + + SET @VALIDATION_SQL = N' + SELECT @tgt = COUNT(*) FROM {#TARGETDB_Q#}.sys.schemas s + WHERE s.name{#COLLATION#} NOT IN (N''sys'',N''INFORMATION_SCHEMA'',N''dbo'',N''guest'',N''db_owner'',N''db_accessadmin'',N''db_securityadmin'',N''db_ddladmin'',N''db_backupoperator'',N''db_datareader'',N''db_datawriter'',N''db_denydatareader'',N''db_denydatawriter'') + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND s.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#}) OR (ex.IsWildcard = 0 AND s.name{#COLLATION#} = ex.Pattern{#COLLATION#}));'; + SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); + EXEC sys.sp_executesql @VALIDATION_SQL, N'@tgt INT OUTPUT', @tgt = @VALIDATION_TARGET_COUNT OUTPUT; + + INSERT INTO #ValidationResults VALUES ('SCHEMA', 'Schemas', NULL, @VALIDATION_SOURCE_COUNT, @VALIDATION_TARGET_COUNT, + CASE WHEN @VALIDATION_SOURCE_COUNT <= @VALIDATION_TARGET_COUNT THEN 'OK' ELSE 'ERROR' END, + CASE WHEN @VALIDATION_SOURCE_COUNT <= @VALIDATION_TARGET_COUNT THEN NULL ELSE 'Missing in Target: ' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT - @VALIDATION_TARGET_COUNT) + ' schema(s)' END); + IF @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END; + PRINT 'Schemas: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT <= @VALIDATION_TARGET_COUNT THEN ' [OK]' ELSE ' [ERROR]' END; + + END; -- /IF @SYNC_SCHEMAS + + IF @SYNC_TABLES = 1 BEGIN -- Validate Tables SET @VALIDATION_SQL = N' SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.tables t JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = t.schema_id @@ -2184,17 +2325,20 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} EXEC sys.sp_executesql @VALIDATION_SQL, N'@tgt INT OUTPUT', @tgt = @VALIDATION_TARGET_COUNT OUTPUT; INSERT INTO #ValidationResults VALUES ('SCHEMA', 'Tables', NULL, @VALIDATION_SOURCE_COUNT, @VALIDATION_TARGET_COUNT, - CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' ELSE 'ERROR' END, - CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN NULL ELSE 'Mismatch: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) END); - IF @VALIDATION_SOURCE_COUNT <> @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END; - PRINT 'Tables: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' ELSE ' [ERROR]' END; + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN 'ERROR' ELSE 'WARN' END, + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN NULL WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN 'Missing in Target: ' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT - @VALIDATION_TARGET_COUNT) + ' object(s)' ELSE 'Extra in Target: ' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT - @VALIDATION_SOURCE_COUNT) + ' object(s) (additive sync)' END); + IF @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END + ELSE IF @VALIDATION_SOURCE_COUNT < @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_WARNINGS = @VALIDATION_WARNINGS + 1; END; + PRINT 'Tables: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN ' [ERROR]' ELSE ' [WARN]' END; - -- Validate Views - SET @VALIDATION_SQL = N' - SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.views v - JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = v.schema_id - WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} - AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (v.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + v.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (v.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + v.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; + END; -- /IF @SYNC_TABLES + + IF @SYNC_VIEWS = 1 BEGIN -- Validate Views + SET @VALIDATION_SQL = N' + SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.views v + JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = v.schema_id + WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (v.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + v.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (v.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + v.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); EXEC sys.sp_executesql @VALIDATION_SQL, N'@src INT OUTPUT', @src = @VALIDATION_SOURCE_COUNT OUTPUT; @@ -2210,16 +2354,19 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} EXEC sys.sp_executesql @VALIDATION_SQL, N'@tgt INT OUTPUT', @tgt = @VALIDATION_TARGET_COUNT OUTPUT; INSERT INTO #ValidationResults VALUES ('SCHEMA', 'Views', NULL, @VALIDATION_SOURCE_COUNT, @VALIDATION_TARGET_COUNT, - CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' ELSE 'ERROR' END, NULL); - IF @VALIDATION_SOURCE_COUNT <> @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END; - PRINT 'Views: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' ELSE ' [ERROR]' END; + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN 'ERROR' ELSE 'WARN' END, NULL); + IF @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END + ELSE IF @VALIDATION_SOURCE_COUNT < @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_WARNINGS = @VALIDATION_WARNINGS + 1; END; + PRINT 'Views: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN ' [ERROR]' ELSE ' [WARN]' END; - -- Validate Stored Procedures - SET @VALIDATION_SQL = N' - SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.procedures p - JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = p.schema_id - WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} - AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (p.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + p.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (p.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + p.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; + END; -- /IF @SYNC_VIEWS + + IF @SYNC_PROCEDURES = 1 BEGIN -- Validate Stored Procedures + SET @VALIDATION_SQL = N' + SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.procedures p + JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = p.schema_id + WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (p.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + p.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (p.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + p.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); EXEC sys.sp_executesql @VALIDATION_SQL, N'@src INT OUTPUT', @src = @VALIDATION_SOURCE_COUNT OUTPUT; @@ -2235,16 +2382,19 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} EXEC sys.sp_executesql @VALIDATION_SQL, N'@tgt INT OUTPUT', @tgt = @VALIDATION_TARGET_COUNT OUTPUT; INSERT INTO #ValidationResults VALUES ('SCHEMA', 'Procedures', NULL, @VALIDATION_SOURCE_COUNT, @VALIDATION_TARGET_COUNT, - CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' ELSE 'ERROR' END, NULL); - IF @VALIDATION_SOURCE_COUNT <> @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END; - PRINT 'Procedures: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' ELSE ' [ERROR]' END; + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN 'ERROR' ELSE 'WARN' END, NULL); + IF @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END + ELSE IF @VALIDATION_SOURCE_COUNT < @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_WARNINGS = @VALIDATION_WARNINGS + 1; END; + PRINT 'Procedures: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN ' [ERROR]' ELSE ' [WARN]' END; - -- Validate Functions - SET @VALIDATION_SQL = N' - SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.objects o - JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = o.schema_id - WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} AND o.[type] IN (N''FN'',N''TF'',N''IF'',N''FS'',N''FT'') - AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (o.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + o.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (o.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + o.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; + END; -- /IF @SYNC_PROCEDURES + + IF @SYNC_FUNCTIONS = 1 BEGIN -- Validate Functions + SET @VALIDATION_SQL = N' + SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.objects o + JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = o.schema_id + WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} AND o.[type] IN (N''FN'',N''TF'',N''IF'',N''FS'',N''FT'') + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (o.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + o.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (o.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + o.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); EXEC sys.sp_executesql @VALIDATION_SQL, N'@src INT OUTPUT', @src = @VALIDATION_SOURCE_COUNT OUTPUT; @@ -2260,20 +2410,23 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} EXEC sys.sp_executesql @VALIDATION_SQL, N'@tgt INT OUTPUT', @tgt = @VALIDATION_TARGET_COUNT OUTPUT; INSERT INTO #ValidationResults VALUES ('SCHEMA', 'Functions', NULL, @VALIDATION_SOURCE_COUNT, @VALIDATION_TARGET_COUNT, - CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' ELSE 'ERROR' END, NULL); - IF @VALIDATION_SOURCE_COUNT <> @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END; - PRINT 'Functions: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' ELSE ' [ERROR]' END; + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN 'ERROR' ELSE 'WARN' END, NULL); + IF @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END + ELSE IF @VALIDATION_SOURCE_COUNT < @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_WARNINGS = @VALIDATION_WARNINGS + 1; END; + PRINT 'Functions: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN ' [ERROR]' ELSE ' [WARN]' END; - -- Validate Triggers - SET @VALIDATION_SQL = N' - SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.triggers tr - JOIN {#SOURCEDB_Q#}.sys.objects o ON o.object_id = tr.object_id - JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = o.schema_id - JOIN {#SOURCEDB_Q#}.sys.tables pt ON pt.object_id = tr.parent_id - JOIN {#SOURCEDB_Q#}.sys.schemas ps ON ps.schema_id = pt.schema_id - WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} AND tr.parent_id IS NOT NULL - AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (pt.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (ps.name{#COLLATION#} + N''.'' + pt.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (pt.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (ps.name{#COLLATION#} + N''.'' + pt.name{#COLLATION#}) = ex.Pattern{#COLLATION#}))) - AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (tr.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + tr.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (tr.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + tr.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; + END; -- /IF @SYNC_FUNCTIONS + + IF @SYNC_TRIGGERS = 1 BEGIN -- Validate Triggers + SET @VALIDATION_SQL = N' + SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.triggers tr + JOIN {#SOURCEDB_Q#}.sys.objects o ON o.object_id = tr.object_id + JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = o.schema_id + JOIN {#SOURCEDB_Q#}.sys.tables pt ON pt.object_id = tr.parent_id + JOIN {#SOURCEDB_Q#}.sys.schemas ps ON ps.schema_id = pt.schema_id + WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} AND tr.parent_id IS NOT NULL + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (pt.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (ps.name{#COLLATION#} + N''.'' + pt.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (pt.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (ps.name{#COLLATION#} + N''.'' + pt.name{#COLLATION#}) = ex.Pattern{#COLLATION#}))) + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (tr.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + tr.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (tr.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + tr.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); EXEC sys.sp_executesql @VALIDATION_SQL, N'@src INT OUTPUT', @src = @VALIDATION_SOURCE_COUNT OUTPUT; @@ -2293,17 +2446,20 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} EXEC sys.sp_executesql @VALIDATION_SQL, N'@tgt INT OUTPUT', @tgt = @VALIDATION_TARGET_COUNT OUTPUT; INSERT INTO #ValidationResults VALUES ('SCHEMA', 'Triggers', NULL, @VALIDATION_SOURCE_COUNT, @VALIDATION_TARGET_COUNT, - CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' ELSE 'ERROR' END, NULL); - IF @VALIDATION_SOURCE_COUNT <> @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END; - PRINT 'Triggers: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' ELSE ' [ERROR]' END; + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN 'ERROR' ELSE 'WARN' END, NULL); + IF @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END + ELSE IF @VALIDATION_SOURCE_COUNT < @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_WARNINGS = @VALIDATION_WARNINGS + 1; END; + PRINT 'Triggers: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN ' [ERROR]' ELSE ' [WARN]' END; - -- Validate Indexes - SET @VALIDATION_SQL = N' - SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.indexes i - JOIN {#SOURCEDB_Q#}.sys.tables t ON t.object_id = i.object_id - JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = t.schema_id - WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} AND i.index_id > 0 - AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (t.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + t.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (t.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + t.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; + END; -- /IF @SYNC_TRIGGERS + + IF @SYNC_INDEXES = 1 BEGIN -- Validate Indexes + SET @VALIDATION_SQL = N' + SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.indexes i + JOIN {#SOURCEDB_Q#}.sys.tables t ON t.object_id = i.object_id + JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = t.schema_id + WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} AND i.is_primary_key=0 AND i.is_unique_constraint=0 AND i.is_hypothetical=0 AND i.type IN (1,2) AND t.is_ms_shipped=0 + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (t.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + t.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (t.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + t.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); EXEC sys.sp_executesql @VALIDATION_SQL, N'@src INT OUTPUT', @src = @VALIDATION_SOURCE_COUNT OUTPUT; @@ -2313,7 +2469,7 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} SELECT @tgt = COUNT(*) FROM {#TARGETDB_Q#}.sys.indexes i JOIN {#TARGETDB_Q#}.sys.tables t ON t.object_id = i.object_id JOIN {#TARGETDB_Q#}.sys.schemas s ON s.schema_id = t.schema_id - WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} AND i.index_id > 0 + WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} AND i.is_primary_key=0 AND i.is_unique_constraint=0 AND i.is_hypothetical=0 AND i.type IN (1,2) AND t.is_ms_shipped=0 AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (t.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + t.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (t.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + t.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); @@ -2324,16 +2480,18 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} IF @VALIDATION_SOURCE_COUNT <> @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_WARNINGS = @VALIDATION_WARNINGS + 1; END; PRINT 'Indexes: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' ELSE ' [WARN]' END; - -- Validate Foreign Keys - SET @VALIDATION_SQL = N' - SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.foreign_keys fk - JOIN {#SOURCEDB_Q#}.sys.tables pt ON pt.object_id = fk.parent_object_id - JOIN {#SOURCEDB_Q#}.sys.tables rt ON rt.object_id = fk.referenced_object_id - JOIN {#SOURCEDB_Q#}.sys.schemas spt ON spt.schema_id = pt.schema_id - JOIN {#SOURCEDB_Q#}.sys.schemas srt ON srt.schema_id = rt.schema_id - WHERE spt.name{#COLLATION#}<>N''sys''{#COLLATION#} - AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (pt.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (spt.name{#COLLATION#} + N''.'' + pt.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (pt.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (spt.name{#COLLATION#} + N''.'' + pt.name{#COLLATION#}) = ex.Pattern{#COLLATION#}))) - AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (rt.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (srt.name{#COLLATION#} + N''.'' + rt.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (rt.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (srt.name{#COLLATION#} + N''.'' + rt.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; + END; -- /IF @SYNC_INDEXES + + IF @SYNC_TABLES = 1 BEGIN -- Validate Foreign Keys (belongs to TABLES) + SET @VALIDATION_SQL = N' + SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.foreign_keys fk + JOIN {#SOURCEDB_Q#}.sys.tables pt ON pt.object_id = fk.parent_object_id + JOIN {#SOURCEDB_Q#}.sys.tables rt ON rt.object_id = fk.referenced_object_id + JOIN {#SOURCEDB_Q#}.sys.schemas spt ON spt.schema_id = pt.schema_id + JOIN {#SOURCEDB_Q#}.sys.schemas srt ON srt.schema_id = rt.schema_id + WHERE spt.name{#COLLATION#}<>N''sys''{#COLLATION#} + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (pt.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (spt.name{#COLLATION#} + N''.'' + pt.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (pt.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (spt.name{#COLLATION#} + N''.'' + pt.name{#COLLATION#}) = ex.Pattern{#COLLATION#}))) + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (rt.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (srt.name{#COLLATION#} + N''.'' + rt.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (rt.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (srt.name{#COLLATION#} + N''.'' + rt.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); EXEC sys.sp_executesql @VALIDATION_SQL, N'@src INT OUTPUT', @src = @VALIDATION_SOURCE_COUNT OUTPUT; @@ -2353,9 +2511,61 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} EXEC sys.sp_executesql @VALIDATION_SQL, N'@tgt INT OUTPUT', @tgt = @VALIDATION_TARGET_COUNT OUTPUT; INSERT INTO #ValidationResults VALUES ('SCHEMA', 'ForeignKeys', NULL, @VALIDATION_SOURCE_COUNT, @VALIDATION_TARGET_COUNT, - CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' ELSE 'ERROR' END, NULL); - IF @VALIDATION_SOURCE_COUNT <> @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END; - PRINT 'ForeignKeys: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' ELSE ' [ERROR]' END; + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN 'ERROR' ELSE 'WARN' END, NULL); + IF @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END + ELSE IF @VALIDATION_SOURCE_COUNT < @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_WARNINGS = @VALIDATION_WARNINGS + 1; END; + PRINT 'ForeignKeys: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN ' [ERROR]' ELSE ' [WARN]' END; + + END; -- /IF @SYNC_TABLES + + IF @SYNC_SEQUENCES = 1 BEGIN -- Validate Sequences + SET @VALIDATION_SQL = N' + SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.sequences seq + JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = seq.schema_id + WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (seq.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + seq.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (seq.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + seq.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; + SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); + EXEC sys.sp_executesql @VALIDATION_SQL, N'@src INT OUTPUT', @src = @VALIDATION_SOURCE_COUNT OUTPUT; + + SET @VALIDATION_SQL = N' + SELECT @tgt = COUNT(*) FROM {#TARGETDB_Q#}.sys.sequences seq + JOIN {#TARGETDB_Q#}.sys.schemas s ON s.schema_id = seq.schema_id + WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (seq.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + seq.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (seq.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + seq.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; + SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); + EXEC sys.sp_executesql @VALIDATION_SQL, N'@tgt INT OUTPUT', @tgt = @VALIDATION_TARGET_COUNT OUTPUT; + + INSERT INTO #ValidationResults VALUES ('SCHEMA', 'Sequences', NULL, @VALIDATION_SOURCE_COUNT, @VALIDATION_TARGET_COUNT, + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN 'ERROR' ELSE 'WARN' END, NULL); + IF @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END + ELSE IF @VALIDATION_SOURCE_COUNT < @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_WARNINGS = @VALIDATION_WARNINGS + 1; END; + PRINT 'Sequences: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN ' [ERROR]' ELSE ' [WARN]' END; + + END; -- /IF @SYNC_SEQUENCES + + IF @SYNC_SYNONYMS = 1 BEGIN -- Validate Synonyms + SET @VALIDATION_SQL = N' + SELECT @src = COUNT(*) FROM {#SOURCEDB_Q#}.sys.synonyms syn + JOIN {#SOURCEDB_Q#}.sys.schemas s ON s.schema_id = syn.schema_id + WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (syn.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + syn.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (syn.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + syn.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; + SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); + EXEC sys.sp_executesql @VALIDATION_SQL, N'@src INT OUTPUT', @src = @VALIDATION_SOURCE_COUNT OUTPUT; + + SET @VALIDATION_SQL = N' + SELECT @tgt = COUNT(*) FROM {#TARGETDB_Q#}.sys.synonyms syn + JOIN {#TARGETDB_Q#}.sys.schemas s ON s.schema_id = syn.schema_id + WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND (syn.name{#COLLATION#} LIKE ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + syn.name{#COLLATION#}) LIKE ex.Pattern{#COLLATION#})) OR (ex.IsWildcard = 0 AND (syn.name{#COLLATION#} = ex.Pattern{#COLLATION#} OR (s.name{#COLLATION#} + N''.'' + syn.name{#COLLATION#}) = ex.Pattern{#COLLATION#})));'; + SET @VALIDATION_SQL = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(@VALIDATION_SQL, @PLACEHOLDERSOURCEDBQUOTED, @SOURCEDATABASEQUOTED), @PLACEHOLDERTARGETDBQUOTED, @TARGETDATABASEQUOTED), @PLACEHOLDERSOURCEDB, @SOURCEDATABASE), @PLACEHOLDERTARGETDB, @TARGETDATABASE), @PLACEHOLDERCOLLATION, @COMPARECOLLATION); + EXEC sys.sp_executesql @VALIDATION_SQL, N'@tgt INT OUTPUT', @tgt = @VALIDATION_TARGET_COUNT OUTPUT; + + INSERT INTO #ValidationResults VALUES ('SCHEMA', 'Synonyms', NULL, @VALIDATION_SOURCE_COUNT, @VALIDATION_TARGET_COUNT, + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN 'OK' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN 'ERROR' ELSE 'WARN' END, NULL); + IF @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; END + ELSE IF @VALIDATION_SOURCE_COUNT < @VALIDATION_TARGET_COUNT BEGIN SET @VALIDATION_WARNINGS = @VALIDATION_WARNINGS + 1; END; + PRINT 'Synonyms: Source=' + CONVERT(NVARCHAR(10), @VALIDATION_SOURCE_COUNT) + ', Target=' + CONVERT(NVARCHAR(10), @VALIDATION_TARGET_COUNT) + CASE WHEN @VALIDATION_SOURCE_COUNT = @VALIDATION_TARGET_COUNT THEN ' [OK]' WHEN @VALIDATION_SOURCE_COUNT > @VALIDATION_TARGET_COUNT THEN ' [ERROR]' ELSE ' [WARN]' END; + END; -- /IF @SYNC_SYNONYMS END; --===================== DATA VALIDATION =====================-- @@ -2416,16 +2626,20 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} END CATCH; INSERT INTO #ValidationResults VALUES ('DATA', 'TableRows', @VALIDATION_SCHEMA_NAME + N'.' + @VALIDATION_TABLE_NAME, @VALIDATION_SOURCE_ROWS, @VALIDATION_TARGET_ROWS, - CASE WHEN @VALIDATION_SOURCE_ROWS = @VALIDATION_TARGET_ROWS THEN 'OK' WHEN @VALIDATION_TARGET_ROWS = -1 THEN 'ERROR' ELSE 'ERROR' END, - CASE WHEN @VALIDATION_SOURCE_ROWS = @VALIDATION_TARGET_ROWS THEN NULL WHEN @VALIDATION_TARGET_ROWS = -1 THEN 'Table missing in target' ELSE 'Row mismatch' END); + CASE WHEN @VALIDATION_SOURCE_ROWS = @VALIDATION_TARGET_ROWS THEN 'OK' WHEN @VALIDATION_TARGET_ROWS = -1 OR @VALIDATION_SOURCE_ROWS = -1 THEN 'ERROR' WHEN @VALIDATION_SOURCE_ROWS > @VALIDATION_TARGET_ROWS THEN 'ERROR' WHEN @DELETEMISSING = 1 AND @VALIDATION_SOURCE_ROWS < @VALIDATION_TARGET_ROWS THEN 'ERROR' ELSE 'WARN' END, + CASE WHEN @VALIDATION_SOURCE_ROWS = @VALIDATION_TARGET_ROWS THEN NULL WHEN @VALIDATION_TARGET_ROWS = -1 THEN 'Table missing in target' WHEN @VALIDATION_SOURCE_ROWS = -1 THEN 'Could not read source table' WHEN @VALIDATION_SOURCE_ROWS > @VALIDATION_TARGET_ROWS THEN 'Missing rows: ' + CONVERT(NVARCHAR(20), @VALIDATION_SOURCE_ROWS - @VALIDATION_TARGET_ROWS) WHEN @DELETEMISSING = 1 AND @VALIDATION_SOURCE_ROWS < @VALIDATION_TARGET_ROWS THEN 'Extra rows not deleted (DELETEMISSING=1): ' + CONVERT(NVARCHAR(20), @VALIDATION_TARGET_ROWS - @VALIDATION_SOURCE_ROWS) ELSE 'Extra rows in target: ' + CONVERT(NVARCHAR(20), @VALIDATION_TARGET_ROWS - @VALIDATION_SOURCE_ROWS) + ' (additive sync)' END); - IF @VALIDATION_SOURCE_ROWS <> @VALIDATION_TARGET_ROWS BEGIN + IF @VALIDATION_SOURCE_ROWS = @VALIDATION_TARGET_ROWS BEGIN + PRINT @VALIDATION_SCHEMA_NAME + N'.' + @VALIDATION_TABLE_NAME + N': ' + CONVERT(NVARCHAR(20), @VALIDATION_SOURCE_ROWS) + N' rows [OK]'; + END + ELSE IF @VALIDATION_TARGET_ROWS = -1 OR @VALIDATION_SOURCE_ROWS = -1 OR @VALIDATION_SOURCE_ROWS > @VALIDATION_TARGET_ROWS OR (@DELETEMISSING = 1 AND @VALIDATION_SOURCE_ROWS < @VALIDATION_TARGET_ROWS) BEGIN SET @VALIDATION_PASSED = 0; SET @VALIDATION_ERRORS = @VALIDATION_ERRORS + 1; PRINT @VALIDATION_SCHEMA_NAME + N'.' + @VALIDATION_TABLE_NAME + N': Source=' + CONVERT(NVARCHAR(20), @VALIDATION_SOURCE_ROWS) + N', Target=' + CONVERT(NVARCHAR(20), @VALIDATION_TARGET_ROWS) + N' [ERROR]'; END ELSE BEGIN - PRINT @VALIDATION_SCHEMA_NAME + N'.' + @VALIDATION_TABLE_NAME + N': ' + CONVERT(NVARCHAR(20), @VALIDATION_SOURCE_ROWS) + N' rows [OK]'; + SET @VALIDATION_WARNINGS = @VALIDATION_WARNINGS + 1; + PRINT @VALIDATION_SCHEMA_NAME + N'.' + @VALIDATION_TABLE_NAME + N': Source=' + CONVERT(NVARCHAR(20), @VALIDATION_SOURCE_ROWS) + N', Target=' + CONVERT(NVARCHAR(20), @VALIDATION_TARGET_ROWS) + N' [WARN]'; END; FETCH NEXT FROM data_val_cur INTO @VALIDATION_SCHEMA_NAME, @VALIDATION_TABLE_NAME; @@ -2437,8 +2651,8 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} IF OBJECT_ID('tempdb..#TBDD_SYNC_DATABASE_DATA_VALIDATION') IS NOT NULL DROP TABLE #TBDD_SYNC_DATABASE_DATA_VALIDATION; END; - -- Log validation results - IF (UPPER(@LOGLEVEL) IN (N'INFO')) BEGIN + -- Log validation results (filtered by log-level severity) + IF @LOGLEVEL IS NOT NULL BEGIN INSERT INTO [TBDD_SYNC_DATABASE_LOG] ([LOG_LEVEL], [MESSAGE1], [MESSAGE2], [MESSAGE3], [ADDED_WHO], [ADDED_WHEN]) SELECT @@ -2448,7 +2662,10 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} 'Source=' + CONVERT(NVARCHAR(20), SourceCount) + ', Target=' + CONVERT(NVARCHAR(20), TargetCount) + ' [' + Status + ']', @MY_PROCEDURE_NAME, GETDATE() - FROM #ValidationResults; + FROM #ValidationResults + WHERE (Status = 'ERROR') + OR (Status = 'WARN' AND @LOGLEVEL IN (N'INFO', N'WARN')) + OR (Status = 'OK' AND @LOGLEVEL = N'INFO'); END; -- Output validation summary @@ -2511,7 +2728,7 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} IF @vr_HasRows = 0 PRINT N'(No validation results to display)'; PRINT N''; - -- ===================== DETAILED MISMATCH REPORT (Bidirectional) ===================== + -- ===================== DETAILED MISMATCH REPORT (Bidirectional, table-driven) ===================== -- Show specific objects that differ between Source and Target IF @VALIDATION_PASSED = 0 AND UPPER(@VALIDATION_MODE) IN (N'ALL', N'SCHEMA') BEGIN PRINT N''; @@ -2521,165 +2738,93 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} DECLARE @MismatchSQL NVARCHAR(MAX); DECLARE @MismatchName NVARCHAR(500); DECLARE @MismatchFound BIT = 0; + DECLARE @MismatchLabel NVARCHAR(200); CREATE TABLE #TempMismatch (ObjectName NVARCHAR(500)); + CREATE TABLE #TempMismatchQueries (SortOrder INT, Label NVARCHAR(200), Query NVARCHAR(MAX)); - -- Tables: Missing in Target (exist in Source) - SET @MismatchSQL = N' - SELECT s.name + N''.'' + t.name - FROM ' + @SOURCEDATABASEQUOTED + N'.sys.tables t - JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = t.schema_id + -- Exclude-Filter Template (Platzhalter {OBJ}/{SCH} werden pro Query ersetzt) + DECLARE @EXCLUDE_FILTER NVARCHAR(MAX) = N' + AND NOT EXISTS (SELECT 1 FROM #TBDD_SYNC_DATABASE_EXCLUDEDOBJECTS ex WHERE (ex.IsWildcard = 1 AND ({OBJ}.name' + @COMPARECOLLATION + N' LIKE ex.Pattern' + @COMPARECOLLATION + N' OR ({SCH}.name' + @COMPARECOLLATION + N' + N''.'' + {OBJ}.name' + @COMPARECOLLATION + N') LIKE ex.Pattern' + @COMPARECOLLATION + N')) OR (ex.IsWildcard = 0 AND ({OBJ}.name' + @COMPARECOLLATION + N' = ex.Pattern' + @COMPARECOLLATION + N' OR ({SCH}.name' + @COMPARECOLLATION + N' + N''.'' + {OBJ}.name' + @COMPARECOLLATION + N') = ex.Pattern' + @COMPARECOLLATION + N')))'; + + -- Tables + INSERT INTO #TempMismatchQueries VALUES (1, N'[Tables] Missing in Target (exist in Source):', N' + SELECT s.name + N''.'' + t.name FROM ' + @SOURCEDATABASEQUOTED + N'.sys.tables t JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = t.schema_id WHERE s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' AND t.is_ms_shipped = 0 - AND NOT EXISTS (SELECT 1 FROM ' + @TARGETDATABASEQUOTED + N'.sys.tables tt - JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas ts ON ts.schema_id = tt.schema_id - WHERE ts.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' - AND tt.name' + @COMPARECOLLATION + N'=t.name' + @COMPARECOLLATION + N')'; - INSERT INTO #TempMismatch EXEC sys.sp_executesql @MismatchSQL; - IF EXISTS (SELECT 1 FROM #TempMismatch) BEGIN - SET @MismatchFound = 1; - PRINT N'[Tables] Missing in Target (exist in Source):'; - DECLARE mismatch_cur CURSOR LOCAL FAST_FORWARD FOR SELECT ObjectName FROM #TempMismatch; - OPEN mismatch_cur; FETCH NEXT FROM mismatch_cur INTO @MismatchName; - WHILE @@FETCH_STATUS = 0 BEGIN PRINT N' - ' + @MismatchName; FETCH NEXT FROM mismatch_cur INTO @MismatchName; END; - CLOSE mismatch_cur; DEALLOCATE mismatch_cur; - END; - TRUNCATE TABLE #TempMismatch; - - -- Tables: Extra in Target (not in Source) - SET @MismatchSQL = N' - SELECT s.name + N''.'' + t.name - FROM ' + @TARGETDATABASEQUOTED + N'.sys.tables t - JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = t.schema_id + AND NOT EXISTS (SELECT 1 FROM ' + @TARGETDATABASEQUOTED + N'.sys.tables tt JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas ts ON ts.schema_id = tt.schema_id WHERE ts.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND tt.name' + @COMPARECOLLATION + N'=t.name' + @COMPARECOLLATION + N')' + REPLACE(REPLACE(@EXCLUDE_FILTER, N'{OBJ}', N't'), N'{SCH}', N's')); + INSERT INTO #TempMismatchQueries VALUES (2, N'[Tables] Extra in Target (not in Source):', N' + SELECT s.name + N''.'' + t.name FROM ' + @TARGETDATABASEQUOTED + N'.sys.tables t JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = t.schema_id WHERE s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' AND t.is_ms_shipped = 0 - AND NOT EXISTS (SELECT 1 FROM ' + @SOURCEDATABASEQUOTED + N'.sys.tables st - JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas ss ON ss.schema_id = st.schema_id - WHERE ss.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' - AND st.name' + @COMPARECOLLATION + N'=t.name' + @COMPARECOLLATION + N')'; - INSERT INTO #TempMismatch EXEC sys.sp_executesql @MismatchSQL; - IF EXISTS (SELECT 1 FROM #TempMismatch) BEGIN - SET @MismatchFound = 1; - PRINT N'[Tables] Extra in Target (not in Source):'; - DECLARE mismatch_cur CURSOR LOCAL FAST_FORWARD FOR SELECT ObjectName FROM #TempMismatch; - OPEN mismatch_cur; FETCH NEXT FROM mismatch_cur INTO @MismatchName; - WHILE @@FETCH_STATUS = 0 BEGIN PRINT N' - ' + @MismatchName; FETCH NEXT FROM mismatch_cur INTO @MismatchName; END; - CLOSE mismatch_cur; DEALLOCATE mismatch_cur; - END; - TRUNCATE TABLE #TempMismatch; - - -- Views: Missing in Target - SET @MismatchSQL = N' - SELECT s.name + N''.'' + v.name FROM ' + @SOURCEDATABASEQUOTED + N'.sys.views v - JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = v.schema_id + AND NOT EXISTS (SELECT 1 FROM ' + @SOURCEDATABASEQUOTED + N'.sys.tables st JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas ss ON ss.schema_id = st.schema_id WHERE ss.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND st.name' + @COMPARECOLLATION + N'=t.name' + @COMPARECOLLATION + N')' + REPLACE(REPLACE(@EXCLUDE_FILTER, N'{OBJ}', N't'), N'{SCH}', N's')); + -- Views + INSERT INTO #TempMismatchQueries VALUES (3, N'[Views] Missing in Target:', N' + SELECT s.name + N''.'' + v.name FROM ' + @SOURCEDATABASEQUOTED + N'.sys.views v JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = v.schema_id WHERE s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' - AND NOT EXISTS (SELECT 1 FROM ' + @TARGETDATABASEQUOTED + N'.sys.views tv - JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas ts ON ts.schema_id = tv.schema_id - WHERE ts.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND tv.name' + @COMPARECOLLATION + N'=v.name' + @COMPARECOLLATION + N')'; - INSERT INTO #TempMismatch EXEC sys.sp_executesql @MismatchSQL; - IF EXISTS (SELECT 1 FROM #TempMismatch) BEGIN - SET @MismatchFound = 1; - PRINT N'[Views] Missing in Target:'; - DECLARE mismatch_cur CURSOR LOCAL FAST_FORWARD FOR SELECT ObjectName FROM #TempMismatch; - OPEN mismatch_cur; FETCH NEXT FROM mismatch_cur INTO @MismatchName; - WHILE @@FETCH_STATUS = 0 BEGIN PRINT N' - ' + @MismatchName; FETCH NEXT FROM mismatch_cur INTO @MismatchName; END; - CLOSE mismatch_cur; DEALLOCATE mismatch_cur; - END; - TRUNCATE TABLE #TempMismatch; - - -- Views: Extra in Target - SET @MismatchSQL = N' - SELECT s.name + N''.'' + v.name FROM ' + @TARGETDATABASEQUOTED + N'.sys.views v - JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = v.schema_id + AND NOT EXISTS (SELECT 1 FROM ' + @TARGETDATABASEQUOTED + N'.sys.views tv JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas ts ON ts.schema_id = tv.schema_id WHERE ts.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND tv.name' + @COMPARECOLLATION + N'=v.name' + @COMPARECOLLATION + N')' + REPLACE(REPLACE(@EXCLUDE_FILTER, N'{OBJ}', N'v'), N'{SCH}', N's')); + INSERT INTO #TempMismatchQueries VALUES (4, N'[Views] Extra in Target:', N' + SELECT s.name + N''.'' + v.name FROM ' + @TARGETDATABASEQUOTED + N'.sys.views v JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = v.schema_id WHERE s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' - AND NOT EXISTS (SELECT 1 FROM ' + @SOURCEDATABASEQUOTED + N'.sys.views sv - JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas ss ON ss.schema_id = sv.schema_id - WHERE ss.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND sv.name' + @COMPARECOLLATION + N'=v.name' + @COMPARECOLLATION + N')'; - INSERT INTO #TempMismatch EXEC sys.sp_executesql @MismatchSQL; - IF EXISTS (SELECT 1 FROM #TempMismatch) BEGIN - SET @MismatchFound = 1; - PRINT N'[Views] Extra in Target:'; - DECLARE mismatch_cur CURSOR LOCAL FAST_FORWARD FOR SELECT ObjectName FROM #TempMismatch; - OPEN mismatch_cur; FETCH NEXT FROM mismatch_cur INTO @MismatchName; - WHILE @@FETCH_STATUS = 0 BEGIN PRINT N' - ' + @MismatchName; FETCH NEXT FROM mismatch_cur INTO @MismatchName; END; - CLOSE mismatch_cur; DEALLOCATE mismatch_cur; - END; - TRUNCATE TABLE #TempMismatch; - - -- Procedures: Missing in Target - SET @MismatchSQL = N' - SELECT s.name + N''.'' + p.name FROM ' + @SOURCEDATABASEQUOTED + N'.sys.procedures p - JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = p.schema_id + AND NOT EXISTS (SELECT 1 FROM ' + @SOURCEDATABASEQUOTED + N'.sys.views sv JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas ss ON ss.schema_id = sv.schema_id WHERE ss.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND sv.name' + @COMPARECOLLATION + N'=v.name' + @COMPARECOLLATION + N')' + REPLACE(REPLACE(@EXCLUDE_FILTER, N'{OBJ}', N'v'), N'{SCH}', N's')); + -- Procedures + INSERT INTO #TempMismatchQueries VALUES (5, N'[Procedures] Missing in Target:', N' + SELECT s.name + N''.'' + p.name FROM ' + @SOURCEDATABASEQUOTED + N'.sys.procedures p JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = p.schema_id WHERE s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' - AND NOT EXISTS (SELECT 1 FROM ' + @TARGETDATABASEQUOTED + N'.sys.procedures tp - JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas ts ON ts.schema_id = tp.schema_id - WHERE ts.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND tp.name' + @COMPARECOLLATION + N'=p.name' + @COMPARECOLLATION + N')'; - INSERT INTO #TempMismatch EXEC sys.sp_executesql @MismatchSQL; - IF EXISTS (SELECT 1 FROM #TempMismatch) BEGIN - SET @MismatchFound = 1; - PRINT N'[Procedures] Missing in Target:'; - DECLARE mismatch_cur CURSOR LOCAL FAST_FORWARD FOR SELECT ObjectName FROM #TempMismatch; - OPEN mismatch_cur; FETCH NEXT FROM mismatch_cur INTO @MismatchName; - WHILE @@FETCH_STATUS = 0 BEGIN PRINT N' - ' + @MismatchName; FETCH NEXT FROM mismatch_cur INTO @MismatchName; END; - CLOSE mismatch_cur; DEALLOCATE mismatch_cur; - END; - TRUNCATE TABLE #TempMismatch; - - -- Procedures: Extra in Target - SET @MismatchSQL = N' - SELECT s.name + N''.'' + p.name FROM ' + @TARGETDATABASEQUOTED + N'.sys.procedures p - JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = p.schema_id + AND NOT EXISTS (SELECT 1 FROM ' + @TARGETDATABASEQUOTED + N'.sys.procedures tp JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas ts ON ts.schema_id = tp.schema_id WHERE ts.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND tp.name' + @COMPARECOLLATION + N'=p.name' + @COMPARECOLLATION + N')' + REPLACE(REPLACE(@EXCLUDE_FILTER, N'{OBJ}', N'p'), N'{SCH}', N's')); + INSERT INTO #TempMismatchQueries VALUES (6, N'[Procedures] Extra in Target:', N' + SELECT s.name + N''.'' + p.name FROM ' + @TARGETDATABASEQUOTED + N'.sys.procedures p JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = p.schema_id WHERE s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' - AND NOT EXISTS (SELECT 1 FROM ' + @SOURCEDATABASEQUOTED + N'.sys.procedures sp - JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas ss ON ss.schema_id = sp.schema_id - WHERE ss.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND sp.name' + @COMPARECOLLATION + N'=p.name' + @COMPARECOLLATION + N')'; - INSERT INTO #TempMismatch EXEC sys.sp_executesql @MismatchSQL; - IF EXISTS (SELECT 1 FROM #TempMismatch) BEGIN - SET @MismatchFound = 1; - PRINT N'[Procedures] Extra in Target:'; - DECLARE mismatch_cur CURSOR LOCAL FAST_FORWARD FOR SELECT ObjectName FROM #TempMismatch; - OPEN mismatch_cur; FETCH NEXT FROM mismatch_cur INTO @MismatchName; - WHILE @@FETCH_STATUS = 0 BEGIN PRINT N' - ' + @MismatchName; FETCH NEXT FROM mismatch_cur INTO @MismatchName; END; - CLOSE mismatch_cur; DEALLOCATE mismatch_cur; - END; - TRUNCATE TABLE #TempMismatch; + AND NOT EXISTS (SELECT 1 FROM ' + @SOURCEDATABASEQUOTED + N'.sys.procedures sp JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas ss ON ss.schema_id = sp.schema_id WHERE ss.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND sp.name' + @COMPARECOLLATION + N'=p.name' + @COMPARECOLLATION + N')' + REPLACE(REPLACE(@EXCLUDE_FILTER, N'{OBJ}', N'p'), N'{SCH}', N's')); + -- Functions + INSERT INTO #TempMismatchQueries VALUES (7, N'[Functions] Missing in Target:', N' + SELECT s.name + N''.'' + o.name FROM ' + @SOURCEDATABASEQUOTED + N'.sys.objects o JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = o.schema_id + WHERE o.type IN (N''FN'',N''TF'',N''IF'',N''FS'',N''FT'') AND s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' + AND NOT EXISTS (SELECT 1 FROM ' + @TARGETDATABASEQUOTED + N'.sys.objects tobj JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas ts ON ts.schema_id = tobj.schema_id WHERE ts.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND tobj.name' + @COMPARECOLLATION + N'=o.name' + @COMPARECOLLATION + N' AND tobj.type IN (N''FN'',N''TF'',N''IF'',N''FS'',N''FT''))' + REPLACE(REPLACE(@EXCLUDE_FILTER, N'{OBJ}', N'o'), N'{SCH}', N's')); + INSERT INTO #TempMismatchQueries VALUES (8, N'[Functions] Extra in Target:', N' + SELECT s.name + N''.'' + o.name FROM ' + @TARGETDATABASEQUOTED + N'.sys.objects o JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = o.schema_id + WHERE o.type IN (N''FN'',N''TF'',N''IF'',N''FS'',N''FT'') AND s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' + AND NOT EXISTS (SELECT 1 FROM ' + @SOURCEDATABASEQUOTED + N'.sys.objects sobj JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas ss ON ss.schema_id = sobj.schema_id WHERE ss.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND sobj.name' + @COMPARECOLLATION + N'=o.name' + @COMPARECOLLATION + N' AND sobj.type IN (N''FN'',N''TF'',N''IF'',N''FS'',N''FT''))' + REPLACE(REPLACE(@EXCLUDE_FILTER, N'{OBJ}', N'o'), N'{SCH}', N's')); + -- Sequences + INSERT INTO #TempMismatchQueries VALUES (9, N'[Sequences] Missing in Target:', N' + SELECT s.name + N''.'' + seq.name FROM ' + @SOURCEDATABASEQUOTED + N'.sys.sequences seq JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = seq.schema_id + WHERE s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' + AND NOT EXISTS (SELECT 1 FROM ' + @TARGETDATABASEQUOTED + N'.sys.sequences tseq JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas ts ON ts.schema_id = tseq.schema_id WHERE ts.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND tseq.name' + @COMPARECOLLATION + N'=seq.name' + @COMPARECOLLATION + N')' + REPLACE(REPLACE(@EXCLUDE_FILTER, N'{OBJ}', N'seq'), N'{SCH}', N's')); + INSERT INTO #TempMismatchQueries VALUES (10, N'[Sequences] Extra in Target:', N' + SELECT s.name + N''.'' + seq.name FROM ' + @TARGETDATABASEQUOTED + N'.sys.sequences seq JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = seq.schema_id + WHERE s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' + AND NOT EXISTS (SELECT 1 FROM ' + @SOURCEDATABASEQUOTED + N'.sys.sequences sseq JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas ss ON ss.schema_id = sseq.schema_id WHERE ss.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND sseq.name' + @COMPARECOLLATION + N'=seq.name' + @COMPARECOLLATION + N')' + REPLACE(REPLACE(@EXCLUDE_FILTER, N'{OBJ}', N'seq'), N'{SCH}', N's')); + -- Synonyms + INSERT INTO #TempMismatchQueries VALUES (11, N'[Synonyms] Missing in Target:', N' + SELECT s.name + N''.'' + syn.name FROM ' + @SOURCEDATABASEQUOTED + N'.sys.synonyms syn JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = syn.schema_id + WHERE s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' + AND NOT EXISTS (SELECT 1 FROM ' + @TARGETDATABASEQUOTED + N'.sys.synonyms tsyn JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas ts ON ts.schema_id = tsyn.schema_id WHERE ts.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND tsyn.name' + @COMPARECOLLATION + N'=syn.name' + @COMPARECOLLATION + N')' + REPLACE(REPLACE(@EXCLUDE_FILTER, N'{OBJ}', N'syn'), N'{SCH}', N's')); + INSERT INTO #TempMismatchQueries VALUES (12, N'[Synonyms] Extra in Target:', N' + SELECT s.name + N''.'' + syn.name FROM ' + @TARGETDATABASEQUOTED + N'.sys.synonyms syn JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = syn.schema_id + WHERE s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' + AND NOT EXISTS (SELECT 1 FROM ' + @SOURCEDATABASEQUOTED + N'.sys.synonyms ssyn JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas ss ON ss.schema_id = ssyn.schema_id WHERE ss.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND ssyn.name' + @COMPARECOLLATION + N'=syn.name' + @COMPARECOLLATION + N')' + REPLACE(REPLACE(@EXCLUDE_FILTER, N'{OBJ}', N'syn'), N'{SCH}', N's')); - -- Functions: Missing in Target - SET @MismatchSQL = N' - SELECT s.name + N''.'' + o.name FROM ' + @SOURCEDATABASEQUOTED + N'.sys.objects o - JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = o.schema_id - WHERE o.type IN (N''FN'',N''TF'',N''IF'') AND s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' - AND NOT EXISTS (SELECT 1 FROM ' + @TARGETDATABASEQUOTED + N'.sys.objects tobj - JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas ts ON ts.schema_id = tobj.schema_id - WHERE ts.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND tobj.name' + @COMPARECOLLATION + N'=o.name' + @COMPARECOLLATION + N' AND tobj.type IN (N''FN'',N''TF'',N''IF''))'; - INSERT INTO #TempMismatch EXEC sys.sp_executesql @MismatchSQL; - IF EXISTS (SELECT 1 FROM #TempMismatch) BEGIN - SET @MismatchFound = 1; - PRINT N'[Functions] Missing in Target:'; - DECLARE mismatch_cur CURSOR LOCAL FAST_FORWARD FOR SELECT ObjectName FROM #TempMismatch; - OPEN mismatch_cur; FETCH NEXT FROM mismatch_cur INTO @MismatchName; - WHILE @@FETCH_STATUS = 0 BEGIN PRINT N' - ' + @MismatchName; FETCH NEXT FROM mismatch_cur INTO @MismatchName; END; - CLOSE mismatch_cur; DEALLOCATE mismatch_cur; - END; - TRUNCATE TABLE #TempMismatch; - - -- Functions: Extra in Target - SET @MismatchSQL = N' - SELECT s.name + N''.'' + o.name FROM ' + @TARGETDATABASEQUOTED + N'.sys.objects o - JOIN ' + @TARGETDATABASEQUOTED + N'.sys.schemas s ON s.schema_id = o.schema_id - WHERE o.type IN (N''FN'',N''TF'',N''IF'') AND s.name' + @COMPARECOLLATION + N'<>N''sys''' + @COMPARECOLLATION + N' - AND NOT EXISTS (SELECT 1 FROM ' + @SOURCEDATABASEQUOTED + N'.sys.objects sobj - JOIN ' + @SOURCEDATABASEQUOTED + N'.sys.schemas ss ON ss.schema_id = sobj.schema_id - WHERE ss.name' + @COMPARECOLLATION + N'=s.name' + @COMPARECOLLATION + N' AND sobj.name' + @COMPARECOLLATION + N'=o.name' + @COMPARECOLLATION + N' AND sobj.type IN (N''FN'',N''TF'',N''IF''))'; - INSERT INTO #TempMismatch EXEC sys.sp_executesql @MismatchSQL; - IF EXISTS (SELECT 1 FROM #TempMismatch) BEGIN - SET @MismatchFound = 1; - PRINT N'[Functions] Extra in Target:'; - DECLARE mismatch_cur CURSOR LOCAL FAST_FORWARD FOR SELECT ObjectName FROM #TempMismatch; - OPEN mismatch_cur; FETCH NEXT FROM mismatch_cur INTO @MismatchName; - WHILE @@FETCH_STATUS = 0 BEGIN PRINT N' - ' + @MismatchName; FETCH NEXT FROM mismatch_cur INTO @MismatchName; END; - CLOSE mismatch_cur; DEALLOCATE mismatch_cur; + -- Process all mismatch queries in order + DECLARE mm_config_cur CURSOR LOCAL FAST_FORWARD FOR + SELECT Label, Query FROM #TempMismatchQueries ORDER BY SortOrder; + OPEN mm_config_cur; + FETCH NEXT FROM mm_config_cur INTO @MismatchLabel, @MismatchSQL; + WHILE @@FETCH_STATUS = 0 BEGIN + TRUNCATE TABLE #TempMismatch; + INSERT INTO #TempMismatch EXEC sys.sp_executesql @MismatchSQL; + IF EXISTS (SELECT 1 FROM #TempMismatch) BEGIN + SET @MismatchFound = 1; + PRINT @MismatchLabel; + DECLARE mismatch_cur CURSOR LOCAL FAST_FORWARD FOR SELECT ObjectName FROM #TempMismatch; + OPEN mismatch_cur; FETCH NEXT FROM mismatch_cur INTO @MismatchName; + WHILE @@FETCH_STATUS = 0 BEGIN PRINT N' - ' + @MismatchName; FETCH NEXT FROM mismatch_cur INTO @MismatchName; END; + CLOSE mismatch_cur; DEALLOCATE mismatch_cur; + END; + FETCH NEXT FROM mm_config_cur INTO @MismatchLabel, @MismatchSQL; END; + CLOSE mm_config_cur; + DEALLOCATE mm_config_cur; DROP TABLE #TempMismatch; + DROP TABLE #TempMismatchQueries; IF @MismatchFound = 0 PRINT N'(Count mismatch but no specific objects found - may be due to exclusions)'; PRINT N''; @@ -2700,10 +2845,14 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} -- Nur für Tabellen, die im Data-Sync waren, Statistiken aktualisieren DECLARE stats_cursor CURSOR LOCAL FAST_FORWARD FOR SELECT DISTINCT - SUBSTRING(Command, CHARINDEX('MERGE ', Command) + 6, - CHARINDEX(' AS tgt', Command) - CHARINDEX('MERGE ', Command) - 6) + SUBSTRING(Command, + CHARINDEX(N'MERGE ' + QUOTENAME(@TARGETDATABASE) + N'.', Command) + LEN(N'MERGE ' + QUOTENAME(@TARGETDATABASE) + N'.'), + CHARINDEX(N' AS tgt', Command) - + CHARINDEX(N'MERGE ' + QUOTENAME(@TARGETDATABASE) + N'.', Command) - LEN(N'MERGE ' + QUOTENAME(@TARGETDATABASE) + N'.')) FROM #TBDD_SYNC_DATABASE_COMMANDS - WHERE Phase = '20-Data' AND Command LIKE '%MERGE %'; + WHERE Phase = N'20-Data' + AND Command LIKE N'%MERGE ' + QUOTENAME(@TARGETDATABASE) + N'.%' + AND CHARINDEX(N' AS tgt', Command) > CHARINDEX(N'MERGE ' + QUOTENAME(@TARGETDATABASE) + N'.', Command); OPEN stats_cursor; FETCH NEXT FROM stats_cursor INTO @StatTableName; @@ -2748,4 +2897,4 @@ WHERE s.name{#COLLATION#}<>N''sys''{#COLLATION#} RETURN @RETURN_STATUS; END; -GO +GO \ No newline at end of file diff --git a/dev/[DD_ECM_REF]-Database/[PRMOT_MON_GET_TREEVIEW_RESULTS]_error.sql b/dev/[DD_ECM_REF]-Database/[PRMOT_MON_GET_TREEVIEW_RESULTS]_error.sql new file mode 100644 index 0000000..b1a2871 --- /dev/null +++ b/dev/[DD_ECM_REF]-Database/[PRMOT_MON_GET_TREEVIEW_RESULTS]_error.sql @@ -0,0 +1,169 @@ +USE [DD_ECM_REF] +GO + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +-- PRMOT_MON_GET_TREEVIEW_RESULTS (Value: STRING) +-- ================================================================= +-- Haupteinstiegspunkt in die Monitor-Suche +-- +-- Returns: Tabelle +-- ================================================================= +-- Copyright (c) 2026 by Digital Data GmbH +-- +-- Digital Data GmbH • Ludwig-Rinn-Strasse 16 • D-35452 Heuchelheim +-- Tel.: 0641/202360 • E-Mail: info-flow@digitaldata.works +-- ================================================================= +-- History: +-- 10.03.2026 / MP - Prozedur erstellt. +-- 13.03.2026 / MP - Prozedur für MOT-Tabellen angepasst + +CREATE OR ALTER PROCEDURE [dbo].[PRMOT_MON_GET_TREEVIEW_RESULTS] + @SEARCH_VALUE NVARCHAR(100), -- Belegnummer. Muss länger als n Zeichen sein + @USR_ID INTEGER -- UserID aus Monitor +AS +BEGIN + -- Optimierungen + SET NOCOUNT ON; + SET ARITHABORT ON; + + DECLARE @MIN_SEARCH_LEN INT, @BATCH_SIZE INT; + SET @MIN_SEARCH_LEN = 5; -- Mindestlänge der Belegnummer + SET @BATCH_SIZE = 10; -- Max. Belege, für die Daten gesucht werden. + + DECLARE @ID INTEGER, @PID INTEGER, @PID_OFFSET INTEGER, @EMAILMSGID VARCHAR(200), @GLOB_COUNTER INTEGER, + @ERG_COUNTER INTEGER, @STRING VARCHAR(50), @ADDED_WHEN DATETIME, @EXPANDED_SWITCH SMALLINT; + + DECLARE @tt1 TABLE (GUID INT); -- temp Tabelle für GUIDs + + SET @ID = 0; + SET @PID = 1; + SET @PID_OFFSET = 0; + SET @EXPANDED_SWITCH = 1; + + -- ### CLEAR former Results ## + DELETE FROM [DD_ECM_REF].dbo.MOTB_MON_TREEVIEW_RESULTS WITH (SNAPSHOT) WHERE USR_ID = @USR_ID; + +---------------------------------------------------------------------------------------------------------------- +-- Such-Parameter bearbeiten +---------------------------------------------------------------------------------------------------------------- + + IF LEN(@SEARCH_VALUE) < @MIN_SEARCH_LEN + BEGIN + EXEC [DD_ECM_REF].dbo.PRMOT_MON_TREEVIEW_ADD_ROW @USR_ID, NULL, 1, 0, NULL, NULL, 'Belegnummer zu kurz!', NULL, NULL, 0; + SELECT * FROM [DD_ECM_REF].dbo.MOTB_MON_TREEVIEW_RESULTS WITH (SNAPSHOT) WHERE USR_ID = @USR_ID ORDER BY GUID; + RETURN; + END + + ---- führende 00er entfernen + DECLARE @SEARCH_VALUE2 VARCHAR(50); + SELECT @SEARCH_VALUE2 = SUBSTRING(Spalte, PATINDEX('%[^0]%', Spalte + ' '), LEN(Spalte)) + FROM (SELECT @SEARCH_VALUE AS Spalte) AS t; + +---------------------------------------------------------------------------------------------------------------- +-- Such-Menge (MessageIDs) eingrenzen +---------------------------------------------------------------------------------------------------------------- + DECLARE @tbl TABLE (EMAILMSGID VARCHAR(200)); + DELETE FROM @tbl; + + ---- XML-Daten zuerst + INSERT INTO @tbl + SELECT DISTINCT REFERENCE_GUID + FROM DD_ECM.DBO.TBEDMI_ITEM_VALUE WITH (NOLOCK) + WHERE SPEC_NAME = 'INVOICE_NUMBER' AND ITEM_VALUE = @SEARCH_VALUE; + + ---- sonstige E-Mail-Eingänge, der letzten 6 Monate, ohne führende 00er + INSERT INTO @tbl + SELECT EMAIL_MSGID + FROM DD_ECM.dbo.TBEMLP_HISTORY WITH (NOLOCK) + WHERE EMAIL_SUBJECT LIKE '%' + TRIM(@SEARCH_VALUE2) + '%' + AND datediff(month, EMAIL_DATE, getdate()) <= 6 + AND EMAIL_FROM <> 'donotreply@wisag.de' + AND EMAIL_MSGID NOT IN (SELECT EMAILMSGID from @tbl); + +---------------------------------------------------------------------------------------------------------------- +-- CURSOR über gefundene MessageIDs +---------------------------------------------------------------------------------------------------------------- + + SELECT @GLOB_COUNTER = count(*) FROM @tbl; + IF @GLOB_COUNTER >= 1 + BEGIN + SET @ERG_COUNTER = @GLOB_COUNTER + + DECLARE main_msgid_cursor CURSOR LOCAL FAST_FORWARD FOR + + SELECT TOP (@BATCH_SIZE) EMAILMSGID FROM @tbl; + + OPEN main_msgid_cursor; + FETCH NEXT FROM main_msgid_cursor INTO @EMAILMSGID; + WHILE @@FETCH_STATUS = 0 + BEGIN + --PRINT 'PRDD_MONITORING_GET_TREEVIEW_RESULT 3' + + -- ## Ermittele die Start ID ## + SET @ID = (SELECT coalesce(max(GUID),0) FROM [DD_ECM_REF].dbo.MOTB_MON_TREEVIEW_RESULTS WITH (SNAPSHOT) WHERE USR_ID = @USR_ID); + + -- ## Ermittele die Start PID ## + IF @GLOB_COUNTER = 1 + SET @PID = 0; + ELSE + BEGIN + SET @ID +=1; + SET @STRING = 'Ergebnis '+ CONVERT(varchar, @ERG_COUNTER); + + IF @GLOB_COUNTER = @ERG_COUNTER + SET @EXPANDED_SWITCH = 1; + ELSE + SET @EXPANDED_SWITCH = 0; + + SELECT @ADDED_WHEN = MIN(CREATEDWHEN) FROM DD_ECM.dbo.TBEDMI_ITEM_VALUE WHERE REFERENCE_GUID = @EMAILMSGID; + + EXEC [DD_ECM_REF].dbo.PRMOT_MON_TREEVIEW_ADD_ROW @USR_ID, NULL, @ID, 0, @ADDED_WHEN, @STRING, NULL, NULL, NULL, @EXPANDED_SWITCH; + SET @ERG_COUNTER -= 1; + SET @PID = @ID; + END + + --PRINT 'PRDD_MONITORING_GET_TREEVIEW_RESULT 4' + EXEC [DD_ECM_REF].dbo.[PRMOT_MON_GET_TREEVIEW_RESULTS_PER_MESSAGEID] @EMAILMSGID, @USR_ID, @ID, @PID; + --PRINT 'PRDD_MONITORING_GET_TREEVIEW_RESULT 5' + + FETCH NEXT FROM main_msgid_cursor INTO @EMAILMSGID + END + CLOSE main_msgid_cursor + DEALLOCATE main_msgid_cursor + END + ELSE + BEGIN + -- DIESE ABFRAGE IST TEUER!!!! + + --PRINT 'SEARCH @EMAILMSGID IN TBEMLP_EMAIL_OUT' + DECLARE @E_SUBJ VARCHAR(256) + SET @E_SUBJ = '% '+ @SEARCH_VALUE2 +' %'; + SELECT @EMAILMSGID = REFERENCE_STRING FROM DD_ECM.dbo.TBEMLP_EMAIL_OUT WHERE EMAIL_SUBJ like @E_SUBJ; + + IF LEN(@EMAILMSGID) = 0 OR @EMAILMSGID IS NULL + BEGIN + -- Ohne EMail-MessageID werden keine weiteren DAten gefunden + --PRINT 'NO @EMAILMSGID FOUND' + EXEC [DD_ECM_REF].dbo.PRMOT_MON_TREEVIEW_ADD_ROW @USR_ID,NULL,@ID,@PID,NULL,'Fehlende Belegdaten ','Es wurden keine Belegdaten gefunden!','HIGHLIGHT'; + RETURN + END + ELSE + BEGIN + --PRINT 'PRDD_MONITORING_GET_TREEVIEW_RESULT 6' + EXEC [DD_ECM_REF].[dbo].[PRMOT_MON_GET_TREEVIEW_RESULTS_PER_MESSAGEID] @EMAILMSGID, @USR_ID, 0, 0; + --PRINT 'PRDD_MONITORING_GET_TREEVIEW_RESULT 7' + END + END + + --PRINT 'PRDD_MONITORING_GET_TREEVIEW_RESULT 8' + -- ### LAST STEP - Get all results ### + SELECT * FROM [DD_ECM_REF].dbo.MOTB_MON_TREEVIEW_RESULTS WITH (SNAPSHOT) WHERE USR_ID = @USR_ID ORDER BY GUID; + +END +GO + + diff --git a/dev/[DD_ECM_REF]-Database/[PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql b/dev/[DD_ECM_REF]-Database/[PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql new file mode 100644 index 0000000..e91cb94 --- /dev/null +++ b/dev/[DD_ECM_REF]-Database/[PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql @@ -0,0 +1,174 @@ +USE [DD_ECM_REF] +GO + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +-- PRMOT_MON_GET_TREEVIEW_RESULTS (Value: STRING) +-- ================================================================= +-- Haupteinstiegspunkt in die Monitor-Suche +-- +-- Returns: Tabelle +-- ================================================================= +-- Copyright (c) 2026 by Digital Data GmbH +-- +-- Digital Data GmbH • Ludwig-Rinn-Strasse 16 • D-35452 Heuchelheim +-- Tel.: 0641/202360 • E-Mail: info-flow@digitaldata.works +-- ================================================================= +-- History: +-- 10.03.2026 / MP - Prozedur erstellt. +-- 13.03.2026 / MP - Prozedur für MOT-Tabellen angepasst + +CREATE OR ALTER PROCEDURE [dbo].[PRMOT_MON_GET_TREEVIEW_RESULTS] + @SEARCH_VALUE NVARCHAR(100), -- Belegnummer. Muss länger als n Zeichen sein + @USR_ID INTEGER -- UserID aus Monitor +AS +BEGIN + -- Optimierungen + SET NOCOUNT ON; + SET ARITHABORT ON; + + DECLARE @MIN_SEARCH_LEN INT, @BATCH_SIZE INT; + SET @MIN_SEARCH_LEN = 5; -- Mindestlänge der Belegnummer + SET @BATCH_SIZE = 10; -- Max. Belege, für die Daten gesucht werden. + + DECLARE @ID INTEGER, @PID INTEGER, @PID_OFFSET INTEGER, @EMAILMSGID VARCHAR(200), @GLOB_COUNTER INTEGER, + @ERG_COUNTER INTEGER, @STRING VARCHAR(50), @ADDED_WHEN DATETIME, @EXPANDED_SWITCH SMALLINT; + + DECLARE @tt1 TABLE (GUID INT); -- temp Tabelle für GUIDs + + SET @ID = 0; + SET @PID = 1; + SET @PID_OFFSET = 0; + SET @EXPANDED_SWITCH = 1; + + -- ### CLEAR former Results ## + DELETE FROM [DD_ECM_REF].dbo.MOTB_MON_TREEVIEW_RESULTS WITH (SNAPSHOT) WHERE USR_ID = @USR_ID; + +---------------------------------------------------------------------------------------------------------------- +-- Such-Parameter bearbeiten +---------------------------------------------------------------------------------------------------------------- + + IF LEN(@SEARCH_VALUE) < @MIN_SEARCH_LEN + BEGIN + EXEC [DD_ECM_REF].dbo.PRMOT_MON_TREEVIEW_ADD_ROW @USR_ID, NULL, 1, 0, NULL, NULL, 'Belegnummer zu kurz!', NULL, NULL, 0; + SELECT * FROM [DD_ECM_REF].dbo.MOTB_MON_TREEVIEW_RESULTS WITH (SNAPSHOT) WHERE USR_ID = @USR_ID ORDER BY GUID; + RETURN; + END + + ---- führende 00er entfernen + DECLARE @SEARCH_VALUE2 VARCHAR(50); + SELECT @SEARCH_VALUE2 = SUBSTRING(Spalte, PATINDEX('%[^0]%', Spalte + ' '), LEN(Spalte)) + FROM (SELECT @SEARCH_VALUE AS Spalte) AS t; + +---------------------------------------------------------------------------------------------------------------- +-- Such-Menge (MessageIDs) eingrenzen +---------------------------------------------------------------------------------------------------------------- + DECLARE @tbl TABLE (EMAILMSGID VARCHAR(200)); + DELETE FROM @tbl; + + ---- XML-Daten zuerst + INSERT INTO @tbl + SELECT DISTINCT REFERENCE_GUID + FROM DD_ECM.DBO.TBEDMI_ITEM_VALUE WITH (NOLOCK) + WHERE SPEC_NAME = 'INVOICE_NUMBER' AND ITEM_VALUE = @SEARCH_VALUE; + + ---- sonstige E-Mail-Eingänge, der letzten 6 Monate, ohne führende 00er + INSERT INTO @tbl + SELECT EMAIL_MSGID + FROM DD_ECM.dbo.TBEMLP_HISTORY WITH (NOLOCK) + WHERE EMAIL_SUBJECT LIKE '%' + TRIM(@SEARCH_VALUE2) + '%' + AND datediff(month, EMAIL_DATE, getdate()) <= 6 + AND EMAIL_FROM <> 'donotreply@wisag.de' + AND EMAIL_MSGID NOT IN (SELECT EMAILMSGID from @tbl); + +---------------------------------------------------------------------------------------------------------------- +-- CURSOR über gefundene MessageIDs +---------------------------------------------------------------------------------------------------------------- + + SELECT @GLOB_COUNTER = count(*) FROM @tbl; + IF @GLOB_COUNTER >= 1 + BEGIN + SET @ERG_COUNTER = @GLOB_COUNTER + + DECLARE main_msgid_cursor CURSOR LOCAL FAST_FORWARD FOR + + SELECT TOP (@BATCH_SIZE) EMAILMSGID FROM @tbl; + + OPEN main_msgid_cursor; + FETCH NEXT FROM main_msgid_cursor INTO @EMAILMSGID; + WHILE @@FETCH_STATUS = 0 + BEGIN + --PRINT 'PRDD_MONITORING_GET_TREEVIEW_RESULT 3' + + -- ## Ermittele die Start ID ## + DELETE FROM @tt1; + INSERT INTO @tt1 + SELECT coalesce(max(GUID),0) + FROM [DD_ECM_REF].dbo.MOTB_MON_TREEVIEW_RESULTS WITH (SNAPSHOT) + WHERE USR_ID = @USR_ID; + SELECT @ID = GUID from @tt1; + + -- ## Ermittele die Start PID ## + IF @GLOB_COUNTER = 1 + SET @PID = 0; + ELSE + BEGIN + SET @ID +=1; + SET @STRING = 'Ergebnis '+ CONVERT(varchar, @ERG_COUNTER); + + IF @GLOB_COUNTER = @ERG_COUNTER + SET @EXPANDED_SWITCH = 1; + ELSE + SET @EXPANDED_SWITCH = 0; + + SELECT @ADDED_WHEN = MIN(CREATEDWHEN) FROM DD_ECM.dbo.TBEDMI_ITEM_VALUE WHERE REFERENCE_GUID = @EMAILMSGID; + + EXEC [DD_ECM_REF].dbo.PRMOT_MON_TREEVIEW_ADD_ROW @USR_ID, NULL, @ID, 0, @ADDED_WHEN, @STRING, NULL, NULL, NULL, @EXPANDED_SWITCH; + SET @ERG_COUNTER -= 1; + SET @PID = @ID; + END + + --PRINT 'PRDD_MONITORING_GET_TREEVIEW_RESULT 4' + EXEC [DD_ECM_REF].dbo.[PRMOT_MON_GET_TREEVIEW_RESULTS_PER_MESSAGEID] @EMAILMSGID, @USR_ID, @ID, @PID; + --PRINT 'PRDD_MONITORING_GET_TREEVIEW_RESULT 5' + + FETCH NEXT FROM main_msgid_cursor INTO @EMAILMSGID + END + CLOSE main_msgid_cursor + DEALLOCATE main_msgid_cursor + END + ELSE + BEGIN + -- DIESE ABFRAGE IST TEUER!!!! + + --PRINT 'SEARCH @EMAILMSGID IN TBEMLP_EMAIL_OUT' + DECLARE @E_SUBJ VARCHAR(256) + SET @E_SUBJ = '% '+ @SEARCH_VALUE2 +' %'; + SELECT @EMAILMSGID = REFERENCE_STRING FROM DD_ECM.dbo.TBEMLP_EMAIL_OUT WHERE EMAIL_SUBJ like @E_SUBJ; + + IF LEN(@EMAILMSGID) = 0 OR @EMAILMSGID IS NULL + BEGIN + -- Ohne EMail-MessageID werden keine weiteren DAten gefunden + --PRINT 'NO @EMAILMSGID FOUND' + EXEC [DD_ECM_REF].dbo.PRMOT_MON_TREEVIEW_ADD_ROW @USR_ID,NULL,@ID,@PID,NULL,'Fehlende Belegdaten ','Es wurden keine Belegdaten gefunden!','HIGHLIGHT'; + RETURN + END + ELSE + BEGIN + --PRINT 'PRDD_MONITORING_GET_TREEVIEW_RESULT 6' + EXEC [DD_ECM_REF].[dbo].[PRMOT_MON_GET_TREEVIEW_RESULTS_PER_MESSAGEID] @EMAILMSGID, @USR_ID, 0, 0; + --PRINT 'PRDD_MONITORING_GET_TREEVIEW_RESULT 7' + END + END + + --PRINT 'PRDD_MONITORING_GET_TREEVIEW_RESULT 8' + -- ### LAST STEP - Get all results ### + SELECT * FROM [DD_ECM_REF].dbo.MOTB_MON_TREEVIEW_RESULTS WITH (SNAPSHOT) WHERE USR_ID = @USR_ID ORDER BY GUID; + +END +GO + + diff --git a/dev/[DD_ECM_REF]-Database/[PRMOT_MON_GET_TREEVIEW_RESULTS]_safe.sql b/dev/[DD_ECM_REF]-Database/[PRMOT_MON_GET_TREEVIEW_RESULTS]_safe.sql new file mode 100644 index 0000000..22be3af --- /dev/null +++ b/dev/[DD_ECM_REF]-Database/[PRMOT_MON_GET_TREEVIEW_RESULTS]_safe.sql @@ -0,0 +1,249 @@ +USE [DD_ECM_REF] +GO + +SET ANSI_NULLS ON +GO +SET QUOTED_IDENTIFIER ON +GO + +-- PRMOT_MON_GET_TREEVIEW_RESULTS_SAFE (Value: STRING) +-- ================================================================= +-- Msg 41317-safe Variante: +-- - wird in DD_ECM_REF erstellt/ausgefuehrt +-- - liest aus DD_ECM (nur READ) +-- - nutzt nur lokale Tabellenvariablen fuer Ergebnisaufbau +-- - kein Zugriff auf memory-optimized MOTB_MON_TREEVIEW_RESULTS +-- ================================================================= +-- Copyright (c) 2026 by Digital Data GmbH + +CREATE OR ALTER PROCEDURE [dbo].[PRMOT_MON_GET_TREEVIEW_RESULTS_SAFE] + @SEARCH_VALUE NVARCHAR(100), + @USR_ID INT +AS +BEGIN + SET NOCOUNT ON; + SET ARITHABORT ON; + + DECLARE @MIN_SEARCH_LEN INT = 5; + DECLARE @BATCH_SIZE INT = 10; + + DECLARE @ID INT = 0; + DECLARE @PID INT = 1; + DECLARE @EMAILMSGID VARCHAR(200); + DECLARE @GLOB_COUNTER INT = 0; + DECLARE @ERG_COUNTER INT = 0; + DECLARE @STRING VARCHAR(50); + DECLARE @ADDED_WHEN DATETIME; + DECLARE @EXPANDED_SWITCH SMALLINT = 1; + + IF LEN(ISNULL(@SEARCH_VALUE, N'')) < @MIN_SEARCH_LEN + BEGIN + SELECT + @USR_ID AS USR_ID, + CAST(1 AS INT) AS GUID, + CAST(0 AS INT) AS PID, + CAST(NULL AS DATETIME) AS ADDED_WHEN, + CAST('Belegnummer zu kurz!' AS VARCHAR(255)) AS TITLE, + CAST(NULL AS VARCHAR(500)) AS DETAILS, + CAST(NULL AS VARCHAR(50)) AS STYLE, + CAST(0 AS SMALLINT) AS EXPANDED, + CAST(NULL AS VARCHAR(200)) AS EMAILMSGID; + RETURN; + END + + DECLARE @SEARCH_VALUE2 VARCHAR(50); + SELECT @SEARCH_VALUE2 = SUBSTRING(Spalte, PATINDEX('%[^0]%', Spalte + ' '), LEN(Spalte)) + FROM (SELECT CONVERT(VARCHAR(50), @SEARCH_VALUE) AS Spalte) AS t; + + DECLARE @tbl TABLE + ( + EMAILMSGID VARCHAR(200) NOT NULL PRIMARY KEY + ); + + INSERT INTO @tbl (EMAILMSGID) + SELECT DISTINCT REFERENCE_GUID + FROM DD_ECM.dbo.TBEDMI_ITEM_VALUE WITH (NOLOCK) + WHERE SPEC_NAME = 'INVOICE_NUMBER' + AND ITEM_VALUE = @SEARCH_VALUE; + + INSERT INTO @tbl (EMAILMSGID) + SELECT DISTINCT h.EMAIL_MSGID + FROM DD_ECM.dbo.TBEMLP_HISTORY AS h WITH (NOLOCK) + WHERE h.EMAIL_SUBJECT LIKE '%' + TRIM(@SEARCH_VALUE2) + '%' + AND DATEDIFF(MONTH, h.EMAIL_DATE, GETDATE()) <= 6 + AND h.EMAIL_FROM <> 'donotreply@wisag.de' + AND NOT EXISTS + ( + SELECT 1 + FROM @tbl AS t + WHERE t.EMAILMSGID = h.EMAIL_MSGID + ); + + DECLARE @results TABLE + ( + USR_ID INT NOT NULL, + GUID INT NOT NULL, + PID INT NOT NULL, + ADDED_WHEN DATETIME NULL, + TITLE VARCHAR(255) NULL, + DETAILS VARCHAR(500) NULL, + STYLE VARCHAR(50) NULL, + EXPANDED SMALLINT NOT NULL, + EMAILMSGID VARCHAR(200) NULL + ); + + SELECT @GLOB_COUNTER = COUNT(*) FROM @tbl; + + IF @GLOB_COUNTER >= 1 + BEGIN + SET @ERG_COUNTER = @GLOB_COUNTER; + + DECLARE main_msgid_cursor CURSOR LOCAL FAST_FORWARD FOR + SELECT TOP (@BATCH_SIZE) EMAILMSGID + FROM @tbl + ORDER BY EMAILMSGID; + + OPEN main_msgid_cursor; + FETCH NEXT FROM main_msgid_cursor INTO @EMAILMSGID; + + WHILE @@FETCH_STATUS = 0 + BEGIN + SET @ID += 1; + + IF @GLOB_COUNTER = 1 + BEGIN + SET @PID = 0; + SET @STRING = 'Ergebnis 1'; + SET @EXPANDED_SWITCH = 1; + END + ELSE + BEGIN + SET @PID = @ID; + SET @STRING = 'Ergebnis ' + CONVERT(VARCHAR(10), @ERG_COUNTER); + + IF @GLOB_COUNTER = @ERG_COUNTER + SET @EXPANDED_SWITCH = 1; + ELSE + SET @EXPANDED_SWITCH = 0; + END + + SELECT @ADDED_WHEN = MIN(CREATEDWHEN) + FROM DD_ECM.dbo.TBEDMI_ITEM_VALUE WITH (NOLOCK) + WHERE REFERENCE_GUID = @EMAILMSGID; + + INSERT INTO @results + ( + USR_ID, + GUID, + PID, + ADDED_WHEN, + TITLE, + DETAILS, + STYLE, + EXPANDED, + EMAILMSGID + ) + VALUES + ( + @USR_ID, + @ID, + @PID, + @ADDED_WHEN, + @STRING, + NULL, + NULL, + @EXPANDED_SWITCH, + @EMAILMSGID + ); + + SET @ERG_COUNTER -= 1; + FETCH NEXT FROM main_msgid_cursor INTO @EMAILMSGID; + END + + CLOSE main_msgid_cursor; + DEALLOCATE main_msgid_cursor; + END + ELSE + BEGIN + DECLARE @E_SUBJ VARCHAR(256); + SET @E_SUBJ = '% ' + @SEARCH_VALUE2 + ' %'; + + SELECT TOP (1) @EMAILMSGID = REFERENCE_STRING + FROM DD_ECM.dbo.TBEMLP_EMAIL_OUT WITH (NOLOCK) + WHERE EMAIL_SUBJ LIKE @E_SUBJ + ORDER BY REFERENCE_STRING; + + IF @EMAILMSGID IS NULL OR LEN(@EMAILMSGID) = 0 + BEGIN + INSERT INTO @results + ( + USR_ID, + GUID, + PID, + ADDED_WHEN, + TITLE, + DETAILS, + STYLE, + EXPANDED, + EMAILMSGID + ) + VALUES + ( + @USR_ID, + 1, + 0, + NULL, + 'Fehlende Belegdaten', + 'Es wurden keine Belegdaten gefunden!', + 'HIGHLIGHT', + 0, + NULL + ); + END + ELSE + BEGIN + SELECT @ADDED_WHEN = MIN(CREATEDWHEN) + FROM DD_ECM.dbo.TBEDMI_ITEM_VALUE WITH (NOLOCK) + WHERE REFERENCE_GUID = @EMAILMSGID; + + INSERT INTO @results + ( + USR_ID, + GUID, + PID, + ADDED_WHEN, + TITLE, + DETAILS, + STYLE, + EXPANDED, + EMAILMSGID + ) + VALUES + ( + @USR_ID, + 1, + 0, + @ADDED_WHEN, + 'Ergebnis 1', + NULL, + NULL, + 1, + @EMAILMSGID + ); + END + END + + SELECT + USR_ID, + GUID, + PID, + ADDED_WHEN, + TITLE, + DETAILS, + STYLE, + EXPANDED, + EMAILMSGID + FROM @results + ORDER BY GUID; +END +GO diff --git a/dev/[DD_ECM_REF]-Database/plan.md b/dev/[DD_ECM_REF]-Database/plan.md new file mode 100644 index 0000000..49f115c --- /dev/null +++ b/dev/[DD_ECM_REF]-Database/plan.md @@ -0,0 +1,39 @@ +## Plan: Neue transaktionssichere Treeview-Prozedur + +Die neue Prozedur wird in DD_ECM_REF erstellt und ausgeführt, liest zuerst aus DD_ECM, verarbeitet die Daten vollständig lokal in temporären/klassischen Tabellen und vermeidet jede Schreiboperation auf memory-optimized Tabellen innerhalb desselben Aufrufs. Dadurch bleibt sie auch bei offener äußerer User-Transaktion lauffähig und umgeht Msg 41317. Die Ausgabe erfolgt als Resultset direkt aus lokaler Arbeitsmenge statt aus MOTB_MON_TREEVIEW_RESULTS. + +**Steps** +1. Phase 1: Ist-Logik in DD_ECM_READ-Teil und REF_WRITE-Teil zerlegen, inklusive aller Stellen mit Cross-DB-Read und MOT-Zugriff. Grundlage sind die Zugriffe in [PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql. +2. Phase 1: Neue Zielprozedur in DD_ECM_REF entwerfen, die Eingaben SEARCH_VALUE und USR_ID beibehält und die Ergebnisstruktur zur bisherigen Ausgabe kompatibel liefert. Diese Prozedur verwendet nur lokale #Temp-Tabellen für den Aufbau der Baumdaten. +3. Phase 2: Cross-DB-Vorstufe implementieren: DD_ECM-Reads ausschließlich in lokale #Temp-Tabellen laden (MessageIDs, AddedWhen und ggf. weitere Felder), bevor irgendeine weitere Verarbeitung stattfindet. Diese Phase ist nur lesend gegenüber DD_ECM. +4. Phase 2: Bestehende Cursor-/Loop-Logik auf lokale #Temp-Tabellen umstellen; Aufrufe von PRMOT_MON_TREEVIEW_ADD_ROW durch direkte Inserts in lokale Ergebnistabelle ersetzen. Abhängigkeit: Schritt 3. +5. Phase 2: Aufruf von PRMOT_MON_GET_TREEVIEW_RESULTS_PER_MESSAGEID entkoppeln. Falls diese Prozedur auf MOT schreibt, wird eine neue lokale Hilfsvariante erstellt, die nur in #Temp-Ergebnistabellen schreibt. Abhängigkeit: Schritt 4. +6. Phase 3: Finale Ausgabe ausschließlich per SELECT aus lokaler Ergebnistabelle zurückgeben, sortiert wie bisher nach GUID. Kein Zugriff auf MOTB_MON_TREEVIEW_RESULTS in der neuen Prozedur. +7. Phase 3: Vorhandene Prozedur unverändert lassen und neue Prozedur mit neuem Namen bereitstellen (zuerst Parallelbetrieb), damit Rückfallpfad vorhanden bleibt. + +**Relevant files** +- [PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql([PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql) — Referenz für bestehende Suchlogik, Cursorfluss und Ausgabeverhalten. +- [PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql([PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql#L48) — aktueller MOT-DELETE-Zugriff, in neuer Prozedur zu vermeiden. +- [PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql([PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql#L70) — DD_ECM-Read INVOICE_NUMBER. +- [PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql([PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql#L74) — DD_ECM-Read HISTORY. +- [PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql([PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql#L125) — DD_ECM-Read CREATEDWHEN. +- [PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql([PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql#L135) — Abhängigkeit zu PER_MESSAGEID. +- [PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql([PRMOT_MON_GET_TREEVIEW_RESULTS]_ok.sql#L173) — bisherige Endausgabe aus MOT-Tabelle. + +**Verification** +1. Technischer Negativtest: Ausführung der neuen Prozedur innerhalb BEGIN TRAN/COMMIT bei offenem Transaktionskontext; erwartetes Ergebnis: kein Msg 41317. +2. Funktionaler Vergleichstest: identische Suchwerte mit alter und neuer Prozedur ausführen, Ergebnisanzahl und Sortierung vergleichen (mindestens 10 reale Belegnummern). +3. Randfalltest: Suche mit zu kurzer Belegnummer, keine Treffer, Treffer > BATCH_SIZE, führende Nullen in SEARCH_VALUE. +4. Parallelitätstest: gleichzeitige Aufrufe mit unterschiedlichen USR_ID; erwartetes Ergebnis: keine gegenseitige Beeinflussung. +5. Performance-Schnelltest: Laufzeitvergleich alt/neu für typische und teure Suchfälle (LIKE mit Wildcards). + +**Decisions** +- Muss auch bei offener äußerer User-Transaktion laufen. +- Darf weiterhin aus DD_ECM lesen. +- Neue Prozedur wird in DD_ECM_REF gespeichert und ausgeführt. +- Zur Behebung von Msg 41317 werden MOT-Schreib-/Lesezugriffe in der neuen Prozedur vollständig vermieden. + +**Further Considerations** +1. Kompatibilitätsentscheidung: Soll die alte MOTB_MON_TREEVIEW_RESULTS als Persistenzziel künftig entfallen, oder braucht ihr zusätzlich eine optionale Nachschreib-Prozedur außerhalb der offenen Transaktion? +2. Abhängigkeitsentscheidung: Falls PER_MESSAGEID zwingend benötigt wird und MOT-Zugriffe enthält, sollte eine zweite, temp-table-basierte Variante mit gleicher Fachlogik erstellt werden. +3. Betriebsentscheidung: Für den Produktivschnitt kann ein Feature-Flag sinnvoll sein, um schrittweise von alt auf neu umzuschalten. \ No newline at end of file diff --git a/current/[DD_SYS]-Database/[PRDD_GET_DATABASE_DEADLOCK]/[PRDD_GET_DATABASE_DEADLOCK].sql b/dev/[DD_SYS]-Database/[PRDD_GET_DATABASE_DEADLOCK]/[PRDD_GET_DATABASE_DEADLOCK].sql similarity index 99% rename from current/[DD_SYS]-Database/[PRDD_GET_DATABASE_DEADLOCK]/[PRDD_GET_DATABASE_DEADLOCK].sql rename to dev/[DD_SYS]-Database/[PRDD_GET_DATABASE_DEADLOCK]/[PRDD_GET_DATABASE_DEADLOCK].sql index f5855f7..5235d2d 100644 --- a/current/[DD_SYS]-Database/[PRDD_GET_DATABASE_DEADLOCK]/[PRDD_GET_DATABASE_DEADLOCK].sql +++ b/dev/[DD_SYS]-Database/[PRDD_GET_DATABASE_DEADLOCK]/[PRDD_GET_DATABASE_DEADLOCK].sql @@ -26,7 +26,7 @@ GO -- 26.03.2025 / MK - First Version CREATE OR ALTER PROCEDURE [dbo].[PRDD_GET_DATABASE_DEADLOCK]( - pKILL_DEADLOCK_SESSIONS BIT = NULL + @pKILL_DEADLOCK_SESSIONS BIT = NULL ) AS BEGIN diff --git a/dev/[VWCUST_WINLINE_EMAIL_OUT_DD_CWLDATEN_DDVP].sql b/dev/[VWCUST_WINLINE_EMAIL_OUT_DD_CWLDATEN_DDVP].sql new file mode 100644 index 0000000..a7901bd --- /dev/null +++ b/dev/[VWCUST_WINLINE_EMAIL_OUT_DD_CWLDATEN_DDVP].sql @@ -0,0 +1,47 @@ +use [DD_ECM] +go + +create view [VWCUST_WINLINE_EMAIL_OUT_DD_CWLDATEN_DDVP] +as +SELECT + --[mesokey] + --,[c000] + --,[c001] + --,[c002] + --,[c003] + --,[c004] + --,[c005] + --,[c006] + --,[c007] + --,[c008] + --,[c009] + 'invoice-flow@digitaldata.works' as 'E-Mail-From' + ,[c010] as 'E-Mail-To' + ,SUBSTRING(convert(VARCHAR(100),[c010]),(charindex('<',convert(VARCHAR(100),[c010]),0)+1),(charindex('>',convert(VARCHAR(100),[c010]),0)-(charindex('<',convert(VARCHAR(100),[c010]),0)+1))) as 'E-Mail-To_clean' + ,RTRIM(LTRIM([c016])) as 'E-Mail-Subject' + ,convert(date,[c012]) as 'E-Mail-Date' + --,[c013] + --,[c014] + --,[c015] + --,[c017] + --,[c018] + --,[c019] + --,[c020] + --,[c021] + --,[c022] + --,[c023] + --,[c024] + --,[c025] + --,[c026] + --,[c027] + --,[c028] + --,[c029] + --,[c030] + --,[c031] + --,[c032] + --,[c033] + --,[mesobin] + --,[mesocomp] + --,[mesoyear] + --,[ts] + FROM [DD_CWLDATEN_DDVP].[dbo].[T190]