From 47206b9bea021e25b8ec279ff2a724f31ca37dff Mon Sep 17 00:00:00 2001 From: Rohit Bhati Date: Fri, 7 Nov 2025 14:51:29 +0530 Subject: [PATCH] Add support of DEPENDS/NO DEPENDS ON EXTENSION for MATERIALIZED VIEW. #6390 --- .../images/materialized_view_definition.png | Bin 61313 -> 70170 bytes docs/en_US/materialized_view_dialog.rst | 3 + .../databases/schemas/views/__init__.py | 15 + .../schemas/views/static/js/mview.js | 11 + .../schemas/views/static/js/mview.ui.js | 18 +- .../mviews/pg/13_plus/sql/create.sql | 57 +++ .../mviews/pg/13_plus/sql/properties.sql | 118 ++++++ .../mviews/pg/13_plus/sql/update.sql | 221 ++++++++++++ .../mviews/pg/15_plus/sql/create.sql | 57 +++ .../mviews/pg/15_plus/sql/properties.sql | 118 ++++++ .../mviews/pg/15_plus/sql/update.sql | 15 + .../mviews/ppas/13_plus/sql/create.sql | 57 +++ .../mviews/ppas/13_plus/sql/properties.sql | 118 ++++++ .../mviews/ppas/13_plus/sql/update.sql | 221 ++++++++++++ .../mviews/ppas/15_plus/sql/create.sql | 57 +++ .../mviews/ppas/15_plus/sql/properties.sql | 118 ++++++ .../mviews/ppas/15_plus/sql/update.sql | 14 + .../tests/pg/12_plus/create_mview_with_am.sql | 15 + .../views/tests/pg/12_plus/test_mview.json | 3 +- .../pg/13_plus/alter_mview_no_depends.msql | 2 + .../pg/13_plus/alter_mview_no_depends.sql | 18 + .../pg/13_plus/create_mview_no_depends.msql | 17 + .../pg/13_plus/create_mview_no_depends.sql | 21 ++ .../views/tests/pg/13_plus/test_mview.json | 341 ++++++++++++++++++ .../views/tests/pg/15_plus/test_mview.json | 63 +++- .../views/tests/pg/16_plus/test_mview.json | 63 +++- .../ppas/12_plus/create_mview_with_am.sql | 15 + .../views/tests/ppas/12_plus/test_mview.json | 3 +- .../ppas/13_plus/alter_mview_no_depends.msql | 2 + .../ppas/13_plus/alter_mview_no_depends.sql | 18 + .../ppas/13_plus/create_mview_no_depends.msql | 17 + .../ppas/13_plus/create_mview_no_depends.sql | 21 ++ .../views/tests/ppas/13_plus/test_mview.json | 340 +++++++++++++++++ .../views/tests/ppas/15_plus/test_mview.json | 63 +++- .../views/tests/ppas/16_plus/test_mview.json | 63 +++- .../schemas/views/tests/view_test_data.json | 6 +- .../schema_ui_files/mview.ui.spec.js | 7 + 37 files changed, 2307 insertions(+), 9 deletions(-) create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/13_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/13_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/13_plus/sql/update.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/13_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/13_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/13_plus/sql/update.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/create.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/properties.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/create_mview_with_am.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/alter_mview_no_depends.msql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/alter_mview_no_depends.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/create_mview_no_depends.msql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/create_mview_no_depends.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/test_mview.json create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/create_mview_with_am.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/alter_mview_no_depends.msql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/alter_mview_no_depends.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/create_mview_no_depends.msql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/create_mview_no_depends.sql create mode 100644 web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/test_mview.json diff --git a/docs/en_US/images/materialized_view_definition.png b/docs/en_US/images/materialized_view_definition.png index ec6999f797f61d836b191c4f5628eaedf3757ed0..0341f2361745970b8beb154d430e63e955924629 100644 GIT binary patch literal 70170 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 VOj`|${s!`q5|1%YXZv z^PKa%@ArPYSFSsoWRg3{WHK|q*`RkSvbb2Uu@DdtaOLHs)DRGme!>$11{%Bs)j*jG z0RgMjTvGC#yrd-MJ9`^bb4wEh1i7Htc=QkIb1#34w(L=5()m%-UC_%he2>A`MnK)8 zWTL{vR|xbTI~Z8S2ty?zDA_Ft^vPB;W(j=r5)GB;;JGpW`<@P;f&vJ335waW>v3uQ z%skY6Zf-~PF2!k7?+!`q({`ZLUIiBdNvEYGMJ}!w|Abhol81WRsj-Q@1)Ynd{8xX`YF&NIO8b~nG#qa4fXh+ZxYAJ$9w@riT z8*x7uy<)^)yNgZ%4*!Zy;qU&+5&N8=Mv8lFN6KMJa`X+6d8x$?K;&En+0swrSuJLwB$rTFjzgw{{@e{WU-i$E~RF~cT#D07CMcDb|a3K`)r>P2;NZHASq{H<9L%)NGxNjwBv#h z4e&7}#83iJgAs{yzT@Pa=~j@HAWCPTSRx9Eq0XW|^T}RC;YWSlAz+KCi^|twWs3(y zQsY3-_a-<&43Wh5^XD?2UXaLi&?aC(+v!ip5)ir9DEX1}Q5b$Ht|2wxFQdf& z`gmg3fY^$%;&txE z_SP*qBYH@0EZFG%&ZGBJanUbNz zLEk_qfdP~d`OLkBpP6VI%pvxQp$K0&=%@?h3zHpgWs0UEM8aLkJwGGEFk>~VLQFiP zLOWA;EvJ*mU&LRP_G1)kkn~RmdAVdcSvl4m^c)vst~tL0=`b3zXuine{`h{?ehMPS zpVL1rrPJ1#x)r+7x~;os6j11l=<+7M;v{kydwQihxr+Ae!O_;uc##}Ak`>AlJTW5 z?*lJSthR)(_+d_1L1B?Vfppjp&JYZ=b(Tj#F7s5|V~ydVHFBZ&q~vo3CJ| z$fY>kd}!iiV%6e>#gzHtm@@b;dHLWQv>*|K; zpJu5^uy>@>bz{#a_47R5HA}jEkk#llkj<%9+^HI=U{jt^`{*4i(O2^F?c*>6dSWR#nS6GM-fdj^%nIMjV76r zTeeI$jo-q^vIXoM>PF1d&xd=)>6f-6hG}#@E{HAE)(zL$9I_lVILA7>9QI#&UKSrD zAFS|e3Z9T(3NE_j@Q*m?9?$My|L&iYKllKByJ@+ZvI<#fj2AcY1$uD0UCvmGM_9m9MSV6j%VarA=8q-*xg7F4=SMq1`CpCWaP1JW@6{dR|R2hV> z1h!>AaXrN$D2csmpZ>02_bhp^%rqQD5WNh;5}O*;AN?bWFm@frOLV?b-yPJE1>WOR z_l=v*n@}oBKk_QpP5A=z-H9;+Vnbp-wgTM~;1I7RSksN4&Rzbx@&u1ynIM@4Ae|(w zK&_J zrNO~v?90THiU2i^D zyz!MklFyZAk6MbZr^Cwy<;CRUU~BqdbtF%HpYkX)GN&?^ouHq{o`iCpkYJLS`4@G* z{j8H`ZK`h?->3G0Hj2$jugPdHkYCQ7AA3MM=68&;^y}!wYu_U5mkSu;Gu`!CAa4xT!m0+Oh^sqNk$yVk?*Jf)uATvs~yKK#%lZ6!MY zX%jOW6BFw`*S7@PU|2{W@JgDEsVQ`*p4@KHsnGG$ajkQ;7S=9O(|$MKX0=@ReLGEKg6Sx$fXrEmF;{e4@F^y8iMAx4HN70+|5u% zSU2uFNzY$$Mhe+AjCF-j%hkDQ)B5dOgHkVHdzB~MEpY95GCMx|3;l!!OYGNPUuZ^P=@p(t=awLiODQdAg9san!}H zuD-w75A;(=&q$jd?AHdpHL^4|eo1>3-8bIV&Oy1ozz@GU3AwpWWbRGZ4|`maj>8}> zpcTQ_g0~lvJprec>)}Zh;htaIzdeyXfNgg`W`o z`BP$0+81aLB8(6-7G-V&{3jnSV#Fs`5Y$l~pQ~Ois&Au+v2rQZNte7tP@%T2dOa@V zUPbrw1gWB>WznSN_(Qsgx#niDN!uu`@NC_?JjVJxz+-dMlYo!>NA#1?Q-eV)bPo2_ z^hvn>8fT&@Z>p?}zy!}@AfO@=A|S(ai1050;%fxdzw!tO3W%it$*Up0`F9&61cU%{ z1eAZb(S|?&d?MfpPW|sEa?}q5boehqc=F3Y`nxsK&kW@MaXe-Fh?&9LY=EBWpV{gXJDIg%g&cVgb#l;G5 z!Ri3EcKi%twRWKSS0{h>BW2=XWN&WkXl`Ro`KRB{Uu>Klg{i6k4D_GRzuwaXWd7fg ztR4P6E%*f4|J1N^vT?BgUu2HvrvE==e`@|k_Sd}rH5~9yXM*p{K_-@(Qs!3hrG~$n z2k@A65S# z{WA$cH4_ILOQ%1J_|e+jQG^S~{(lw!Zz`?-lEEkV_TNPREdAdUn*S%oKTH2Ng{r+d zd?7ync{LHve~<9bvVXS+vj5rqe=x(pIPI@eIID?Z0onh%%04guNF-w^G1i{xFhKl;|8is zV%0vtZ^TH;v5Suqg5e;l#*bLjoS94y{%2UZbj4+CqKt!Jsv8OO+F0co^+`}>6L#+J z4+h$0WldPI%rP<^{u35Sadq{r>;1RUJ3QmZXPy^ad;EL;6S|&Gy~c@~VC9S4Ee#FX zk9+=(5i$k+E^UHy61Ua!GxycJO&Sc%O&2_sWqE=YOd7GQ#gmmy7dd4TTsZ{a><=TE zb9@~oK7zG^Vnw6R`p;u?t19=;uwx75wY6;o_2mKvZE15V&+jd*FRR~abBTJi3f|1; z<-_PVcByj?NAo^CH45q!u{Typsi~eV=0=&PJm3H3Q0MsIk!MvLq}R^{Gm+OeL(1P8 zj8~MGuZ)R}op-766Ql}CVq0o*j@mXcxm_Cm*6ukI3slR~Vw;?R0kau$ZU{)&56t_s zx1a$t9hf_Nh9+`Ddv%jj0x;S`TaqwqUvkzW$ZUu~)CRx%=; zFWl95LWRAS!>MN6_)`&bgI@&{v`DIIbjzAjd{VwK7s%(mHAqdh)wBO?_Hk#QS6Bed zeAL7f3asYL994<7+q7>|vKv7wRvfMDK68+*T53%xAlLnI8#OaF`4GslbK4)VKR_a> zz{_aBz_sU2tXj~wmwAr`o{2@Z@E=Y~vm(~EpP8&N7OeuK4n*KSo0DADS9Es&8dmR% zp~)j{+pfNUVdIAEy|L@?4>GjIw}U%0W*VKqK`vlv#eN_8k}isz z;ujNtdkQVRISH_EOh0yM13(M8Ix)@0L~h`>c%`LV^%je;jvouQX|kvB)*|ol#M{Ba zeiHf|li|VF(gJ4=Xq4$fFg53k%UhR`b%7v=$iTPH#gigcNY=!hy|gziSI~A&=3=Yg zUbB&<@zEvvlj)O(u6jL=#k)*eETi_u)J3;p z+SJ~Jc}rm@D{5fcru8sb9pvPX+sdIDTY>Ak8O{bz478c^Az ze>X*W+^`JL9Qd&rXPFW+#Pq)$rHH=OWz#Xabf~oN+~YPSHuIEH(0?|?K*6GFAJXq33s4gMMG!pXpAfCA;!VT^F#kt?@NSi#Bc}K> z+lkYKO7m)@rp8$(m4|K%`0nY#*@-E2@b$Y$}b@;9~gu%oO~ z=BgA=UJG`ndbxRQZ0u!?Vek6?m53CchhEBWm-x4|IDHZV;7XLR1kZ1 zz#|nL8(nFW+Xeht%bSrH)vAr}o#MH#(DXK_8h2rmYw&k>VfoG}sC2j}ORVXLNy;L{ z{}AOsc|pnJp5U9rz;u_$z!yd33J0Y4n(~MTQxLg`u2)lmQEX4=q?Lv->xlw19Q60{ zRq)cRZd9EI@vNc3{E>N$gTBO#PAMFBv5Q8KIEcosQ#&h|VNMod*%B}bd^oFDiD%7G z4lbi#P!bMSvBV+>?m-wSveM!)p_@SdArM}$a7^s>I|`O8Asm)HqgQ~&kIFH!#+(NYGE>K6eZA2wy{AVxBO^-uWu+KA_en|Bbjl^4xUQH zl)tCx{lwnKI=$Yn14QW_BjEU##6*e^>8F_8xPOeU;5eNm?AeP=c+&|WHg+Jm#jJ^ z#*-l=+?(ZI55+^NLK?T1hZcT;Rn`o$7dZ=Sw|XO1j>+;a!emt1&*_yS+>To`T(9<7 zOSS6>fz|zIDe9if5U~Av5W{}(TSen&W!}jAbWd%O>s4eDAgE$1dlag;5UZp*?{kzh z+;+Egyeay06MoQocLc`U$&wB}cG?a`Wfu6mRuBfMpCy*>zAYK zHhScr9v@gmwHPqNH0JA!AM|^+l;6Am=j?>OK%^LCP)?$)U$hTC&D=?I8wp$zgqB3_ zaQ;ply+&tP9qm;ND-%uCPi+OCzwE2px|L*^BNj3Zl6LY3di5-h=BnSNRq2mf+h7w;})Q4RhwnmoBxG-qZKQ}q@VOK^Cd1-prEBYv3x9n8YGo$ZTYFXL+ z(!Q76B>^Y&T;?XShcM7BDH<(Izvn!TP4AnzdcI05_XxkFOcw3mi}R9rb!yYl%gaV$yR%Js`w4l5{wZ^Hf@&D9K3)}|V8EUdzwUpYHmxX%#x{w=LCDyhe^z}Pn@zwow7sz;(I9!~7J)$?iYJHYKes(Zg>?kt8)A|pyh3B`KiuHi{PD9 znN@_H?PQy{WA`1Qv%UQEBoYJnQ-AO#zvs!QWNkFok^tATSf8y^_7IJ_F8 zva!sUs){XvAUBdRH_5$8BfY%^2VtSI1+N4gl7>(g?J65murGE50a{!YKr5J~K9uh#-} zmT#fuHeD#k(=_2g>R$nP@rQK_Dq({AZ)iehPc9d17Gh2#s3a}tpI7a4^@_`mu&rXH zNvny7sbP3Mo~Lg`zfa$sr1Aj`VBo);uLF&LX*@U^%yGLqs#^O&s*taeTB2;!6GCvX z1ZSeHpUhjMsFurlMaopsn|@UmJbSl; z%HAZ_zWdvmHr`G&UVL}Kl?-uTL9zr>pr(xjnd!WJ?k?bCGzjj8y`Vk3C zE9OY^U!h2V=+a|I8pfSMM{M9;c}mi=Jda{ZLV|~RQix9BJ{Fgv2i}Supkk|cblIGm zlE)Bzm-W>IdjI~@yhI#}4okMEm+aH>htc%_u5Sm$Ty_JmbOJPWb8={V<5It~s{6pg z2zg#l6n%8I+O+q$bE&sp^7Ho0Pj!jv4kk`k#*d5FcbDf~a#U}GPirf_?LIdWsc%-9 zZ;93mzEny_S8Y!%;QbTJ$g7p7M-A(?2WOg~@36B$_Ju{!uIKicRKj-$)uHb94`pqG znE`-rTkp1=lh%K`C(Nh_n@7|=TrP}GZ#C{_hl_kO#y)-n;0T;^7!@_6{po}bI!M40 z-HK5U;b?`Q)Vfc2Zj_!J9(fyybv?;Hny;f2*$6Hs2q+^hUxVT7rW_ER8ON%lz0eNp zA+>pXyam6UREx277m@c>*{jV)dBF_n+Lmn+>s@eZ@=Gr;Iclah0Cm0`H_agh8&?gFmrb zp+!3%&d=3Sr;3qu1`^O5^l^P(yEQ~eq~(8KEBB9!4F$1B`0AkY6NRV!nm_St4Z~7u z#R1@T!{O;Br_hM0Wr&%($kY8fYch#Yik#Q&WID?;0)OZfeLI21tx4Sc3ui5~b^lD?Re6RNG!e8l^4YIc_E*61^sea(&LgY(ax&|=_K9kdat{&!%X47lJApMF#YFXi} z{Mq?vVs0Iu%O^Uxm%?iiXa%a9W$C=g+p+V5R0tqTTyIc3&8|nhV|%tN21&!09$0ho z#gB`Pox1=*r%Q*Qt%HOrN$?EYJRgkLbAq<@{NAk9I+8$QKyT!;B`de_@aS$(`gqb5 zAh```b3mWL#P$okY%oV5c=}QjNyu^65F~ux_p9nxm=MM$@%>4| zx}EU=3Hw{T7obYIK$N2fgELI8+pahYQt_^`mqr+oJG zvdigH;h$yHy+3MGxAwIx7pi<~*uF6nv2OR52<&rxlu7X5thXN2Z=Kq1V${k(s~dN+ z6me2~{bN#&!NuG#PdVLGJ!z|DSo#k zp!|-H4NO$Bk+6-o57&qyWRbo;*4{`R&RX(b0h`1da zZMEpCE%!H2n3qQj$T4*YyW?-2j|h!UQ1;?mkNU0>P{KWWVStK$EB}!7Qsd_lZXq2( z-#ub{-+n=F2zxD{@B^3B^v2y>b4Tuu^1j5zWS@+5_j$xuV2NSRTj377%72^_+@SAj z7(H$j=bZkPMCf>FqGY-#6w%Qe`6eIE*IWf|8-OPJFPOKg>wgz$(vgzJyeW&)5B59w zfu`SEWjIcjDBx1WVqVDsRi1KT&T5iEcUDR8+2#TI+0#9bD2D3+y@B|+K1v+JSS0JQ z+@v;;%Klr~yUW8Zt<)o9kHti@G;=Y@HHzzOsyPK z!nP%Y*?>UWraqSpMwiV<*?Ec`07Rr+5}?-GB$D?*OB54Rnq7TciF4yrGLF$+j@rCr z%}C)IF5Y+v_Zm)U#lF8F@I3LQc=fU-z;zK>4tT@NXU$FS&Ep#(<*avH@#`6v>%~`{ zs~vsK3yC_6qj4v9TUE&rDyXBbj|=bO8eEo!uMIb00=-JgY56;HpIHvNk~^?{iSBcD zKQrgvOqOV#wKZ>KKF+EN`1{oqd1@!n7VLj)Rvxd!xc!PRtl~O~`Dc0&kcVVZd z@~q2>#}-`oueOUleF@%q_7O4bi_-!OB2ieU{Zwzhq@rE>l|kJ!B+{-)#_o2ga-!}d zy7~KQiCY+eI@ct3qIr;hqSZ-*d7x|u84uV#;&pm%@G6nyeD0NwuM9O5eF=FR*BdB~ zl`wDILYBtAY}6+x5~$LBk2Tp_!$7+S*Kf0xb)qmRQKrY&yuWD2wL?EsQcUJ6*9*9> z=pCGqMSFdEbK24U!_eN2QpB>v(5OGn?a17G3e_%)bs3OXtR)%57xFzUYn{3|K`DD8 zsLA>8oBBZw@t1!89i(b?GF4i@FOyhii1U>AY9M;FSo19B{g@=478%m^p}o$@zIgj? z3PhcN3sk6*?8};_6)1#~>cXz?^#B9wXexGSO9O*hQcS9G)TcmZl_Xpmi4}Or_kvug zs_n%Xr^eqB5q`|_TbN$@uPPODZz=0k2ACj%a67PV=so<}*{oYJ06T?4ZLjq6F?(eH zwv5LRFs^46f3uhyX%QzIQU$S`3tlZc%p}lqEpvXVic6n4B+w)bP#-X(*BaP|1otHavJVF8HO1WtnP&BFtOULg@NPryECD=62*)~cx6TkafVKhF_0H1wY z$bS5EyE1rA*htA`5{>uAs1F-nmALH5Ix<}7jk zV(W+|O;>OYEZXzob}o;2a|tja40>(VF5=TXC%}+yG31NB_8s|I#Yih$L7lJNHV+g` zdErZgSc0i*}HEx^G4US83fKGRY8{z6vtHZn9fM2i=#%sZ4{EkT-gwbb}i z7$+$Meu_^!GYn(Ighj0zox5jP(8Z&hBKH?{C5;U8vV9ePZ|nK^+kR4Pw`nKLM0*1^fFe>Tua`4QRyz zu__=pQnC0TOpW)(oW(5Nu_Sq#-iHM1sr?B(w$${n za+Q%u3wxz~r8KuW3G*A^D>v&M^^fNMf@<0}R3tN6Ge%UYQ;KgKABu_?td94Mv400y zX1Y!aPM-e$O|bX3_18WVgrK;3ov1UtejfJ%;wi%YX~p@Pe_wXSV3LzCi{C7*bzN0f zpIv9eDEyh^X3OcJ@rUlO3mqx6*bb(u@jv|?avknECUQetHJgUf_Q{H3wy^Ky7hcZI zj8T?9m4162finkLq)$xI=z}?wsE8B>JG^qLB0KsdMb)@6)?T)wTpAz=W1g3IZ8Eu4FuE0OLXJFe4W8f~>1WQFgb^|AfX(%~`hUe* zK>;9>s7qu#`GumQ=iu@gs6wxv85#256YTLpDDT)fF2)jh{m@3uoq3`v=40Z$bC`fz)t+z7ea~uRU2cKUlASR z70P31oodi9Je3K?u663C3Ds*EtvK}=*JM|lCHimg%E;b5N?6!bIF%-B4JsYmO|?1d zqM}(WV10(I_iz5bRR3z9(LwNrX%o%Lwz%{Ae+T?ig(i&<)B6c|cF%Z4QR!M!^74E*-6X<0Z*a%Fe+a`0H zwN~}fhTr$B65`_iqa`JNA62`^iv}vP_i(o=;M06?d9)P4Ojd97PFQv`AoBEnb9{^c zWz?xVyX2yiE1*|`mv)dcI?V00Z27_{_ExD1z24RSzFlJuTwzLij#V4($euoRyt8LS zCER~j#;!$tv&U}_0FJ^Uj$pR}y%MfbCebDl3?NV5I(r@Y;v$vu(eN@Fy|9Lv=s4wl z)j+^yyfbq(4tU2K|IU(`vIn_mP2Z$!3m9Cnw z=GI_M?r{GcU3f%EuM@bbw?*mftN(Kf{Qw3qq{yfV5T5TuyTKM+6I$aaoVE?uI64NS zw_njZfn3$tw3g3>S@otTqnm_>!^6zDj&}B3_3&=?nsmblL0aJqgAJad^iFhJ!YkqO z0uxbAdFK!%H3O<-T{aI#j~s?Uy3t9nJh}ezR=b?-RmFJ6}IDF9&-73tJ?(~gfuM)vY!vzyx|x>_$SY`24R%cBudlV zPp-J?BX%nUztW)X)%sh__!rwgmo+2;6p(S=1&=F3*2W?Kq(}0er>U55dtqS!RQMm` zW4x6{Iq+XluKc{5C-YFuUHA5b*^>iQa%r1?n#{YsY+KXc`0ruf5u+$rax1bb-XaW# z>oAO36mByUKNWepFD#^3idpSv0nZ-Y=IYYrM86gN8gzR=-LQ00J&JKzLjww0*DT!W zDKF^u9q=&f$QdY4Kyc0HepJv|NjjZ6iWaIo77w|Qb+CdTKTd1OxilR)Lf$2oQ?qK> zoGn7n-iABW+{vyBg$>P*;YC{op2Mg1brGYaDlwOSJI_YO(?}tIMrvlBX~Rlo{+RDf z0xT~uqG!4{ksJ3>TRW*`&!U8$-xVAWYhYB|y>eHz=`)&t$JBGBck!z!q_w?K5 zISwi(K)&`tI0so)r9e+z?;F03Q{U`}J~19H)W^g96I+KTg5TU6Tc(7a_CF*7!Bs;k z0_tAlreQVTeh9^ ztVtM`6mwaF{|Y#hI(>YjAID`u2mv^b5sTa%a6_?KwQDLwl85p`?+F&!f_DRU8X-IR zThVsL4>sT}dqyUdeI;7e2O{1j(9>heWBf_QBvn=Tu1#<5Ub5@d4OPHhKJ3OF zKB%VQu);2${L#~;G+wKulcnv^L5H^Fx8_kx!TV6{Qu*dAOE{00JYWnZYfzmtzmz*= zm8TzVdj1i zD%=O>0zT~~HtCC?n#hz4aMy{d1CuWCT3_newA3y-PAXS*ztl-6{bR>jHg3g%C)N&O z&Y9sgaA)6OxhITy4zv*(O8dv}ukU$dvbWOKw$?-G@Bo_`{Emp6qZrR7qaWi|;#UYo zLMso*p4qZ0MOG?)VW&rS+yrH7Jn6&^#RooKZ=7vLt7<1x_2CSmv|W-38gpgJ zE}G}39^ArN^7n0MeaAwiWj;~ShHNXY;AhWy^Zfo)mu2(K?cW*(v2FKT?41a$<1(Zq zc2^b$hwb$Bz79_gq^UK(r2r&&@;49Lx;`>qNNX|OJJa7uB5NVP*n$Uv@Y&xT){_EU7VQF*61lo9 z*8!5CtyqmsxPf2i*?aYX=XLFiL&`e@c-x~{r(c4`#uO#c4>st z;D=H?uIKbBzwZoxi`#so&)};bg1hzO6NTOCx?>|uVnR&VS}rC&zMzzBMR$BNUioHc zKXhMG{PI`+HP$og$wq3u zaCdML_;xS9ls}=6n8BeP5#2ZjSe8Qw*<0xs^U8R_@4K>)OLHcDUcIOG-|tazq>e9{fff&rFL0f0L^8ur=L@C!kC^3~ z`SaO96j>@Z46?A@az_fWw8xYfbffZk8gNYRupiiAXUk6Za@Ht(c+nMF8i$Vd_)vlJ zAl6f!ng4rh_b}t2?djoo=)Ej?Y+KreFWiVUfrA~QiQiycuk}ZP=ONvU#mg5%a04@W zJP}usl;_(A(-zqD;8kOe=kvhuzc&6`5W*sUSV6K@5njA^4qhjZ6sS0ep7$BCDnhhnC-*s^YkZ6Cm+nTC35H4j{QF#iCo1U zwzHYG$B)lMt_{z*zQ98^fc&7Sb~Lx~AS+OB0ebl?TpXDIMxs>(wX|#C*g;rUHXCBf zB65Lm8t|kYISbiP{}>LPTGrX8Rs>t%@ha^=5m*%ljNzxRzE$=CbYcxTm4V`|KF%eK zo`FGs@S>+cLMmu9eCCO@+`_eb@y-RRj0P;=!_&*v(jG0WGqFz~q%VKkgQAzicEeOA5|>fo2`gh%2R&n@#)XY^cB$sC3_r=1;{_qfY>Zfx2f z>O5p)rRE-_DXh0(eERiU+zOXgg;)veO9${+0`S4fNV>=6oO9~Q4) zXqUN_F4u24Xu>yR95o6THdSBm+EZMl3BaRJnc`SYI`>%D2f@A2b1)4;iLm`b@Fg8v# zn;cK{z5;A~@gwbhmRTA$gUT`|WePbRANsqJGB> zOz~;qT)`7F$BaG*+`AnYP8{!EK?S*5b|cY4PkjF+3LZTH2c${JuUYVP-V|?AX6Lk5 zWR*nW530JFvSh|l#12+1e*x0MV>cX@=`Va3ymTFq>b_H0&G2L-&KP(t&3iwf=nb0M z(fMvmzpt{i^AM}NCrsw+Af24OaSgD;)6Pq&IQN}6eoGmw}v7|&IWef zL~)mJNXs}(^brJIs7Y@9gXm}iRuE65gdXaObh)aW^b%FvsR{#~^o z2zscqA+tUshq_wgIJ&@O?jVX1pPe4lXLF0&wH2x|ff?81maDpB0xLx{NZ{>Q^~9BI zklJ#z?6Qs5oz6M$zP3TNdQk3`Z}=67Bf!3oDp8igV`@tDtS_4$n;yi2Iiv4lwap-U z6O;<|{kde&;IdY_)m#U^XA*kx5L+EQ?ka?v@*AwLw-nZ{qwr9V#6n8?4r7vfF+R-RnZ9KUm+!)oTBQbjjf{u-dC4WovZunS-81yJpPx ztSX1o>6p)z!x;ZUOb`YZ5q!`UmaQtWPb|1n5Og`R^u>U=8E%BQ*0NxE;;>o1Hr(Oe zoH$|EvJ-BPskz1I_nfTNaV{clsmU$SdcSP#%vSB|zMChBOLNfm48tc{I52M`_?e~O zSMW+E`ve}|cpdY%Zhm>ZkjW+GG<>}H_;+q=k0V-CSw>m-lpv*^ zQZ61BZu`N1JR>VW6x-+%mE>Y|kVl-mo&(YV_*5pLRR@ z8nrVrvqo2)Rav$!uSWBorA+ppy)r(PdW467jjo81U}%O{B?sTh#WIUb-KG&-ql#CAdF(yv^}c@86D@X zgiribKN7S?HiqZL0}tTHoKf>j;D^=s=iea) ziX)Al%ckooZXz?p;jf{DRNoE7lCG+aMb}b9>fv#4v&d!9161^t{n;ikAnQM1^<9z5o-_Ar zI0E~Z&fsKz*W^fX_L*P4Dm)9qs`;SO@bxX)+2V+w)tZf#R$=b!i-02|P`k&>6+Aq` z43D&=F}M8m5)B~YXfFNO+#%_$Qn(;!wx6qqukdsPy8C9N-uG7+XayG1Vtp)ANmQ$X z#8H1d;to8FC>kDYXW)pNvXnyUqxx{n*eox}e?rDtn+H8V$m{-ou_}o-KTOtwv%VN2 zyo!6ykBp{z#L{P0ggSS3)W&{H&=DO6DU<}r|3V7`QM$jA67{9yySRM@BF`I5uyz)Y zNDP~IpWWsH?u33$ir>@GHxd`3hd6ai{(RiWtET9^$DZn z&k2S-8ogVzZ&(#MiBc2tI*0T+}}5ZrzhWo`>eyinzRK5k&(#VVw%lKg2uTi={KyubDP z4k;ehAZ~j^>u?O82T|59$v66c0%a#FkR5mzzY}qztxBY{yLbn1^$FxeSd11MV}KMA zQ%^)B^yVz;*VE9CZtD=EcaX^+$FR|Ku>+IJxQXPlMH{9z>k>7zS5bf%?p~GNGoVvL zsRj7omEl233tY&?AlxZ*3Qt2t^6OUnmf6iN4>TY7_Gx(d>KtrKsJ(U@PeNYI=3f^5 zw{S7;!c*1jo6u15I;B(2k6jm}$V6#Cy^QoLsY>i5(dD~t<)mbx&8T+4j7@bBeTnp> z4f0bW;o_dEzLho4M7A&GC2F1S#EIlL5mo==n&H| zWFZ|Y`G;Frb!}STTDScu5&+Zkb19J^Rhfo?6Wl_Q#wI3_VGH)W8nV@=@aFZ#^!SdL z;v)8iri-Ym-I3H=q$9%<_FH4HdQ`*$4+m(u>P=gbol4$xaOro=Wq7V4$sit~fPp&W zO`ekjHGRh1yiLIzi0UzLde#x&l)_Tw93>*|wb_hB;B1e+xB9uSoZMMFjjCOj0RwR> zb(5yoRnLY-7O1_f`eqd7a?JZcaeRx}q)({IwSu}*8p1N!RN}Jf5x0u+-Y>>>q(;Oe zIQ1OmHpPpbH4`9GLO!7J19}zfhM_OGzk1gpC|oA&eTNBUNYrY8EA1io-=AM+BC{WC z#T!^3uWcq7xE zwxthAniAw9?MaWnA_J%n_;(f^a=h9eFIQbosL*u`WO-;G6Z6vvmb#3uWCQ6eI<>A2 z6hBnN-*x83>wjCJyT!j!1$?Pof)@D}zNdv>8m%1|t8dIN_mgS3THG9C^@W?Kv9KVx zz)Cnil0y%c{DQwuk8?vA(W@@ZCrfb<7;VjG0dR%UkAx<4AggWU5RzDX#%$0Z!W!V$ zk#!shhhGhy??XHv^8OyOP(|{0R(U*pn5&rSc06~kQ}Q&poDj@htF^Jr%aP$8_vTIT zXeqhUVE#gPt>J!zII+&e%@n42`(!(1N*6n8a;Xq>FGJS@{bG`RmrvKg$3U?hn-Fu) z)Rik$m9!$U&IcPrhi-MYhYTv6Fk$_SD>?z9`wbR4`Lbb`x5AA(06P_txO)(6h8T4s zqk;P-1129jH~K~N`T%7-c(#uNg*l-hfy(|$I`&W!bAykfC%o$DD|)v`hjwa7Lp!%o zqYrd@v0F)ZS82{-2$=dW**jHlsNP=%v`bRR7Vf;Pm!1(^KHGw zu;y;McN-EOJucjQe&5>Z5&1Z>%@&y1de|PwdinpT`s%Q#y0vdXBt*KTOQb5?vy z&QV|p=@>diq`Rb%?(SB)Wyk?3VW=U8lK!^mc|7O+u5139J#6;OUTf`p{pyC2rW8Hd zI%U3N_zySn#t`kfTH14>=jtPbeI`o8-g6&Wo;%o^IPq|Lny{=)J*J)lhY{V#rE&n2 z)TVFdR6RhB-R!?S*d7~Mb0G>N-k2M~u-w=W@tq+~-B0tzL$NsLP>5bU&o>l*4y+NI@ zbM>LDD^_%$KEFzahjYmSsW+`Es2ePK$(%FY+X20L4yEd&J*9Cjrc zv)YF)J(1|!)|X@K>{JfIkIm2CeHvjJiC0rt;lLhx4vyc_$2mLMX>1W_>RG4aR9%E4 z7NI=Wi}A-BEeMrDrin@A42g?!rjsR7XgB#~KBu*Qg3EOW(o49tqLRxR!vJs8 z)O)7coWI&X7N{x9T6K!vS%pJ)2>wH9F!*e-ZuJ{k6j)HHatPu#;?n59KK8+kMN-jr93p4jp+F) zxoRWXo#N_)qb*DFAFi5@0xg5G-|bb$Gmpn?5MyXY%gIdHcGoI_-z=MV+4qO`)C*1e zU@`3^I0G-fUIf0Ctx0bKX6p-n;40HFQRRrE2zM~J`W+04%Z)0lVpwK%KWPnW`+Moh zsi(0nEjGo=UJ;rsJw8$m%9GolnG+xW1x|u?YP+-`Z}JLcPmomKDm9MrAODYZlZ$+C zGeG`z->b36g8HT_td~V%seHKxV}+KR@m|2hyh`n=j_V3R`63sSol$avRl~>vQPuRs zicuGF@J3qW9r#u6|MW$~_yLr)4tbx5+$OZOIO=5=SNNDIG{@lJf~)vVCg*RR=|g+e z0CPJwVxH(Lm4Mz^bpC@qg&nY0XAtmU;+4D(t`O{YamJYqaOc@phKq+zV4partf>zvM9(0oT}mXiU74nBF<_HvwJh%@hnXc!AySkaUMWCEC8#X z$zYZ_HP`=)6?FJ|Z3GI=siGRA3DFI0b~d(Rnm=gvY-Ok8iC~_{FJwd6=KRk_ypw4= zaHF#}X~mXeE>CY11(-?35TJsL=j9CP3JMtp8Zp^}ba5^1=o2Yk7* zFwQd7BD=}>|DT%ml9miJ{Y{9#8hP{2g!%WkA(EzJl$9b%|8W*s`1eGA&i6(gvzuU@ zf9MR&q8RJ{9LQm%@6P(9mp7kSX;shkzkiMz==GYe3(-OY`CKZQqe$0X7N1;qrhM<% zbpn0n);BOgA`mu08TIeQ7Nej_5!*a?8|qVs@93=e)`$ZRaMz<`RxE}aTU;r->ZH;P zo*KUYR8zp^5UdK8DJN2ql93Jl^uz`)q}1)ZcOSEnT6=}K+2tz_ zG`=l=<}?Ha7fM_nj2Y-Y{huFBE>bd&KHS4_sDxi_rzh`yMnqMzY?$|$!H zPNef>EtD`-+@-Sp^jyIc9^`~P-hlCd?@UXy0%yTYJjI&qFw-}9FzXTe+PeUgbGMRV zxChxf{|0}6(CdG1!z>TlERZsVn5KG$!ySnM4NXuRtlVL%Wfe)7tA{6fn5LyZxg1PR zOjNM8F7a|8-5Pn@+1kBZvyiB|pj~0#fSq1vH*7^&OOwAlEbG_9_$HS|g3%!?8yYwa zf7Nx%5S48cQb#4eLUEjGMug zB3igGUv_I)?$5%!V;;Hx4HrUGVbs|rA|AlN!)Of#gXIpMDzNiaw0pWRh8CN&x|ZB= z#%+!n4*qO$;q1^Z(|HauF|qH(&lR*=;JaK6BB;GR7x|**s=f712AxpQ6KQ^FKCJ-r zO1H~zZ*Pf%Zpb=|4a&%2&BJ$oV2stq!b$X1tmZyG!Zx2RPle{nDqF8~cEr64JqoXd zIUmE0FdebzLq$bL(+ufBR*YA-Xek3^M-R4VWIWk1BMQ9 z%f45GF9)b>Hf*8!iq7AU2L=!Q{1cv#*9H=^hIwE16>ThgAI#QM!n5yxx7AxO%BcbT z2h(TXjUGJl*iPSTrHSPZ^I^c5HBXN*+&eUtl-Ljp9!Uld72#g(38P*64Vu?X+t^Rg1}*3+*pG(Tv6Q?k2X}@POVx_ zq1g%r_9kC=EgLf+=Pk8!%h!6Hi|>Me<$WVq^>W17;@0C}lv9s=nb4Wor(8Ez%eKxE zvgPz^THkreCJ$VMJ651|#$hnrBe@oTG(gB%r@P|jyt7WL(55p6|8nd8<4(`KEk8m> zx4ODj;lC0f3Qkl=8oQZeaA-xHn#84JFQz^~N+(+R{A{j4F4$BJv78+c@F+FEI+S=9 zFhuJ-__g-h-kSx>h>L{e1b(Wio~W4c{4o_y)vqk?eLJ)A3c#r8r;wD$Q5YKp&g<4-{omN^=Q0~{1zi6^^tMz(qSCd8-U+pt~A6&{&Ixc zeQ3hZuZ0S-(KPLiMQ&FUJ{RxB$oB-*h~154BD3pFme;M>rQ;s4Z-Ni6^-R0gLL)~N z5-(o2a=8~vvn!E0=~=F2*!e_hGtG@tYOO5hI_{F;$eFq?9iv=SUF|&KUv0C>%bmTy zSpfJ}Y?#vvdD|w!q4QS=ytuBPcb1I4u|*n;^1~r|Ju)okCnA_qp$>0f)(Y8EO0zMGAJhj_{3 znIa>;_no@Sp4Xhl>WwNiKC6BwxYEx-K5L$T%y+gFJ|WcZ@pes1y6%*o zHzYvjj3=PWJx)9>yLAoJT(O(~I`4Z+dEH4zJ z(j{da`gV?TJWXh1mKLzoVL11vT8>PYXdTn(Dl55?u$fg6tExdSIF&@39SU6Z3^ ze{aZ^Zd+SYfB54Y`ZWOX%qlEe^n6aex!k&yw3x^OPmSOU-wlr#4qhL2uzMeLMm#Zb zH~u3)Xg~VtvO8n+&W5q;#`*KjFK9N~OU}5wn9IgUn%l6SK2wKLXwtTA5Cqp!n|lhN zRVFV1;I}RKZdqmG(#5={8%<{fRrSg;5}@P0kU4h;NVPWBwp3`|tlVcM0&K4GL{^82 zZfsxw3?$#pl!z=O7%x_=-j<3rd5l3rf1CyBz_TLKq_1(4NWie$|NlGldlEVYMA7l+2#uH>wa(km|W9M{MIfl!2q|$*I}FZ z-twZd$35|y)5i!Oc!j<@A;3jpq21QG+g>Pq`$5{#ztcUd7nY~!!)C8Yd$+1|6+ocxjRt5 zkj?V=g|#zRm2J;c!WTmWu6<~o{K@xg)*xKz&ULCJYWhi)Cqv=u$sn9Iih+k=WG*9| zP08K|cPU=PTjX(O51*hV%pD(%_qZS9RyJjMai>!{-TclYDAo0^(}f%jxC)pP6TbR& zdr=V6`K#z&xI=5j$nzXl1Q|07gGu?FY{F}o&KKEhMmw`#I%HFl4WP>g+-XghD;OXS zEaqu^3kp#{{7aGUj1(ZFN%)6+hDGkPB&7xQtL;-4YwOIcwhvmmnEx#(aRR$3qHN1| zOb3vKG9gOtOV2*aNAG}5ip5;FEqH9_HycOD2{EM1>}Vgh2|p}QO&6$bI{2_`pUw%7 z5?o1w*1ku+L;T1tGztnpg?hTv3UQ$P~PLpnt7x(Xs%&tOhxF#dGGA(Hp(*7 zH+rwihOBAHUZl)r@_XN|n30vhlNtU*?>zw{cjb#%2U_p;3|Azp^Y12Hs45?~0^EQ6PJ)(IyP7S%^+V}yhQs-WfeL7ly@v$o<)j)(BP&kRP5ee{CK~Mhp#@ zJs&C}vKT~N!ot}JdP4d*-`ST}7FZ3;*vVg-rJYVUL>IJLH44W(lUS1n`FW0;Uc!$8 zdCcF?GKMWrJf0!@Z{$h$!e_}2{Jv*9N~qNzywa>H_Kp<+#Hnm1^R1z_kZb;l7@(gO z3*MNzByjLRYj$h5YEuy`v=uO?CZBFf2euXOtE7<_VbVI%#K(Nxu<9z?_HnDrb(g#X zeQ-@Z`+7%sqF$=`hnQemHWZRet62si2P=1&`+%ygF<1Pt$VBj)==y&j=?x@-Ui9HM zHtRhHg~1QhOa=6`cfAP=8(0z=uSCYn81I*z-Na8S)kIgtTI(BDLhiP(vj=})0=H!f zW~+0|YOBD+J#Ui3QBx0d7BY)Ca9%xnf8MD!&v>X=UMXHB82uNO=w1kr#P4fZV+)RI zkbY3xuT_7WxH63U?W0$%xkgc?VME-0)3R18#Gbt><|#X^>KD$0EzY<{%5guap-L2O z0^IR|#*2fbh>LhtL8@|Yk3&-%us$RCvl_bgxTpW@1glAbt+f+pr^oxNU4npmSUB3X zUWbu@ygR&1l%_{ViBxbpW$7#mz`?%3bLHY%wW-ZGQR!N!0l?7Rm*Btyzl}Xm`2BMb~=nYr+$g#$LByG7KeDey_5ePj{%7D1s}N{Om=MHhTSZauBbnAD{Am0J<(_}RjE zG70Q|t`0udKOZj{A&)A-LyP}J;H&6tb$moOi!u834;lzOaNluC(uMvqaE$xj`&p{H zD37x6y!a0U_n&96l?R&XBflO{Q1#z6?LSB4!hjnf=c)g__-{G)=P(6LAYC|)KhF1$ z|KGbzz}KaOgR%1d`*a5m11AQq>xLf_`~Q145fe?rHZg@M^8dhgk~wPxn7Q*ub95a4 z-KGP7l%v6bfB4Ubl^Am*5^H~r&1FRR9sRPAnCK#1Bz*h5ohSWtqpZ$YErC-k#UXb` z)Ev{A8a7R`v*RooHE%RZ~xKYMCj}%o0uF z^)?od8!s7gm}*!ejCi&BmJ`3vu7s_iD$Ch`{zu*JT<4_aYL5R$2&L_4f@LrOZL;g3}BI0%>gbH z>I>KCA<=OxEuGb$uTMUI*$78+Wpia~Cb55RX}|(dt00|00Zdfa-QO+k=z-#F|L&r# z-eQ`YUn2P?%Uc7bh|Bt!ohhH9_)!P17z0R3s=?c~@uluU`Ln+hTar;GCp9sVxQvKT zq;a;lnJ%1Piq)I~4Mi9kU!V*g`o#o`UZT^{07o9ZOAPBz6O1YQNCe!i(*4*Qr~y7(mLc z?0MqM%E|gtUIkKtldDH99k)Vj28=Xpl>2StX@ z74#aT^NTD_zwcNu_y8VJEg8<=#*1$R3)0cC=nZ(3GSr@*_3FNm z?u{?=T_GL8{(l`*o%U$ED#WQPS-}2E64P_QSVN;`%+r!*WS{f7-9qC`W+_whW|TAG zEB6BBIQ5G0-_x)44l5>d?f0Fh`-{2@4Tp3Gu1L zCwL6Kgwoq!f5-C+cxBhU^3?_HJ9DCr%ImW^P{PHsr#zs&Y);m<4J9KZOJ^oD4d+7F z-VlnHcjSI)_4TDhk^g&0^fj_HN8@-rcE%>liA_$_Ce4PxUL%0|3D5!h~Z|9y+P<&v+}^1`Qv; z+;8P*H7DC~gKyk+qxNRnnmC%inUrS`scyWI=l&EWacV{e$%zpCH7!roktI*{OHaq- z`G|*nwim|``&+RjgXpUzwZcvzX4;A8o6k?u=5$l)6HUcJP8&2QOpDa0qfSXk$c8MleV@mO-sBJt!Jsvo%tA*wLE!Fyz*?0d ziicC!6B5i-?a125%RNn)d)Gtr`RXxkUtT7!q$}w`+2-@aA4wzgFSCbw@Wfc^v?o4O z+CKwaGBNejS9HGIok#7eX6q$Cfrt$7?<3>U-lF@9M1uZcY_bKdKO#|v>%F#Y*yrwn zT`V9>Zw|uP0z(KHE7;n28Ps@Y0zM9|sK1PN} z+_rR6*a9{44*T64JNqic>j@0n$k?W3FT-fD^LZa~2kgtg6>O&oS~G@! z300n9lRe0xZ)RG@(j5)wdqT)u)Ws5~ak8%v638I4TmAIL*k|(5Ci%^|)4&K|=-F7X zsT8=}yc$k8Uhj%+TJbZS1^I_Qp%zwgTY*@Ti(L_&Ew4e0?1hJC5Q6%!vqOLPOh62- zr}q0G3<*`{9+Xj{m^?lZaTr+(p?Zhr8ba-s*n=yiFtl|dXOgW;=yj?Q!Y;MX;(gGP zlHs%vhWrtP_f#W87#yDAw=h(D7fbK_(~0>DwSUX40Oh-5xx39Y&`2ct6j*|(3JxCw zuXMO22?=Mac{|MRxGnf0hl)~lx2pVGR7p7v%$GHxjC`V~sVW7L-WT?l8%bs6du@Uv zUz+S=YaH%P5Hov_8XS}w{9u+NBi=voXz}jLVuudcf-g6a@n9- zRVN=8?z8$$vuB~oA}la|jI*o#m(tEsTMUl4$B7%v6QgAVn!P9)!W>hAuxnbDPA*wD z+Zc?2Uv6b-LYq@ng;J7}VeihS6Ji!m&$-$TENtkzZui%ds1CS8sJy;-YLk}DS*>enTn}dzXAS**&*nK29%t@e|B9G^tNS-A zn)sfG>04$(MzLE)a2E%^hWII?SG85n7%pPtBhSJfpp~R@%!MRh@@Az}29YTtaBsn| zUyoV2?6|Nu{a8Wm{*{T1zY_{C#=V#6qF}L{hcBbCNja)9VuBZ{NI8t?sD)hz6J(j+ zt2{ixm!cUk-M?lk2<|dan?J%I|MIdYiwXmW!aPfAm)9X@q31KVE9Bs(kU9&q$``t- zj`K7l-?JHZF{j*wqBqIX)f+uS40tbMo~H~nSws;1Klx-{E#YNXs{{L zoXDm?K}@+*r@r)UwQagRe~yixDGX^eu-L(-wcdW7ZeKbz$UVP0_`s<2A?HJ;hpQp9 zessE^Gj>DlA+3c~ddh9#!An%nn_C>gA@ZVZhH0nm_bc&0JYYZi>)~G-@9{y!LEwRC zYRFY{lil~7pDhup@++=AXPeqS>t}P|Out*4)tAD?o%eSbsTWpPk+9_R4&HIC+GZmY z|8@QySXqqyua(&*ta^zjx@|R6eCvf@m$!{DhHA9?ER zmZHeP{Q4>VF8);TPaQ)$CXv1BpuS@YX-V~0YiNeRGE5xr0k}a@w{HG~u^bN3c<;SO z+E>Z``gbb?_|5|)zS-!V4~U6+W}mxQc&$lts47KELHPZm!g6&-7r38%*MznM8Gr!% zx)Caa7ke*y7wNg!A4SO=b9U=$jsR|O4~-viRw%YZp?qh^360pM12 zX#8)S7<~Xc}-U@&k|A|FYMX&k|lvv#E z%brDlQvG&Y#I@!I#OZ+StafpHJG)l;#GcPM2|&h~!5p<8-Jjs0cf7Y(e~gZhnW_Ci zS?IKUH>rXdhH;8F;K%yH(dz;Xv+)&=TnQ29f1Lg~?+F|U2YEXGSUWPD0B2!6IWrRT zXB{j>O8m7GU^nBf-3B8TJ_=W9sOSzpC}xbr;lXd$=d~P4soUJ1c5z?~0*o8cYTPmP zpC#Gk{gGkqU#q@-r9zN%cWlVl_9YvB$UF0m-2G};Z}m0Pp|g)vnCZ4WkvL_Lv`2s+ zHH1cC6JVv}?Ys8XH#=ZvF&(EJk(3JzzPk>UHrOD)9j0_)wETg)YY^;x(c1TGYUb_F z0iGl$qXG-Z0PQjeWr9)9QQFnVb(~{xTa@W=&baVObwaiS0Sg1p%lpm?nkgaI1RRJ# zbws3=bi39ZKhM%O8GDp!ZxwdSnt{I74} zepJ4&cj5mS0VzmOE2b6uZ?j=K%%6TvT&_p)=E=u2lB*wF9OYkO+U#kZekDI2M%X^p zdtXnOu=r(;26-`MF)K2+-NLAa?%dXV*V_hRT=dUqkKsDFyFTWXw4r*aVxCYqT?>#e}}qfq@c z5CKrxN&66ejQrRV^Uff&*=Gw6Gy0~pKdh7#koL%>Fj5QIUaX#biT;J(a6%qjm>(=U zl30Y(g#oRddcFl=ES3{*{TzVti@oc9&^DlHp?bJw^O~64>S_DCCc))X3=tl|==aqy zY=4g$D$nW3-2#@TZ%Kh9@d_;nKkp74+o?j;q#!&YEzoR7v?uRVw2PTBChr|~N2?bi zGBHA%dYOL9V})6%=inT$Bcg&PfzqLMCX`0At6a)ll}sRKON%K{WOsUXnpG2G_g>xm z7H221YcEB2doz)HR82H!UQT3ii$sLdp}s~%dr=s&Yum^h%aa4dTUH8m47j?sH8Lv+ zGT}U#AK~{`<(BJ#d@FqGk{qdT<6K0AED7UF7&=i>bLN2Z==eA;9oKpW4Ax);`=P^n z%C-YL)AkcJHm z70nPQxm^pP-3;Tr<*`<;rOx-Jah{jIkNIaSNcZCv!D`l6N179A?e?+^75Wj8$CKzM zR8Rdt7uPpw^;S_uSuZJq=s-{So<_V+N*am8ti8jtQ0|F+UoD+A##DYu@#0<1cwUvm zr&!&ooEVg5nULsNE_6jGT_7c^XAmn9^D9MT-L17Do26D&zkNC&*pkxge2+A40JF^zTe5ZKiQrWiJ^mzmdphN5s<@KVbvz&x zXuS?t?ibLX(pY)SZ3DJ1D^DLP&yBdo5&= zZJ%=QS1lgQALT>l!6JMz%6sDWV}QN`&2}Bn5OcnbV%heu>yqxr3rt7<&kw&996jS1 z2_{-AV+gBvjuH)5{Bm>zdyt?$J(swR9ZbeO+Yk}9$}`CPa3^bku2A9WB?HbIx?mck zXvW?siE(;c56f3u4FZ`nlnO$-(jh4_F)1#YM`#Un+&$bi9tz2foYvmL6C=Gf?*V+j zmb6h}t`Rvd~{Bf`i*K<42k>K~xu;7Z1CRgh=gQ4;~5c6aR zQn)WzsnPEpVu0-UpJBSyL!$6UeJ_@D&vg%l5KlZGKLfa50lDAvLQxm7Atjn>LVd^| zHH-Fb@VU%b4556#SpoZ|B{%0Grj##5aj3R_imHKBkeS`-oP)piuyXRrA}XO zZOsJ)5ga}K3hjD|tC8Hx@hWfv9;-5<(~*!S`@V-gB)UfLpW$;e(7ei8229KW%y=3BtG`;gDl(M*V2wPv)S_6Yg4Q=y zqAZCz3KN9JZ4%%G6}TVgSeS-_1;A9L@<8NnJ&Cck39SRW=OQHCuAbtVBE}aHHV)z` zo>PYGLeL8)(kGj8v%2eh`64+OThD5Rji^2je0+~;9>GoTAIlX=(-r&CGP+1ufhkL< z-3@=_A?~a04Hg8*B=k#)yJ^ubGRxMyMSm6M62H9>Ey@hZAc}>T#7k5KWsai7)MfF| z>c%T5Af!m46#vR`a@O!yvrMMmT{v9?Y&`qG>?6b*LK+HeV4?Og{#<0jfE1#g8XPZ%gWO*;!T3J9k@sG7$!{T3_EK-?^E-E zjhz$;yrJFlcpw&Qfo%Cy&oRW6P{CXla$-xhSQ~5{{nYbkju96-LH56xB#0SRpmVzL zJ4ug>ozjewKw*~6BVA1YOw4J&U7`2X=2Ze9I>rwrs94D4A4dDEXtod(2GYN>B7Bxl z4@N>gW?;HvI=#~_^rwvb>A??tY|nf+V`Q_iNf{hVdlXl8JL?;dl^Ws>X<7{=2sSIi z68=SA9e7a7-5qS{3$rK}NwB=%VonF_7buzM4I@9SwwI}yL(nG6%*W_a;-8{TYJ{2n z%UBrWJBG*@5Bq6@KeT3^mX%7JqNA#!2JT{l6Rgbn82(vxSJ`EAUPd!X5qCkAX@(Ku z-Qi%rnai791DQnZzdFxO7-soX8{HTg6|pLs^g(M$G(DbBY#>^GVceTo=&fK(`im>C+Pr?( zB5YzYmQ_^cIP$i8cUBf%z|PRcPomL&^)J21biz(9(jVLOi?ZO{#RfabIl59aAI)!>hhqy8U{GDF`T zBXy)Z#bgZN^D=x$N>UW#*BUxHrQCFIUA6i7c$2bi>&~6N6S3&aU?_BF&?9w2$eE^8 zS$&I$x!Gh~EXoCM=f<3hoLk1LHX2BB>!R%tb&|Mfjc+x|$}4g?0KdA3<;WIgmf$>e zk|+d2|8!%4K2KrIAAuWj^W+1nf4&svsMz|c_2jR#im-ZdbLiQ#b(6-}yWNd=NJ}~G zl0cON`PR>oR-dbFxY79fQ0)-kc*3{E1aXE0wG-i==;k*WjP$JQPAT*UTZ)&bp0y^! z`0+fj#P8Nz>5W0Bt_D1vt-@kUh|^|Tn^Hmj<%tBlU!o;bV9~Ld{OcB4u_&{*%uXMR zobK*{rZ?}X`p)jN?S^VOF6^J^^#^|d*wQbgUdnVR(%2o(PVtojKmqvD3Ych^^z>`$ z(s*AlOzfsq1XoSIbtvmJ-5-j0AKKeDGzsfFPx%eZjvb7q3-V?!wcRd{?qwxO+0thm z7RkdHSB8K4aV&8^6sfD(FRoqVTMSW`_}$5|wA<5Zm!1jJv$d=Cji?Z3Cu^+psk<=i ziYzb`sXlbLzHHnd@DtPF3a#0Y0L5X(5QmHF+E=BZIZChhj{D^N9;+7&>PseDt^(1B zJ58zdJCr`j)zN_a8rohKWFLtWDj2lAuCSTSN9Du;WqPP;}jOS|(XyJ>MRD0T<~5x^qjU9SIrOHrtpZ@ffU> z5FWc>5InLoe19EzU(S=3;VW(}y`WJV$pnY&1$o^H-}s^J_)!K4e`M1X7#=ID? zDI6K*vYFi}FK-0WJ+^dpQne^^r)m+yABqs6aEyXmA6v!^aZu3B>db}NBI&hTW2S>i zKbMtZser26;n*rpX&AXk8GR29>*OW5p#yf|*^OM%#qh>_{+m&h&qJKqlDBx#TG>+$ zmHjU<$s&;1F{&K~9n$Z!*KQqQ#W%(EjxFWBRes72xU|-wMuKq0QXGB0_Qfx5o3&#} z(F?jwQBL9&x|j1`?2Iz%qJ(&PmKhdv;7FD`wb7!9ZJl|23d$h>BBv!^ z0VdwXNNaz-$&Kq`V>7)7q6`*{;E|AuG_nnriM1EnWUL+*-_(KH-tgQtHjM0*Q~k1S zv+eK9w8N+f8i=fbf77iL_VHdB-wna5d+DESasA#fKbEw1%z!Ytz|9sy^ zKw|vG*{`BUi)RxqU()<-4XNjGG3rik(FIb?>;)7AMI_|B-X&N^z$}o}BxvlEdtc3u zU_ai7X+ZLgJ|rHSS#M74%0%LC+U!VGo-xe>N?l%&6B}!(vDuF*R33xpmSB8CA^$~a zd9=!{#z4>3eoC=_#+#7f$O)Bfj)|(3z3(+JhDK54k-c>0k)dc_w^V^oG0JXXqcp|`sYX1`htYHSdi2?|N#H(Uv^o2$dS zj5vAkDdbxsC3dgFlC-s7S~DOtja$ZOM?0)uRCFUZV>l6_%fdCmTh>I*MYb%DlCR&| zcSZ$|TfIIW8!PJD5slI45al0+a~q4-6To}MI17D(M;YBS@nSF{IXKHCUoWojPOvTh zP#bPK#9O@UY{4wLyuNcw_ATDma2sE)t3!s??R7L-6nH=4So-B9E^4^=$u8)eo|2t% zYvp2R@fz$yxhQA5=qDt>nW8FoP0TB?WM|mgXYuZu)X?i;4KQunOkM)FFWbvai10hO zoU8Yd-GahgC3Qh-Yk$%>hhMl`KS7@rS6SwVh}Y@sn-QC*4GYu;@{gQ&%sL*aS)oO~ zK(7H-rO#@d3!xOTr&G>$7!7@02Ko_W!tF7x5@RckJQ_6)TMi+&{93cf9`Ro{pX}^b zOixlx@)OktZKvy0!N6~lN(jriakZVRn={K09$l7u!!|6iH*t=D74kS2Fp6+Z+{pE< zIj`MT9~R%RbZJ<(3>&oe?bKR-nY=Bt%;tL9L10aL(iw>~6>l$;t-E*v1-IAN9~RfU zT0}=_k)L3*`!8~ns9jv#+OZR0)mCIOl1kS!}y zwfi`~w>Z_J5w~u?t^K@jUHuoEj+@Nv%6Ul*r52m!p_HMwtvCB#eWG18ZfB3tvDSFj ze2ok>f^oiYIIhR1+r4&5!ZqI1d~aknYmpUJT`atg{C@s^QQ&b`1uk5Gznj~Kgp^cZ zW(Hkf+~ut|s7zomt9tU^1+dzWaL~xcrKw6^j+p*Kc=$q#L1}5}sbLUvu*+P>xbu%r zAg^s`IEfvy-5^{>y^Z~e<~0TK9TC~PkauqU{QPP!)}wO^(IOQDQmP8;gTVh?ZD(;& ztYXhpW%#XM6HrSB=v|$sI{^Hj!;*lowdWw9o$g~)JDpIU;I5L}-Q9hcMiPtezb5*- zsa2)@@)3PE-2?fKi%OsCeZk6(+2_4azoiR9O4|X9_^pXavY%h};oM%3z;yE!-EMez zI1o42KYZVI0ji{e{z!H_TD0#RMYof?{t*pC0Z9UoxW>Sf$eu=>Lh!()?@sZQNONwq z`-nx)a@;>__A^vOx&qqbb8Okj3~e2q;XblV?yk;XJj~8M8bJ|)wm_T)2ek;q8TGMs zK;YAlgTUi?1FG_b9*@x*kPs)G?=Kd;eoLqFK8P=oor_Bi8!f-bAq1D&m}a;q=Fx@> zi;j-YU?9dGbJt~88Tb+juf)N36$rnW@V?^;p=$5qFm9d38cJeE7?~8QrHXfV8a8q9 z*#CUxxgIr_FEbE5KGELd0*9xVJXxsRuWP)%{ZM2lx2UY7RBwIt>6slF>cV54%tXzB zc!pF7hb$i+xAKv7Wzj%^M|MA7@+2S6j-}Y-`rFMd`iSK)|7W=i+@uRYNKQ9&7a&}$ zbCKWA7F0}M`5GSxDzfCR*=fzIe0gEwb-w#(h*7gh#f{9CQu~vh%s|&9!2oLlb4w=! zjx;u-Bfi}ra8GK9z(4^R)?Qo7Lw+%nf_fax)A*Wn5l|*fI)g^O2V-aIy(Ui#o(I(H zpHK8nOb!aa7#FZa#i=z-DV;BS(|R5UZ$X}&+AtqEej9K-CAPaSzF3aCyS)|x1$to5 zV&!IQK38|6`SDrEWpih6-4OY+ZlbyKt2+K?k-g?T@uFgBd5*3mPqy=N<0I{S2#0?A zAlB$%*Zs08?7Do_><{6*w08;B=(FsK5*$Zt)QUgnH>rLXSgu#|oqD~Y@4)~ODBRJ< z=?VEiMMAvtgE^G8EXqe#L@CR{gLS9HPv?k7tr$$QzklG)?-^rnmYm(@W0ji*;+S5O z$g^(%sfEdZP)_^^wuNL4eFpzdxCO~)2;0*#FhEc`-(WE-UK}ie`y+vro{FYdHTAAL zgfPDlYIu=^m{hp7t!gHZtl!0=O@ZZv36I@^meB2J9TN1;a&8hq2hulIJ!we==iY*TWhM;4k{9O)+{01EU#7w9LEgu+dW1*|Cfpol(?2fv;bMX*7`YS`3zPckQ9kaFsJ>d$iwd7t<=!l9)cF?%}hS z&(r~WvS5Q@NU-y{e$fb^uE-UTAE9nqc^-t0lT4&0syGbfG#%x<1-he!?zJK?Tcl)v zVX?8`37x(%zPJc8x<#;?mvJ`56N)_mOa{g6S67DP2LR_6Yk238@I?1LKhTLvXn#5Z zJ~c5QB;gM|-OBPcK>RKcd1Zx{*g=HOMu97OMCYkEA~Omk(>qe5WIO}f3B^(Qo~myE zP$DjF;rX?H%{CwgdrJj zSEoF2sc%nxEf7&IvF*HOKznS*O5lb1~HC6df>0P}>SZ#x9QU4qf$#~v0Z;IVi|HSLz zLt;Q^gNkyIap+ww9~+p*pXpWc4Q zr0QJ>KuI4OZ+qg-Xll1Wygfz-N9IQ#ND;dsmR0-AKrQfzCIsfP8xqKC8S2F%+K{AH zMJ#uOoGw{0URv#0+7G*bRO=8wUy)zp+i$MwS1h>uISNE6vP~7KyJ)rn97$*-4Zl+1 z4*q^8+u+?w7p>#Ib(PJ1S$(Dk0nQXr2Hw3@L)?M@+& z>*9OlY`Q~pUs`tLtsa6Kl9%;mp}&~;$`ME;94!1GVhw$rS~1mU?7Fle;?Px+r(AKC zbD{Ok=*v|h{!iB1I!(2t{iYQuue05+dHEuPfX3x#*m247Hjnw>X6>P$#1Fs3!Rq&m zLz(`!>Ft-Bh=WCR`)Z;6Q{MVYRo8k~Mwst~nCmG~o&f;{bxM0U<$pF)^?(NCEC1-T+ zlQnFV+4w(gE|5U)!B=q~4#UbnJB9pbhn3Su)a@+v(>=gjfbJ;)<2y>msKEg!A6i>< zb0(0#!cFm5Z`=}Pq5tC!Rc~h$yvn}afHB+(O^f^Wv{h!Q?@r&AHt`vByeXM1%Udq6 z9%71__a1n>I!(30+1c`yzP(4Qkx?|fJjzqgs0B)USIL?}2Y~9*=(5`YX4Q1bdKR)$ z&CKlTsbIO0>oF751P>K$cIB`|_eGx%oTSUSle_tdkXgJY>#)SqB$oN^;!B3_=8o{A z&fpB+@d+@{@Nn$oXE(ssHm2%%*gT~s+~=FAl78IrIQRm-DuW9-Q^^$WqgMGj2rY0S zyZoIOgErN#x1pzL$S879U)R_+d|9FSGGqYt{Vl!PgPWii`Xw2q{M4E|3Im~Ry?kga zoxa3mO({_VyIZsDrd_3_2CeQ0E|Oic6|y7M{3JnWLn}s0K}rwh$m>ObG(A}Ug8zrG zOQX3~r9uEI0{s`#5e-FuI{5$rQuj`af3yO5(Za*3hB8K`#yeeiXWY8D-;r;qCp&?t z;H@CnCxjPZQBGIv zi*MVRDr!TZp@-+BpyN_)f65JO>36Pm*312DqXu{swbY+DE}(j1T17;?lh(u`=gC)u z7*Ogev*f+YUN2uoGIAaT3Oc-CmRm#x7u^^cZ&8`J!8VVx{0I_ z3qFs+w}{bgo?{?bXlHRusVQb@b#!%0npxa`yyP(`LJ;~pkJi)z+Kt^oP%5cTO|gV; z(0Mnh;J4L9)ZR?mqwC&-?wxHSTyqe$hVNAgbLNZwC^k&|Yx+-8e4ScQxVn1x<`w(H|TQD@3ng3P^`+x>FGlLAq0H$1RyIt<} zpuVRZp7a#w$%oPuE-<4XcYEo-Y$+&9vjy?&@sLRkpjI&jjDBj)Ihxjh|;Z` zTwOx;8`qoA20llcSu3 zmkWejx*#Ehy=QB@O0?g3K~fJkRM}nfS)w&^Vlgr>u;9UtD6m*y!3NjPnT%z9-T~Z8 zRTlM2;Q{zP6wV8;6L$JedpmGH=@IurZJJ*4XuHIdJ73{jPdfg($BhH9&Y#lif4$L8 zKbKDb`LmxcU45s!Y8ksx3`nlpbPqmt*dEQa4trT(`rRz(G zvujC-IzhL;og;whVBG6*CkTYtW7!#uZ@mt>)dINNw z7DxZ)DNk_{b*H1l$af)SJkFW$?)MxVp<;BPw9XR-3<(r0^|zxNo}&z-LS=roQYl3& z5ycbxY8I0CB!(Cq+NrogXY4bg`?PU!j?n8aUxQs9np6h+NX~S^QO})C7Z_ z(a$-o>oRsT`lkpve!KdzR~qZzj^wtIqxRtpzI>;Bnqslxcl(QWX15Z@j($h1o)sS* z!RIjILG<_Vaaxx5QiL=>Cxzw2F0luI43^hc(5Y;*#cC_B!?{N6%Pc3+M>Bd$M+I`A zJF>Yr{{5tVo+HuU=yPJm zSA{xHi^dvvx|L5=U46|51@C>bRe`AGh8w%>2! zIl-3AUci(MfDYy<4i`AKBS;X52xpV@F4H?Zo;aej+y#wY_E`N@P+~_Rlps5&armKG z1y&yv*1cnX{IckEwy{VYGrShu#sdz|v6a7i> zj_;Q*+VX1n7m2sm2$r=3JG0%3W4@oQiU7tVHvi`s(A}IwX{L7!I!rdm>nUY$arWmf zc<7=m73*s5S0$Wwd}oFrFm-%0Q3C^c0CBnW9qTIA4jSA zfEdQ{IQCCiV>JOwmVxJC;Pbl%*!^%*roru`vSJ?)=vtCJd$q^-kG`Mg33X2J+9iqS;^@l{f!~GJ z4qdyek@wciA){#gSs5B$qoSlrfnYIqL`?YTs1pXi`EaAuPqU){I;HC1U5I@$my2J~ zbTEx}*4oEl?%C4rKw3*%4k>yBEXb_1JN4kF)Yf(~sUqCYRXGApFn^#PhnNuFZVLs+ z-z-TuN^9Flolv6~*L49G$bTbgo zwhkDOouY(&{U|`>9ekBrwVa;M{v&V8;vj0TWr8wzj>;^9B?lD@bZ9y$OLl;q%jw3K z{8tmxi&6R}s)=8B2(`1>F*xO^#)8^j6sZMz`$Ee0CU&P+61A){G3e{~Ez(3SedrpC zj>R;>n+*_6ZMl3m+G?zzaU6j;sOy=H8_6su20`4x+)n3Snr@xm(6Me?jIEkaQ*>rvtS0%ck5roFB3Gt*qb+5Vk% zdJoTwQkl0nY)ak1q)%NYz6Y$FxAo!rGA_tiSF{;-K*r5zrguo9>@z?U*Qkf z!#l`sjS9_3oe=q!P#X1Rx9o1}yE_;?{I$M3{>P8Id_Q#??eN|feZIWs#P-^AKMA2X zS(sT{V93@RCJA|f*mV3^42<#fM|%(;(>d>xZo0D17NXelGde_{n7)ORXxS^ZabwD* zuwUtmb0rq%+|E$@Ku;XHEKGL!)HdGI`#FgrWcQM~Mm!02J)I3^J1LJKh1DN*OO{#9 z($w0R-hg|~xcAEs6CI>)kVI6wcOin^e<^c)&)zLG&pJ(`qzo6-13XhI?2u01_e^Fp zNfv$cwP@VtyL@~>=|Vb(nECn>zjl^e#>%WDPF#_Vphze*<9B0H1W~jyk#T8fe*3k@ zn23;Oy;J;nQ@8NH1iG(c)SpHXW`gq17-+8Qbl-kh)0{{u%Pkcn42|F;tJ1N-yrSVy zqjhLX2F~NjuALH)`(^0W&H~+^?uzzIu=b8pCmGX|Y|mFNnrp@u4l@cq&qt~K^cic# zDow$yAP@`*o}$mykSFj*V$YY+_iEgO zqTwBZC%dSe)!g(s$l?bb|DUFgUm*UdoJI4g6JaQ(01r6sz)*=z!Em8{z zy7Xa(2t(nxkCoGy`eJO}2l*8hZ%jvY7~r8try&nKRN*`~w}lguFqsl~_tm*q2Kfd4 zowM}Z)wNj2O{wazVI{^PpmSqyr05u}b>Bo()VvBiwURK}Pw9Yg2!E@@%_n)5eo9+r z`7pD&?cs1$_Wio~&T8Ot?aPT5wA*rPjmL8B@D{3S(`;@^MI>|Wt5b5;eHC00Avf^B ztmKSWPswc)okRRe$nd&%z$Bp2312nO$~)N;O0I)8GtHP*(4qLS!j_(5#z1&#qR>#S zfIx5C;4F2Mv4>PpFa_J3h9SG8qwidLed_QLxq^Nyhv&Vm6js#!*1XKsJ(m-HXVo&p zDin`bO~D%E6{rfygjy@>6%7LozY)PoiEHf#eF7X+s_~)HQ+!TG=kF0FTKpHqL&Vu! z5UXYbk_#K*qQ!(mLod7Q8^h-14)HiWCUlS**knJk#=g0DPD}TvI=_9hV34WV4kVp5 z12o){9z74{Q8LkA?cWKDubFlE{0hZ3tRL5YuSJtjO;zvCt5UjQFt00NtA~|sy%mOi z$=08E4QS*_ij&}Ryuq55L&*7yMeoIn(}1sSOyk+Jb&fE0Q>f)V>E=V7Wmj?2Y)w7O z$OS&_)y91@N}X={d(`ob_h`fEPjAgl^UarXp_nzeUE@wNSG^yC;w8u}*0@{uwNsgd zroPz5eE`Rsdk=nK{hn|bx)aG^yCI~fns?mVJg2E!GJ9zP_9lbi52izFI;okw$_Bf? zvN%7yH(7v~CWT2Sv<-2>&)b$SNO=osSaaWnXLmF@DIgf)~1wFC@S2yWwu)$kOnI z-&W?0aHSQOM>5!Wyj|;QO4-Pf_x)ETtKO@}P?6~zJdAVvaf z1J+yZow390{Ddp+jf+h!soUZBZ#tamP5Y{oHkIjAmK_#rA`_?Paz<8nkPR(or~X%x zDI-dQiNbJTnse&LL87|4I>KFa8*PjO{PoX`oTfpvfR5o$=g=XyokNA%(7=3w!enJ9?LJ)RyPTROAH48?v2 z|GEoeV+Iu?zv}oT z%wPlO)SJesEWf7~DT4?yMa|ksM1L>GhD4JETBe^5m_ki%q8v|6>>yTUB-ZJ0t*0Vj zuxuqq@32JI~b8b((xkn5;AtHLOq4A=tONt+1O-s^7nL*mYV3!}L@P$6O(~uAmy@@)| znYOb~7y9!6S79Mh2vjB3oswXh?g6c=H#&>`vsBf+&{FNX_e9n)gw+;X*82HH z`Lba{?%mkWTS)?chD@OiCO1*y_mWo%62B{wftxD-**Wzkp7~l>Nf?&D7RRUcM*aNR zu%A%>-OF68y|YrCH~UkQlf9{Ym5VxHpb4Fb`j~h-->_I;U_myx6PS?gzlsu$v({RllP|ocyEp3)Y!=c=tWX&za&&tiVVgzki@i*k= zYNDEbhE!U)qY!LZX@VfCX3>=YRJU%}DHQ+Cm3hNv4 zxr#`2I2bW0EQZ8&g(cQ=!b72QT10iECXyZ;6?1RyA#(B&Bp(~fg)1uT&+{55DAv&a zS#~X3QB<`U>V*LZ4=}|;@3GJE{^kPCw6U?FAZnIx%XR99(G9=_R@yZDSl&6&V8Ezgu?g# zrb7XL=BM8zzq0cu`0<#8HO^TIZhRE|tYi^%RBkfy-`Vi<1+rw>2oN1%+3VwO)w^Uqy zrv=mmw%FH24PGN6%2!jz)Vf}iPVoHApUn=E2C17FZ)SF>wz8ep-e?TSS6T9vLh)z*H_CQ^?u64+THzl)#SYS{+%1yB8g7Yt?(T#U~w6Rm2m-O$>Hwoi9FzBa+4OwWW zS;ebXHNr1iP2a{!@EV?t%hOvtU3eY~{*P8kA7BB!7ZvZ`{ z&P%uZxnH%$J|}AvT~JWqv>|tHnwXdF-i|4_z|myfXIKX~nE{nj>L7-fD_3!%AsJdn zcQ#pY3{1sOFP@FpIml?_G|NP}E82L^y_dlk=nFj|+Hs1SX8dz5{9Wip8zae+DHRnK z$MWdo5rxHnU~}8R9O7rW{<*JXSH%f5H4wP zeB4&rx~vfiOtnWhR6ZTCZ#;)UH@+2?#_6T{WP08X@tn-%rT3=WG;~ZwrWk;CS_;6l zw3@~8e~z2Kf8Ep}DD$ay(<7zuQL%KE{E4y%Oa-jnd~$2;r)6`ZFI6&w@kL!~Z2QNK zRvP+Ezs)pzd8A#ypXVThC(M{H?09Oan@S^b>NEK9AC7_wR*M}eR_IbJcRT4Q8v$)U;Zhp&**p<>Eon}ESQi4yG zOOCvx40G~$t}gJOCq`6`=ABy2`~Lpp)ZO;f#h)c5N-0F+yZ2Ge+EaNhxJ`&Zp6A)A zph;tKv9;>tP%LUXz}H1|?!B23|-RpbdKwhTshG z`?U2s0Gi&pI=A`fPX0r5(BJF89sy!-E8i(`!G%TXJbgVtf!*LVJ3ulYpX5T(GRgTV zPl1XR#uQw#JR|QvCXOM3qDTE@K%dGV$7i;iYPYqtR&-Wu*?_7Y$1Qk;M4ZTitnge- z11~z#S1?XOOCPsQQx&2;@n`|;jot12bHpZ{X^`a4F$Y*zWqJLkh(pb-8C&g9gSj5p zL0DjhFdXyQ9x4gigu#;vqVba2wA&8}yfMKLC5DnA+RpkDI^P0Q zL2U|=;#$|&$yMe$2WUO_V)g=c93QQrb&O?xPOxFcQ?Dy%-QD$$sZIHY0o60@Jh;pT z`ilxZuZDd7K|SXJeKyOeNzaKv;_@j26MR~AcOc?ms=uura! zf|bWcFyR@}zh1P6MihFTDLxb6S=cN|0U& zUl#wlE0ciK8*oA-ucggHw3%=@9G%ICFkZo)4?| zs5mHSethB)M6W6OnnX-HGTKtoj#WD9d&DM?|km zf;ua$)Sp)fI-qAWF6GrqJbQmzM7gC9MBEl?#Yi4?aXT?@*JxlC6?L$=@AaiUR76-U zmY*)Z`T>%jq40stwXw%pvs8I@Vt@$`orjbd7cEl_c2O_RJ*nBIcw54&M~JXD8W!W& z)CA)XEze(=Q51kRm5WI)irLIZb6x>SO!!2gqjyOg3*9}rH$cl!#@y%6RM*3hlSo+DB8rR?U@61g! zb_$#)_mCIVI~pr?oNwn|rk5<1WS;N6X^^|F0#h&IPUD2dm_dhI4)O+mmVU^*8C096 z%WA9?<3p*U?`nm1gkr7WEO5&T|}_1yUx%t_S)nC1-z#^TXy> z=4$0_M0C(V&u*)zxco!Z!2OBoHeJj^hH@_DTO;EWuXnHq#(3k2FE$Rh<}Vs+hZq`? z7>jq^O)5F>-q6gGT^!c5g-*+zKAJP-hhVcMaCB$*C(&lm^ZTt3Q~XnIwuuG%mG`4nv-pko8< z>*0%0-Q~m1u{ToN!i$Q!hJ7T? zXB;-G8RNEY&ui`&$nDQ6`Md1V2h94I!dLtJ{}gMTfXyG!*aZLioGd$_VWCiYI;Z_}EL;U7vF|i%x3;MFHuJV7eP+3`A32H{W*Wk zcMNn_%awco{MdLhz(xFfyMPMv-`n+{Lg?S8>+iSy-(8qF?^6F~llymP z{Ig2@TS)w=CH^fW{#2a*77~A2!~d44e;?ETt?K`rXZ|fD{w*Z_Jz~rL|E@@6h}(Ve zZ}?wH0s&K!K>Y=|QaD|Q%HQWFK$;f>go@5|B$U4o5W;F#>dNQ;>DB+f$DG+g z=9#m(@)ks)n5OOjBcLE)%1#FxGA(w<8oIfC7Ip`{;mD?OsO+C%tqHnwAk$KlxQH0S zg&I*k3ss&ac2+W%wHd~n$?cx5tcOQ1lEfzz3PqF;ZDa!`Z6%*s8CNR!8 zMAt8UeFn6-Mkg=vCo6?H8!1RzI|66j)kd`_KMSvZ6%;P#75t7s4wW_U5b& z#Zu>{5yvLCpRW#rE${9#SO=nh@}-(>uq<9=59E?%CY$0m*ghSoyhve_8`(#P^H6z{ zFX3EpT_o5zCE18T;Mx$`8huD`hfi7gUAULC)?l}Yb%Lo$*2UUMmgkg>%yOGz)I3;0 zmCAB|M6m;sqh)DsN)kCVY&g)8dEcft)#O2WlLnDXU$H4tRygu9)#lba4H7Y1I-*$9=xJDa>^0}?oa!Yw3KoIw z%6$85dmCeYO`KBPm0)e>octEVOyS(7XB!@HmVu9|tF=H_^`&Nx$SaBm& z&?(vc2y05g2-}uT$I=By#6i%gwK0_!$VcD^w819J1+}$2N8g!)B#>O;Tog5?Z*6J0 z*V;Ty$p>o|V5Pi$W6GrMQX6UOojYvV0vS@Ro|=(+^h!6>M=Bk#s5A!SuR}e^j>;SgGEf&5i}Uo#SjZ; zYSxB$>F*^*6+-8?db|ZHChnVTLD{Ew&aLgROQ^{X@$J&xh2%zxmCE;YVoS5is)}GQ z=uvZZ8-O|R67klkEazop)1HP!F_NsC-56L6=#)J0A!@;D^uUd9sEN(36-MHti+c#F zi9;ghmYJY5V6Fq~HzuwrpWeZu^zv*h;1?5|+`c;9B;)rwP@L89w45OLP-!|qO_GehF^Xn0|iuCP1s#Z-bHUAGqxUFx6NsK(>Db1hfwY~8;F5V0%hEY zHSR0J8@^C))V~eSe{9eGmM@;-J}0F)?*WKxDQq?IRn}?6_Mnp{`xolvf5ni?Z{J=D$jS7n10${dV#RVDoiw=aRG5SnSC-vw2gkoSBSTqJ#gQ)uE zMCGPPefQ66p$XdG?{^h5(w;Sf;r+_&EFv1`mTII?q~T8VZ+I|f0%74yquyEIPo zwWM`vgGY?_t?-3h^<~mvNvzTM;?XS@!>%>WNBM>MR+)rEE5|}&TJ~w=Wz~&8e|{<` zDbSHC#`-C?_yP{)6NA^76odWae~ZwqXyUEH^l%3cWb+F$b2{n9lVmJP2e)srt_8v_IPFH-74tFO**UchrieT;LSd81{CWq!0-H+kfGQgxVy*YR$B{*fz} z=#kUTq!?O)_4;lN_}Z%MRi|>U4_jDb+-oQV)k0|!4L1+v$}h(&rxG$Vzg`my{p-ff z>D?qI7LS@ird}M>2p#h=V(Rn?IDY#&tEr5`X7 zTUBwpOsFvYZ0(D&p|`pYee;yZ`BnplL%w;PI9!KL8a@Yj z5KZO>`NjcLJ#u2JG5%vonofBqr(&#an3}ueUg}yLCdzs$s@(bsG(9><Flbo@p zQ<(zC3o83KtGYf4Cp7Q5q@9y%fNi$N78S3%D6mBs)>fC(GKi#(jhF&9pRDrTK%#2JnVr=T_tG(rr7sQixXoXK zU`fn9kqasbYE%8wdv364$J178lTw_M(b;7Cqx_MLPFm^BqVcm#k4VE3o9DK{@02uH zQg%U45tR!IjBBVapLp_NQ7&!oj*`TE);pz8qjYQgm|1I+0uKw**5cob>RoohV3~E! zfmGJk788WNn>=vO9k&K3DWhnx)7r;t&VT5Qqi857%&T0vElieUPkelch<}cY=>|(C}!y7HV*b z2@Peu_8u0eC$uX*N6i}Z#YnW4dY?^O6Q(*To2i@aU{1+YX=*fSoz<>scxwSMJzavx zGwqD#$Zig6t$(#Im)JW>oLRF=efQ>^KD`Ta6wZy{XJw6`gg(V@$gzuqLO;5y$M}QC z5e8v#rgQxf`E)C?7~9T&*wWqu)Bf!{G$igq4s0S5;ol3)^FYy~Id!EEFVY0ivJJ1o zMUSds!V^xVZI6{6)91{{q>B;au*(sgMriSV zv%TD}k5Kw?$HAb~8ius@LEp3KNAD2Yf@FdQ>eY4L zuTz;3c_iZVq1wCSljPpX#-j#sf8M)1lQkrJC)DpMJJ{;S33j^RBEhEQ9Jl&UHR?XU z?l0|usKj0XNNpyAl!ccaOd;UxNENqRlN zPel)q>}xIPrExkkEoMqi0JQnc{r#?5%U3zpI?0=}o!C>HOk1~uzlzU5Oyd&1~E{=V$;LUcne~dutWOKBI^_%9yAWC;x1ps?L=eCumlLmMN z%YO$S*aJvnx!a2_PSZisy8ViQAIfE_K{Q%cp=K3UzZKK%-M&IOd8L2}swgAr+ z`F;42r9s4?4CFOf3(N8(ZKIq)LeX~cgn7FQH&63`ELvdnEfI9&rzV?~{^{&&u*)xv z*vG0lE-Q*NDLOYqB#*3Zj;eH2XXZ&DFQ z+S10?X6A}hT?PgDY-L_fcu&K-8HqyWEsH}sLqi_{p`R&fvI_v6!=yj%<-t%e0kPp@ zTDzpLUnms7MOyoFm3ahl0Pm#;iG4ZbsN%uSnNpbI1sYMMB z6sM+i92Gm+$xDB9b2dJ})&~SCFwW@tGzkwjuykd${RQ2y@b$%{#2|)3K2e7rnE^AY z)h}2jua75+JcXNAcQr`dK5`-5ywlNPS?i8)m{|itW%w1mZZG1!F6Lw)3-)p@v=}#5 z7uK|^U9&eD3_<+i@#!<#P>XCF3nqnRO(I+FLd`xadN_;6Va11|y-%N_h0}ah;l8B& zreovwb=M-Lz4x%e1c_Ux1Sz5^>-l+4nlDy<3PvP5U#r!&m}BR=KG3-59Y5TB{D$-) zfr#-f$CTBx51-+iMA=y4-Ew8HqSEV@U%w7XiR@;e4WvcN{V6Xwk9o-XZKrGLY9Ns<5%zFVbI^fG zPb;}9MWVAlEvLGp<4VdWxHnk2;NAsrocn=)!PDl*CoKXD>04ZPP(4rsq;}_GdmBQ5 z_d}Bk^?wawVqh#gkfhJyF_XrX`Hna=JTR-5wQg`f*B+$wwuQG*Bl?Ft!$81#B&yy< zvX5WHT0?OBWL?I1T?t&TvZh>I{E-LE!297ey}{xbK&Bj&6xKo>_Vj)|(Vi%&U44`+ zKGs}}Z>N{Ps&ET6l+qTBIp&bX2fD$YprSwMaK z2Y&mj@yV_eg6f8gUaO7Hwx;zdjR8l(3e|a{DmxQ)7Hq9xnOb%>*~jQ2*c+qHg7s)n z3&xD6^7YB6;*V?c*CgE^uD5gq!a_rhAMUQLJBP@0GjIpHG01_NuYi;)h!@Ul06gd} zE)xR)8Jpqvi0eSd>+w{?^EUe2Bt7qI6Q1*?k4i^a&#JJg$hVPmQ}Csup2981Ait?T z4K;QouiE8+tb+dRQgGHT=ha`1ztQJN7a9?J0{|g~)nRMcsq({B>X)RB^Ue~Xq`G;4 z&bdBkmLA`9G0(JhV|U8uedl_)K{Z1eoF^85R=4p!>AaouC39Lmz&`omad}XJd*#{V zgzN*cYJXzo3tM)Fyx-H^C<&T&n}t^6KxVBE_P$M-z*}PlM)QD>h-vI$ecO(bhHa|A zBLFe>>^DJ0@VJwpVoVyuXX@P$PNW`yislA}T5`3WKba9^Z_j_;-#UF>O!QqKKrb2d zCN)0qUi#>?EXp3E?0jx@hc1>*;mHE+Xm-#1bxhPXzt=*xa)u(MmmRRF49Qj8Q+ll{ z>y!q2JB`M)Rs7_Cx{z7y>Dn{0sQAdHUP-a;+CMvI5%&FSX^R%~;ylS46KrWM(-qLXbloahxOwpdV(^hk^m-B8@bf!hZ(3mCMp)iQ67;u$9g%VN2g-?TE*lzTRo zG|l6<#Ya{k@tAo7<5Hxk8zqC;IvqdZbNZ|HNwGXg;)f~TwtTuFN=+WA;Q2mouX)Eh zV98yW7YddRmPr*QeP9J*(Pm(-i}FlsC?HPbU{Gd9wu62EPg4Y=HvpF@3Am899A5gS zSd=c=T0?s$cDE9_1$+ku>)I7Go~}k#~PPM7z-qNr6Xtn0L1J+ zG(X%}@Pwgw2%=#lVfYgwZoI>t_d9_^>=8diN4{F01CQTVcz+*IM`ojIWj_gxk;H;D z9(RK(CKLqtVm`vHV9iaSxVCVrl4_nM*KDIuNXp04l%Q8dQ$5_bamorYl_SE?W8s?~ z8G+;PQ;HwhyD>O+&weuigWQkJ+*Elk$~zxtQMM&%K9Gfc(3$$l>wwr}+itIsA)>=P z;MlGFt3P4q;_IVib=8+wIlL%GFX1!Fto+tgPX$^QA~06#0`a^kR1lhl&Fbz}qT%by zO)g(K(mk1K7JpSV9!;yySp~6d^yxjk>mJl(eNn%3e4Q+}-o>`nXF)*H&$YJ6cRZsi zwL1Hm$$0RNvj&2%JX<+XxE?<@ke0EZwa1X2Uag`_$)l%x?d&HgVCPr$A;E%XIow%f zrKWz^P86S*4fD%UIa+&eRE#x!tD2to3w7M!m~Ko0x>_FE{e4M}%q!q+s}smR{!&eV z?fs2xP)*(`VmSa2pk>>zdooae@$C%4XpWIjFKG$5y53?vte(+zxVUl-;Gq$g9aRVy zUDZn9u$BHZ;{NdoqG#^B*#)lm5pvr%`@#KXcfUMEeU-;FcCEgM2d7uS9`{wZ$vtOa z{pTHkR7tRSI3&B?QS|u+Zo?X1y4`0<)O9b=l8d6ZSNFx}44+X}6xxsm)d0{YzGYwJ zRNg>rGyz?&jTC6k4+I42k=K%9Dj%*-3fUIl|D*yO=GJ8>Rx(<4#ci?N>{&s3RQbl8{Y`-1(M zr0F?Mg4tb<^y$Tq8R~$q!mb~H5fxNLHb0x9ji9D;-0T?jgfG7552P!vgloSD1Cj0u zT%wZ)K*oC{m$mih=q?O~d7PDoZizPo8Q+I)FJtzsVT$ffd(>0zYnVtk%6aW&@AATq zWBtT1&J+_P;T$&mDCE+2?AYN-;>oJ44OkT0-kMi=K`@qzY|hEE$QNCll0G_S&}NE_ zp#8dH$FZQ1C<-18?^~GC`<(M7yF1x}QN6von-JWE;7vOL+&B>ADYatL zb@H9Zq)OdGQrgD$y^DSL(v^Pd-EIM{iR9(i#=}kpr>r)NrodF2QT9Z?w6nUCXIIpX z3S&03Nn}?&A`dHXIreP~@h~^hE#$MB=hjbP+m7UtLbJrShHFESJe&vZ-8`(plAdAh zeUZ4-p80VJ3H35J8L3{-z)|DBnspz&k!snYP6j|m01#{Fp;%J4NmlopmHQx-s-GE8@DJ?UXe}=ekG#?PRuo(Q}`>LNA zlF?8->b}TB=bCjtXm8f8gRaEjqriMHeyxu4To*P&s`t%~bu^0G19z_{H=`<*cdHYY zaJtu~1|M*2NOhGK-t`~7IT>Kn@n9#jcnef$9+&F;;es?txHYlvek^EqcNbadNsw*^ zRwOjIunTFO-+oA{Ao8*vldri`yn@x7>7s^NmkwsTfSdrL49lr{3@)I zR-N!re|$3mtgC8rl>H9mPMQNtYp(q4#_O?~@g@s;x6ACpbu)Au*6~Vph1;H#6Z9th z%`nsrdnm3;f`gB{FSB-|wzL3b^Xb%1TpiPT#$r(a z=(GC`7}dyErYLecGm2Z}WIhi+&tv#2zJt-ljRYzc zrFMYBfgw>vVMAJ#{8tk}e~6&f?3Lsr;YyCIV78;HRUALWmGfKJuO%TqWFD;bdN@IV zO|77TBlZjh);sFuO7e%}nFd9hL^Ke{OQIckzxL4Z6ok%I5?kzAB7l*&`*j(Sn;1}h z2gVC&e7mMrs_$P7vR!$$Iq3wgt!yY>NVHm#B`_P1kvJ{S2h^)EeN1OwCJPnzo9KK^ zfXWj|Lrvj@!i8alf?-m$CE4nPZD_aJ8Diee+TkH~%bp*gq*O&R(7)t;YsF&{^#T#2 zw(j)q@v!1dn0GrRG7DY|>3tUiGm^BR9g9?J>liTGvT9A!C2Y;!bUG}sNP7m~2X z^yof_dfyM`Rd_{RaGH(T*ByU1TOT=;$8&RU_B^|m=5!20q|t%)4`jD|)v1Arvr;uD zFTDEn^$b>(2*Xab@W+S zRifL903j;FIIyq#X7{7uA~ne}f+hIT=l}GcGUhOs9p+KU6Tk*2k0yqbgsVXcwx<#n z+C{YfI&8;t5lZY0#B=BLT7)P(A7-l&15ib7=SIeLZ_nUs2c%z?#qV9kyMb&&`b)xa z+DP7ZOqy_6@plGv*e>KPH@k%j%q!A;Kzi{3^Wx4YvZW)|2)sZb>q#UHqYK>0 zAdSf(g==TUW7+;v8X3RHnwz(CwtrYkG!8uilcJ8Kg_%ka1 zs@i+)=Us6Bu}%i6l~-8r6sEU0A68+9ec6Xzw6``;J)9+nByHQ1XBA3O3ika?Hgauh zTWV z#wpKI`e)d*SBJA%)7~tQ^%*q1F-Dc;b{?mOPb;j? z%@Y=hbZSas&Co8(N1eD5WML`T3O*;7Si|UU{qOHq17p^VNx0@24muX;a;`te4a(SO zKg>Y{16!o*&|>y2l1HSrWlFCHEr*i1dNimh()UPFY5`bG8g=J5tribh1o!aKa z`T;9J?nu1IZtzNCSaX7fwYQqC&$bGm?T?bjO-Fon2jd+k+X=`UnPy7~19}f{mYTF@ z>Mq6w4$e2@U&dEk53RC7abf}{R~AsiHoixh_A1;gNLL+Jmge=RP(>vkq(SBCgnR6k zzH;v5x`@v#=b<`%PJ`vqalDtgnb!1jajr0m8Wak~ z;Gtb${DzJy-iiv~+gBGrO29(UFTh-wUn4-qO}*+mC-9OGDM!PfQ7i&|W}Ezs`1Gv= zum;!Xg^Ds8-2giCxvL7r$ucr+1UGlv5SVw9v`bs<5^?!eg|hh|J*>CDrJ1!@tvC+7 zyuY;N_+({TIG&PvP+1>cJv(nT z9g>YSif34>EiW;R7THobo~f(EGpaCkyZ0+U#9Bkf7ur0ta0L6&sc>B12zl$`(Q`NV z=`)bSu#V;NVJaLyq8b`Ub*l()=P3n^%RtgHw@1=gVXK?gJomr5N&sbYc8hy@)If)- zd0FIoJywBGtQKBwcEl{YVC+98sjc@mTtmaiRPTu6#iM7RV}v~)*67XT7uvc_lZwct z8>mgGG0MN=&IHt)p~-~DJzK7eAeHZ+m`M8cCAb|Mgz=wXQ=qmiZ?GT}$2m9rM#f{d z{=}q2Uzlxa10ViHqzV%r;999aL$^-r`*@sDRizg=dhF!}mzO+2L>k}M5#L2cW>lqo zUHh1V=S&nqJbINw;_BrBpTibLNipuiFJFRFJny8Y4h&ipu=J~AbxLgq{0tIXp)O73 zt4`Wo1>tLBqG@DpVQG;Ss)@y;%G`jgF;uK>%p!lXf%y0;&72Wt<~W^t!h!WVIaHp~ zDweY!u?77qv@1D3opUTFY9y`iW=`!p*do80+3-pcv%cq;$;o!ye@7Fw%aG$p>rU#RJ0VCWB5|>Po532+czudo z+K;_O@nYh^E0g(Mi`VU0T+Pz2_tu^+jkg+N6c|&^d1RAVF~XA#=1cpM6dAB9An)wZ z`VpChz|ogBcA>j95EbzyjcDKswmDC&=yOV^Nu`4yqTaDEN!zcqNrwcHB4WCL?Cl~a zBJ6uK)YUAtdf_FgH71Q!o^H_-l-5Cw&`FUSh<~Jki$7Ut zW;^jB*QuNmH|kA5{@nAM^1X>XUc!v%^3b&}xbfCwKJE)T2>?eo3DA6~DQ zN$&mengEe{ftmWk?k#)uJuuze7aB_B5AuAAW%L7&7P5?PhpU8*mXB-Iv~$VRx25NK zApM-f6&c$A5i(n2WVB)^3vcn6u#0=U1;# z-n(J6+afA+$bN&aWa^IJ5dR6<@I$tHSo`^{u3M>gMu}dwgexM)9+{S>9PB7a*Ao1 z2L+E#ra~M{Zk&F_RN^cteKso>yzZtyX{c$A_qug-8r+;FCPlV{r{3f1`^?RApriNMm*Qun<+{ihyswXQgWxPR z3#-KF(3Cl%3td};(PO){yf;xLX-+sIq~FiqE^G>>b@af%T9%tQnuN@S$a{20&-`qd z)u|(Jv5VZ=2>BHpG1NWfIx!<yyRy*06pENx{&O)A!ZrL4?u zU3b2$JX4}&G`%?=zIKbyV9=%q=C+Yzg3k}!S!~nSW=DVF(Injra%X+)R6=VDjLwnq zO6VZ=Y4-JRngg!`!6!JK3wUkj_c{0Hob&!bFL>UP03pX^j6a+bIX=-b(n3oGw!HYierUa*bX4~Uqk(;6 ziQ70^xv2L?R3fgM@u6RSN}WniM{-(X0QF(_IT`8cLxp$@Mp>zC-VLd6C2K|w3H{EM z=XQEHA#SIB_`Hd8m<4c( zFbzCPGq*K-9lDP7oq3QooL#?ZQFMXYtRbz@0t{^DD)CgE{)Zo#y4WAMxvRNf8N#9K zYm00xt2WJ^7Fr#6Kx93jZi=72Z0b#(?yTZ#4*f^AZBYADLg~fG9Efd$cm5F6$*NTy zp?EYoLL4?1r&~Hwzw-%mbudehIDCyZVRGx1OmM*NTXO9$*<&zx=cC2=q+r|jqLyJH zdN#!BxZQt?yYFlsl~4qf$-~QpZ_9hLuSYgf7K3M~OOy=K`lW^%O8u8ismh#u{j5X~ zIPpGAOZH(O=49FVr=D_iLTXoc2y&0dviR)e;Dog?oim{I*zzEMjF&1tyt_?FvW;C- zsKsZo%(w-ojKNGqB#D_YGDD4;MK0aSHF-3C^uSgr1-BQ6D!*QnouXX&0;pYZ%eG3r z!YvQ>YV%S9oer+u-6p+kejg0<`%H_6UJ9_sM1D7SiW_3jXg3RiUfr5tPlZqr?|?TX zQS}}^tayCUCH7?}My8|8*JI{)*-?&MfY8}qTf6TGND&s+b8KdxPr0d|v30bbJ-cD? zqb4${UMKEhj-`@A-vpmF>c@TvLR&{oFetsmq6TzEiC+|%n`*jkU59k2YZ%;OKr5Ui z44F8+C86p)w0~{Y3XEW2GxeCs9OoLmNI~^Jbdi}s)KhAbH@y_H*_7|GxY9v{HfxVoI~F2vv_rz$wYr4P>2hLjWcuOzoHzGnfCWOP!%cP?a~nRQ?uLGPVfR5h z^AU?ej;V>x+5wUr;8z~%I9iWl>i4taFwsx?{-)^(UwlW9ZhYN#AKPALrTq+)%o=q5 zmMIBv3SObw*bv_KEw@KmVI{wDxiIzvsYY5vgsFLccO8)L_bcuE1%SF?XYi}SL)P7$ zK7K@Z8qY=XDtlmfcb}Qe^A~tc_SdB1NMIq3Yu_mdDH~@Cy!Q*#I(sL3Iy4Pb>Zr!+ zdRItoC44S%*!OC{)i?R0rM{P!w9$IL8kb*`S>Y8n`(^T6v>|O4$>(15oH|#{C4VNf zP}__^o_*L8s3xnSzyB1r9~?7;nLf?(gZ%ipD)u7OeeDJcqmbZw#-T#2_8zNut?hp3 zkV|?040D?G+`tX9f+jj<=`KH{fH6U)l@s1xa}kIE&Zz+EatuYhY3c(BQ#}jHO)!3S zUhfz*Eifc`nca8lv2`pzWD;b{PSTS$;5IhJP+y)JG72B@eI%9b`9u4oXXO%&C52j5 zt`H%*(OrQ0&D{#%O_SR@)0foSg!Vuvde&XQ<;|o+hk0`|X3j;et@YpOk#-m|b?b3Y z=0NJ^u1|cs3oJ?Xv4<7WX8%NfyhP+*DEXvwxBKLaa`}#XCEII%bx`V99Xh za6ap+OQZa|5;xKjvt5OA(R|bH&{psnv9+QAWh0+nJ{MGbmb7ZoF*$`Xs@|?M&sqUS z&Tn9EFc<&o?T2|!_>75C%;}G$l0O$^iAT?8->($0(kd^g`KxnU|7|!Z*R;B50y+su z;O86t>=-eBKuOlt-9KtRTt^!(DpAxU?}hgxe)th4cy#pEB-i@#E zR(7+D>K?O!IegTgLE^4Kb!L`VqU#bSOoKSbrft%B*`xW(um7){4~=@X`-KT*1{HkD zIUY63-lXiTBOwi3XlKJS|E^`o6+-gX)N=x-^)9%cUPPQg`n0(_kVzAsFv)z|4K^FO zuI})vzgLC)AM(K=TnnV*X`IEzu~ip08Taai-~s+E>s9_)pz9avED}ooy&=Ng7|8L zV@2cXT_ik>5<#SZDua{#EM&f$cRuD_Do{Z*Z-!RcMKZ#eggvA@$Y6Q@gJ++E@i)8H zi~p7Z3f8@c1}rBhMaIJ&g&cJs+*xny++Whe1}ADYxd7u}aOQ~H?pz_(6W9TNT{hV& z0o2B*mEIZ-d4A_?)!eYi%3~std6Fbu@OL`Yo4(b%A7%B^pIqBT{w8}+7~S%!VyC`) z`z-=EF@I>`mDS#EMw=ra5SpTVAnWSPIjMF^n|9w`&g}$H*fJQT&qSd3;e8tLbsFDW zgdMLYGob5VOa)J7B-9!^^zJ4umk4cP?j+jguBI);1UWk|-=#E|6gzJWx;*NBFvW-Q z4o>=Y{M09}E=^1M#c?j;)3-ZSHlhMvx*a`F6}+GJy`mhv6=}3oiP{Y23_rPVguF3g z@KS7jH49*icb?Y|&aR89e0>nzTIkGtbKObMaews35gvQJ)qjX-ZA)S%sXT*KsDmzi z;g@I5#}IyvIC8tuIi?tCVyn6VtvmmBzDsj@IQP9V1INZh&HeJp9+xAdrjHYbQB2MI zso7X(Pk9QNA=_HSckfclXM*8KDY#i*D4Hq=3@NDaA#-O{;7G*4Puk;?;A?SmSFVk% z8-h?0IGRYKjU%>}{cC4h)?}a+zVQpk5|AX2rEtUc*LbMl%tidr*gCf2ASa6dD@|~{ zmJ%*;r1QUa;2pVMF0=d9 zHP~5NyBuJ6=mT_7R%F%){pQESt5@nkPJP22gGoA)p#`s*-EyfzdLU_`k6!&SK*C~9PX_hKAtE00jY{@4T~>E zWfG>lNnBY<(|U{4cG%u`riik85t_FV*?dh%!%5C}#;;qnXjR&j+9%lTTWo@*;LU3X&I)wIHaj>E)c6 z(Ce5j7v+_m<|S6z_*-+*MW&NV&|R0JZW98*TKv8RK1=XGHWsJv6~}@WD|VwY%wJ;n zi@qR41Bq0;Z*(Vu)bAut$7`D9GK;*;ZvIU&!zMO-C4}noL!-HWzt0)nlQ!RNny=j4 zh=f#SG_l+(~Oqb=>`JRLnE6V)T8W7*6ZL$B)>E4G_06Z!b0*|C)9+%P$PC)LsjW5j@zUBVj9AdARrll?P zmz~=trmLqe?GJJPu7myout@qI$CIu@z2%*pZs1^!GAba6%Xs5X^*ys7@3pw?wT-Ve zD~n%1VZExpaoK{-GyKV@$m!Tz>+H(M@e?<=o&uW{@u9j&e`)lSUV&3TC|1K6wHTf@ zm=)S(^+_0B0TJ%&{6E+k9P9+fOBPup$;PANH@ySD1tfL3=q{vtn%9_|dnTVw=fWdz z;e$jqko|r~1HuKYnTq zsTJI*3(kZuiHaeg^}aNOlX%4V;mI&lls+PvfvCA`ka0I(91CBI4%V;`*W#@OHT(7? z=^($96RK9#5mm-uUikC8I4O}jiB>kW@tF#}@X5O*eXb)D>u0sRI~{_hJ8Z>L@;VbP z=m$Xly%K=4G$bLUEFX+E77k2(ZWtpqU*&ZCsgetNodePrivilegeRoleSchema('', treeNodeInfo, itemNodeData, privileges), ()=>getNodeVacuumSettingsSchema(this, treeNodeInfo, itemNodeData), @@ -142,6 +143,16 @@ define('pgadmin.node.mview', [ return (m.label != 'pg_global'); }), table_amname_list: ()=>getNodeAjaxOptions('get_access_methods', this, treeNodeInfo, itemNodeData), + extensionsList:()=>getNodeAjaxOptions('nodes', nodeObj, treeNodeInfo, itemNodeData, { cacheLevel: 'server'}, + (data)=>{ + let res = []; + if (data && _.isArray(data)) { + _.each(data, function(d) { + res.push({label: d.label, value: d.label, data: d}); + }); + } + return res; + }), nodeInfo: treeNodeInfo, }, { diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.ui.js b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.ui.js index f5875c949fe..e56620e77e1 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.ui.js +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/static/js/mview.ui.js @@ -106,7 +106,23 @@ export default class MViewSchema extends BaseUISchema { id: 'fillfactor', label: gettext('Fill factor'), group: gettext('Definition'), mode: ['edit', 'create'], noEmpty: false, type: 'int', controlProps: {min: 10, max: 100} - },{ + }, + { + id: 'dependsonextensions', + label: gettext('Depends on extensions'), + group: gettext('Definition'), + type: 'select', + options: this.fieldOptions.extensionsList, + controlProps: { + multiple: true, + allowClear: true, + allowSelectAll: true, + placeholder: gettext('Select the Depends on extensions...'), + }, + min_version: 130000, + mode: ['create', 'edit', 'properties'] + }, + { id: 'vacuum_settings_str', label: gettext('Storage settings'), type: 'multiline', group: gettext('Definition'), mode: ['properties'], },{ diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/13_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/13_plus/sql/create.sql new file mode 100644 index 00000000000..67b6111e02d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/13_plus/sql/create.sql @@ -0,0 +1,57 @@ +{# ===================== Create new view ===================== #} +{% if display_comments %} +-- View: {{ data.schema }}.{{ data.name }} + +-- DROP MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE MATERIALIZED VIEW{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{ conn|qtIdent(data.schema, data.name) }} +{% if data.default_amname and data.default_amname != data.amname %} +USING {{data.amname}} +{% elif not data.default_amname and data.amname %} +USING {{data.amname}} +{% endif %} +{% if(data.fillfactor or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') or data['vacuum_data']|length > 0) %} +{% set ns = namespace(add_comma=false) %} +WITH ( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% set ns.add_comma = true%}{% endif %}{% if data.autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %}{% if data.toast_autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %} +{% for field in data['vacuum_data'] %} +{% if field.value is defined and field.value != '' and field.value != none %} +{% if ns.add_comma %}, +{% endif %} {{ field.name }} = {{ field.value|lower }}{% set ns.add_comma = true%}{% endif %}{% endfor %} +{{ '\n' }}) +{% endif %} +{% if data.spcname %}TABLESPACE {{ data.spcname }} +{% endif %}AS +{{ data.definition.rstrip(';') }} +{% if data.with_data %} +WITH DATA; +{% else %} +WITH NO DATA; +{% endif %} +{% if data.owner %} + +ALTER TABLE IF EXISTS {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.dependsonextensions %} +{% for ext in data.dependsonextensions %} + +ALTER MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} + DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }}; +{% endfor %} +{% endif %} +{% if data.comment %} + +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral(conn) }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/13_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/13_plus/sql/properties.sql new file mode 100644 index 00000000000..ae9406471a6 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/13_plus/sql/properties.sql @@ -0,0 +1,118 @@ +{# ========================== Fetch Materialized View Properties ========================= #} +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relname AS name, + c.reltablespace AS spcoid, + c.relispopulated AS with_data, + CASE WHEN length(spcname::text) > 0 THEN spcname ELSE + (SELECT sp.spcname FROM pg_catalog.pg_database dtb + JOIN pg_catalog.pg_tablespace sp ON dtb.dattablespace=sp.oid + WHERE dtb.oid = {{ did }}::oid) + END as spcname, + (SELECT st.setting from pg_catalog.pg_show_all_settings() st + WHERE st.name = 'default_table_access_method') as default_amname, + c.relacl, + nsp.nspname as schema, + pg_catalog.pg_get_userbyid(c.relowner) AS owner, + description AS comment, + ( + SELECT array_agg(DISTINCT e.extname) + FROM pg_depend d + JOIN pg_extension e ON d.refobjid = e.oid + WHERE d.objid = c.oid + ) AS dependsonextensions, + pg_catalog.pg_get_viewdef(c.oid, true) AS definition, + {# ============= Checks if it is system view ================ #} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} + pg_catalog.array_to_string(c.relacl::text[], ', ') AS acl, + (SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_seclabels sl1 WHERE sl1.objoid=c.oid AND sl1.objsubid=0) AS seclabels, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'fillfactor=([0-9]*)') AS fillfactor, + (substring(pg_catalog.array_to_string(c.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS autovacuum_enabled, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age, + (substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS toast_autovacuum_enabled, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, + c.reloptions AS reloptions, tst.reloptions AS toast_reloptions, am.amname, + (CASE WHEN c.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable +FROM + pg_catalog.pg_class c +LEFT OUTER JOIN pg_catalog.pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_catalog.pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = c.reltoastrelid +LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = c.relam + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_catalog.pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (pg_catalog.bpchar(r.ev_type) = '1'::bpchar)) ))) + AND (c.relkind = 'm'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid +ORDER BY + c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_catalog.pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_catalog.pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/13_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/13_plus/sql/update.sql new file mode 100644 index 00000000000..2c2d3501cdf --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/13_plus/sql/update.sql @@ -0,0 +1,221 @@ +{# ===================== Update View ===================#} +{% import 'macros/schemas/security.macros' as SECLABEL %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{%- if data -%} +{% set view_name = data.name if data.name else o_data.name %} +{% set view_schema = data.schema if data.schema else o_data.schema %} +{% set def = data.definition.rstrip(';') if data.definition %} +{# ===== Rename mat view ===== #} +{% if data.name and data.name != o_data.name %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(o_data.schema, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; + +{% endif %} +{# ===== Alter schema view ===== #} +{% if data.schema and data.schema != o_data.schema %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(o_data.schema, view_name ) }} + SET SCHEMA {{ conn|qtIdent(data.schema) }}; + +{% endif %} +{# ===== Alter Table owner ===== #} +{% if data.owner and data.owner != o_data.owner %} +ALTER TABLE IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; + +{% endif %} +{# ===== First Drop and then create mat view ===== #} +{% if def and def != o_data.definition.rstrip(';') %} +DROP MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }}; +CREATE MATERIALIZED VIEW IF NOT EXISTS {{ conn|qtIdent(view_schema, view_name) }} +{% if data.amname and data.amname != o_data.amname %} +USING {{ data.amname }} +{% endif %} +{% if data.fillfactor or o_data.fillfactor %} +WITH( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} +{% elif o_data.fillfactor %} + FILLFACTOR = {{ o_data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} +{% endif %} + +{% if data['vacuum_data']['changed']|length > 0 %} +{% for field in data['vacuum_data']['changed'] %} {{ field.name }} = {{ field.value|lower }}{% if not loop.last %}, +{% endif %} +{% endfor %} +{% endif %} +) +{% endif %} + AS +{{ def }} +{% if data.with_data is defined %} + WITH {{ 'DATA' if data.with_data else 'NO DATA' }}; +{% elif o_data.with_data is defined %} + WITH {{ 'DATA' if o_data.with_data else 'NO DATA' }}; + +{% endif %} +{% if o_data.owner and not data.owner %} +ALTER TABLE IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + OWNER TO {{ conn|qtIdent(o_data.owner) }}; + +{% endif %} +{% if o_data.comment and not data.comment %} +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + IS {{ o_data.comment|qtLiteral(conn) }}; +{% endif %} +{% else %} +{# ======= Alter Tablespace ========= #} +{%- if data.spcname and o_data.spcname != data.spcname -%} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + SET TABLESPACE {{ data.spcname }}; + +{% endif %} +{# ======= SET/RESET Fillfactor ========= #} +{% if data.fillfactor and o_data.fillfactor != data.fillfactor %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} +SET( + FILLFACTOR = {{ data.fillfactor }} +); + +{% elif data.fillfactor == '' and o_data.fillfactor|default('', 'true') != data.fillfactor %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} +RESET( + FILLFACTOR +); + +{% endif %} +{# ===== Check for with_data property ===== #} +{% if data.with_data is defined and o_data.with_data|lower != data.with_data|lower %} +REFRESH MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} WITH{{ ' NO' if data.with_data|lower == 'false' else '' }} DATA; + +{% endif %} +{# ===== Check for Autovacuum options ===== #} +{% if data.autovacuum_custom is defined and data.autovacuum_custom == False %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} RESET( + autovacuum_enabled, + autovacuum_vacuum_threshold, + autovacuum_analyze_threshold, + autovacuum_vacuum_scale_factor, + autovacuum_analyze_scale_factor, + autovacuum_vacuum_cost_delay, + autovacuum_vacuum_cost_limit, + autovacuum_freeze_min_age, + autovacuum_freeze_max_age, + autovacuum_freeze_table_age +); + +{% endif %} + +{% if data.toast_autovacuum is defined and data.toast_autovacuum == False %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} RESET( + toast.autovacuum_enabled, + toast.autovacuum_vacuum_threshold, + toast.autovacuum_analyze_threshold, + toast.autovacuum_vacuum_scale_factor, + toast.autovacuum_analyze_scale_factor, + toast.autovacuum_vacuum_cost_delay, + toast.autovacuum_vacuum_cost_limit, + toast.autovacuum_freeze_min_age, + toast.autovacuum_freeze_max_age, + toast.autovacuum_freeze_table_age +); + +{% endif %}{#-- toast_endif ends --#} +{% if data['vacuum_data']['changed']|length > 0 or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(data.schema, data.name) }} SET( +{% if data.autovacuum_enabled in ('t', 'f') %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if data['vacuum_data']['changed']|length > 0 or data.toast_autovacuum_enabled in ('t', 'f') %}, +{% endif %} +{% endif %} +{% if data.toast_autovacuum_enabled in ('t', 'f') %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if data['vacuum_data']['changed']|length > 0 %}, +{% endif %} +{% endif %} +{% for field in data['vacuum_data']['changed'] %} +{% if field.value != None %} {{ field.name }} = {{ field.value|lower }}{% if not loop.last %}, +{% endif %} +{% endif %} +{% endfor %} + +); +{% endif %} +{% if data['vacuum_data']['reset']|length > 0 or data.autovacuum_enabled == 'x' or data.toast_autovacuum_enabled == 'x' %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} RESET( +{% if data.autovacuum_enabled == 'x' %} + autovacuum_enabled{% if data['vacuum_data']['reset']|length > 0 or data.toast_autovacuum_enabled == 'x' %}, +{% endif %} +{% endif %} +{% if data.toast_autovacuum_enabled == 'x' %} + toast.autovacuum_enabled{% if data['vacuum_data']['reset']|length > 0 %}, +{% endif %} +{% endif %} +{% for field in data['vacuum_data']['reset'] %} {{ field.name }}{% if not loop.last %}, +{% endif %} +{% endfor %} + +); +{% endif %} +{# ===== End check for custom autovacuum ===== #} +{% endif %}{# ===== End block for check data definition ===== #} +{% set old_comment = o_data.comment|default('', true) %} +{% if (data.comment is defined and (data.comment != old_comment)) %} + +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + IS {{ data.comment|qtLiteral(conn) }}; +{% endif %} +{# ============= The SQL generated below will change privileges ============= #} +{% if data.datacl %} +{% if 'deleted' in data.datacl %} +{% for priv in data.datacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.datacl %} +{% for priv in data.datacl.changed -%} +{% if priv.grantee != priv.old_grantee %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.old_grantee, data.name, data.schema) }} +{% else %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endif %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{%- endfor %} +{% endif %} +{% if 'added' in data.datacl %} +{% for priv in data.datacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{# ============== The SQL generated below will change Security Label ========= #} +{% if data.seclabels is not none and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABEL.UNSET(conn, 'MATERIALIZED VIEW', data.name, r.provider, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABEL.SET(conn, 'MATERIALIZED VIEW', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABEL.SET(conn, 'MATERIALIZED VIEW', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{% set old_exts = (o_data.dependsonextensions or []) | list %} +{% set new_exts = data.dependsonextensions if 'dependsonextensions' in data else None %} +{% if new_exts is not none and old_exts != new_exts %} +{% for ext in (old_exts + new_exts) | unique %} + +{% if ext in new_exts and ext not in old_exts %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }}; +{% elif ext in old_exts and ext not in new_exts %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + NO DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }}; +{% endif %} +{% endfor %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/create.sql new file mode 100644 index 00000000000..67b6111e02d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/create.sql @@ -0,0 +1,57 @@ +{# ===================== Create new view ===================== #} +{% if display_comments %} +-- View: {{ data.schema }}.{{ data.name }} + +-- DROP MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE MATERIALIZED VIEW{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{ conn|qtIdent(data.schema, data.name) }} +{% if data.default_amname and data.default_amname != data.amname %} +USING {{data.amname}} +{% elif not data.default_amname and data.amname %} +USING {{data.amname}} +{% endif %} +{% if(data.fillfactor or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') or data['vacuum_data']|length > 0) %} +{% set ns = namespace(add_comma=false) %} +WITH ( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% set ns.add_comma = true%}{% endif %}{% if data.autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %}{% if data.toast_autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %} +{% for field in data['vacuum_data'] %} +{% if field.value is defined and field.value != '' and field.value != none %} +{% if ns.add_comma %}, +{% endif %} {{ field.name }} = {{ field.value|lower }}{% set ns.add_comma = true%}{% endif %}{% endfor %} +{{ '\n' }}) +{% endif %} +{% if data.spcname %}TABLESPACE {{ data.spcname }} +{% endif %}AS +{{ data.definition.rstrip(';') }} +{% if data.with_data %} +WITH DATA; +{% else %} +WITH NO DATA; +{% endif %} +{% if data.owner %} + +ALTER TABLE IF EXISTS {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.dependsonextensions %} +{% for ext in data.dependsonextensions %} + +ALTER MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} + DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }}; +{% endfor %} +{% endif %} +{% if data.comment %} + +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral(conn) }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/properties.sql new file mode 100644 index 00000000000..ae9406471a6 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/properties.sql @@ -0,0 +1,118 @@ +{# ========================== Fetch Materialized View Properties ========================= #} +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relname AS name, + c.reltablespace AS spcoid, + c.relispopulated AS with_data, + CASE WHEN length(spcname::text) > 0 THEN spcname ELSE + (SELECT sp.spcname FROM pg_catalog.pg_database dtb + JOIN pg_catalog.pg_tablespace sp ON dtb.dattablespace=sp.oid + WHERE dtb.oid = {{ did }}::oid) + END as spcname, + (SELECT st.setting from pg_catalog.pg_show_all_settings() st + WHERE st.name = 'default_table_access_method') as default_amname, + c.relacl, + nsp.nspname as schema, + pg_catalog.pg_get_userbyid(c.relowner) AS owner, + description AS comment, + ( + SELECT array_agg(DISTINCT e.extname) + FROM pg_depend d + JOIN pg_extension e ON d.refobjid = e.oid + WHERE d.objid = c.oid + ) AS dependsonextensions, + pg_catalog.pg_get_viewdef(c.oid, true) AS definition, + {# ============= Checks if it is system view ================ #} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} + pg_catalog.array_to_string(c.relacl::text[], ', ') AS acl, + (SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_seclabels sl1 WHERE sl1.objoid=c.oid AND sl1.objsubid=0) AS seclabels, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'fillfactor=([0-9]*)') AS fillfactor, + (substring(pg_catalog.array_to_string(c.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS autovacuum_enabled, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age, + (substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS toast_autovacuum_enabled, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, + c.reloptions AS reloptions, tst.reloptions AS toast_reloptions, am.amname, + (CASE WHEN c.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable +FROM + pg_catalog.pg_class c +LEFT OUTER JOIN pg_catalog.pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_catalog.pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = c.reltoastrelid +LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = c.relam + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_catalog.pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (pg_catalog.bpchar(r.ev_type) = '1'::bpchar)) ))) + AND (c.relkind = 'm'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid +ORDER BY + c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_catalog.pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_catalog.pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/update.sql index ca6ba22b2e5..5e0b0a2b6c4 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/update.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/pg/15_plus/sql/update.sql @@ -211,4 +211,19 @@ COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} {% endfor %} {% endif %} {% endif %} +{% set old_exts = (o_data.dependsonextensions or []) | list %} +{% set new_exts = data.dependsonextensions if 'dependsonextensions' in data else None %} +{% if new_exts is not none and old_exts != new_exts %} +{% for ext in (old_exts + new_exts) | unique %} + +{% if ext in new_exts and ext not in old_exts %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }}; +{% elif ext in old_exts and ext not in new_exts %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + NO DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }}; +{% endif %} +{% endfor %} +{% endif %} + {% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/13_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/13_plus/sql/create.sql new file mode 100644 index 00000000000..3bea9ebfaac --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/13_plus/sql/create.sql @@ -0,0 +1,57 @@ +{# ===================== Create new view ===================== #} +{% if display_comments %} +-- View: {{ data.schema }}.{{ data.name }} + +-- DROP MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE MATERIALIZED VIEW{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{ conn|qtIdent(data.schema, data.name) }} +{% if data.default_amname and data.default_amname != data.amname %} +USING {{data.amname}} +{% elif not data.default_amname and data.amname %} +USING {{data.amname}} +{% endif %} +{% if(data.fillfactor or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') or data['vacuum_data']|length > 0) %} +{% set ns = namespace(add_comma=false) %} +WITH ( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% set ns.add_comma = true%}{% endif %}{% if data.autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %}{% if data.toast_autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %} +{% for field in data['vacuum_data'] %} +{% if field.value is defined and field.value != '' and field.value != none %} +{% if ns.add_comma %}, +{% endif %} {{ field.name }} = {{ field.value|lower }}{% set ns.add_comma = true%}{% endif %}{% endfor %} +{{ '\n' }}) +{% endif %} +{% if data.spcname %}TABLESPACE {{ data.spcname }} +{% endif %}AS +{{ data.definition.rstrip(';') }} +{% if data.with_data %} +WITH DATA; +{% else %} +WITH NO DATA; +{% endif %} +{% if data.owner %} + +ALTER TABLE IF EXISTS {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.dependsonextensions %} +{% for ext in data.dependsonextensions %} + +ALTER MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} + DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }}; +{% endfor %} +{% endif %} +{% if data.comment %} + +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral(conn) }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/13_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/13_plus/sql/properties.sql new file mode 100644 index 00000000000..2d5c91a8d47 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/13_plus/sql/properties.sql @@ -0,0 +1,118 @@ +{# ========================== Fetch Materialized View Properties ========================= #} +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relname AS name, + c.reltablespace AS spcoid, + c.relispopulated AS with_data, + CASE WHEN length(spcname::text) > 0 THEN spcname ELSE + (SELECT sp.spcname FROM pg_catalog.pg_database dtb + JOIN pg_catalog.pg_tablespace sp ON dtb.dattablespace=sp.oid + WHERE dtb.oid = {{ did }}::oid) + END as spcname, + (SELECT st.setting from pg_catalog.pg_show_all_settings() st + WHERE st.name = 'default_table_access_method') as default_amname, + c.relacl, + nsp.nspname as schema, + pg_catalog.pg_get_userbyid(c.relowner) AS owner, + description AS comment, + ( + SELECT array_agg(DISTINCT e.extname) + FROM pg_depend d + JOIN pg_extension e ON d.refobjid = e.oid + WHERE d.objid = c.oid + ) AS dependsonextensions, + pg_catalog.pg_get_viewdef(c.oid) AS definition, + {# ============= Checks if it is system view ================ #} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} + pg_catalog.array_to_string(c.relacl::text[], ', ') AS acl, + (SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_seclabels sl1 WHERE sl1.objoid=c.oid AND sl1.objsubid=0) AS seclabels, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'fillfactor=([0-9]*)') AS fillfactor, + (substring(pg_catalog.array_to_string(c.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS autovacuum_enabled, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age, + (substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS toast_autovacuum_enabled, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, + c.reloptions AS reloptions, tst.reloptions AS toast_reloptions, am.amname, + (CASE WHEN c.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable +FROM + pg_catalog.pg_class c +LEFT OUTER JOIN pg_catalog.pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_catalog.pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = c.reltoastrelid +LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = c.relam + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_catalog.pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (pg_catalog.bpchar(r.ev_type) = '1'::bpchar)) ))) + AND (c.relkind = 'm'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid +ORDER BY + c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_catalog.pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_catalog.pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/13_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/13_plus/sql/update.sql new file mode 100644 index 00000000000..840135c546d --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/13_plus/sql/update.sql @@ -0,0 +1,221 @@ +{# ===================== Update View ===================#} +{% import 'macros/schemas/security.macros' as SECLABEL %} +{% import 'macros/schemas/privilege.macros' as PRIVILEGE %} +{%- if data -%} +{% set view_name = data.name if data.name else o_data.name %} +{% set view_schema = data.schema if data.schema else o_data.schema %} +{% set def = data.definition.rstrip(';') if data.definition %} +{# ===== Rename mat view ===== #} +{% if data.name and data.name != o_data.name %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(o_data.schema, o_data.name) }} + RENAME TO {{ conn|qtIdent(data.name) }}; + +{% endif %} +{# ===== Alter schema view ===== #} +{% if data.schema and data.schema != o_data.schema %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(o_data.schema, view_name ) }} + SET SCHEMA {{ conn|qtIdent(data.schema) }}; + +{% endif %} +{# ===== Alter Table owner ===== #} +{% if data.owner and data.owner != o_data.owner %} +ALTER TABLE IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; + +{% endif %} +{# ===== First Drop and then create mat view ===== #} +{% if def and def != o_data.definition.rstrip(';') %} +DROP MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }}; +CREATE MATERIALIZED VIEW IF NOT EXISTS {{ conn|qtIdent(view_schema, view_name) }} +{% if data.amname and data.amname != o_data.amname %} +USING {{ data.amname }} +{% endif %} +{% if data.fillfactor or o_data.fillfactor %} +WITH( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} +{% elif o_data.fillfactor %} + FILLFACTOR = {{ o_data.fillfactor }}{% if (data['vacuum_data'] is defined and data['vacuum_data']['changed']|length > 0) %},{% endif %} +{% endif %} + +{% if data['vacuum_data']['changed']|length > 0 %} +{% for field in data['vacuum_data']['changed'] %} {{ field.name }} = {{ field.value|lower }}{% if not loop.last %}, +{% endif %} +{% endfor %} +{% endif %} +) +{% endif %} + AS +{{ def }} +{% if data.with_data is defined %} + WITH {{ 'DATA' if data.with_data else 'NO DATA' }}; +{% elif o_data.with_data is defined %} + WITH {{ 'DATA' if o_data.with_data else 'NO DATA' }}; + +{% endif %} +{% if o_data.owner and not data.owner %} +ALTER TABLE IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + OWNER TO {{ conn|qtIdent(o_data.owner) }}; + +{% endif %} +{% if o_data.comment and not data.comment %} +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + IS {{ o_data.comment|qtLiteral(conn) }}; +{% endif %} +{% else %} +{# ======= Alter Tablespace ========= #} +{%- if data.spcoid and o_data.spcoid != data.spcoid -%} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} + SET TABLESPACE {{ data.spcoid }}; + +{% endif %} +{# ======= SET/RESET Fillfactor ========= #} +{% if data.fillfactor and o_data.fillfactor != data.fillfactor %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} +SET( + FILLFACTOR = {{ data.fillfactor }} +); + +{% elif data.fillfactor == '' and o_data.fillfactor|default('', 'true') != data.fillfactor %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} +RESET( + FILLFACTOR +); + +{% endif %} +{# ===== Check for with_data property ===== #} +{% if data.with_data is defined and o_data.with_data|lower != data.with_data|lower %} +REFRESH MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} WITH{{ ' NO' if data.with_data|lower == 'false' else '' }} DATA; + +{% endif %} +{# ===== Check for Autovacuum options ===== #} +{% if data.autovacuum_custom is defined and data.autovacuum_custom == False %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} RESET( + autovacuum_enabled, + autovacuum_vacuum_threshold, + autovacuum_analyze_threshold, + autovacuum_vacuum_scale_factor, + autovacuum_analyze_scale_factor, + autovacuum_vacuum_cost_delay, + autovacuum_vacuum_cost_limit, + autovacuum_freeze_min_age, + autovacuum_freeze_max_age, + autovacuum_freeze_table_age +); + +{% endif %} + +{% if data.toast_autovacuum is defined and data.toast_autovacuum == False %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} RESET( + toast.autovacuum_enabled, + toast.autovacuum_vacuum_threshold, + toast.autovacuum_analyze_threshold, + toast.autovacuum_vacuum_scale_factor, + toast.autovacuum_analyze_scale_factor, + toast.autovacuum_vacuum_cost_delay, + toast.autovacuum_vacuum_cost_limit, + toast.autovacuum_freeze_min_age, + toast.autovacuum_freeze_max_age, + toast.autovacuum_freeze_table_age +); + +{% endif %}{#-- toast_endif ends --#} +{% if data['vacuum_data']['changed']|length > 0 or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(data.schema, data.name) }} SET( +{% if data.autovacuum_enabled in ('t', 'f') %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if data['vacuum_data']['changed']|length > 0 or data.toast_autovacuum_enabled in ('t', 'f') %}, +{% endif %} +{% endif %} +{% if data.toast_autovacuum_enabled in ('t', 'f') %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}true{% else %}false{% endif %}{% if data['vacuum_data']['changed']|length > 0 %}, +{% endif %} +{% endif %} +{% for field in data['vacuum_data']['changed'] %} +{% if field.value != None %} {{ field.name }} = {{ field.value|lower }}{% if not loop.last %}, +{% endif %} +{% endif %} +{% endfor %} + +); +{% endif %} +{% if data['vacuum_data']['reset']|length > 0 or data.autovacuum_enabled == 'x' or data.toast_autovacuum_enabled == 'x' %} +ALTER MATERIALIZED VIEW IF EXISTS {{ conn|qtIdent(view_schema, view_name) }} RESET( +{% if data.autovacuum_enabled == 'x' %} + autovacuum_enabled{% if data['vacuum_data']['reset']|length > 0 or data.toast_autovacuum_enabled == 'x' %}, +{% endif %} +{% endif %} +{% if data.toast_autovacuum_enabled == 'x' %} + toast.autovacuum_enabled{% if data['vacuum_data']['reset']|length > 0 %}, +{% endif %} +{% endif %} +{% for field in data['vacuum_data']['reset'] %} {{ field.name }}{% if not loop.last %}, +{% endif %} +{% endfor %} + +); +{% endif %} +{# ===== End check for custom autovacuum ===== #} +{% endif %}{# ===== End block for check data definition ===== #} +{% set old_comment = o_data.comment|default('', true) %} +{% if (data.comment is defined and (data.comment != old_comment)) %} + +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + IS {{ data.comment|qtLiteral(conn) }}; +{% endif %} +{# ============= The SQL generated below will change privileges ============= #} +{% if data.datacl %} +{% if 'deleted' in data.datacl %} +{% for priv in data.datacl.deleted %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in data.datacl %} +{% for priv in data.datacl.changed -%} +{% if priv.grantee != priv.old_grantee %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.old_grantee, data.name, data.schema) }} +{% else %} +{{ PRIVILEGE.UNSETALL(conn, 'TABLE', priv.grantee, data.name, data.schema) }} +{% endif %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{%- endfor %} +{% endif %} +{% if 'added' in data.datacl %} +{% for priv in data.datacl.added %} +{{ PRIVILEGE.SET(conn, 'TABLE', priv.grantee, data.name, priv.without_grant, priv.with_grant, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{# ============== The SQL generated below will change Security Label ========= #} +{% if data.seclabels is not none and data.seclabels|length > 0 %} +{% set seclabels = data.seclabels %} +{% if 'deleted' in seclabels and seclabels.deleted|length > 0 %} +{% for r in seclabels.deleted %} +{{ SECLABEL.UNSET(conn, 'MATERIALIZED VIEW', data.name, r.provider, data.schema) }} +{% endfor %} +{% endif %} +{% if 'added' in seclabels and seclabels.added|length > 0 %} +{% for r in seclabels.added %} +{{ SECLABEL.SET(conn, 'MATERIALIZED VIEW', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% if 'changed' in seclabels and seclabels.changed|length > 0 %} +{% for r in seclabels.changed %} +{{ SECLABEL.SET(conn, 'MATERIALIZED VIEW', data.name, r.provider, r.label, data.schema) }} +{% endfor %} +{% endif %} +{% endif %} +{% set old_exts = (o_data.dependsonextensions or []) | list %} +{% set new_exts = data.dependsonextensions if 'dependsonextensions' in data else None %} +{% if new_exts is not none and old_exts != new_exts %} +{% for ext in (old_exts + new_exts) | unique %} + +{% if ext in new_exts and ext not in old_exts %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }}; +{% elif ext in old_exts and ext not in new_exts %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + NO DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }}; +{% endif %} +{% endfor %} +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/create.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/create.sql new file mode 100644 index 00000000000..3bea9ebfaac --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/create.sql @@ -0,0 +1,57 @@ +{# ===================== Create new view ===================== #} +{% if display_comments %} +-- View: {{ data.schema }}.{{ data.name }} + +-- DROP MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }}; + +{% endif %} +{% if data.name and data.schema and data.definition %} +CREATE MATERIALIZED VIEW{% if add_not_exists_clause %} IF NOT EXISTS{% endif %} {{ conn|qtIdent(data.schema, data.name) }} +{% if data.default_amname and data.default_amname != data.amname %} +USING {{data.amname}} +{% elif not data.default_amname and data.amname %} +USING {{data.amname}} +{% endif %} +{% if(data.fillfactor or data.autovacuum_enabled in ('t', 'f') or data.toast_autovacuum_enabled in ('t', 'f') or data['vacuum_data']|length > 0) %} +{% set ns = namespace(add_comma=false) %} +WITH ( +{% if data.fillfactor %} + FILLFACTOR = {{ data.fillfactor }}{% set ns.add_comma = true%}{% endif %}{% if data.autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + autovacuum_enabled = {% if data.autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %}{% if data.toast_autovacuum_enabled in ('t', 'f') %} +{% if ns.add_comma %}, +{% endif %} + toast.autovacuum_enabled = {% if data.toast_autovacuum_enabled == 't' %}TRUE{% else %}FALSE{% endif %}{% set ns.add_comma = true%}{% endif %} +{% for field in data['vacuum_data'] %} +{% if field.value is defined and field.value != '' and field.value != none %} +{% if ns.add_comma %}, +{% endif %} {{ field.name }} = {{ field.value|lower }}{% set ns.add_comma = true%}{% endif %}{% endfor %} +{{ '\n' }}) +{% endif %} +{% if data.spcname %}TABLESPACE {{ data.spcname }} +{% endif %}AS +{{ data.definition.rstrip(';') }} +{% if data.with_data %} +WITH DATA; +{% else %} +WITH NO DATA; +{% endif %} +{% if data.owner %} + +ALTER TABLE IF EXISTS {{ conn|qtIdent(data.schema, data.name) }} + OWNER TO {{ conn|qtIdent(data.owner) }}; +{% endif %} +{% if data.dependsonextensions %} +{% for ext in data.dependsonextensions %} + +ALTER MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} + DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }}; +{% endfor %} +{% endif %} +{% if data.comment %} + +COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(data.schema, data.name) }} + IS {{ data.comment|qtLiteral(conn) }}; +{% endif %} +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/properties.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/properties.sql new file mode 100644 index 00000000000..2d5c91a8d47 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/properties.sql @@ -0,0 +1,118 @@ +{# ========================== Fetch Materialized View Properties ========================= #} +{% if (vid and datlastsysoid) or scid %} +SELECT + c.oid, + c.xmin, + c.relname AS name, + c.reltablespace AS spcoid, + c.relispopulated AS with_data, + CASE WHEN length(spcname::text) > 0 THEN spcname ELSE + (SELECT sp.spcname FROM pg_catalog.pg_database dtb + JOIN pg_catalog.pg_tablespace sp ON dtb.dattablespace=sp.oid + WHERE dtb.oid = {{ did }}::oid) + END as spcname, + (SELECT st.setting from pg_catalog.pg_show_all_settings() st + WHERE st.name = 'default_table_access_method') as default_amname, + c.relacl, + nsp.nspname as schema, + pg_catalog.pg_get_userbyid(c.relowner) AS owner, + description AS comment, + ( + SELECT array_agg(DISTINCT e.extname) + FROM pg_depend d + JOIN pg_extension e ON d.refobjid = e.oid + WHERE d.objid = c.oid + ) AS dependsonextensions, + pg_catalog.pg_get_viewdef(c.oid) AS definition, + {# ============= Checks if it is system view ================ #} + {% if vid and datlastsysoid %} + CASE WHEN {{vid}} <= {{datlastsysoid}} THEN True ELSE False END AS system_view, + {% endif %} + pg_catalog.array_to_string(c.relacl::text[], ', ') AS acl, + (SELECT pg_catalog.array_agg(provider || '=' || label) FROM pg_catalog.pg_seclabels sl1 WHERE sl1.objoid=c.oid AND sl1.objsubid=0) AS seclabels, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'fillfactor=([0-9]*)') AS fillfactor, + (substring(pg_catalog.array_to_string(c.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS autovacuum_enabled, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(c.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS autovacuum_freeze_table_age, + (substring(pg_catalog.array_to_string(tst.reloptions, ',') FROM 'autovacuum_enabled=([a-z|0-9]*)'))::BOOL AS toast_autovacuum_enabled, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_threshold=([0-9]*)') AS toast_autovacuum_vacuum_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_vacuum_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_threshold=([0-9]*)') AS toast_autovacuum_analyze_threshold, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_analyze_scale_factor=([0-9]*[.]?[0-9]*)') AS toast_autovacuum_analyze_scale_factor, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_delay=([0-9]*)') AS toast_autovacuum_vacuum_cost_delay, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_vacuum_cost_limit=([0-9]*)') AS toast_autovacuum_vacuum_cost_limit, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_min_age=([0-9]*)') AS toast_autovacuum_freeze_min_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_max_age=([0-9]*)') AS toast_autovacuum_freeze_max_age, + substring(pg_catalog.array_to_string(tst.reloptions, ',') + FROM 'autovacuum_freeze_table_age=([0-9]*)') AS toast_autovacuum_freeze_table_age, + c.reloptions AS reloptions, tst.reloptions AS toast_reloptions, am.amname, + (CASE WHEN c.reltoastrelid = 0 THEN false ELSE true END) AS hastoasttable +FROM + pg_catalog.pg_class c +LEFT OUTER JOIN pg_catalog.pg_namespace nsp on nsp.oid = c.relnamespace +LEFT OUTER JOIN pg_catalog.pg_tablespace spc on spc.oid=c.reltablespace +LEFT OUTER JOIN pg_catalog.pg_description des ON (des.objoid=c.oid and des.objsubid=0 AND des.classoid='pg_class'::regclass) +LEFT OUTER JOIN pg_catalog.pg_class tst ON tst.oid = c.reltoastrelid +LEFT OUTER JOIN pg_catalog.pg_am am ON am.oid = c.relam + WHERE ((c.relhasrules AND (EXISTS ( + SELECT + r.rulename + FROM + pg_catalog.pg_rewrite r + WHERE + ((r.ev_class = c.oid) + AND (pg_catalog.bpchar(r.ev_type) = '1'::bpchar)) ))) + AND (c.relkind = 'm'::char) + ) +{% if (vid and datlastsysoid) %} + AND c.oid = {{vid}}::oid +{% elif scid %} + AND c.relnamespace = {{scid}}::oid +ORDER BY + c.relname +{% endif %} + +{% elif type == 'roles' %} +SELECT + pr.rolname +FROM + pg_catalog.pg_roles pr +WHERE + pr.rolcanlogin +ORDER BY + pr.rolname + +{% elif type == 'schemas' %} +SELECT + nsp.nspname +FROM + pg_catalog.pg_namespace nsp +WHERE + (nsp.nspname NOT LIKE E'pg\\_%' + AND nsp.nspname != 'information_schema') +{% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/update.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/update.sql index 6661e105440..f379047c409 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/update.sql +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/templates/mviews/ppas/15_plus/sql/update.sql @@ -211,4 +211,18 @@ COMMENT ON MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} {% endfor %} {% endif %} {% endif %} +{% set old_exts = (o_data.dependsonextensions or []) | list %} +{% set new_exts = data.dependsonextensions if 'dependsonextensions' in data else None %} +{% if new_exts is not none and old_exts != new_exts %} +{% for ext in (old_exts + new_exts) | unique %} + +{% if ext in new_exts and ext not in old_exts %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }}; +{% elif ext in old_exts and ext not in new_exts %} +ALTER MATERIALIZED VIEW {{ conn|qtIdent(view_schema, view_name) }} + NO DEPENDS ON EXTENSION {{ conn|qtIdent(ext) }}; +{% endif %} +{% endfor %} +{% endif %} {% endif %} diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/create_mview_with_am.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/create_mview_with_am.sql new file mode 100644 index 00000000000..39d07b539a4 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/create_mview_with_am.sql @@ -0,0 +1,15 @@ +-- View: public.testmview_am_$%{}[]()&*^!/@`# + +-- DROP MATERIALIZED VIEW IF EXISTS public."testmview_am_$%{}[]()&*^!/@`#"; + +CREATE MATERIALIZED VIEW IF NOT EXISTS public."testmview_am_$%{}[]()&*^!/@`#" +TABLESPACE pg_default +AS + SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_am_$%{}[]()&*^!/@`#" + OWNER TO postgres; + +COMMENT ON MATERIALIZED VIEW public."testmview_am_$%{}[]()&*^!/@`#" + IS 'comment1'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/test_mview.json index 146fb124100..a8bf5ef7d1d 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/test_mview.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/12_plus/test_mview.json @@ -272,7 +272,8 @@ "definition": "SELECT 1 AS col1", "amname": "heap" }, - "expected_msql_file": "create_mview_with_am_msql.sql" + "expected_msql_file": "create_mview_with_am_msql.sql", + "expected_sql_file": "create_mview_with_am.sql" } ] } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/alter_mview_no_depends.msql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/alter_mview_no_depends.msql new file mode 100644 index 00000000000..5285163e9ee --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/alter_mview_no_depends.msql @@ -0,0 +1,2 @@ +ALTER MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + NO DEPENDS ON EXTENSION postgres_fdw; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/alter_mview_no_depends.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/alter_mview_no_depends.sql new file mode 100644 index 00000000000..a16142a0fc1 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/alter_mview_no_depends.sql @@ -0,0 +1,18 @@ +-- View: public.testmview_$%{}[]()&*^!/@`# + +-- DROP MATERIALIZED VIEW IF EXISTS public."testmview_$%{}[]()&*^!/@`#"; + +CREATE MATERIALIZED VIEW IF NOT EXISTS public."testmview_$%{}[]()&*^!/@`#" +TABLESPACE pg_default +AS + SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_$%{}[]()&*^!/@`#" + OWNER TO postgres; + +ALTER MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + DEPENDS ON EXTENSION plpgsql; + +COMMENT ON MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + IS 'comment1'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/create_mview_no_depends.msql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/create_mview_no_depends.msql new file mode 100644 index 00000000000..c986e30a474 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/create_mview_no_depends.msql @@ -0,0 +1,17 @@ +CREATE MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" +TABLESPACE pg_default +AS +SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_$%{}[]()&*^!/@`#" + OWNER TO postgres; + +ALTER MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + DEPENDS ON EXTENSION plpgsql; + +ALTER MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + DEPENDS ON EXTENSION postgres_fdw; + +COMMENT ON MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + IS 'comment1'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/create_mview_no_depends.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/create_mview_no_depends.sql new file mode 100644 index 00000000000..6b0ad596eda --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/create_mview_no_depends.sql @@ -0,0 +1,21 @@ +-- View: public.testmview_$%{}[]()&*^!/@`# + +-- DROP MATERIALIZED VIEW IF EXISTS public."testmview_$%{}[]()&*^!/@`#"; + +CREATE MATERIALIZED VIEW IF NOT EXISTS public."testmview_$%{}[]()&*^!/@`#" +TABLESPACE pg_default +AS + SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_$%{}[]()&*^!/@`#" + OWNER TO postgres; + +ALTER MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + DEPENDS ON EXTENSION plpgsql; + +ALTER MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + DEPENDS ON EXTENSION postgres_fdw; + +COMMENT ON MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + IS 'comment1'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/test_mview.json new file mode 100644 index 00000000000..05f3415e6f3 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/13_plus/test_mview.json @@ -0,0 +1,341 @@ +{ + "scenarios": [ + { + "type": "create", + "name": "Create Extension", + "endpoint": "NODE-extension.obj", + "sql_endpoint": "NODE-extension.sql_id", + "data": { + "name": "postgres_fdw", + "version": "", + "relocatable": true + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Materialised Views with extensions.", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "postgres", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "dependsonextensions": ["plpgsql", "postgres_fdw"] + }, + "expected_sql_file": "create_mview_no_depends.sql", + "expected_msql_file": "create_mview_no_depends.msql" + }, + { + "type": "alter", + "name": "Alter Materialised Views with NO DEPENDS ON", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "dependsonextensions": ["plpgsql"] + }, + "expected_sql_file": "alter_mview_no_depends.sql", + "expected_msql_file": "alter_mview_no_depends.msql" + }, + { + "type": "delete", + "name": "Drop Materialised Views", + "endpoint": "NODE-mview.delete_id", + "data": { + } + }, + { + "type": "delete", + "name": "Drop Extension", + "endpoint": "NODE-extension.delete", + "data": { + "ids": [""] + }, + "preprocess_data": true + }, + { + "type": "create", + "name": "Create Materialised Views", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "postgres", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1" + }, + "expected_sql_file": "create_mview.sql", + "expected_msql_file": "create_mview_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Adding privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "added": [ + { + "grantee": "PUBLIC", + "grantor": "postgres", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview.sql", + "expected_msql_file": "alter_mview_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Remove all privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "deleted": [ + { + "grantee": "PUBLIC", + "grantor": "postgres", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_drop_all_priv.sql", + "expected_msql_file": "alter_mview_drop_all_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (change grantee in privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "changed": [ + { + "grantee": "PUBLIC", + "grantor": "postgres", + "old_grantee": "postgres", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_change_grantee_priv.sql", + "expected_msql_file": "alter_mview_change_grantee_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (change definition)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "definition": "SELECT 12 AS col1;" + }, + "expected_sql_file": "alter_mview_definition.sql", + "expected_msql_file": "alter_mview_definition_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Fillfactor)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "fillfactor": "18", + "with_data": true + }, + "expected_sql_file": "alter_mview_add_fillfactor.sql", + "expected_msql_file": "alter_mview_add_fillfactor_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (add table parameters)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "autovacuum_custom": true, + "autovacuum_enabled": "t", + "vacuum_table": { + "changed": [ + { + "name": "autovacuum_analyze_scale_factor", + "value": 0.2 + } + ] + } + }, + "expected_sql_file": "alter_mview_add_table_parameter.sql", + "expected_msql_file": "alter_mview_add_table_parameter_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (remove table parameters)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "autovacuum_custom": true, + "autovacuum_enabled": "x", + "vacuum_table": { + "changed": [ + { + "name": "autovacuum_analyze_scale_factor", + "value": null + } + ] + } + }, + "expected_sql_file": "alter_mview_remove_table_parameter.sql", + "expected_msql_file": "alter_mview_remove_table_parameter_msql.sql" + }, + { + "type": "create", + "name": "Create Materialised Views with access method", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "postgres", + "datacl": [], + "seclabels": [], + "name": "testmview_am_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "amname": "heap" + }, + "expected_msql_file": "create_mview_with_am_msql.sql", + "expected_sql_file": "create_mview_with_am.sql" + + } + ] + } + \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/15_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/15_plus/test_mview.json index 0141eec0e1c..1a97f355907 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/15_plus/test_mview.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/15_plus/test_mview.json @@ -1,5 +1,65 @@ { "scenarios": [ + { + "type": "create", + "name": "Create Extension", + "endpoint": "NODE-extension.obj", + "sql_endpoint": "NODE-extension.sql_id", + "data": { + "name": "postgres_fdw", + "version": "", + "relocatable": true + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Materialised Views with extensions.", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "postgres", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "dependsonextensions": ["plpgsql", "postgres_fdw"] + }, + "expected_sql_file": "create_mview_no_depends.sql", + "expected_msql_file": "create_mview_no_depends.msql" + }, + { + "type": "alter", + "name": "Alter Materialised Views with NO DEPENDS.", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "dependsonextensions": ["plpgsql"] + }, + "expected_sql_file": "alter_mview_no_depends.sql", + "expected_msql_file": "alter_mview_no_depends.msql" + }, + { + "type": "delete", + "name": "Drop Materialised Views", + "endpoint": "NODE-mview.delete_id", + "data": { + } + }, + { + "type": "delete", + "name": "Drop Extension", + "endpoint": "NODE-extension.delete", + "data": { + "ids": [""] + }, + "preprocess_data": true + }, { "type": "create", "name": "Create Materialised Views", @@ -272,7 +332,8 @@ "definition": "SELECT 1 AS col1", "amname": "heap" }, - "expected_msql_file": "create_mview_with_am_msql.sql" + "expected_msql_file": "create_mview_with_am_msql.sql", + "expected_sql_file": "create_mview_with_am.sql" } ] } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/16_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/16_plus/test_mview.json index 0141eec0e1c..52352f1cf87 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/16_plus/test_mview.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/pg/16_plus/test_mview.json @@ -1,5 +1,65 @@ { "scenarios": [ + { + "type": "create", + "name": "Create Extension", + "endpoint": "NODE-extension.obj", + "sql_endpoint": "NODE-extension.sql_id", + "data": { + "name": "postgres_fdw", + "version": "", + "relocatable": true + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Materialised Views with extensions.", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "postgres", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "dependsonextensions": ["plpgsql", "postgres_fdw"] + }, + "expected_sql_file": "create_mview_no_depends.sql", + "expected_msql_file": "create_mview_no_depends.msql" + }, + { + "type": "alter", + "name": "Alter Materialised Views with NO DEPENDS.", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "dependsonextensions": ["plpgsql"] + }, + "expected_sql_file": "alter_mview_no_depends.sql", + "expected_msql_file": "alter_mview_no_depends.msql" + }, + { + "type": "delete", + "name": "Drop Materialised Views", + "endpoint": "NODE-mview.delete_id", + "data": { + } + }, + { + "type": "delete", + "name": "Drop Extension", + "endpoint": "NODE-extension.delete", + "data": { + "ids": [""] + }, + "preprocess_data": true + }, { "type": "create", "name": "Create Materialised Views", @@ -272,7 +332,8 @@ "definition": "SELECT 1 AS col1", "amname": "heap" }, - "expected_msql_file": "create_mview_with_am_msql.sql" + "expected_msql_file": "create_mview_with_am_msql.sql", + "expected_sql_file": "create_mview_with_am.sql" } ] } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/create_mview_with_am.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/create_mview_with_am.sql new file mode 100644 index 00000000000..dc2495d5f51 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/create_mview_with_am.sql @@ -0,0 +1,15 @@ +-- View: public.testmview_am_$%{}[]()&*^!/@`# + +-- DROP MATERIALIZED VIEW public."testmview_am_$%{}[]()&*^!/@`#"; + +CREATE MATERIALIZED VIEW IF NOT EXISTS public."testmview_am_$%{}[]()&*^!/@`#" +TABLESPACE pg_default +AS + SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_am_$%{}[]()&*^!/@`#" + OWNER TO enterprisedb; + +COMMENT ON MATERIALIZED VIEW public."testmview_am_$%{}[]()&*^!/@`#" + IS 'comment1'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/test_mview.json index ed01fea1993..2dc012bf264 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/test_mview.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/12_plus/test_mview.json @@ -272,7 +272,8 @@ "definition": "SELECT 1 AS col1", "amname": "heap" }, - "expected_msql_file": "create_mview_with_am_msql.sql" + "expected_msql_file": "create_mview_with_am_msql.sql", + "expected_sql_file": "create_mview_with_am.sql" } ] } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/alter_mview_no_depends.msql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/alter_mview_no_depends.msql new file mode 100644 index 00000000000..5285163e9ee --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/alter_mview_no_depends.msql @@ -0,0 +1,2 @@ +ALTER MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + NO DEPENDS ON EXTENSION postgres_fdw; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/alter_mview_no_depends.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/alter_mview_no_depends.sql new file mode 100644 index 00000000000..864379ca086 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/alter_mview_no_depends.sql @@ -0,0 +1,18 @@ +-- View: public.testmview_$%{}[]()&*^!/@`# + +-- DROP MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#"; + +CREATE MATERIALIZED VIEW IF NOT EXISTS public."testmview_$%{}[]()&*^!/@`#" +TABLESPACE pg_default +AS + SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_$%{}[]()&*^!/@`#" + OWNER TO enterprisedb; + +ALTER MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + DEPENDS ON EXTENSION plpgsql; + +COMMENT ON MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + IS 'comment1'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/create_mview_no_depends.msql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/create_mview_no_depends.msql new file mode 100644 index 00000000000..770f48c130c --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/create_mview_no_depends.msql @@ -0,0 +1,17 @@ +CREATE MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" +TABLESPACE pg_default +AS +SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_$%{}[]()&*^!/@`#" + OWNER TO enterprisedb; + +ALTER MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + DEPENDS ON EXTENSION plpgsql; + +ALTER MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + DEPENDS ON EXTENSION postgres_fdw; + +COMMENT ON MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + IS 'comment1'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/create_mview_no_depends.sql b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/create_mview_no_depends.sql new file mode 100644 index 00000000000..ccd6c5f2d84 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/create_mview_no_depends.sql @@ -0,0 +1,21 @@ +-- View: public.testmview_$%{}[]()&*^!/@`# + +-- DROP MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#"; + +CREATE MATERIALIZED VIEW IF NOT EXISTS public."testmview_$%{}[]()&*^!/@`#" +TABLESPACE pg_default +AS + SELECT 1 AS col1 +WITH NO DATA; + +ALTER TABLE IF EXISTS public."testmview_$%{}[]()&*^!/@`#" + OWNER TO enterprisedb; + +ALTER MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + DEPENDS ON EXTENSION plpgsql; + +ALTER MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + DEPENDS ON EXTENSION postgres_fdw; + +COMMENT ON MATERIALIZED VIEW public."testmview_$%{}[]()&*^!/@`#" + IS 'comment1'; \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/test_mview.json new file mode 100644 index 00000000000..f73dd28fd21 --- /dev/null +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/13_plus/test_mview.json @@ -0,0 +1,340 @@ +{ + "scenarios": [ + { + "type": "create", + "name": "Create Extension", + "endpoint": "NODE-extension.obj", + "sql_endpoint": "NODE-extension.sql_id", + "data": { + "name": "postgres_fdw", + "version": "", + "relocatable": true + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Materialised Views with extensions.", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "enterprisedb", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "dependsonextensions": ["plpgsql", "postgres_fdw"] + }, + "expected_sql_file": "create_mview_no_depends.sql", + "expected_msql_file": "create_mview_no_depends.msql" + }, + { + "type": "alter", + "name": "Alter Materialised Views with NO DEPENDS ON.", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "dependsonextensions": ["plpgsql"] + }, + "expected_sql_file": "alter_mview_no_depends.sql", + "expected_msql_file": "alter_mview_no_depends.msql" + }, + { + "type": "delete", + "name": "Drop Materialised Views", + "endpoint": "NODE-mview.delete_id", + "data": { + } + }, + { + "type": "delete", + "name": "Drop Extension", + "endpoint": "NODE-extension.delete", + "data": { + "ids": [""] + }, + "preprocess_data": true + }, + { + "type": "create", + "name": "Create Materialised Views", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "enterprisedb", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1" + }, + "expected_sql_file": "create_mview.sql", + "expected_msql_file": "create_mview_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Adding privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "added": [ + { + "grantee": "PUBLIC", + "grantor": "enterprisedb", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview.sql", + "expected_msql_file": "alter_mview_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Remove all privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "deleted": [ + { + "grantee": "PUBLIC", + "grantor": "enterprisedb", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_drop_all_priv.sql", + "expected_msql_file": "alter_mview_drop_all_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (change grantee in privileges)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "datacl": { + "changed": [ + { + "grantee": "PUBLIC", + "grantor": "enterprisedb", + "old_grantee": "enterprisedb", + "privileges": [ + { + "privilege_type": "a", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "r", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "w", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "d", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "D", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "x", + "privilege": true, + "with_grant": false + }, + { + "privilege_type": "t", + "privilege": true, + "with_grant": false + } + ] + } + ] + } + }, + "expected_sql_file": "alter_mview_change_grantee_priv.sql", + "expected_msql_file": "alter_mview_change_grantee_priv_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (change definition)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "definition": "SELECT 12 AS col1;" + }, + "expected_sql_file": "alter_mview_definition.sql", + "expected_msql_file": "alter_mview_definition_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (Fillfactor)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "fillfactor": "18", + "with_data": true + }, + "expected_sql_file": "alter_mview_add_fillfactor.sql", + "expected_msql_file": "alter_mview_add_fillfactor_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (add table parameters)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "autovacuum_custom": true, + "autovacuum_enabled": "t", + "vacuum_table": { + "changed": [ + { + "name": "autovacuum_analyze_scale_factor", + "value": 0.2 + } + ] + } + }, + "expected_sql_file": "alter_mview_add_table_parameter.sql", + "expected_msql_file": "alter_mview_add_table_parameter_msql.sql" + }, + { + "type": "alter", + "name": "Alter Materialised Views (remove table parameters)", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "autovacuum_custom": true, + "autovacuum_enabled": "x", + "vacuum_table": { + "changed": [ + { + "name": "autovacuum_analyze_scale_factor", + "value": null + } + ] + } + }, + "expected_sql_file": "alter_mview_remove_table_parameter.sql", + "expected_msql_file": "alter_mview_remove_table_parameter_msql.sql" + }, + { + "type": "create", + "name": "Create Materialised Views with access method", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "enterprisedb", + "datacl": [], + "seclabels": [], + "name": "testmview_am_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "amname": "heap" + }, + "expected_msql_file": "create_mview_with_am_msql.sql", + "expected_sql_file": "create_mview_with_am.sql" + } + ] + } + \ No newline at end of file diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/15_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/15_plus/test_mview.json index 5969e3cfac0..9e18388d61a 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/15_plus/test_mview.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/15_plus/test_mview.json @@ -1,5 +1,65 @@ { "scenarios": [ + { + "type": "create", + "name": "Create Extension", + "endpoint": "NODE-extension.obj", + "sql_endpoint": "NODE-extension.sql_id", + "data": { + "name": "postgres_fdw", + "version": "", + "relocatable": true + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Materialised Views with extensions.", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "enterprisedb", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "dependsonextensions": ["plpgsql", "postgres_fdw"] + }, + "expected_sql_file": "create_mview_no_depends.sql", + "expected_msql_file": "create_mview_no_depends.msql" + }, + { + "type": "alter", + "name": "Alter Materialised Views with NO DEPENDS ON.", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "dependsonextensions": ["plpgsql"] + }, + "expected_sql_file": "alter_mview_no_depends.sql", + "expected_msql_file": "alter_mview_no_depends.msql" + }, + { + "type": "delete", + "name": "Drop Materialised Views", + "endpoint": "NODE-mview.delete_id", + "data": { + } + }, + { + "type": "delete", + "name": "Drop Extension", + "endpoint": "NODE-extension.delete", + "data": { + "ids": [""] + }, + "preprocess_data": true + }, { "type": "create", "name": "Create Materialised Views", @@ -272,7 +332,8 @@ "definition": "SELECT 1 AS col1", "amname": "heap" }, - "expected_msql_file": "create_mview_with_am_msql.sql" + "expected_msql_file": "create_mview_with_am_msql.sql", + "expected_sql_file": "create_mview_with_am.sql" } ] } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/16_plus/test_mview.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/16_plus/test_mview.json index 5969e3cfac0..9e18388d61a 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/16_plus/test_mview.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/ppas/16_plus/test_mview.json @@ -1,5 +1,65 @@ { "scenarios": [ + { + "type": "create", + "name": "Create Extension", + "endpoint": "NODE-extension.obj", + "sql_endpoint": "NODE-extension.sql_id", + "data": { + "name": "postgres_fdw", + "version": "", + "relocatable": true + }, + "store_object_id": true + }, + { + "type": "create", + "name": "Create Materialised Views with extensions.", + "endpoint": "NODE-mview.obj", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql", + "data": { + "spcname": "pg_default", + "schema": "public", + "owner": "enterprisedb", + "datacl": [], + "seclabels": [], + "name": "testmview_$%{}[]()&*^!/@`#", + "comment": "comment1", + "definition": "SELECT 1 AS col1", + "dependsonextensions": ["plpgsql", "postgres_fdw"] + }, + "expected_sql_file": "create_mview_no_depends.sql", + "expected_msql_file": "create_mview_no_depends.msql" + }, + { + "type": "alter", + "name": "Alter Materialised Views with NO DEPENDS ON.", + "endpoint": "NODE-mview.obj_id", + "sql_endpoint": "NODE-mview.sql_id", + "msql_endpoint": "NODE-mview.msql_id", + "data": { + "dependsonextensions": ["plpgsql"] + }, + "expected_sql_file": "alter_mview_no_depends.sql", + "expected_msql_file": "alter_mview_no_depends.msql" + }, + { + "type": "delete", + "name": "Drop Materialised Views", + "endpoint": "NODE-mview.delete_id", + "data": { + } + }, + { + "type": "delete", + "name": "Drop Extension", + "endpoint": "NODE-extension.delete", + "data": { + "ids": [""] + }, + "preprocess_data": true + }, { "type": "create", "name": "Create Materialised Views", @@ -272,7 +332,8 @@ "definition": "SELECT 1 AS col1", "amname": "heap" }, - "expected_msql_file": "create_mview_with_am_msql.sql" + "expected_msql_file": "create_mview_with_am_msql.sql", + "expected_sql_file": "create_mview_with_am.sql" } ] } diff --git a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/view_test_data.json b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/view_test_data.json index 2a8663c012c..015bce58767 100644 --- a/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/view_test_data.json +++ b/web/pgadmin/browser/server_groups/servers/databases/schemas/views/tests/view_test_data.json @@ -88,7 +88,8 @@ "datacl": [], "seclabels": [], "name": "test_mview_add_", - "definition": "SELECT 'test_pgadmin';" + "definition": "SELECT 'test_pgadmin';", + "dependsonextensions": ["plpgsql"] }, "mocking_required": false, "mock_data": {}, @@ -1054,7 +1055,8 @@ "query": "\"CREATE MATERIALIZED VIEW %s.%s TABLESPACE pg_default AS SELECT 'test_pgadmin' WITH NO DATA;ALTER TABLE %s.%s OWNER TO %s\" % (schema_name, view_name, schema_name, view_name, server['username'])" }, "test_data": { - "comment": "This is test comment" + "comment": "This is test comment", + "dependsonextensions": ["plpgsql"] }, "mocking_required": false, "mock_data": {}, diff --git a/web/regression/javascript/schema_ui_files/mview.ui.spec.js b/web/regression/javascript/schema_ui_files/mview.ui.spec.js index 94fc63739bb..0e91db34e94 100644 --- a/web/regression/javascript/schema_ui_files/mview.ui.spec.js +++ b/web/regression/javascript/schema_ui_files/mview.ui.spec.js @@ -53,6 +53,13 @@ describe('MaterializedViewSchema', ()=>{ await getPropertiesView(createSchemaObject(), getInitData); }); + it('dependsonextensions field exists', ()=>{ + let field = _.find(schemaObj.fields, (f)=>f.id=='dependsonextensions'); + expect(field).toBeTruthy(); + expect(field.type).toBe('select'); + expect(field.controlProps.multiple).toBe(true); + }); + it('validate', ()=>{ initializeSchemaWithData(schemaObj, {}); let state = {};