* [Tarantool-patches] [PATCH v1 0/7] sql: properly check arguments types of built-in functions
@ 2020-08-12 15:15 imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 1/7] box: add has_vararg option for functions imeevma
` (6 more replies)
0 siblings, 7 replies; 8+ messages in thread
From: imeevma @ 2020-08-12 15:15 UTC (permalink / raw)
To: v.shpilevoy; +Cc: tarantool-patches
This patch-set makes SQL to use the ApplyType opcode to validate the argument
types of built-in functions.
https://github.com/tarantool/tarantool/issues/4159
https://github.com/tarantool/tarantool/tree/imeevma/gh-4159-rework-sql-builtins
@ChangeLog
- Built-in function argument types are now properly checked (gh-4159).
Mergen Imeev (7):
box: add has_vararg option for functions
sql: do not return UNSIGNED in built-in functions
sql: move built-in function definitions in _func
box: add param_list to 'struct func'
sql: check built-in functions argument types
sql: VARBINARY and STRING in built-in functions
sql: refactor sql/func.c
src/box/alter.cc | 12 +-
src/box/bootstrap.snap | Bin 5976 -> 6291 bytes
src/box/func.c | 1 +
src/box/func_def.c | 5 +
src/box/func_def.h | 8 +
src/box/lua/call.c | 2 +
src/box/lua/upgrade.lua | 143 +++
src/box/sql/expr.c | 4 +
src/box/sql/func.c | 894 +++----------------
src/box/sql/resolve.c | 2 +-
src/box/sql/select.c | 26 +
src/box/sql/sqlInt.h | 14 +
src/box/sql/vdbeapi.c | 2 +-
test/box-py/bootstrap.result | 2 +-
test/sql-tap/cse.test.lua | 4 +-
test/sql-tap/func.test.lua | 36 +-
test/sql-tap/orderby1.test.lua | 2 +-
test/sql-tap/position.test.lua | 6 +-
test/sql/boolean.result | 32 +-
test/sql/checks.result | 8 -
test/sql/checks.test.lua | 2 -
test/sql/types.result | 1489 +++++++++++++++++++++++++++++++-
test/sql/types.test.lua | 250 ++++++
23 files changed, 2092 insertions(+), 852 deletions(-)
--
2.25.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Tarantool-patches] [PATCH v1 1/7] box: add has_vararg option for functions
2020-08-12 15:15 [Tarantool-patches] [PATCH v1 0/7] sql: properly check arguments types of built-in functions imeevma
@ 2020-08-12 15:15 ` imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 2/7] sql: do not return UNSIGNED in built-in functions imeevma
` (5 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: imeevma @ 2020-08-12 15:15 UTC (permalink / raw)
To: v.shpilevoy; +Cc: tarantool-patches
The has_vararg option allows us to work with functions with a variable number of
arguments. This is required for built-in SQL functions.
Suppose this option is TRUE for a built-in SQL function. Then:
1) If param_list is empty, all arguments can be of any type.
2) If the length of param_list is not less than the number of the given
arguments, the types of the given arguments must be compatible with the
corresponding types described in param_list.
3) If the length of param_list is less than the number of given arguments, the
rest of the arguments must be compatible with the last type in param_list.
Part of #4159
---
src/box/func_def.c | 5 +++++
src/box/func_def.h | 6 ++++++
2 files changed, 11 insertions(+)
diff --git a/src/box/func_def.c b/src/box/func_def.c
index 11d2bdb84..be12ce970 100644
--- a/src/box/func_def.c
+++ b/src/box/func_def.c
@@ -40,10 +40,13 @@ const char *func_aggregate_strs[] = {"none", "group"};
const struct func_opts func_opts_default = {
/* .is_multikey = */ false,
+ /* .has_vararg = */ false,
};
const struct opt_def func_opts_reg[] = {
OPT_DEF("is_multikey", OPT_BOOL, struct func_opts, is_multikey),
+ OPT_DEF("has_vararg", OPT_BOOL, struct func_opts, has_vararg),
+ OPT_END,
};
int
@@ -51,6 +54,8 @@ func_opts_cmp(struct func_opts *o1, struct func_opts *o2)
{
if (o1->is_multikey != o2->is_multikey)
return o1->is_multikey - o2->is_multikey;
+ if (o1->has_vararg != o2->has_vararg)
+ return o1->has_vararg - o2->has_vararg;
return 0;
}
diff --git a/src/box/func_def.h b/src/box/func_def.h
index d99d89190..89d5a404a 100644
--- a/src/box/func_def.h
+++ b/src/box/func_def.h
@@ -68,6 +68,12 @@ struct func_opts {
* packed in array.
*/
bool is_multikey;
+ /**
+ * TRUE if the function can have a variable number of arguments.
+ *
+ * Currently only used in built-in SQL functions.
+ */
+ bool has_vararg;
};
extern const struct func_opts func_opts_default;
--
2.25.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Tarantool-patches] [PATCH v1 2/7] sql: do not return UNSIGNED in built-in functions
2020-08-12 15:15 [Tarantool-patches] [PATCH v1 0/7] sql: properly check arguments types of built-in functions imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 1/7] box: add has_vararg option for functions imeevma
@ 2020-08-12 15:15 ` imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 3/7] sql: move built-in function definitions in _func imeevma
` (4 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: imeevma @ 2020-08-12 15:15 UTC (permalink / raw)
To: v.shpilevoy; +Cc: tarantool-patches
This patch forces functions to return INTEGER instead of UNSIGNED.
Part of #4159
---
src/box/sql/vdbeapi.c | 2 +-
test/sql/types.result | 12 ++++++++++++
test/sql/types.test.lua | 6 ++++++
3 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c
index 7c59ef83f..d1eeaf114 100644
--- a/src/box/sql/vdbeapi.c
+++ b/src/box/sql/vdbeapi.c
@@ -328,7 +328,7 @@ sql_result_double(sql_context * pCtx, double rVal)
void
sql_result_uint(sql_context *ctx, uint64_t u_val)
{
- mem_set_u64(ctx->pOut, u_val);
+ mem_set_int(ctx->pOut, u_val, false);
}
void
diff --git a/test/sql/types.result b/test/sql/types.result
index 442245186..95f7713e8 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -2795,3 +2795,15 @@ box.execute([[DROP TABLE ts;]])
---
- row_count: 1
...
+--
+-- gh-4159: Make sure that functions returns values of type INTEGER
+-- instead of values of type UNSIGNED.
+--
+box.execute([[SELECT typeof(length('abc'));]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['integer']
+...
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index 0270d9f8a..fff0057bd 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -623,3 +623,9 @@ box.execute([[DROP TABLE tb;]])
box.execute([[DROP TABLE tt;]])
box.execute([[DROP TABLE tv;]])
box.execute([[DROP TABLE ts;]])
+
+--
+-- gh-4159: Make sure that functions returns values of type INTEGER
+-- instead of values of type UNSIGNED.
+--
+box.execute([[SELECT typeof(length('abc'));]])
--
2.25.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Tarantool-patches] [PATCH v1 3/7] sql: move built-in function definitions in _func
2020-08-12 15:15 [Tarantool-patches] [PATCH v1 0/7] sql: properly check arguments types of built-in functions imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 1/7] box: add has_vararg option for functions imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 2/7] sql: do not return UNSIGNED in built-in functions imeevma
@ 2020-08-12 15:15 ` imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 4/7] box: add param_list to 'struct func' imeevma
` (3 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: imeevma @ 2020-08-12 15:15 UTC (permalink / raw)
To: v.shpilevoy; +Cc: tarantool-patches
This patch moves SQL built-in function definitions to _func. This helps
create an unified way to check the types of arguments. It also allows
users to see these definitions.
Part of #4159
---
src/box/bootstrap.snap | Bin 5976 -> 6291 bytes
src/box/lua/upgrade.lua | 143 +++++++++++++++++++++++++++++++++++
src/box/sql/func.c | 7 +-
src/box/sql/resolve.c | 2 +-
test/box-py/bootstrap.result | 2 +-
test/sql/types.result | 4 +-
6 files changed, 148 insertions(+), 10 deletions(-)
diff --git a/src/box/bootstrap.snap b/src/box/bootstrap.snap
index 8bd4f7ce24216a8bcced6aa97c20c83eb7a02c77..9163165b13b27771414243650051e900b3af8def 100644
GIT binary patch
literal 6291
zcmV;E7;NWLPC-x#FfK7O3RY!ub7^mGIv_GGHZCwNGc+w{V`5}vGBPz{W(rAeb97;D
zV`VxZWMnmFWnwZnEi*P`Gc7bUF)=MTV`MTdGiG8mH#svmHDoj}3RXjGZ)0mZAbWiZ
z3e~y`y3H6G0M66h;g_WV00000D77#B08ov<04mfRFi8+_T4gZIFvAQp%phAsj|nab
zs5-VJi8<h_tr@YvL1fnQrzEzgy=&ff`aj)$GRGulV?jmAXDe)N{kFnyK;8)(lj6ZE
z%R~b40`CI90>n60MkAamBQlQBNCoHrH^?UiRPEJsf;YUCfCAn|Fad9Q3xNa=L@<Lo
z0KwO=O%7XV0}s#`aNukBT%duk;Zp$yXbF5RFmt28mpe>C+a&NsW8>y)xaO<P*AM|V
zU&G<^fHhxyXaE9y$cJhUXom$D&<>~6w8M6IEMPd4ni>wDQODuc@M)CFY2K)u<{NXG
zoW{R?_wP59_uKDc7j73yxOq{yg`4Oe*_I#KA@Rr_*);9T?%~U_X<qhag_~uAEX!&k
z%Rbj2%c`1Xfh+sWs@4PmwNA6v0}w!i3XsmA0Spk8*<@5^p#TWLvS<Qe*)ssJ?9&XI
zS6JrED<os)6~4k>8JZm*nVFs5Z&|aYJ!psL3kJvZg25+V@VOh)LUm6wsF+>5gGp#k
zN9zhBW(UFKcCgOw!iCvEConts1-FAc`1Ilw4Boy3gH2w7!Kdx^KU35HHQWEsE=;sN
zTxwgoths-$w=#G4-)rtaO}*Zug-ez#T4T|o^_48HUc%yPr7Ny>wUs5Ut0-wr#fsL?
zDOG?TN}~ew(AgBAUz0!&O`_5EAkAibq$K%jNxs^iC`hy}C{ku!PofN6HGR`tQ>s_4
zq3Z%QciCc^>Mkcx^4jD{UXPsQHLpfZj!ce@$0bI`qY@@Q$rA68DDnPClB_;uNV57Y
zI+E3^tUis%Xk0`^Gp-^=nr%PYxQGz>Aw|3wLd5%_AzVlZ=Rt-z2O^|_KZ0mr5D*R2
zKp#J*rg{WTP4VzCH3ihe`yD*I*8${xjvc+@(9!#i9KGAXK_u3=K_t?!K_uqqj2bi<
zG*<4a+GEXP%n0VIB%cOz`h+3l*fZZi=1&ab?#1R-)2tYbpBT)|vFH7}{!aD_x$fUP
z+0gmfa7nCJSKa(=Vk=qD&rb~IW(}P)yqXTj#KfArTnV$11^vWeZelTF+}*xwV>1r^
ziNW0T!O?Z6Qklp^%78Eo_5x5F0a7FlB))K{xd0;uYZK|(>K)YLTgWw2PRhhWL!$IH
z`lD|eQ!V^MNHG(W{uf<kR^66aJpQhEl)JpL;_m*rZCy3Z!a+k`x&`L8eR=A)mVVo8
zTpoE&x;g4$Qpk7zp4kSu1}621nz+nF&8j|aVjvvNz2~KFi|=1@-zHbhh1>Jjsf)+2
zTz9I~T=Y&&%v{+94qkU!eBCZ|vVrN=Wru2Rfmr(MR<G%*d)Gm|rtOh$V~Pi39F-#z
z3K9gw$B&nt>Jh}l2T%_^bo=)^c+l?X0Gi#&v11?kF5bbRgVuE;$E?c+4(Ke2HUkQ~
zYTTgVp<!b-14nU`ovM>rD#8s+@yMXTPQ{qPPQj4DPO(!zF=#Oy#nBnY(VycHhNC!2
z>+@wL3&PQ;sOJ|j9F2N<(T4`@;)@xS3omk1GDktT=)yH>!G&wgVhh*k8nMt~8?VS>
z8?C@%8@I8FEBZ@?75$x}ivIRj3M$?=iYeX~3Mt;_6H(B(oPc7+)x;BD@0IZ7V#103
zmuRAYC79^H|0I_99|<M?KO%|$pGF|@e-TIg|0KeQtLG3!uwMuw*dN3Y>}Nj^Lj3<j
z5dZrC#Q)D8e#oB(AM)R!hy3%`fd^Wi9Cn!H!9fS3x3g+ucZ0g8snO@TAqVemz`^?(
zZtzbUY@l(?P{WK%1{#__=hE)EVwj<O7-Z=Fg&4Z;J_-Yr|9Sz+yAXx)P`-sP?^$rc
z`xRR7UIiAsPhkb`QBc7@Pe_5L#|wp-9zG|id-Ypg-D{d|ug3(h?MvXZJqadkzx@a$
zXfFZ@+J`WL_S%CWLiT$?$X*W!*=OIi$L)FaxE)WI+ueRAPh0!|Ph0fhPFrk?Tp#3O
z2Oi|29j;u=#X22y7iy=w&pO@h?iQ5jYCVZ=))vtvx>#DyEZ6fU)|cl=4`n*}vdOuU
z$$4@K<X1`{=O78>Ku+iCZ@|I-8qoPagAF<c8uWfa2EAK=K|AMywynT|wv{tyNVKY;
zO3sit47djIjc$kQ@or?Am_}>n=9I)UhP;}SO^Icsxi#%<INh&_V{D%e$9rO87_67w
z?dgn<iGPG%!k&9JrarS-Y;t3IUQ{}qFNgavrMWRZEi4Ad^C@vGn3QzI3hfF~Qqe34
ziV_kOq#4r813GJJzg&{aiw_^o-8cLVI_cDYxg>Ujd`Icpzfqz{xxf!F_5tfbW~9}u
zv0xH^^#j|CR|1f0>cj*11OO8Nb^^c&4eoNLi<zY|OJtUQNM=mQ2UF_(AmJ$SlEx%G
zCGC)ONMew3M`4b@P#xinoQ%Fu8F`W2kg}#C8?uOrs7BO<hzsj8TVx9nEkv>q!7_AZ
zXlY0(78A09kyL!JP!%C6Kc@VkVLS^;f+4BA^b585%VeW<|4JATj#|lzka$jd9eeI>
zk*Gfwo0wL&v1{M-LcagkKIQKAUi-8ItVT-H2}cY6C@nB^o%)@%x~lT~q?MXNaSKJO
zb=9oA7GLgSsXr5!T3q*B#9G_Us&hWyxqr`HH5~?1C|;lBqH@_a*TU5AEv>3L*ym)4
z)IY2I?LWoBV4A=Y3U~jh6FVKfO62!%tENue#mKmOafyjgx7)aT5v%7ms~hX9It|d(
z(%StzcVW}Gdof*Nr6pBe``4H<agq}DzqzVw|E5cflq8PI-=HyN;v*zo|2C)J=XUF7
z-PNWh5?!_F7NvBvZL^xT?aNm!<pNiped_m?y1(Ci6TAL;P5rjxwW{W{h4OWN7V0h(
zW-QP9`*m;n-KNCcb1^H`eE-+&TgTM}DuwwK^4vP#ue}dg4=R6y=@J_qu`;GjER*$I
zT<)ZmlwSExnYgHEjxo)`L`HsIQz$M%#ItT)7uc#t&8k^l{+_>IN@c!@$*zU^^W7}!
z@0D}7exbBau`rP$a*Syc4-xs9*xevgnA_m;^Vd}aM!vvabouEb28N5JEt0f2%0h+(
z(G^2h;2$^|griF;Y*R2vQH!Dr6kMLz;)IqavM_;Vi7QGhC830bl_RPcL8XW(M9_wq
z36T^85)e{;h~fj39-i>vWQQg?9OYny1Ctw;*r23_Bs3tI;fM^f7>Zyp@&Zw`$QKb8
zhO{7rg`pLMR0xs+5EOo#5ai{9PY)A#lmJA+juCW-kRt>fAl%qvLr;w^8hK{mk#Q%+
z2QWPN;fi&DW4KDDgrj}>^mzf-5rS#owQ=*;355}Z;VPNZv+LsPm)OXby4#}eTKGpx
zw{BOey9K^QCXQ9fkZ_c5;+mHjSILmDv<QQ2@#x!H7%!@mF=%wuQTLIGVWPB=HHMIs
zSr4U{Srv;-*Zx(0uV3L3!>VLR&e|=v#I|P7iJ6$SUoMHHTDdMdGCEqb+Zz3@z0XBO
zM|yQtqbWMnmVfizMalZN2*q5IUklTpzfW5zpFZ)HE8WkDwQ#`1S?KJXaJgF;TrLY^
z*`P`H+x43GiUz&jEyu)58Te{9-j^m;!eG}^Vk;NeYCNBrTN78Yz}Lf>xiK-7IlLR0
z+Y(Qyz>BJP%hh%^C#K0UQxlWKGb@~!Bu=XG+VO5^oERw%5|_*UbWAJ-4xgTlSWLSd
zQx=YbBvVUbC{#7y&bP!*-u!w=?1Tc|n4S_hnc!)Ok0i)lVWSAl+>)3H1YHA(FK1Hq
zm}*J9<bg1_oDwT>V2P77;HCTRY-yPt4+|q<z<2Z6c3b$!0y{BDEK^{&%XwMiq6BJA
zHZ5$#P0G9ZY&BlZ$z}%=wfUmM<#0D!6Bl8FyV;bO$QnLxc1^k(kBNsMfXwB7IxjdT
z7IHwDU2cho44}F_J^hwgNKFfT-Ia-K(*1V4B@R-657*m0IWdqaC*K#{Eyu(^jzLmS
zVrsr#2iQkc>eJnLyq|3g_b__l`Fc*w<GuN6O->B-#o&BOyu;U;lvqc9bEej$tKo7#
zFjzPT)Dr2d*>pQw`t;lJzHDI}MPHBU*JI)vE*x7e_jKbmu?_Cq{l+W<h#IKmCvZ?f
z=@?To17JV^0J9nd5CrwKw6YTv000aoaIkQ~l7JCG;czG%PDm-Fau5Q5G64W!1T#=G
z*8!z>+JJZn8hTr4x|Mybfh&wP5CyZ@l^U&=<_w9=x`vXk@lVJty?`5V`RFq@QY+uH
zJ>M}s)?ppC=Q_S;`>fA<)?s?4=eoSdy1dJFY{&OZk9T;7?^(xoe3$oGpLdv^>6k9-
z@h<PPJ=^o0>98K_@g3K*9p7bL*5y5>=Q^&-d)#GRzT<ng>(yn%7XX8xZgGfR<`oR#
zGq+1rTV!BHt9kfc+2WC5Ro)U$W(Ks-5Vw@IK_o18jRhZ`5K6trOBwG42~lNdMMp7Y
z`DTTrLvLg)m@23W!2r`x704MfMUS)#S68$t)tR_7IvKv)jlsnV{ytA2=k{?rVd^7<
z-GKH7h$J9Rs81uq#n@@gpurDZNY$Iq>#bPu1_&c%wGWA)?^J?F5>J@6iOrICQK+Tt
zL-kkEWH@f2sHCX=;mATa+^w?x;|GcOPkLt6B?}k~`n2j%9T4(sMx$(z#R>pAHHYm%
zyCqXfh?X-k_eZE6tg%*s^PXj^SU~?QO(z-n*P0?_@|zK%2I%TX_#&PFypLBr@ymgH
z1tf;)lE*HLMlcE>QqW~v%IwO4aAyx5VDBGp9&pz-s2pFPi$NAI0_sPBdR*m`!%FKT
zs~0p}X6l!@H95CEE^Xc*M#Cm2F@K9}$A=Y18gw>TKmwW;d7e=QL6BZ$@ZcZvj`}}M
z+6tPYNL&E>Sv$x^V>Yv9`o=(i+`Xc$i~#2<Ac)`->0~ZYHL%tiy9;}qO0uI_VM0N;
z%JL-ok5MfhFpH`Wb9*=P(UGi2Z0Y!xK)J3GH<EKbihdP(bM9&Cg)crkoKTU4R8<L?
z5ATInz4FW%tdH@Ie;pL)0vp-B-%>WnzqWpF;VAMC=pRjcYf#m<PUxz>rw~lhW@qI^
z#I0G3{&dJ^qK<(ii=HEXGPAWU_IJ?(4KSN2b6wuPpuEoPKlclSBbO$GZZRVKk)lwa
zMfIhsafyNKc30)>t%4(^<**P0kM3uS$Br?jqga8g7#=_y)QGKRdVnP;jp7f{yZ}I#
zy4GXy@y&oiXfuV<!1Kv-{07=bQC5#wANzB^HJpibMf+{zQ~uj!Z~qXr0GMFKQAa~j
z(e_cQ8YDx&?2=4Odk%l98N*0V{ePw-gjQvq0X2;2hH4^;)fRM~Bfz^T(ZqE)|Ela6
z`T}>NF<T2}d5VJ?{C=0jH%AoCX8>VDLzfj?OWJDng{yeTf1J@0vkQ%$Q5loHNM88h
zknbywHwK@dT#v*>3PLD5k?-h#vtMM0?dgFKqL8b^sfEN3#`q&z(QP|E%qAZEPiM3=
zOn4R=#_Yc;6gMKMhaQkQT#V<JID<!Uf9zt8gWpEx)!a*zDgoeXpFcsUU%uN>feCRX
z1}&sdI`*WvK0k(vcoHuA5z}lvv4`nAIR90)uo#1WRz>A6gm?}t{V61smc61pUt#&J
zBG0>CNyrSINO>C^oMzz;b8MAXTwd|r@V+!V0+O>Oa^WT@RfHL^9Jvw@^Z9bG8lMBv
zR6^w7`#DYu_5z%@{e9F}-^iI<RBMjxf=(DZ?=0lypibAgv9S<>W1Dd4Ab1nO*!ZuR
zzo)#T`{uXp!EnM)%=H-hu7^<ZbdG+tzrw|sKMQUQ?_2Yqw2q0>ZRfkiC6EZ`K(trj
z`29i?R<B{?<SjA5Tkp{(l=8^iuLZH=`%I%Dnm2ii0)LD^BYdz&XHS@0mvgfgr>-e{
z1?CF`#Q$HJd7+pB@&=?!^GEDZ_}^HCU=a2}Y&iZrjs@-?hPWv%rkg8mr5rVJ=*~29
zujSkVTn$foc&p5t(k#xZ5*@Ezz{B_+9Z3(@mT<6Pz&C-L;SOyZpL7myTTmb0^60R8
zx3yOpaM5`=2N9&Ql^3BUq(5ru3k_DRQDQ#eIkE5c%wqg1q0z-DxX{>jh8Fy#Y83I^
zw>XK-z~Fm_Vg|%1bs<_{y(Qddp^nKrcjo^se(OP;AmF-_5c8anln(_}Bq$9VYp{pK
z6Vfs|)AJJha(K6TPw}NozS1q455AheeDftI$(RbJq?A9i4VFYSN0+%sEuA+zEc^OX
zpaeP{@MzK56QWp6oQLB)9u7e%@%@1vF3v>9?!mx>$fzskHdA4wH7sdn=Z|PB=1K5|
zK;e9X6W|@vLjy^@sCJdrm?Kqq!N@hEi)kN;AYP0ztK)X7j3(;E7f48Mhpndx0TCyk
z_pV03qQ_jy@IygM^7K*>sqSycOQDs#;ara*L=>Tt=E7A~EGa7x$ef~GqgEwt1n==o
zAuIukKNQ`IhU7s>ehKYFb1KnQA|^MJ{h_at@+v~EQU<(rIw28}3Sx`ng$ox@K??>z
zswB7uG5W8XK#;h2Lp-G9oHBT{WPyX^jzhR8xCk@4qnJXFI^`G&i|^NpKzHJsd&i2J
zq8bOXa}P@ba6uTC4u-houwfXhsvAOnZ90@O70eHT#37EMxXFH-u+~pg6QS)Tt1YO9
zhd-$pOU6M<@yMO7ppyoJmMmnk+}`YuieZlSEsT}|E{O7!$q|O$kq-!xxW=!DJCG5m
zTm5X@d5l2a<AT1<%|0iQmvb#A*t?byd+$QaMaJ>*qo23M=A>#jo{SrRLX&Rt8n%c~
zKcpNY8gF6%B2o};ha2qICK$>bUl1;DG9-*HYm%7d+}+qu#qngDizFjCIIa)OTBuN7
zA>tO*x#gfoV4no)!!1%KI67~@lW@D4Piq0_hsQKbsGtA{9fj*4Mtu}B4l+0Fh?A?l
zk%p0#JYZ0ku}Bl8`yfX36axkm7c7XMtGv;MlavH#P@eHfm8I(-Mt>Aj2oe`;h?lCI
zQHGb4EO1bUF-VoA;~+-+G(!fH8`g-CUEWB;Nm>H9C=2f*x6+-GauDrB@&TBOq}p_B
z+T-5gD0`QkI+GPl#}gSV_9WVnD)x?J?pl!tmZ8&xn~mAn4U$yo$b<s5bA6t8Mu!14
z3p0jC=qOwvMO6Hx;y=)Se>_q=MwC4#5y}26|J20L$x{Ty@L4Qqb_762URRB+F#d6h
zhUSQXZsAgzy;3M<AjI2u3@PrNl@gKSq7>75-ukpn>4hvt^l)h1>Aj<d!#`V9fu2WC
zqfYjQ7@^>myoF?F;*ZExp2&nnIs#E>{7qoJ;5zB!rmqpc_;~A#5>??KA0g7q%tZ@C
z4P#s<yF0NK1FQ3=KF0=Ht4|$->!-Z958)-zJSErZ5jDf30~J_84zZsoz~0UVn`Q49
z;zd`Gj&2qhjCcEtCBzzOms|@vqm9GX`@F<NE(RwqP-q)z-z-~*ZWt_$lX@Ai4R&3@
zgDZmi4J=i{_kIif+H!U+dUN=c4nk^Zl}KC2k@V*z$HNA$C*7Fj@UU(vV|X{P3n|y@
zi_qM2OE$u&!t9qyJgpMr&uq}pOdf_w?bvx9uYfg)GN%^(E<8qTokZ3Yi6fmM<u-Op
zwea-7qOGl&k+<A;$_P2Q%|dZpHAW0If13zgpX2#=laW_7oN9(w33!DlvgmDcp$!uZ
z-|2+ws~F`y#@Qs6sy8E|1GCRTKhVw0@q>sNYCB8Bp;gtVcIXM|1(XV`tw1bsIJ!RB
z7pmU*WCfeu#ipg;r=574oSPOSHZofO>L!#AT0ykS(3KiD1uAk>a>)BWLqhbOH&m@q
zL)ZXS9tUZAcmRMDMjr*pgDNvVKx5)@i^_x#&=@!lybwj~b{c9N44Kf!z4@ySb3O)7
z7znyRy|IDQ+)U;QByD4A7i$Z#nj4$vvyOlVtDb_veBR7}=5FDlAd}7;kdX}B&`{1D
z-;F7Z2@qq^VJew!OB7FBX`Ewapa#W8niT_wk&-}<9kvl{Tzhi8*%t&{Q1lX*4EIe;
z=>FFn1(AHb$uQV3L(x%%0E<z^9~^!`Bt9>7txHrPJu@6a4=_z}eh*7AE+YKb`B<<`
zj7K-QX(8mLPnAItuVMmDiEmgJ$y;G3S*gl!GXk7qep^O>$h|!3_wM6lL?1E(>usrV
Jf<M&|t?j=z`0@Y%
literal 5976
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
G5UuU4uRFp3
diff --git a/src/box/lua/upgrade.lua b/src/box/lua/upgrade.lua
index add791cd7..54fc82dc6 100644
--- a/src/box/lua/upgrade.lua
+++ b/src/box/lua/upgrade.lua
@@ -971,6 +971,148 @@ local function upgrade_to_2_3_1()
create_session_settings_space()
end
+--------------------------------------------------------------------------------
+-- Tarantool 2.5.2
+--------------------------------------------------------------------------------
+
+local function update_sql_builtin_functions()
+ local _func = box.space[box.schema.FUNC_ID]
+ local updates
+
+ _func:run_triggers(false)
+ updates = {{'=', 'param_list', {'number'}}, {'=', 'returns', 'number'},
+ {'=', 'is_deterministic', true}, {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('ABS', updates)
+
+ updates = {{'=', 'param_list', {'number'}}, {'=', 'returns', 'number'},
+ {'=', 'aggregate', 'group'}, {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('AVG', updates)
+ _func.index[2]:update('SUM', updates)
+ _func.index[2]:update('TOTAL', updates)
+
+ updates = {{'=', 'param_list', {'unsigned'}}, {'=', 'returns', 'string'},
+ {'=', 'is_deterministic', true}, {'=', 'exports', {'SQL'}},
+ {'=', 'opts', {has_vararg = true}}}
+ _func.index[2]:update('CHAR', updates)
+
+ updates = {{'=', 'param_list', {'scalar'}}, {'=', 'returns', 'integer'},
+ {'=', 'is_deterministic', true}, {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('CHARACTER_LENGTH', updates)
+ _func.index[2]:update('CHAR_LENGTH', updates)
+ _func.index[2]:update('LENGTH', updates)
+
+ updates = {{'=', 'param_list', {'scalar'}}, {'=', 'returns', 'scalar'},
+ {'=', 'is_deterministic', true}, {'=', 'exports', {'SQL'}},
+ {'=', 'opts', {has_vararg = true}}}
+ _func.index[2]:update('COALESCE', updates)
+
+ updates = {{'=', 'param_list', {'scalar'}}, {'=', 'returns', 'integer'},
+ {'=', 'aggregate', 'group'}, {'=', 'exports', {'SQL'}},
+ {'=', 'opts', {has_vararg = true}}}
+ _func.index[2]:update('COUNT', updates)
+
+ updates = {{'=', 'param_list', {'scalar'}}, {'=', 'returns', 'scalar'},
+ {'=', 'is_deterministic', true}, {'=', 'exports', {'SQL'}},
+ {'=', 'opts', {has_vararg = true}}}
+ _func.index[2]:update('GREATEST', updates)
+ _func.index[2]:update('LEAST', updates)
+
+ updates = {{'=', 'param_list', {'scalar', 'scalar'}},
+ {'=', 'returns', 'string'}, {'=', 'aggregate', 'group'},
+ {'=', 'exports', {'SQL'}}, {'=', 'opts', {has_vararg = true}}}
+ _func.index[2]:update('GROUP_CONCAT', updates)
+
+ updates = {{'=', 'param_list', {'scalar'}}, {'=', 'returns', 'string'},
+ {'=', 'is_deterministic', true}, {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('HEX', updates)
+
+ updates = {{'=', 'param_list', {'scalar', 'scalar'}},
+ {'=', 'returns', 'scalar'}, {'=', 'is_deterministic', true},
+ {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('IFNULL', updates)
+ _func.index[2]:update('NULLIF', updates)
+
+ updates = {{'=', 'param_list', {'scalar', 'scalar', 'scalar'}},
+ {'=', 'returns', 'boolean'}, {'=', 'is_deterministic', true},
+ {'=', 'exports', {'SQL'}}, {'=', 'opts', {has_vararg = true}}}
+ _func.index[2]:update('LIKE', updates)
+
+ updates = {{'=', 'param_list', {'scalar', 'double'}},
+ {'=', 'returns', 'scalar'}, {'=', 'is_deterministic', true},
+ {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('LIKELIHOOD', updates)
+
+ updates = {{'=', 'param_list', {'scalar'}}, {'=', 'returns', 'scalar'},
+ {'=', 'is_deterministic', true}, {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('LIKELY', updates)
+ _func.index[2]:update('UNLIKELY', updates)
+
+ updates = {{'=', 'param_list', {'scalar'}}, {'=', 'returns', 'string'},
+ {'=', 'is_deterministic', true}, {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('LOWER', updates)
+ _func.index[2]:update('QUOTE', updates)
+ _func.index[2]:update('SOUNDEX', updates)
+ _func.index[2]:update('TYPEOF', updates)
+ _func.index[2]:update('UPPER', updates)
+ _func.index[2]:update('UNICODE', updates)
+
+ updates = {{'=', 'param_list', {'scalar'}}, {'=', 'returns', 'scalar'},
+ {'=', 'aggregate', 'group'}, {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('MAX', updates)
+ _func.index[2]:update('MIN', updates)
+
+ updates = {{'=', 'param_list', {'scalar', 'scalar'}},
+ {'=', 'returns', 'integer'}, {'=', 'is_deterministic', true},
+ {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('POSITION', updates)
+
+ updates = {{'=', 'param_list', {'scalar'}}, {'=', 'returns', 'string'},
+ {'=', 'is_deterministic', true}, {'=', 'exports', {'SQL'}},
+ {'=', 'opts', {has_vararg = true}}}
+ _func.index[2]:update('PRINTF', updates)
+ _func.index[2]:update('TRIM', updates)
+
+ updates = {{'=', 'returns', 'integer'}, {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('RANDOM', updates)
+
+ updates = {{'=', 'returns', 'integer'}, {'=', 'is_deterministic', true},
+ {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('ROW_COUNT', updates)
+
+ updates = {{'=', 'param_list', {'unsigned'}},
+ {'=', 'returns', 'varbinary'}, {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('RANDOMBLOB', updates)
+
+ updates = {{'=', 'param_list', {'unsigned'}},
+ {'=', 'returns', 'varbinary'}, {'=', 'is_deterministic', true},
+ {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('ZEROBLOB', updates)
+
+ updates = {{'=', 'param_list', {'scalar', 'scalar', 'scalar'}},
+ {'=', 'returns', 'string'}, {'=', 'is_deterministic', true},
+ {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('REPLACE', updates)
+
+ updates = {{'=', 'param_list', {'double', 'unsigned'}},
+ {'=', 'returns', 'double'}, {'=', 'is_deterministic', true},
+ {'=', 'exports', {'SQL'}}, {'=', 'opts', {has_vararg = true}}}
+ _func.index[2]:update('ROUND', updates)
+
+ updates = {{'=', 'param_list', {'scalar', 'integer', 'integer'}},
+ {'=', 'returns', 'string'}, {'=', 'is_deterministic', true},
+ {'=', 'exports', {'SQL'}}, {'=', 'opts', {has_vararg = true}}}
+ _func.index[2]:update('SUBSTR', updates)
+
+ updates = {{'=', 'returns', 'string'}, {'=', 'is_deterministic', true},
+ {'=', 'exports', {'SQL'}}}
+ _func.index[2]:update('VERSION', updates)
+ _func:run_triggers(true)
+end
+
+local function upgrade_to_2_5_2()
+ update_sql_builtin_functions()
+end
+
--------------------------------------------------------------------------------
local function get_version()
@@ -1007,6 +1149,7 @@ local function upgrade(options)
{version = mkversion(2, 2, 1), func = upgrade_to_2_2_1, auto = true},
{version = mkversion(2, 3, 0), func = upgrade_to_2_3_0, auto = true},
{version = mkversion(2, 3, 1), func = upgrade_to_2_3_1, auto = true},
+ {version = mkversion(2, 5, 2), func = upgrade_to_2_5_2, auto = true},
}
for _, handler in ipairs(handlers) do
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 487cdafe1..df15d303a 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -2188,7 +2188,7 @@ sql_func_by_signature(const char *name, int argc)
if (base == NULL || !base->def->exports.sql)
return NULL;
- if (base->def->param_count != -1 && base->def->param_count != argc)
+ if (!base->def->opts.has_vararg && base->def->param_count != argc)
return NULL;
return base;
}
@@ -2929,11 +2929,6 @@ func_sql_builtin_new(struct func_def *def)
func->flags = sql_builtins[idx].flags;
func->call = sql_builtins[idx].call;
func->finalize = sql_builtins[idx].finalize;
- def->param_count = sql_builtins[idx].param_count;
- def->is_deterministic = sql_builtins[idx].is_deterministic;
- def->returns = sql_builtins[idx].returns;
- def->aggregate = sql_builtins[idx].aggregate;
- def->exports.sql = sql_builtins[idx].export_to_sql;
return &func->base;
}
diff --git a/src/box/sql/resolve.c b/src/box/sql/resolve.c
index 6f625dc18..5238555c3 100644
--- a/src/box/sql/resolve.c
+++ b/src/box/sql/resolve.c
@@ -614,7 +614,7 @@ resolveExprStep(Walker * pWalker, Expr * pExpr)
pNC->nErr++;
return WRC_Abort;
}
- if (func->def->param_count != -1 &&
+ if (!func->def->opts.has_vararg &&
func->def->param_count != n) {
uint32_t argc = func->def->param_count;
const char *err = tt_sprintf("%d", argc);
diff --git a/test/box-py/bootstrap.result b/test/box-py/bootstrap.result
index 0876e77a6..c56f07cef 100644
--- a/test/box-py/bootstrap.result
+++ b/test/box-py/bootstrap.result
@@ -4,7 +4,7 @@ box.internal.bootstrap()
box.space._schema:select{}
---
- - ['max_id', 511]
- - ['version', 2, 3, 1]
+ - ['version', 2, 5, 2]
...
box.space._cluster:select{}
---
diff --git a/test/sql/types.result b/test/sql/types.result
index 95f7713e8..2498f3a48 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -231,7 +231,7 @@ box.execute("SELECT s LIKE NULL FROM t1;")
---
- metadata:
- name: COLUMN_1
- type: integer
+ type: boolean
rows:
- [null]
...
@@ -257,7 +257,7 @@ box.execute("SELECT NULL LIKE s FROM t1;")
---
- metadata:
- name: COLUMN_1
- type: integer
+ type: boolean
rows:
- [null]
...
--
2.25.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Tarantool-patches] [PATCH v1 4/7] box: add param_list to 'struct func'
2020-08-12 15:15 [Tarantool-patches] [PATCH v1 0/7] sql: properly check arguments types of built-in functions imeevma
` (2 preceding siblings ...)
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 3/7] sql: move built-in function definitions in _func imeevma
@ 2020-08-12 15:15 ` imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 5/7] sql: check built-in functions argument types imeevma
` (2 subsequent siblings)
6 siblings, 0 replies; 8+ messages in thread
From: imeevma @ 2020-08-12 15:15 UTC (permalink / raw)
To: v.shpilevoy; +Cc: tarantool-patches
This is needed to create an uniform way to check the types of arguments
of SQL built-in functions.
Part of #4159
---
src/box/alter.cc | 12 ++++++++++--
src/box/func.c | 1 +
src/box/func_def.h | 2 ++
src/box/lua/call.c | 2 ++
src/box/sql/func.c | 1 +
5 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/src/box/alter.cc b/src/box/alter.cc
index ba96d9c62..0914a7615 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -3293,7 +3293,11 @@ func_def_new_from_tuple(struct tuple *tuple)
diag_set(OutOfMemory, def_sz, "malloc", "def");
return NULL;
}
- auto def_guard = make_scoped_guard([=] { free(def); });
+ def->param_list = NULL;
+ auto def_guard = make_scoped_guard([=] {
+ free(def->param_list);
+ free(def);
+ });
if (func_def_get_ids_from_tuple(tuple, &def->fid, &def->uid) != 0)
return NULL;
if (def->fid > BOX_FUNCTION_MAX) {
@@ -3403,6 +3407,8 @@ func_def_new_from_tuple(struct tuple *tuple)
if (param_list == NULL)
return NULL;
uint32_t argc = mp_decode_array(¶m_list);
+ uint32_t size = sizeof(enum field_type) * argc;
+ def->param_list = (enum field_type *)malloc(size);
for (uint32_t i = 0; i < argc; i++) {
if (mp_typeof(*param_list) != MP_STR) {
diag_set(ClientError, ER_FIELD_TYPE,
@@ -3412,7 +3418,8 @@ func_def_new_from_tuple(struct tuple *tuple)
}
uint32_t len;
const char *str = mp_decode_str(¶m_list, &len);
- if (STRN2ENUM(field_type, str, len) == field_type_MAX) {
+ def->param_list[i] = STRN2ENUM(field_type, str, len);
+ if (def->param_list[i] == field_type_MAX) {
diag_set(ClientError, ER_CREATE_FUNCTION,
def->name, "invalid argument type");
return NULL;
@@ -3433,6 +3440,7 @@ func_def_new_from_tuple(struct tuple *tuple)
/* By default export to Lua, but not other frontends. */
def->exports.lua = true;
def->param_count = 0;
+ assert(def->param_list == NULL);
}
if (func_def_check(def) != 0)
return NULL;
diff --git a/src/box/func.c b/src/box/func.c
index 8087c953f..1d20f8872 100644
--- a/src/box/func.c
+++ b/src/box/func.c
@@ -510,6 +510,7 @@ func_c_destroy(struct func *base)
{
assert(base->vtab == &func_c_vtab);
assert(base != NULL && base->def->language == FUNC_LANGUAGE_C);
+ free(base->def->param_list);
struct func_c *func = (struct func_c *) base;
func_c_unload(func);
TRASH(base);
diff --git a/src/box/func_def.h b/src/box/func_def.h
index 89d5a404a..8b86167af 100644
--- a/src/box/func_def.h
+++ b/src/box/func_def.h
@@ -117,6 +117,8 @@ struct func_def {
bool is_sandboxed;
/** The count of function's input arguments. */
int param_count;
+ /** List of input arguments to the function. */
+ enum field_type *param_list;
/** The type of the value returned by function. */
enum field_type returns;
/** Function aggregate option. */
diff --git a/src/box/lua/call.c b/src/box/lua/call.c
index 0315e720c..1dc4589dd 100644
--- a/src/box/lua/call.c
+++ b/src/box/lua/call.c
@@ -783,6 +783,7 @@ func_lua_destroy(struct func *func)
{
assert(func != NULL && func->def->language == FUNC_LANGUAGE_LUA);
assert(func->vtab == &func_lua_vtab);
+ free(func->def->param_list);
TRASH(func);
free(func);
}
@@ -812,6 +813,7 @@ func_persistent_lua_destroy(struct func *base)
assert(base != NULL && base->def->language == FUNC_LANGUAGE_LUA &&
base->def->body != NULL);
assert(base->vtab == &func_persistent_lua_vtab);
+ free(base->def->param_list);
struct func_lua *func = (struct func_lua *) base;
func_persistent_lua_unload(func);
free(func);
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index df15d303a..91755380d 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -2937,6 +2937,7 @@ func_sql_builtin_destroy(struct func *func)
{
assert(func->vtab == &func_sql_builtin_vtab);
assert(func->def->language == FUNC_LANGUAGE_SQL_BUILTIN);
+ free(func->def->param_list);
free(func);
}
--
2.25.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Tarantool-patches] [PATCH v1 5/7] sql: check built-in functions argument types
2020-08-12 15:15 [Tarantool-patches] [PATCH v1 0/7] sql: properly check arguments types of built-in functions imeevma
` (3 preceding siblings ...)
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 4/7] box: add param_list to 'struct func' imeevma
@ 2020-08-12 15:15 ` imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 6/7] sql: VARBINARY and STRING in built-in functions imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 7/7] sql: refactor sql/func.c imeevma
6 siblings, 0 replies; 8+ messages in thread
From: imeevma @ 2020-08-12 15:15 UTC (permalink / raw)
To: v.shpilevoy; +Cc: tarantool-patches
This patch creates a uniform way to check the argument types of SQL
built-in functions. Prior to this patch, argument types were checked
inside functions. They are now checked in most cases in the ApplyType
opcode.
The only case where there is additional validation in a function is when
a function can take either STRING or VARBINARY as an argument. In this
case, the definition says that the function accepts a SCALAR, but in
fact only STRING or VARBINARY should be accepted. This case will be
completely fixed in the next patches of the patch set.
Part of #4159
---
src/box/sql/expr.c | 4 ++++
src/box/sql/select.c | 26 ++++++++++++++++++++++++++
src/box/sql/sqlInt.h | 14 ++++++++++++++
test/sql-tap/func.test.lua | 22 +++++++++++-----------
test/sql/boolean.result | 2 +-
test/sql/checks.result | 8 --------
test/sql/checks.test.lua | 2 --
test/sql/types.result | 2 +-
8 files changed, 57 insertions(+), 23 deletions(-)
diff --git a/src/box/sql/expr.c b/src/box/sql/expr.c
index bc2182446..e2c8e1385 100644
--- a/src/box/sql/expr.c
+++ b/src/box/sql/expr.c
@@ -4120,6 +4120,10 @@ sqlExprCodeTarget(Parse * pParse, Expr * pExpr, int target)
} else {
r1 = 0;
}
+ if (func->def->language == FUNC_LANGUAGE_SQL_BUILTIN) {
+ sql_emit_func_arg_type_check(v, func, r1,
+ nFarg);
+ }
if (sql_func_flag_is_set(func, SQL_FUNC_NEEDCOLL)) {
sqlVdbeAddOp4(v, OP_CollSeq, 0, 0, 0,
(char *)coll, P4_COLLSEQ);
diff --git a/src/box/sql/select.c b/src/box/sql/select.c
index b0554a172..49f01eb0d 100644
--- a/src/box/sql/select.c
+++ b/src/box/sql/select.c
@@ -124,6 +124,31 @@ clearSelect(sql * db, Select * p, int bFree)
}
}
+void
+sql_emit_func_arg_type_check(struct Vdbe *vdbe, struct func *func, int reg,
+ uint32_t argc)
+{
+ if (argc == 0 || func->def->param_list == NULL)
+ return;
+ assert(func->def->param_count > 0);
+ uint32_t len = (uint32_t)func->def->param_count;
+ assert(len > 0);
+ size_t size = (argc + 1) * sizeof(enum field_type);
+ enum field_type *types = sqlDbMallocZero(sql_get(), size);
+ if (argc <= len) {
+ for (uint32_t i = 0; i < argc; ++i)
+ types[i] = func->def->param_list[i];
+ } else {
+ for (uint32_t i = 0; i < len; ++i)
+ types[i] = func->def->param_list[i];
+ for (uint32_t i = len; i < argc; ++i)
+ types[i] = func->def->param_list[len - 1];
+ }
+ types[argc] = field_type_MAX;
+ sqlVdbeAddOp4(vdbe, OP_ApplyType, reg, argc, 0, (char *)types,
+ P4_DYNAMIC);
+}
+
/*
* Initialize a SelectDest structure.
*/
@@ -5420,6 +5445,7 @@ updateAccumulator(Parse * pParse, AggInfo * pAggInfo)
vdbe_insert_distinct(pParse, pF->iDistinct, pF->reg_eph,
addrNext, 1, regAgg);
}
+ sql_emit_func_arg_type_check(v, pF->func, regAgg, nArg);
if (sql_func_flag_is_set(pF->func, SQL_FUNC_NEEDCOLL)) {
struct coll *coll = NULL;
struct ExprList_item *pItem;
diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h
index adf90d824..d02614140 100644
--- a/src/box/sql/sqlInt.h
+++ b/src/box/sql/sqlInt.h
@@ -3883,6 +3883,20 @@ sql_index_type_str(struct sql *db, const struct index_def *idx_def);
void
sql_emit_table_types(struct Vdbe *v, struct space_def *def, int reg);
+/**
+ * Code an OP_ApplyType opcode that try to cast implicitly types
+ * for given range of register starting from @a reg. These values
+ * then will be used as arguments of a function.
+ *
+ * @param vdbe VDBE.
+ * @param func Definition of the function.
+ * @param reg Register where types will be placed.
+ * @param argc Number of arguments.
+ */
+void
+sql_emit_func_arg_type_check(struct Vdbe *vdbe, struct func *func,
+ int reg, uint32_t argc);
+
enum field_type
sql_type_result(enum field_type lhs, enum field_type rhs);
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index 3c088920f..82cf350ea 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -412,13 +412,13 @@ test:do_execsql_test(
-- </func-4.4.1>
})
-test:do_execsql_test(
+test:do_catchsql_test(
"func-4.4.2",
[[
SELECT abs(t1) FROM tbl1
]], {
-- <func-4.4.2>
- 0.0, 0.0, 0.0, 0.0, 0.0
+ 1, "Type mismatch: can not convert this to number"
-- </func-4.4.2>
})
@@ -502,13 +502,13 @@ test:do_execsql_test(
-- </func-4.12>
})
-test:do_execsql_test(
+test:do_catchsql_test(
"func-4.13",
[[
SELECT round(t1,2) FROM tbl1
]], {
-- <func-4.13>
- 0.0, 0.0, 0.0, 0.0, 0.0
+ 1, "Type mismatch: can not convert this to double"
-- </func-4.13>
})
@@ -893,7 +893,7 @@ test:do_execsql_test(
test:do_execsql_test(
"func-8.5",
[[
- SELECT sum(x) FROM (SELECT '9223372036' || '854775807' AS x
+ SELECT sum(x) FROM (SELECT CAST('9223372036' || '854775807' AS INTEGER) AS x
UNION ALL SELECT -9223372036854775807)
]], {
-- <func-8.5>
@@ -904,7 +904,7 @@ test:do_execsql_test(
test:do_execsql_test(
"func-8.6",
[[
- SELECT typeof(sum(x)) FROM (SELECT '9223372036' || '854775807' AS x
+ SELECT typeof(sum(x)) FROM (SELECT CAST('9223372036' || '854775807' AS INTEGER) AS x
UNION ALL SELECT -9223372036854775807)
]], {
-- <func-8.6>
@@ -915,7 +915,7 @@ test:do_execsql_test(
test:do_execsql_test(
"func-8.7",
[[
- SELECT typeof(sum(x)) FROM (SELECT '9223372036' || '854775808' AS x
+ SELECT typeof(sum(x)) FROM (SELECT CAST('9223372036' || '854775808' AS INTEGER) AS x
UNION ALL SELECT -9223372036854775807)
]], {
-- <func-8.7>
@@ -926,7 +926,7 @@ test:do_execsql_test(
test:do_execsql_test(
"func-8.8",
[[
- SELECT sum(x)>0.0 FROM (SELECT '9223372036' || '854775808' AS x
+ SELECT sum(x)>0.0 FROM (SELECT CAST('9223372036' || '854775808' AS INTEGER) AS x
UNION ALL SELECT -9223372036850000000)
]], {
-- <func-8.8>
@@ -985,7 +985,7 @@ test:do_execsql_test(
test:do_execsql_test(
"func-9.5",
[[
- SELECT length(randomblob(32)), length(randomblob(-5)),
+ SELECT length(randomblob(32)), length(randomblob(0)),
length(randomblob(2000))
]], {
-- <func-9.5>
@@ -2918,7 +2918,7 @@ test:do_catchsql_test(
SELECT ROUND(X'FF')
]], {
-- <func-76.1>
- 1, "Type mismatch: can not convert varbinary to numeric"
+ 1, "Type mismatch: can not convert varbinary to double"
-- </func-76.1>
})
@@ -2928,7 +2928,7 @@ test:do_catchsql_test(
SELECT RANDOMBLOB(X'FF')
]], {
-- <func-76.2>
- 1, "Type mismatch: can not convert varbinary to numeric"
+ 1, "Type mismatch: can not convert varbinary to unsigned"
-- </func-76.2>
})
diff --git a/test/sql/boolean.result b/test/sql/boolean.result
index 51ec5820b..d366aca7d 100644
--- a/test/sql/boolean.result
+++ b/test/sql/boolean.result
@@ -276,7 +276,7 @@ SELECT is_boolean('true');
SELECT abs(a) FROM t0;
| ---
| - null
- | - 'Inconsistent types: expected number got boolean'
+ | - 'Type mismatch: can not convert FALSE to number'
| ...
SELECT lower(a) FROM t0;
| ---
diff --git a/test/sql/checks.result b/test/sql/checks.result
index 7b18e5d6b..3c942fb23 100644
--- a/test/sql/checks.result
+++ b/test/sql/checks.result
@@ -519,14 +519,6 @@ s:insert({1, 'string'})
---
- error: 'Check constraint failed ''complex2'': typeof(coalesce(z,0))==''integer'''
...
-s:insert({1, {map=true}})
----
-- error: 'Check constraint failed ''complex2'': typeof(coalesce(z,0))==''integer'''
-...
-s:insert({1, {'a', 'r','r','a','y'}})
----
-- error: 'Check constraint failed ''complex2'': typeof(coalesce(z,0))==''integer'''
-...
s:insert({1, 3.14})
---
- error: 'Check constraint failed ''complex2'': typeof(coalesce(z,0))==''integer'''
diff --git a/test/sql/checks.test.lua b/test/sql/checks.test.lua
index 301f8ea69..b55abe955 100644
--- a/test/sql/checks.test.lua
+++ b/test/sql/checks.test.lua
@@ -173,8 +173,6 @@ s:format({{name='X', type='integer'}, {name='Z', type='any'}})
_ = s:create_index('pk', {parts = {1, 'integer'}})
_ = box.space._ck_constraint:insert({s.id, 'complex2', false, 'SQL', 'typeof(coalesce(z,0))==\'integer\'', true})
s:insert({1, 'string'})
-s:insert({1, {map=true}})
-s:insert({1, {'a', 'r','r','a','y'}})
s:insert({1, 3.14})
s:insert({1, 666})
s:drop()
diff --git a/test/sql/types.result b/test/sql/types.result
index 2498f3a48..82a82117b 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -1322,7 +1322,7 @@ box.execute("SELECT upper(v) FROM t;")
box.execute("SELECT abs(v) FROM t;")
---
- null
-- 'Inconsistent types: expected number got varbinary'
+- 'Type mismatch: can not convert varbinary to number'
...
box.execute("SELECT typeof(v) FROM t;")
---
--
2.25.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Tarantool-patches] [PATCH v1 6/7] sql: VARBINARY and STRING in built-in functions
2020-08-12 15:15 [Tarantool-patches] [PATCH v1 0/7] sql: properly check arguments types of built-in functions imeevma
` (4 preceding siblings ...)
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 5/7] sql: check built-in functions argument types imeevma
@ 2020-08-12 15:15 ` imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 7/7] sql: refactor sql/func.c imeevma
6 siblings, 0 replies; 8+ messages in thread
From: imeevma @ 2020-08-12 15:15 UTC (permalink / raw)
To: v.shpilevoy; +Cc: tarantool-patches
This patch forces SQL built-in functions to accept VARBINARY arguments
and treat them as STRING arguments if they were given in place of STRING
arguments.
Closes #4159
---
src/box/sql/func.c | 89 +-
test/sql-tap/cse.test.lua | 4 +-
test/sql-tap/func.test.lua | 14 +-
test/sql-tap/orderby1.test.lua | 2 +-
test/sql-tap/position.test.lua | 6 +-
test/sql/boolean.result | 30 +-
test/sql/types.result | 1471 +++++++++++++++++++++++++++++++-
test/sql/types.test.lua | 244 ++++++
8 files changed, 1758 insertions(+), 102 deletions(-)
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 91755380d..694bd0e83 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -463,34 +463,23 @@ typeofFunc(sql_context * context, int NotUsed, sql_value ** argv)
static void
lengthFunc(sql_context * context, int argc, sql_value ** argv)
{
- int len;
-
assert(argc == 1);
UNUSED_PARAMETER(argc);
- switch (sql_value_type(argv[0])) {
- case MP_BIN:
- case MP_ARRAY:
- case MP_MAP:
- case MP_INT:
- case MP_UINT:
- case MP_BOOL:
- case MP_DOUBLE:{
- sql_result_uint(context, sql_value_bytes(argv[0]));
- break;
- }
- case MP_STR:{
- const unsigned char *z = sql_value_text(argv[0]);
- if (z == 0)
- return;
- len = sql_utf8_char_count(z, sql_value_bytes(argv[0]));
- sql_result_uint(context, len);
- break;
- }
- default:{
- sql_result_null(context);
- break;
- }
+ if (sql_value_type(argv[0]) == MP_NIL)
+ return sql_result_null(context);
+ if (sql_value_type(argv[0]) == MP_BIN)
+ return sql_result_uint(context, sql_value_bytes(argv[0]));
+ if (sql_value_type(argv[0]) != MP_STR) {
+ diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+ sql_value_to_diag_str(argv[0]), "string or varbinary");
+ context->is_aborted = true;
+ return;
}
+ const unsigned char *str = sql_value_text(argv[0]);
+ if (str == NULL)
+ return sql_result_null(context);
+ int len = sql_utf8_char_count(str, sql_value_bytes(argv[0]));
+ return sql_result_uint(context, len);
}
/*
@@ -576,9 +565,9 @@ position_func(struct sql_context *context, int argc, struct Mem **argv)
if (haystack_type != MP_STR && haystack_type != MP_BIN)
inconsistent_type_arg = haystack;
if (inconsistent_type_arg != NULL) {
- diag_set(ClientError, ER_INCONSISTENT_TYPES,
- "text or varbinary",
- mem_type_to_str(inconsistent_type_arg));
+ diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+ sql_value_to_diag_str(inconsistent_type_arg),
+ "string or varbinary");
context->is_aborted = true;
return;
}
@@ -748,13 +737,20 @@ substrFunc(sql_context * context, int argc, sql_value ** argv)
if (z == 0)
return;
assert(len == sql_value_bytes(argv[0]));
- } else {
+ } else if (p0type == MP_NIL) {
+ return sql_result_null(context);
+ } else if (p0type == MP_STR) {
z = sql_value_text(argv[0]);
if (z == 0)
return;
len = 0;
if (p1 < 0)
len = sql_utf8_char_count(z, sql_value_bytes(argv[0]));
+ } else {
+ diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+ sql_value_to_diag_str(argv[0]), "string or varbinary");
+ context->is_aborted = true;
+ return;
}
if (argc == 3) {
p2 = sql_value_int(argv[2]);
@@ -906,10 +902,15 @@ case_type##ICUFunc(sql_context *context, int argc, sql_value **argv) \
const char *z2; \
int n; \
UNUSED_PARAMETER(argc); \
- int arg_type = sql_value_type(argv[0]); \
- if (mp_type_is_bloblike(arg_type)) { \
- diag_set(ClientError, ER_INCONSISTENT_TYPES, "text", \
- "varbinary"); \
+ enum mp_type type = sql_value_type(argv[0]); \
+ if (type == MP_NIL) \
+ return sql_result_null(context); \
+ if (type == MP_BIN) \
+ return sql_result_value(context, argv[0]); \
+ if (type != MP_STR) { \
+ diag_set(ClientError, ER_SQL_TYPE_MISMATCH, \
+ sql_value_to_diag_str(argv[0]), \
+ "string or varbinary"); \
context->is_aborted = true; \
return; \
} \
@@ -1452,6 +1453,13 @@ quoteFunc(sql_context * context, int argc, sql_value ** argv)
static void
unicodeFunc(sql_context * context, int argc, sql_value ** argv)
{
+ enum mp_type type = sql_value_type(argv[0]);
+ if (type != MP_NIL && type != MP_STR && type != MP_BIN) {
+ diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+ sql_value_to_diag_str(argv[0]), "string or varbinary");
+ context->is_aborted = true;
+ return;
+ }
const unsigned char *z = sql_value_text(argv[0]);
(void)argc;
if (z && z[0])
@@ -1568,6 +1576,17 @@ replaceFunc(sql_context * context, int argc, sql_value ** argv)
int loopLimit; /* Last zStr[] that might match zPattern[] */
int i, j; /* Loop counters */
+ for (int i = 0; i < 3; ++i) {
+ enum mp_type type = sql_value_type(argv[i]);
+ if (type != MP_NIL && type != MP_STR && type != MP_BIN) {
+ diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
+ sql_value_to_diag_str(argv[i]),
+ "string or varbinary");
+ context->is_aborted = true;
+ return;
+ }
+ }
+
assert(argc == 3);
UNUSED_PARAMETER(argc);
zStr = sql_value_text(argv[0]);
@@ -1880,9 +1899,9 @@ soundexFunc(sql_context * context, int argc, sql_value ** argv)
};
assert(argc == 1);
enum mp_type mp_type = sql_value_type(argv[0]);
- if (mp_type_is_bloblike(mp_type)) {
+ if (mp_type != MP_NIL && mp_type != MP_STR && mp_type != MP_BIN) {
diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
- sql_value_to_diag_str(argv[0]), "text");
+ sql_value_to_diag_str(argv[0]), "string or varbinary");
context->is_aborted = true;
return;
}
diff --git a/test/sql-tap/cse.test.lua b/test/sql-tap/cse.test.lua
index 341b6de01..cfb642cfe 100755
--- a/test/sql-tap/cse.test.lua
+++ b/test/sql-tap/cse.test.lua
@@ -198,7 +198,7 @@ test:do_execsql_test(
test:do_execsql_test(
"cse-1.13",
[[
- SELECT upper(b), typeof(b), b FROM t1
+ SELECT upper(CAST(b AS STRING)), typeof(b), b FROM t1
]], {
-- <cse-1.13>
"11", "integer", 11, "21", "integer", 21
@@ -208,7 +208,7 @@ test:do_execsql_test(
test:do_execsql_test(
"cse-1.14",
[[
- SELECT b, typeof(b), upper(b), typeof(b), b FROM t1
+ SELECT b, typeof(b), upper(CAST(b AS STRING)), typeof(b), b FROM t1
]], {
-- <cse-1.14>
11, "integer", "11", "integer", 11, 21, "integer", "21", "integer", 21
diff --git a/test/sql-tap/func.test.lua b/test/sql-tap/func.test.lua
index 82cf350ea..29d6e422c 100755
--- a/test/sql-tap/func.test.lua
+++ b/test/sql-tap/func.test.lua
@@ -95,7 +95,7 @@ test:do_execsql_test(
test:do_execsql_test(
"func-1.4",
[[
- SELECT coalesce(length(a),-1) FROM t2
+ SELECT coalesce(length(CAST(a AS STRING)),-1) FROM t2
]], {
-- <func-1.4>
1, -1, 3, -1, 5
@@ -197,7 +197,7 @@ test:do_execsql_test(
test:do_execsql_test(
"func-2.9",
[[
- SELECT substr(a,1,1) FROM t2
+ SELECT substr(CAST(a AS STRING),1,1) FROM t2
]], {
-- <func-2.9>
"1", "", "3", "", "6"
@@ -207,7 +207,7 @@ test:do_execsql_test(
test:do_execsql_test(
"func-2.10",
[[
- SELECT substr(a,2,2) FROM t2
+ SELECT substr(CAST(a AS STRING),2,2) FROM t2
]], {
-- <func-2.10>
"", "", "45", "", "78"
@@ -763,7 +763,7 @@ test:do_execsql_test(
test:do_execsql_test(
"func-5.3",
[[
- SELECT upper(a), lower(a) FROM t2
+ SELECT upper(CAST(a AS STRING)), lower(CAST(a AS STRING)) FROM t2
]], {
-- <func-5.3>
"1","1","","","345","345","","","67890","67890"
@@ -797,7 +797,7 @@ test:do_execsql_test(
test:do_execsql_test(
"func-6.2",
[[
- SELECT coalesce(upper(a),'nil') FROM t2
+ SELECT coalesce(upper(CAST(a AS STRING)),'nil') FROM t2
]], {
-- <func-6.2>
"1","nil","345","nil","67890"
@@ -2932,13 +2932,13 @@ test:do_catchsql_test(
-- </func-76.2>
})
-test:do_catchsql_test(
+test:do_execsql_test(
"func-76.3",
[[
SELECT SOUNDEX(X'FF')
]], {
-- <func-76.3>
- 1, "Type mismatch: can not convert varbinary to text"
+ "?000"
-- </func-76.3>
})
diff --git a/test/sql-tap/orderby1.test.lua b/test/sql-tap/orderby1.test.lua
index 51e8d301f..95a8de487 100755
--- a/test/sql-tap/orderby1.test.lua
+++ b/test/sql-tap/orderby1.test.lua
@@ -735,7 +735,7 @@ test:do_execsql_test(
SELECT (
SELECT 'hardware' FROM (
SELECT 'software' ORDER BY 'firmware' ASC, 'sportswear' DESC
- ) GROUP BY 1 HAVING length(b) <> 0
+ ) GROUP BY 1 HAVING length(CAST(b AS STRING)) <> 0
)
FROM abc;
]], {
diff --git a/test/sql-tap/position.test.lua b/test/sql-tap/position.test.lua
index e0455abc9..a84e11cd0 100755
--- a/test/sql-tap/position.test.lua
+++ b/test/sql-tap/position.test.lua
@@ -228,7 +228,7 @@ test:do_test(
return test:catchsql "SELECT position(34, 12345);"
end, {
-- <position-1.23>
- 1, "Inconsistent types: expected text or varbinary got unsigned"
+ 1, "Type mismatch: can not convert 12345 to string or varbinary"
-- </position-1.23>
})
@@ -238,7 +238,7 @@ test:do_test(
return test:catchsql "SELECT position(34, 123456.78);"
end, {
-- <position-1.24>
- 1, "Inconsistent types: expected text or varbinary got real"
+ 1, "Type mismatch: can not convert 123456.78 to string or varbinary"
-- </position-1.24>
})
@@ -248,7 +248,7 @@ test:do_test(
return test:catchsql "SELECT position(x'3334', 123456.78);"
end, {
-- <position-1.25>
- 1, "Inconsistent types: expected text or varbinary got real"
+ 1, "Type mismatch: can not convert 123456.78 to string or varbinary"
-- </position-1.25>
})
diff --git a/test/sql/boolean.result b/test/sql/boolean.result
index d366aca7d..743183f7d 100644
--- a/test/sql/boolean.result
+++ b/test/sql/boolean.result
@@ -280,25 +280,13 @@ SELECT abs(a) FROM t0;
| ...
SELECT lower(a) FROM t0;
| ---
- | - metadata:
- | - name: COLUMN_1
- | type: string
- | rows:
- | - ['false']
- | - ['true']
- | - [null]
- | - [null]
+ | - null
+ | - 'Type mismatch: can not convert FALSE to string or varbinary'
| ...
SELECT upper(a) FROM t0;
| ---
- | - metadata:
- | - name: COLUMN_1
- | type: string
- | rows:
- | - ['FALSE']
- | - ['TRUE']
- | - [null]
- | - [null]
+ | - null
+ | - 'Type mismatch: can not convert FALSE to string or varbinary'
| ...
SELECT quote(a) FROM t0;
| ---
@@ -314,14 +302,8 @@ SELECT quote(a) FROM t0;
-- gh-4462: LENGTH didn't take BOOLEAN arguments.
SELECT length(a) FROM t0;
| ---
- | - metadata:
- | - name: COLUMN_1
- | type: integer
- | rows:
- | - [5]
- | - [4]
- | - [null]
- | - [null]
+ | - null
+ | - 'Type mismatch: can not convert FALSE to string or varbinary'
| ...
SELECT typeof(a) FROM t0;
| ---
diff --git a/test/sql/types.result b/test/sql/types.result
index 82a82117b..c3eb4e27d 100644
--- a/test/sql/types.result
+++ b/test/sql/types.result
@@ -830,19 +830,13 @@ box.execute("DELETE FROM t WHERE i < 18446744073709551613;")
...
box.execute("SELECT lower(i) FROM t;")
---
-- metadata:
- - name: COLUMN_1
- type: string
- rows:
- - ['18446744073709551613']
+- null
+- 'Type mismatch: can not convert 18446744073709551613 to string or varbinary'
...
box.execute("SELECT upper(i) FROM t;")
---
-- metadata:
- - name: COLUMN_1
- type: string
- rows:
- - ['18446744073709551613']
+- null
+- 'Type mismatch: can not convert 18446744073709551613 to string or varbinary'
...
box.execute("SELECT abs(i) FROM t;")
---
@@ -1311,13 +1305,19 @@ box.execute("SELECT group_concat(v) FROM t;")
...
box.execute("SELECT lower(v) FROM t;")
---
-- null
-- 'Inconsistent types: expected text got varbinary'
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['abc']
...
box.execute("SELECT upper(v) FROM t;")
---
-- null
-- 'Inconsistent types: expected text got varbinary'
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['abc']
...
box.execute("SELECT abs(v) FROM t;")
---
@@ -1879,25 +1879,13 @@ box.execute("SELECT group_concat(d) FROM t;")
...
box.execute("SELECT lower(d) FROM t;")
---
-- metadata:
- - name: COLUMN_1
- type: string
- rows:
- - ['10.0']
- - ['-2.0']
- - ['3.3']
- - ['1.8e+19']
+- null
+- 'Type mismatch: can not convert 10.0 to string or varbinary'
...
box.execute("SELECT upper(d) FROM t;")
---
-- metadata:
- - name: COLUMN_1
- type: string
- rows:
- - ['10.0']
- - ['-2.0']
- - ['3.3']
- - ['1.8E+19']
+- null
+- 'Type mismatch: can not convert 10.0 to string or varbinary'
...
box.execute("SELECT abs(d) FROM t;")
---
@@ -2807,3 +2795,1426 @@ box.execute([[SELECT typeof(length('abc'));]])
rows:
- ['integer']
...
+-- Make sure the function argument types are checked.
+box.execute([[SELECT abs(-1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: number
+ rows:
+ - [1]
+...
+box.execute([[SELECT abs(1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: number
+ rows:
+ - [1]
+...
+box.execute([[SELECT abs(1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: number
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT abs(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to number'
+...
+box.execute([[SELECT abs('a');]])
+---
+- null
+- 'Type mismatch: can not convert a to number'
+...
+box.execute([[SELECT abs(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to number'
+...
+box.execute([[SELECT char(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to unsigned'
+...
+box.execute([[SELECT char(1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ["\x01"]
+...
+box.execute([[SELECT char(1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ["\x01"]
+...
+box.execute([[SELECT char(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to unsigned'
+...
+box.execute([[SELECT char('a');]])
+---
+- null
+- 'Type mismatch: can not convert a to unsigned'
+...
+box.execute([[SELECT char(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to unsigned'
+...
+box.execute([[SELECT character_length(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string or varbinary'
+...
+box.execute([[SELECT character_length(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string or varbinary'
+...
+box.execute([[SELECT character_length(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string or varbinary'
+...
+box.execute([[SELECT character_length(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string or varbinary'
+...
+box.execute([[SELECT character_length('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT character_length(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT char_length(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string or varbinary'
+...
+box.execute([[SELECT char_length(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string or varbinary'
+...
+box.execute([[SELECT char_length(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string or varbinary'
+...
+box.execute([[SELECT char_length(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string or varbinary'
+...
+box.execute([[SELECT char_length('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT char_length(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT coalesce(-1, -1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [-1]
+...
+box.execute([[SELECT coalesce(1, 1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [1]
+...
+box.execute([[SELECT coalesce(1.5, 1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT coalesce(true, true);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [true]
+...
+box.execute([[SELECT coalesce('a', 'a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - ['a']
+...
+box.execute([[SELECT coalesce(X'33', X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - ['3']
+...
+box.execute([[SELECT greatest(-1, -1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [-1]
+...
+box.execute([[SELECT greatest(1, 1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [1]
+...
+box.execute([[SELECT greatest(1.5, 1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT greatest(true, true);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [true]
+...
+box.execute([[SELECT greatest('a', 'a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - ['a']
+...
+box.execute([[SELECT greatest(X'33', X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - ['3']
+...
+box.execute([[SELECT hex(-1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['2D31']
+...
+box.execute([[SELECT hex(1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['31']
+...
+box.execute([[SELECT hex(1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['312E35']
+...
+box.execute([[SELECT hex(true);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['54525545']
+...
+box.execute([[SELECT hex('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['61']
+...
+box.execute([[SELECT hex(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['33']
+...
+box.execute([[SELECT ifnull(-1, -1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [-1]
+...
+box.execute([[SELECT ifnull(1, 1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [1]
+...
+box.execute([[SELECT ifnull(1.5, 1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT ifnull(true, true);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [true]
+...
+box.execute([[SELECT ifnull('a', 'a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - ['a']
+...
+box.execute([[SELECT ifnull(X'33', X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - ['3']
+...
+box.execute([[SELECT least(-1, -1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [-1]
+...
+box.execute([[SELECT least(1, 1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [1]
+...
+box.execute([[SELECT least(1.5, 1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT least(true, true);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [true]
+...
+box.execute([[SELECT least('a', 'a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - ['a']
+...
+box.execute([[SELECT least(X'33', X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - ['3']
+...
+box.execute([[SELECT length(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string or varbinary'
+...
+box.execute([[SELECT length(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string or varbinary'
+...
+box.execute([[SELECT length(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string or varbinary'
+...
+box.execute([[SELECT length(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string or varbinary'
+...
+box.execute([[SELECT length('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT length(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT likelihood(-1, -1);]])
+---
+- null
+- Illegal parameters, second argument to likelihood() must be a constant between 0.0
+ and 1.0
+...
+box.execute([[SELECT likelihood(1, 1);]])
+---
+- null
+- Illegal parameters, second argument to likelihood() must be a constant between 0.0
+ and 1.0
+...
+box.execute([[SELECT likelihood(1.5, 1.5);]])
+---
+- null
+- Illegal parameters, second argument to likelihood() must be a constant between 0.0
+ and 1.0
+...
+box.execute([[SELECT likelihood(true, true);]])
+---
+- null
+- Illegal parameters, second argument to likelihood() must be a constant between 0.0
+ and 1.0
+...
+box.execute([[SELECT likelihood('a', 'a');]])
+---
+- null
+- Illegal parameters, second argument to likelihood() must be a constant between 0.0
+ and 1.0
+...
+box.execute([[SELECT likelihood(X'33', X'33');]])
+---
+- null
+- Illegal parameters, second argument to likelihood() must be a constant between 0.0
+ and 1.0
+...
+box.execute([[SELECT likely(-1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [-1]
+...
+box.execute([[SELECT likely(1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT likely(1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: double
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT likely(true);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: boolean
+ rows:
+ - [true]
+...
+box.execute([[SELECT likely('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['a']
+...
+box.execute([[SELECT likely(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: varbinary
+ rows:
+ - ['3']
+...
+box.execute([[SELECT lower(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string or varbinary'
+...
+box.execute([[SELECT lower(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string or varbinary'
+...
+box.execute([[SELECT lower(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string or varbinary'
+...
+box.execute([[SELECT lower(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string or varbinary'
+...
+box.execute([[SELECT lower('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['a']
+...
+box.execute([[SELECT lower(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['3']
+...
+box.execute([[SELECT nullif(-1, -1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [null]
+...
+box.execute([[SELECT nullif(1, 1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [null]
+...
+box.execute([[SELECT nullif(1.5, 1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [null]
+...
+box.execute([[SELECT nullif(true, true);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [null]
+...
+box.execute([[SELECT nullif('a', 'a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [null]
+...
+box.execute([[SELECT nullif(X'33', X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [null]
+...
+box.execute([[SELECT position(-1, -1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string or varbinary'
+...
+box.execute([[SELECT position(1, 1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string or varbinary'
+...
+box.execute([[SELECT position(1.5, 1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string or varbinary'
+...
+box.execute([[SELECT position(true, true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string or varbinary'
+...
+box.execute([[SELECT position('a', 'a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT position(X'33', X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT printf(-1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['-1']
+...
+box.execute([[SELECT printf(1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['1']
+...
+box.execute([[SELECT printf(1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['1.5']
+...
+box.execute([[SELECT printf(true);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['TRUE']
+...
+box.execute([[SELECT printf('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['a']
+...
+box.execute([[SELECT printf(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['3']
+...
+box.execute([[SELECT quote(-1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - [-1]
+...
+box.execute([[SELECT quote(1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - [1]
+...
+box.execute([[SELECT quote(1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['1.5']
+...
+box.execute([[SELECT quote(true);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['TRUE']
+...
+box.execute([[SELECT quote('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['''a''']
+...
+box.execute([[SELECT quote(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['X''33''']
+...
+box.execute([[SELECT randomblob(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to unsigned'
+...
+box.execute([[SELECT randomblob(0);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: varbinary
+ rows:
+ - [null]
+...
+box.execute([[SELECT randomblob(0.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: varbinary
+ rows:
+ - [null]
+...
+box.execute([[SELECT randomblob(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to unsigned'
+...
+box.execute([[SELECT randomblob('a');]])
+---
+- null
+- 'Type mismatch: can not convert a to unsigned'
+...
+box.execute([[SELECT randomblob(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to unsigned'
+...
+box.execute([[SELECT replace(-1, -1, -1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string or varbinary'
+...
+box.execute([[SELECT replace(1, 1, 1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string or varbinary'
+...
+box.execute([[SELECT replace(1.5, 1.5, 1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string or varbinary'
+...
+box.execute([[SELECT replace(true, true, true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string or varbinary'
+...
+box.execute([[SELECT replace('a', 'a', 'a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['a']
+...
+box.execute([[SELECT replace(X'33', X'33', X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['3']
+...
+box.execute([[SELECT round(-1, -1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to unsigned'
+...
+box.execute([[SELECT round(1, 1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: double
+ rows:
+ - [1]
+...
+box.execute([[SELECT round(1.5, 1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: double
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT round(true, true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to double'
+...
+box.execute([[SELECT round('a', 'a');]])
+---
+- null
+- 'Type mismatch: can not convert a to double'
+...
+box.execute([[SELECT round(X'33', X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to double'
+...
+box.execute([[SELECT soundex(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string or varbinary'
+...
+box.execute([[SELECT soundex(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string or varbinary'
+...
+box.execute([[SELECT soundex(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string or varbinary'
+...
+box.execute([[SELECT soundex(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string or varbinary'
+...
+box.execute([[SELECT soundex('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['A000']
+...
+box.execute([[SELECT soundex(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['?000']
+...
+box.execute([[SELECT substr(-1, -1, -1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string or varbinary'
+...
+box.execute([[SELECT substr(1, 1, 1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string or varbinary'
+...
+box.execute([[SELECT substr(1.5, 1.5, 1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string or varbinary'
+...
+box.execute([[SELECT substr(true, true, true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to integer'
+...
+box.execute([[SELECT substr('a', 'a', 'a');]])
+---
+- null
+- 'Type mismatch: can not convert a to integer'
+...
+box.execute([[SELECT substr(X'33', X'33', X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to integer'
+...
+box.execute([[SELECT typeof(-1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['integer']
+...
+box.execute([[SELECT typeof(1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['integer']
+...
+box.execute([[SELECT typeof(1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['double']
+...
+box.execute([[SELECT typeof(true);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['boolean']
+...
+box.execute([[SELECT typeof('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['string']
+...
+box.execute([[SELECT typeof(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['varbinary']
+...
+box.execute([[SELECT unicode(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string or varbinary'
+...
+box.execute([[SELECT unicode(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string or varbinary'
+...
+box.execute([[SELECT unicode(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string or varbinary'
+...
+box.execute([[SELECT unicode(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string or varbinary'
+...
+box.execute([[SELECT unicode('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - [97]
+...
+box.execute([[SELECT unicode(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - [51]
+...
+box.execute([[SELECT unlikely(-1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [-1]
+...
+box.execute([[SELECT unlikely(1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT unlikely(1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: double
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT unlikely(true);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: boolean
+ rows:
+ - [true]
+...
+box.execute([[SELECT unlikely('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['a']
+...
+box.execute([[SELECT unlikely(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: varbinary
+ rows:
+ - ['3']
+...
+box.execute([[SELECT upper(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to string or varbinary'
+...
+box.execute([[SELECT upper(1);]])
+---
+- null
+- 'Type mismatch: can not convert 1 to string or varbinary'
+...
+box.execute([[SELECT upper(1.5);]])
+---
+- null
+- 'Type mismatch: can not convert 1.5 to string or varbinary'
+...
+box.execute([[SELECT upper(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to string or varbinary'
+...
+box.execute([[SELECT upper('a');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['A']
+...
+box.execute([[SELECT upper(X'33');]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['3']
+...
+box.execute([[SELECT zeroblob(-1);]])
+---
+- null
+- 'Type mismatch: can not convert -1 to unsigned'
+...
+box.execute([[SELECT zeroblob(1);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: varbinary
+ rows:
+ - ["\0"]
+...
+box.execute([[SELECT zeroblob(1.5);]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: varbinary
+ rows:
+ - ["\0"]
+...
+box.execute([[SELECT zeroblob(true);]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to unsigned'
+...
+box.execute([[SELECT zeroblob('a');]])
+---
+- null
+- 'Type mismatch: can not convert a to unsigned'
+...
+box.execute([[SELECT zeroblob(X'33');]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to unsigned'
+...
+box.execute([[CREATE TABLE t (i INTEGER PRIMARY KEY, u UNSIGNED, d DOUBLE, b BOOLEAN, s STRING, v VARBINARY);]])
+---
+- row_count: 1
+...
+box.execute([[INSERT INTO t VALUES (-1, 1, 1.5, true, 'a', X'33');]])
+---
+- row_count: 1
+...
+box.execute([[SELECT avg(i) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: number
+ rows:
+ - [-1]
+...
+box.execute([[SELECT avg(u) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: number
+ rows:
+ - [1]
+...
+box.execute([[SELECT avg(d) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: number
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT avg(b) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to number'
+...
+box.execute([[SELECT avg(s) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert a to number'
+...
+box.execute([[SELECT avg(v) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to number'
+...
+box.execute([[SELECT count(i) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT count(u) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT count(d) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT count(b) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT count(s) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT count(v) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: integer
+ rows:
+ - [1]
+...
+box.execute([[SELECT group_concat(i) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['-1']
+...
+box.execute([[SELECT group_concat(u) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['1']
+...
+box.execute([[SELECT group_concat(d) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['1.5']
+...
+box.execute([[SELECT group_concat(b) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['TRUE']
+...
+box.execute([[SELECT group_concat(s) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['a']
+...
+box.execute([[SELECT group_concat(v) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: string
+ rows:
+ - ['3']
+...
+box.execute([[SELECT max(i) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [-1]
+...
+box.execute([[SELECT max(u) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [1]
+...
+box.execute([[SELECT max(d) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT max(b) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [true]
+...
+box.execute([[SELECT max(s) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - ['a']
+...
+box.execute([[SELECT max(v) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - ['3']
+...
+box.execute([[SELECT min(i) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [-1]
+...
+box.execute([[SELECT min(u) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [1]
+...
+box.execute([[SELECT min(d) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT min(b) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - [true]
+...
+box.execute([[SELECT min(s) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - ['a']
+...
+box.execute([[SELECT min(v) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: scalar
+ rows:
+ - ['3']
+...
+box.execute([[SELECT sum(i) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: number
+ rows:
+ - [-1]
+...
+box.execute([[SELECT sum(u) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: number
+ rows:
+ - [1]
+...
+box.execute([[SELECT sum(d) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: number
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT sum(b) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to number'
+...
+box.execute([[SELECT sum(s) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert a to number'
+...
+box.execute([[SELECT sum(v) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to number'
+...
+box.execute([[SELECT total(i) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: number
+ rows:
+ - [-1]
+...
+box.execute([[SELECT total(u) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: number
+ rows:
+ - [1]
+...
+box.execute([[SELECT total(d) FROM t;]])
+---
+- metadata:
+ - name: COLUMN_1
+ type: number
+ rows:
+ - [1.5]
+...
+box.execute([[SELECT total(b) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert TRUE to number'
+...
+box.execute([[SELECT total(s) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert a to number'
+...
+box.execute([[SELECT total(v) FROM t;]])
+---
+- null
+- 'Type mismatch: can not convert varbinary to number'
+...
+box.execute([[DROP TABLE t;]])
+---
+- row_count: 1
+...
diff --git a/test/sql/types.test.lua b/test/sql/types.test.lua
index fff0057bd..ac9128548 100644
--- a/test/sql/types.test.lua
+++ b/test/sql/types.test.lua
@@ -629,3 +629,247 @@ box.execute([[DROP TABLE ts;]])
-- instead of values of type UNSIGNED.
--
box.execute([[SELECT typeof(length('abc'));]])
+
+-- Make sure the function argument types are checked.
+box.execute([[SELECT abs(-1);]])
+box.execute([[SELECT abs(1);]])
+box.execute([[SELECT abs(1.5);]])
+box.execute([[SELECT abs(true);]])
+box.execute([[SELECT abs('a');]])
+box.execute([[SELECT abs(X'33');]])
+
+box.execute([[SELECT char(-1);]])
+box.execute([[SELECT char(1);]])
+box.execute([[SELECT char(1.5);]])
+box.execute([[SELECT char(true);]])
+box.execute([[SELECT char('a');]])
+box.execute([[SELECT char(X'33');]])
+
+box.execute([[SELECT character_length(-1);]])
+box.execute([[SELECT character_length(1);]])
+box.execute([[SELECT character_length(1.5);]])
+box.execute([[SELECT character_length(true);]])
+box.execute([[SELECT character_length('a');]])
+box.execute([[SELECT character_length(X'33');]])
+
+box.execute([[SELECT char_length(-1);]])
+box.execute([[SELECT char_length(1);]])
+box.execute([[SELECT char_length(1.5);]])
+box.execute([[SELECT char_length(true);]])
+box.execute([[SELECT char_length('a');]])
+box.execute([[SELECT char_length(X'33');]])
+
+box.execute([[SELECT coalesce(-1, -1);]])
+box.execute([[SELECT coalesce(1, 1);]])
+box.execute([[SELECT coalesce(1.5, 1.5);]])
+box.execute([[SELECT coalesce(true, true);]])
+box.execute([[SELECT coalesce('a', 'a');]])
+box.execute([[SELECT coalesce(X'33', X'33');]])
+
+box.execute([[SELECT greatest(-1, -1);]])
+box.execute([[SELECT greatest(1, 1);]])
+box.execute([[SELECT greatest(1.5, 1.5);]])
+box.execute([[SELECT greatest(true, true);]])
+box.execute([[SELECT greatest('a', 'a');]])
+box.execute([[SELECT greatest(X'33', X'33');]])
+
+box.execute([[SELECT hex(-1);]])
+box.execute([[SELECT hex(1);]])
+box.execute([[SELECT hex(1.5);]])
+box.execute([[SELECT hex(true);]])
+box.execute([[SELECT hex('a');]])
+box.execute([[SELECT hex(X'33');]])
+
+box.execute([[SELECT ifnull(-1, -1);]])
+box.execute([[SELECT ifnull(1, 1);]])
+box.execute([[SELECT ifnull(1.5, 1);]])
+box.execute([[SELECT ifnull(true, true);]])
+box.execute([[SELECT ifnull('a', 'a');]])
+box.execute([[SELECT ifnull(X'33', X'33');]])
+
+box.execute([[SELECT least(-1, -1);]])
+box.execute([[SELECT least(1, 1);]])
+box.execute([[SELECT least(1.5, 1.5);]])
+box.execute([[SELECT least(true, true);]])
+box.execute([[SELECT least('a', 'a');]])
+box.execute([[SELECT least(X'33', X'33');]])
+
+box.execute([[SELECT length(-1);]])
+box.execute([[SELECT length(1);]])
+box.execute([[SELECT length(1.5);]])
+box.execute([[SELECT length(true);]])
+box.execute([[SELECT length('a');]])
+box.execute([[SELECT length(X'33');]])
+
+box.execute([[SELECT likelihood(-1, -1);]])
+box.execute([[SELECT likelihood(1, 1);]])
+box.execute([[SELECT likelihood(1.5, 1.5);]])
+box.execute([[SELECT likelihood(true, true);]])
+box.execute([[SELECT likelihood('a', 'a');]])
+box.execute([[SELECT likelihood(X'33', X'33');]])
+
+box.execute([[SELECT likely(-1);]])
+box.execute([[SELECT likely(1);]])
+box.execute([[SELECT likely(1.5);]])
+box.execute([[SELECT likely(true);]])
+box.execute([[SELECT likely('a');]])
+box.execute([[SELECT likely(X'33');]])
+
+box.execute([[SELECT lower(-1);]])
+box.execute([[SELECT lower(1);]])
+box.execute([[SELECT lower(1.5);]])
+box.execute([[SELECT lower(true);]])
+box.execute([[SELECT lower('a');]])
+box.execute([[SELECT lower(X'33');]])
+
+box.execute([[SELECT nullif(-1, -1);]])
+box.execute([[SELECT nullif(1, 1);]])
+box.execute([[SELECT nullif(1.5, 1.5);]])
+box.execute([[SELECT nullif(true, true);]])
+box.execute([[SELECT nullif('a', 'a');]])
+box.execute([[SELECT nullif(X'33', X'33');]])
+
+box.execute([[SELECT position(-1, -1);]])
+box.execute([[SELECT position(1, 1);]])
+box.execute([[SELECT position(1.5, 1.5);]])
+box.execute([[SELECT position(true, true);]])
+box.execute([[SELECT position('a', 'a');]])
+box.execute([[SELECT position(X'33', X'33');]])
+
+box.execute([[SELECT printf(-1);]])
+box.execute([[SELECT printf(1);]])
+box.execute([[SELECT printf(1.5);]])
+box.execute([[SELECT printf(true);]])
+box.execute([[SELECT printf('a');]])
+box.execute([[SELECT printf(X'33');]])
+
+box.execute([[SELECT quote(-1);]])
+box.execute([[SELECT quote(1);]])
+box.execute([[SELECT quote(1.5);]])
+box.execute([[SELECT quote(true);]])
+box.execute([[SELECT quote('a');]])
+box.execute([[SELECT quote(X'33');]])
+
+box.execute([[SELECT randomblob(-1);]])
+box.execute([[SELECT randomblob(0);]])
+box.execute([[SELECT randomblob(0.5);]])
+box.execute([[SELECT randomblob(true);]])
+box.execute([[SELECT randomblob('a');]])
+box.execute([[SELECT randomblob(X'33');]])
+
+box.execute([[SELECT replace(-1, -1, -1);]])
+box.execute([[SELECT replace(1, 1, 1);]])
+box.execute([[SELECT replace(1.5, 1.5, 1.5);]])
+box.execute([[SELECT replace(true, true, true);]])
+box.execute([[SELECT replace('a', 'a', 'a');]])
+box.execute([[SELECT replace(X'33', X'33', X'33');]])
+
+box.execute([[SELECT round(-1, -1);]])
+box.execute([[SELECT round(1, 1);]])
+box.execute([[SELECT round(1.5, 1.5);]])
+box.execute([[SELECT round(true, true);]])
+box.execute([[SELECT round('a', 'a');]])
+box.execute([[SELECT round(X'33', X'33');]])
+
+box.execute([[SELECT soundex(-1);]])
+box.execute([[SELECT soundex(1);]])
+box.execute([[SELECT soundex(1.5);]])
+box.execute([[SELECT soundex(true);]])
+box.execute([[SELECT soundex('a');]])
+box.execute([[SELECT soundex(X'33');]])
+
+box.execute([[SELECT substr(-1, -1, -1);]])
+box.execute([[SELECT substr(1, 1, 1);]])
+box.execute([[SELECT substr(1.5, 1.5, 1.5);]])
+box.execute([[SELECT substr(true, true, true);]])
+box.execute([[SELECT substr('a', 'a', 'a');]])
+box.execute([[SELECT substr(X'33', X'33', X'33');]])
+
+box.execute([[SELECT typeof(-1);]])
+box.execute([[SELECT typeof(1);]])
+box.execute([[SELECT typeof(1.5);]])
+box.execute([[SELECT typeof(true);]])
+box.execute([[SELECT typeof('a');]])
+box.execute([[SELECT typeof(X'33');]])
+
+box.execute([[SELECT unicode(-1);]])
+box.execute([[SELECT unicode(1);]])
+box.execute([[SELECT unicode(1.5);]])
+box.execute([[SELECT unicode(true);]])
+box.execute([[SELECT unicode('a');]])
+box.execute([[SELECT unicode(X'33');]])
+
+box.execute([[SELECT unlikely(-1);]])
+box.execute([[SELECT unlikely(1);]])
+box.execute([[SELECT unlikely(1.5);]])
+box.execute([[SELECT unlikely(true);]])
+box.execute([[SELECT unlikely('a');]])
+box.execute([[SELECT unlikely(X'33');]])
+
+box.execute([[SELECT upper(-1);]])
+box.execute([[SELECT upper(1);]])
+box.execute([[SELECT upper(1.5);]])
+box.execute([[SELECT upper(true);]])
+box.execute([[SELECT upper('a');]])
+box.execute([[SELECT upper(X'33');]])
+
+box.execute([[SELECT zeroblob(-1);]])
+box.execute([[SELECT zeroblob(1);]])
+box.execute([[SELECT zeroblob(1.5);]])
+box.execute([[SELECT zeroblob(true);]])
+box.execute([[SELECT zeroblob('a');]])
+box.execute([[SELECT zeroblob(X'33');]])
+
+box.execute([[CREATE TABLE t (i INTEGER PRIMARY KEY, u UNSIGNED, d DOUBLE, b BOOLEAN, s STRING, v VARBINARY);]])
+box.execute([[INSERT INTO t VALUES (-1, 1, 1.5, true, 'a', X'33');]])
+
+box.execute([[SELECT avg(i) FROM t;]])
+box.execute([[SELECT avg(u) FROM t;]])
+box.execute([[SELECT avg(d) FROM t;]])
+box.execute([[SELECT avg(b) FROM t;]])
+box.execute([[SELECT avg(s) FROM t;]])
+box.execute([[SELECT avg(v) FROM t;]])
+
+box.execute([[SELECT count(i) FROM t;]])
+box.execute([[SELECT count(u) FROM t;]])
+box.execute([[SELECT count(d) FROM t;]])
+box.execute([[SELECT count(b) FROM t;]])
+box.execute([[SELECT count(s) FROM t;]])
+box.execute([[SELECT count(v) FROM t;]])
+
+box.execute([[SELECT group_concat(i) FROM t;]])
+box.execute([[SELECT group_concat(u) FROM t;]])
+box.execute([[SELECT group_concat(d) FROM t;]])
+box.execute([[SELECT group_concat(b) FROM t;]])
+box.execute([[SELECT group_concat(s) FROM t;]])
+box.execute([[SELECT group_concat(v) FROM t;]])
+
+box.execute([[SELECT max(i) FROM t;]])
+box.execute([[SELECT max(u) FROM t;]])
+box.execute([[SELECT max(d) FROM t;]])
+box.execute([[SELECT max(b) FROM t;]])
+box.execute([[SELECT max(s) FROM t;]])
+box.execute([[SELECT max(v) FROM t;]])
+
+box.execute([[SELECT min(i) FROM t;]])
+box.execute([[SELECT min(u) FROM t;]])
+box.execute([[SELECT min(d) FROM t;]])
+box.execute([[SELECT min(b) FROM t;]])
+box.execute([[SELECT min(s) FROM t;]])
+box.execute([[SELECT min(v) FROM t;]])
+
+box.execute([[SELECT sum(i) FROM t;]])
+box.execute([[SELECT sum(u) FROM t;]])
+box.execute([[SELECT sum(d) FROM t;]])
+box.execute([[SELECT sum(b) FROM t;]])
+box.execute([[SELECT sum(s) FROM t;]])
+box.execute([[SELECT sum(v) FROM t;]])
+
+box.execute([[SELECT total(i) FROM t;]])
+box.execute([[SELECT total(u) FROM t;]])
+box.execute([[SELECT total(d) FROM t;]])
+box.execute([[SELECT total(b) FROM t;]])
+box.execute([[SELECT total(s) FROM t;]])
+box.execute([[SELECT total(v) FROM t;]])
+
+box.execute([[DROP TABLE t;]])
--
2.25.1
^ permalink raw reply [flat|nested] 8+ messages in thread
* [Tarantool-patches] [PATCH v1 7/7] sql: refactor sql/func.c
2020-08-12 15:15 [Tarantool-patches] [PATCH v1 0/7] sql: properly check arguments types of built-in functions imeevma
` (5 preceding siblings ...)
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 6/7] sql: VARBINARY and STRING in built-in functions imeevma
@ 2020-08-12 15:15 ` imeevma
6 siblings, 0 replies; 8+ messages in thread
From: imeevma @ 2020-08-12 15:15 UTC (permalink / raw)
To: v.shpilevoy; +Cc: tarantool-patches
After changing the way of checking the types of arguments, some of the
code in sql/func.c is no longer used. This patch removes this code.
Follow-up of #4159
---
src/box/sql/func.c | 797 +++++----------------------------------------
1 file changed, 83 insertions(+), 714 deletions(-)
diff --git a/src/box/sql/func.c b/src/box/sql/func.c
index 694bd0e83..651864189 100644
--- a/src/box/sql/func.c
+++ b/src/box/sql/func.c
@@ -493,44 +493,21 @@ absFunc(sql_context * context, int argc, sql_value ** argv)
{
assert(argc == 1);
UNUSED_PARAMETER(argc);
- switch (sql_value_type(argv[0])) {
- case MP_UINT: {
- sql_result_uint(context, sql_value_uint64(argv[0]));
- break;
- }
- case MP_INT: {
+ enum mp_type type = sql_value_type(argv[0]);
+ if (type == MP_NIL)
+ return sql_result_null(context);
+ if (type == MP_UINT)
+ return sql_result_uint(context, sql_value_uint64(argv[0]));
+ if (type == MP_INT) {
int64_t value = sql_value_int64(argv[0]);
assert(value < 0);
- sql_result_uint(context, -value);
- break;
- }
- case MP_NIL:{
- /* IMP: R-37434-19929 Abs(X) returns NULL if X is NULL. */
- sql_result_null(context);
- break;
- }
- case MP_BOOL:
- case MP_BIN:
- case MP_ARRAY:
- case MP_MAP: {
- diag_set(ClientError, ER_INCONSISTENT_TYPES, "number",
- mem_type_to_str(argv[0]));
- context->is_aborted = true;
- return;
- }
- default:{
- /* Because sql_value_double() returns 0.0 if the argument is not
- * something that can be converted into a number, we have:
- * IMP: R-01992-00519 Abs(X) returns 0.0 if X is a string or blob
- * that cannot be converted to a numeric value.
- */
- double rVal = sql_value_double(argv[0]);
- if (rVal < 0)
- rVal = -rVal;
- sql_result_double(context, rVal);
- break;
- }
+ return sql_result_uint(context, -value);
}
+ assert(type == MP_DOUBLE);
+ double value = sql_value_double(argv[0]);
+ if (value < 0)
+ value = -value;
+ return sql_result_double(context, value);
}
/**
@@ -835,19 +812,14 @@ roundFunc(sql_context * context, int argc, sql_value ** argv)
if (argc == 2) {
if (sql_value_is_null(argv[1]))
return;
+ assert(sql_value_type(argv[1]) == MP_UINT);
n = sql_value_int(argv[1]);
if (n < 0)
n = 0;
}
if (sql_value_is_null(argv[0]))
return;
- enum mp_type mp_type = sql_value_type(argv[0]);
- if (mp_type_is_bloblike(mp_type)) {
- diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
- sql_value_to_diag_str(argv[0]), "numeric");
- context->is_aborted = true;
- return;
- }
+ assert(sql_value_type(argv[0]) == MP_DOUBLE);
r = sql_value_double(argv[0]);
/* If Y==0 and X will fit in a 64-bit int,
* handle the rounding directly,
@@ -989,12 +961,7 @@ randomBlob(sql_context * context, int argc, sql_value ** argv)
unsigned char *p;
assert(argc == 1);
UNUSED_PARAMETER(argc);
- if (mp_type_is_bloblike(sql_value_type(argv[0]))) {
- diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
- sql_value_to_diag_str(argv[0]), "numeric");
- context->is_aborted = true;
- return;
- }
+ assert(sql_value_type(argv[0]) == MP_UINT);
n = sql_value_int(argv[0]);
if (n < 1)
return;
@@ -1546,6 +1513,7 @@ zeroblobFunc(sql_context * context, int argc, sql_value ** argv)
i64 n;
assert(argc == 1);
UNUSED_PARAMETER(argc);
+ assert(sql_value_type(argv[0]) == MP_UINT);
n = sql_value_int64(argv[0]);
if (n < 0)
n = 0;
@@ -1968,18 +1936,10 @@ sum_step(struct sql_context *context, int argc, sql_value **argv)
assert(argc == 1);
UNUSED_PARAMETER(argc);
struct SumCtx *p = sql_aggregate_context(context, sizeof(*p));
- int type = sql_value_type(argv[0]);
+ enum mp_type type = sql_value_type(argv[0]);
if (type == MP_NIL || p == NULL)
return;
- if (type != MP_DOUBLE && type != MP_INT && type != MP_UINT) {
- if (mem_apply_numeric_type(argv[0]) != 0) {
- diag_set(ClientError, ER_SQL_TYPE_MISMATCH,
- sql_value_to_diag_str(argv[0]), "number");
- context->is_aborted = true;
- return;
- }
- type = sql_value_type(argv[0]);
- }
+ assert(type == MP_DOUBLE || type == MP_INT || type == MP_UINT);
p->cnt++;
if (type == MP_INT || type == MP_UINT) {
int64_t v = sql_value_int64(argv[0]);
@@ -2246,663 +2206,72 @@ static struct {
uint16_t flags;
void (*call)(sql_context *ctx, int argc, sql_value **argv);
void (*finalize)(sql_context *ctx);
- /** Members below are related to struct func_def. */
- bool is_deterministic;
- int param_count;
- enum field_type returns;
- enum func_aggregate aggregate;
- bool export_to_sql;
} sql_builtins[] = {
- {.name = "ABS",
- .param_count = 1,
- .returns = FIELD_TYPE_NUMBER,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = 0,
- .call = absFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "AVG",
- .param_count = 1,
- .returns = FIELD_TYPE_NUMBER,
- .is_deterministic = false,
- .aggregate = FUNC_AGGREGATE_GROUP,
- .flags = 0,
- .call = sum_step,
- .finalize = avgFinalize,
- .export_to_sql = true,
- }, {
- .name = "CEIL",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "CEILING",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "CHAR",
- .param_count = -1,
- .returns = FIELD_TYPE_STRING,
- .is_deterministic = true,
- .aggregate = FUNC_AGGREGATE_NONE,
- .flags = 0,
- .call = charFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "CHARACTER_LENGTH",
- .param_count = 1,
- .returns = FIELD_TYPE_INTEGER,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = 0,
- .call = lengthFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "CHAR_LENGTH",
- .param_count = 1,
- .returns = FIELD_TYPE_INTEGER,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = 0,
- .call = lengthFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "COALESCE",
- .param_count = -1,
- .returns = FIELD_TYPE_SCALAR,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_COALESCE,
- .call = sql_builtin_stub,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "COUNT",
- .param_count = -1,
- .returns = FIELD_TYPE_INTEGER,
- .aggregate = FUNC_AGGREGATE_GROUP,
- .is_deterministic = false,
- .flags = 0,
- .call = countStep,
- .finalize = countFinalize,
- .export_to_sql = true,
- }, {
- .name = "CURRENT_DATE",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "CURRENT_TIME",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "CURRENT_TIMESTAMP",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "DATE",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "DATETIME",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "EVERY",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "EXISTS",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "EXP",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "EXTRACT",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "FLOOR",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "GREATER",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "GREATEST",
- .param_count = -1,
- .returns = FIELD_TYPE_SCALAR,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_NEEDCOLL | SQL_FUNC_MAX,
- .call = minmaxFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "GROUP_CONCAT",
- .param_count = -1,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_GROUP,
- .is_deterministic = false,
- .flags = 0,
- .call = groupConcatStep,
- .finalize = groupConcatFinalize,
- .export_to_sql = true,
- }, {
- .name = "HEX",
- .param_count = 1,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = 0,
- .call = hexFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "IFNULL",
- .param_count = 2,
- .returns = FIELD_TYPE_INTEGER,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_COALESCE,
- .call = sql_builtin_stub,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "JULIANDAY",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "LEAST",
- .param_count = -1,
- .returns = FIELD_TYPE_SCALAR,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_NEEDCOLL | SQL_FUNC_MIN,
- .call = minmaxFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "LENGTH",
- .param_count = 1,
- .returns = FIELD_TYPE_INTEGER,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_LENGTH,
- .call = lengthFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "LESSER",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "LIKE",
- .param_count = -1,
- .returns = FIELD_TYPE_INTEGER,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_NEEDCOLL | SQL_FUNC_LIKE,
- .call = likeFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "LIKELIHOOD",
- .param_count = 2,
- .returns = FIELD_TYPE_BOOLEAN,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_UNLIKELY,
- .call = sql_builtin_stub,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "LIKELY",
- .param_count = 1,
- .returns = FIELD_TYPE_BOOLEAN,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_UNLIKELY,
- .call = sql_builtin_stub,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "LN",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "LOWER",
- .param_count = 1,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_DERIVEDCOLL | SQL_FUNC_NEEDCOLL,
- .call = LowerICUFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "MAX",
- .param_count = 1,
- .returns = FIELD_TYPE_SCALAR,
- .aggregate = FUNC_AGGREGATE_GROUP,
- .is_deterministic = false,
- .flags = SQL_FUNC_NEEDCOLL | SQL_FUNC_MAX,
- .call = minmaxStep,
- .finalize = minMaxFinalize,
- .export_to_sql = true,
- }, {
- .name = "MIN",
- .param_count = 1,
- .returns = FIELD_TYPE_SCALAR,
- .aggregate = FUNC_AGGREGATE_GROUP,
- .is_deterministic = false,
- .flags = SQL_FUNC_NEEDCOLL | SQL_FUNC_MIN,
- .call = minmaxStep,
- .finalize = minMaxFinalize,
- .export_to_sql = true,
- }, {
- .name = "MOD",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "NULLIF",
- .param_count = 2,
- .returns = FIELD_TYPE_SCALAR,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_NEEDCOLL,
- .call = nullifFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "OCTET_LENGTH",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "POSITION",
- .param_count = 2,
- .returns = FIELD_TYPE_INTEGER,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_NEEDCOLL,
- .call = position_func,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "POWER",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "PRINTF",
- .param_count = -1,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = 0,
- .call = printfFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "QUOTE",
- .param_count = 1,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = 0,
- .call = quoteFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "RANDOM",
- .param_count = 0,
- .returns = FIELD_TYPE_INTEGER,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .call = randomFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "RANDOMBLOB",
- .param_count = 1,
- .returns = FIELD_TYPE_VARBINARY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .call = randomBlob,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "REPLACE",
- .param_count = 3,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_DERIVEDCOLL,
- .call = replaceFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "ROUND",
- .param_count = -1,
- .returns = FIELD_TYPE_INTEGER,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = 0,
- .call = roundFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "ROW_COUNT",
- .param_count = 0,
- .returns = FIELD_TYPE_INTEGER,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = 0,
- .call = sql_row_count,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "SOME",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "SOUNDEX",
- .param_count = 1,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = 0,
- .call = soundexFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "SQRT",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "STRFTIME",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "SUBSTR",
- .param_count = -1,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_DERIVEDCOLL,
- .call = substrFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "SUM",
- .param_count = 1,
- .returns = FIELD_TYPE_NUMBER,
- .aggregate = FUNC_AGGREGATE_GROUP,
- .is_deterministic = false,
- .flags = 0,
- .call = sum_step,
- .finalize = sumFinalize,
- .export_to_sql = true,
- }, {
- .name = "TIME",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "TOTAL",
- .param_count = 1,
- .returns = FIELD_TYPE_NUMBER,
- .aggregate = FUNC_AGGREGATE_GROUP,
- .is_deterministic = false,
- .flags = 0,
- .call = sum_step,
- .finalize = totalFinalize,
- .export_to_sql = true,
- }, {
- .name = "TRIM",
- .param_count = -1,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_DERIVEDCOLL,
- .call = trim_func,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "TYPEOF",
- .param_count = 1,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_TYPEOF,
- .call = typeofFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "UNICODE",
- .param_count = 1,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = 0,
- .call = unicodeFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "UNLIKELY",
- .param_count = 1,
- .returns = FIELD_TYPE_BOOLEAN,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_UNLIKELY,
- .call = sql_builtin_stub,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "UPPER",
- .param_count = 1,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = SQL_FUNC_DERIVEDCOLL | SQL_FUNC_NEEDCOLL,
- .call = UpperICUFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "VERSION",
- .param_count = 0,
- .returns = FIELD_TYPE_STRING,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = 0,
- .call = sql_func_version,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "ZEROBLOB",
- .param_count = 1,
- .returns = FIELD_TYPE_VARBINARY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = true,
- .flags = 0,
- .call = zeroblobFunc,
- .finalize = NULL,
- .export_to_sql = true,
- }, {
- .name = "_sql_stat_get",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "_sql_stat_init",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- }, {
- .name = "_sql_stat_push",
- .call = sql_builtin_stub,
- .export_to_sql = false,
- .param_count = -1,
- .returns = FIELD_TYPE_ANY,
- .aggregate = FUNC_AGGREGATE_NONE,
- .is_deterministic = false,
- .flags = 0,
- .finalize = NULL,
- },
+ {"ABS", 0, absFunc, NULL},
+ {"AVG", 0, sum_step, avgFinalize},
+ {"CEIL", 0, sql_builtin_stub, NULL},
+ {"CEILING", 0, sql_builtin_stub, NULL},
+ {"CHAR", 0, charFunc, NULL},
+ {"CHARACTER_LENGTH", 0, lengthFunc, NULL},
+ {"CHAR_LENGTH", 0, lengthFunc, NULL},
+ {"COALESCE", SQL_FUNC_COALESCE, sql_builtin_stub, NULL},
+ {"COUNT", 0, countStep, countFinalize},
+ {"CURRENT_DATE", 0, sql_builtin_stub, NULL},
+ {"CURRENT_TIME", 0, sql_builtin_stub, NULL},
+ {"CURRENT_TIMESTAMP", 0, sql_builtin_stub, NULL},
+ {"DATE", 0, sql_builtin_stub, NULL},
+ {"DATETIME", 0, sql_builtin_stub, NULL},
+ {"EVERY", 0, sql_builtin_stub, NULL},
+ {"EXISTS", 0, sql_builtin_stub, NULL},
+ {"EXP", 0, sql_builtin_stub, NULL},
+ {"EXTRACT", 0, sql_builtin_stub, NULL},
+ {"FLOOR", 0, sql_builtin_stub, NULL},
+ {"GREATER", 0, sql_builtin_stub, NULL},
+ {"GREATEST", SQL_FUNC_NEEDCOLL | SQL_FUNC_MAX, minmaxFunc, NULL},
+ {"GROUP_CONCAT", 0, groupConcatStep, groupConcatFinalize},
+ {"HEX", 0, hexFunc, NULL},
+ {"IFNULL", SQL_FUNC_COALESCE, sql_builtin_stub, NULL},
+ {"JULIANDAY", 0, sql_builtin_stub, NULL},
+ {"LEAST", SQL_FUNC_NEEDCOLL | SQL_FUNC_MIN, minmaxFunc, NULL},
+ {"LENGTH", SQL_FUNC_LENGTH, lengthFunc, NULL},
+ {"LESSER", 0, sql_builtin_stub, NULL},
+ {"LIKE", SQL_FUNC_NEEDCOLL | SQL_FUNC_LIKE, likeFunc, NULL},
+ {"LIKELIHOOD", SQL_FUNC_UNLIKELY, sql_builtin_stub, NULL},
+ {"LIKELY", SQL_FUNC_UNLIKELY, sql_builtin_stub, NULL},
+ {"LN", 0, sql_builtin_stub, NULL},
+ {"LOWER", SQL_FUNC_DERIVEDCOLL | SQL_FUNC_NEEDCOLL, LowerICUFunc, NULL},
+ {"MAX", SQL_FUNC_NEEDCOLL | SQL_FUNC_MAX, minmaxStep, minMaxFinalize},
+ {"MIN", SQL_FUNC_NEEDCOLL | SQL_FUNC_MIN, minmaxStep, minMaxFinalize},
+ {"MOD", 0, sql_builtin_stub, NULL},
+ {"NULLIF", SQL_FUNC_NEEDCOLL, nullifFunc, NULL},
+ {"OCTET_LENGTH", 0, sql_builtin_stub, NULL},
+ {"POSITION", SQL_FUNC_NEEDCOLL, position_func, NULL},
+ {"POWER", 0, sql_builtin_stub, NULL},
+ {"PRINTF", 0, printfFunc, NULL},
+ {"QUOTE", 0, quoteFunc, NULL},
+ {"RANDOM", 0, randomFunc, NULL},
+ {"RANDOMBLOB", 0, randomBlob, NULL},
+ {"REPLACE", SQL_FUNC_DERIVEDCOLL, replaceFunc, NULL},
+ {"ROUND", 0, roundFunc, NULL},
+ {"ROW_COUNT", 0, sql_row_count, NULL},
+ {"SOME", 0, sql_builtin_stub, NULL},
+ {"SOUNDEX", 0, soundexFunc, NULL},
+ {"SQRT", 0, sql_builtin_stub, NULL},
+ {"STRFTIME", 0, sql_builtin_stub, NULL},
+ {"SUBSTR", SQL_FUNC_DERIVEDCOLL, substrFunc, NULL},
+ {"SUM", 0, sum_step, sumFinalize},
+ {"TIME", 0, sql_builtin_stub, NULL},
+ {"TOTAL", 0, sum_step, totalFinalize},
+ {"TRIM", SQL_FUNC_DERIVEDCOLL, trim_func, NULL},
+ {"TYPEOF", SQL_FUNC_TYPEOF, typeofFunc, NULL},
+ {"UNICODE", 0, unicodeFunc, NULL},
+ {"UNLIKELY", SQL_FUNC_UNLIKELY, sql_builtin_stub, NULL},
+ {"UPPER", SQL_FUNC_DERIVEDCOLL | SQL_FUNC_NEEDCOLL, UpperICUFunc, NULL},
+ {"VERSION", 0, sql_func_version, NULL},
+ {"ZEROBLOB", 0, zeroblobFunc, NULL},
+ {"_sql_stat_get", 0, sql_builtin_stub, NULL},
+ {"_sql_stat_init", 0, sql_builtin_stub, NULL},
+ {"_sql_stat_push", 0, sql_builtin_stub, NULL},
};
static struct func_vtab func_sql_builtin_vtab;
--
2.25.1
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2020-08-12 15:15 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-08-12 15:15 [Tarantool-patches] [PATCH v1 0/7] sql: properly check arguments types of built-in functions imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 1/7] box: add has_vararg option for functions imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 2/7] sql: do not return UNSIGNED in built-in functions imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 3/7] sql: move built-in function definitions in _func imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 4/7] box: add param_list to 'struct func' imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 5/7] sql: check built-in functions argument types imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 6/7] sql: VARBINARY and STRING in built-in functions imeevma
2020-08-12 15:15 ` [Tarantool-patches] [PATCH v1 7/7] sql: refactor sql/func.c imeevma
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox