90 Star 491 Fork 151

平凯星辰(北京)科技有限公司/tidb

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
builtin_time.go 160.07 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382
// Copyright 2013 The ql Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSES/QL-LICENSE file.
// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.
package expression
import (
"fmt"
"math"
"regexp"
"strconv"
"strings"
"time"
"github.com/cznic/mathutil"
"github.com/juju/errors"
"github.com/pingcap/tidb/mysql"
"github.com/pingcap/tidb/sessionctx"
"github.com/pingcap/tidb/sessionctx/stmtctx"
"github.com/pingcap/tidb/terror"
"github.com/pingcap/tidb/types"
tipb "github.com/pingcap/tipb/go-tipb"
log "github.com/sirupsen/logrus"
)
const ( // GET_FORMAT first argument.
dateFormat = "DATE"
datetimeFormat = "DATETIME"
timestampFormat = "TIMESTAMP"
timeFormat = "TIME"
)
const ( // GET_FORMAT location.
usaLocation = "USA"
jisLocation = "JIS"
isoLocation = "ISO"
eurLocation = "EUR"
internalLocation = "INTERNAL"
)
var (
// durationPattern checks whether a string matchs the format of duration.
durationPattern = regexp.MustCompile(`^\s*[-]?(((\d{1,2}\s+)?0*\d{0,3}(:0*\d{1,2}){0,2})|(\d{1,7}))?(\.\d*)?\s*$`)
// timestampPattern checks whether a string matchs the format of timestamp.
timestampPattern = regexp.MustCompile(`^\s*0*\d{1,4}([^\d]0*\d{1,2}){2}\s+(0*\d{0,2}([^\d]0*\d{1,2}){2})?(\.\d*)?\s*$`)
// datePattern determine whether to match the format of date.
datePattern = regexp.MustCompile(`^\s*((0*\d{1,4}([^\d]0*\d{1,2}){2})|(\d{2,4}(\d{2}){2}))\s*$`)
)
var (
_ functionClass = &dateFunctionClass{}
_ functionClass = &dateLiteralFunctionClass{}
_ functionClass = &dateDiffFunctionClass{}
_ functionClass = &timeDiffFunctionClass{}
_ functionClass = &dateFormatFunctionClass{}
_ functionClass = &hourFunctionClass{}
_ functionClass = &minuteFunctionClass{}
_ functionClass = &secondFunctionClass{}
_ functionClass = &microSecondFunctionClass{}
_ functionClass = &monthFunctionClass{}
_ functionClass = &monthNameFunctionClass{}
_ functionClass = &nowFunctionClass{}
_ functionClass = &dayNameFunctionClass{}
_ functionClass = &dayOfMonthFunctionClass{}
_ functionClass = &dayOfWeekFunctionClass{}
_ functionClass = &dayOfYearFunctionClass{}
_ functionClass = &weekFunctionClass{}
_ functionClass = &weekDayFunctionClass{}
_ functionClass = &weekOfYearFunctionClass{}
_ functionClass = &yearFunctionClass{}
_ functionClass = &yearWeekFunctionClass{}
_ functionClass = &fromUnixTimeFunctionClass{}
_ functionClass = &getFormatFunctionClass{}
_ functionClass = &strToDateFunctionClass{}
_ functionClass = &sysDateFunctionClass{}
_ functionClass = &currentDateFunctionClass{}
_ functionClass = &currentTimeFunctionClass{}
_ functionClass = &timeFunctionClass{}
_ functionClass = &timeLiteralFunctionClass{}
_ functionClass = &utcDateFunctionClass{}
_ functionClass = &utcTimestampFunctionClass{}
_ functionClass = &extractFunctionClass{}
_ functionClass = &unixTimestampFunctionClass{}
_ functionClass = &addTimeFunctionClass{}
_ functionClass = &convertTzFunctionClass{}
_ functionClass = &makeDateFunctionClass{}
_ functionClass = &makeTimeFunctionClass{}
_ functionClass = &periodAddFunctionClass{}
_ functionClass = &periodDiffFunctionClass{}
_ functionClass = &quarterFunctionClass{}
_ functionClass = &secToTimeFunctionClass{}
_ functionClass = &subTimeFunctionClass{}
_ functionClass = &timeFormatFunctionClass{}
_ functionClass = &timeToSecFunctionClass{}
_ functionClass = &timestampAddFunctionClass{}
_ functionClass = &toDaysFunctionClass{}
_ functionClass = &toSecondsFunctionClass{}
_ functionClass = &utcTimeFunctionClass{}
_ functionClass = &timestampFunctionClass{}
_ functionClass = &timestampLiteralFunctionClass{}
_ functionClass = &lastDayFunctionClass{}
_ functionClass = &addDateFunctionClass{}
_ functionClass = &subDateFunctionClass{}
)
var (
_ builtinFunc = &builtinDateSig{}
_ builtinFunc = &builtinDateLiteralSig{}
_ builtinFunc = &builtinDateDiffSig{}
_ builtinFunc = &builtinNullTimeDiffSig{}
_ builtinFunc = &builtinTimeStringTimeDiffSig{}
_ builtinFunc = &builtinDurationStringTimeDiffSig{}
_ builtinFunc = &builtinDurationDurationTimeDiffSig{}
_ builtinFunc = &builtinStringTimeTimeDiffSig{}
_ builtinFunc = &builtinStringDurationTimeDiffSig{}
_ builtinFunc = &builtinStringStringTimeDiffSig{}
_ builtinFunc = &builtinTimeTimeTimeDiffSig{}
_ builtinFunc = &builtinDateFormatSig{}
_ builtinFunc = &builtinHourSig{}
_ builtinFunc = &builtinMinuteSig{}
_ builtinFunc = &builtinSecondSig{}
_ builtinFunc = &builtinMicroSecondSig{}
_ builtinFunc = &builtinMonthSig{}
_ builtinFunc = &builtinMonthNameSig{}
_ builtinFunc = &builtinNowWithArgSig{}
_ builtinFunc = &builtinNowWithoutArgSig{}
_ builtinFunc = &builtinDayNameSig{}
_ builtinFunc = &builtinDayOfMonthSig{}
_ builtinFunc = &builtinDayOfWeekSig{}
_ builtinFunc = &builtinDayOfYearSig{}
_ builtinFunc = &builtinWeekWithModeSig{}
_ builtinFunc = &builtinWeekWithoutModeSig{}
_ builtinFunc = &builtinWeekDaySig{}
_ builtinFunc = &builtinWeekOfYearSig{}
_ builtinFunc = &builtinYearSig{}
_ builtinFunc = &builtinYearWeekWithModeSig{}
_ builtinFunc = &builtinYearWeekWithoutModeSig{}
_ builtinFunc = &builtinGetFormatSig{}
_ builtinFunc = &builtinSysDateWithFspSig{}
_ builtinFunc = &builtinSysDateWithoutFspSig{}
_ builtinFunc = &builtinCurrentDateSig{}
_ builtinFunc = &builtinCurrentTime0ArgSig{}
_ builtinFunc = &builtinCurrentTime1ArgSig{}
_ builtinFunc = &builtinTimeSig{}
_ builtinFunc = &builtinTimeLiteralSig{}
_ builtinFunc = &builtinUTCDateSig{}
_ builtinFunc = &builtinUTCTimestampWithArgSig{}
_ builtinFunc = &builtinUTCTimestampWithoutArgSig{}
_ builtinFunc = &builtinAddDatetimeAndDurationSig{}
_ builtinFunc = &builtinAddDatetimeAndStringSig{}
_ builtinFunc = &builtinAddTimeDateTimeNullSig{}
_ builtinFunc = &builtinAddStringAndDurationSig{}
_ builtinFunc = &builtinAddStringAndStringSig{}
_ builtinFunc = &builtinAddTimeStringNullSig{}
_ builtinFunc = &builtinAddDurationAndDurationSig{}
_ builtinFunc = &builtinAddDurationAndStringSig{}
_ builtinFunc = &builtinAddTimeDurationNullSig{}
_ builtinFunc = &builtinAddDateAndDurationSig{}
_ builtinFunc = &builtinAddDateAndStringSig{}
_ builtinFunc = &builtinSubDatetimeAndDurationSig{}
_ builtinFunc = &builtinSubDatetimeAndStringSig{}
_ builtinFunc = &builtinSubTimeDateTimeNullSig{}
_ builtinFunc = &builtinSubStringAndDurationSig{}
_ builtinFunc = &builtinSubStringAndStringSig{}
_ builtinFunc = &builtinSubTimeStringNullSig{}
_ builtinFunc = &builtinSubDurationAndDurationSig{}
_ builtinFunc = &builtinSubDurationAndStringSig{}
_ builtinFunc = &builtinSubTimeDurationNullSig{}
_ builtinFunc = &builtinSubDateAndDurationSig{}
_ builtinFunc = &builtinSubDateAndStringSig{}
_ builtinFunc = &builtinUnixTimestampCurrentSig{}
_ builtinFunc = &builtinUnixTimestampIntSig{}
_ builtinFunc = &builtinUnixTimestampDecSig{}
_ builtinFunc = &builtinConvertTzSig{}
_ builtinFunc = &builtinMakeDateSig{}
_ builtinFunc = &builtinMakeTimeSig{}
_ builtinFunc = &builtinPeriodAddSig{}
_ builtinFunc = &builtinPeriodDiffSig{}
_ builtinFunc = &builtinQuarterSig{}
_ builtinFunc = &builtinSecToTimeSig{}
_ builtinFunc = &builtinTimeToSecSig{}
_ builtinFunc = &builtinTimestampAddSig{}
_ builtinFunc = &builtinToDaysSig{}
_ builtinFunc = &builtinToSecondsSig{}
_ builtinFunc = &builtinUTCTimeWithArgSig{}
_ builtinFunc = &builtinUTCTimeWithoutArgSig{}
_ builtinFunc = &builtinTimestamp1ArgSig{}
_ builtinFunc = &builtinTimestamp2ArgsSig{}
_ builtinFunc = &builtinTimestampLiteralSig{}
_ builtinFunc = &builtinLastDaySig{}
_ builtinFunc = &builtinStrToDateDateSig{}
_ builtinFunc = &builtinStrToDateDatetimeSig{}
_ builtinFunc = &builtinStrToDateDurationSig{}
_ builtinFunc = &builtinFromUnixTime1ArgSig{}
_ builtinFunc = &builtinFromUnixTime2ArgSig{}
_ builtinFunc = &builtinExtractDatetimeSig{}
_ builtinFunc = &builtinExtractDurationSig{}
_ builtinFunc = &builtinAddDateStringStringSig{}
_ builtinFunc = &builtinAddDateStringIntSig{}
_ builtinFunc = &builtinAddDateStringDecimalSig{}
_ builtinFunc = &builtinAddDateIntStringSig{}
_ builtinFunc = &builtinAddDateIntIntSig{}
_ builtinFunc = &builtinAddDateDatetimeStringSig{}
_ builtinFunc = &builtinAddDateDatetimeIntSig{}
_ builtinFunc = &builtinSubDateStringStringSig{}
_ builtinFunc = &builtinSubDateStringIntSig{}
_ builtinFunc = &builtinSubDateStringDecimalSig{}
_ builtinFunc = &builtinSubDateIntStringSig{}
_ builtinFunc = &builtinSubDateIntIntSig{}
_ builtinFunc = &builtinSubDateDatetimeStringSig{}
_ builtinFunc = &builtinSubDateDatetimeIntSig{}
)
func convertTimeToMysqlTime(t time.Time, fsp int) (types.Time, error) {
tr, err := types.RoundFrac(t, fsp)
if err != nil {
return types.Time{}, errors.Trace(err)
}
return types.Time{
Time: types.FromGoTime(tr),
Type: mysql.TypeDatetime,
Fsp: fsp,
}, nil
}
type dateFunctionClass struct {
baseFunctionClass
}
func (c *dateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, types.ETDatetime)
bf.tp.Tp, bf.tp.Flen, bf.tp.Decimal = mysql.TypeDate, 10, 0
sig := &builtinDateSig{bf}
return sig, nil
}
type builtinDateSig struct {
baseBuiltinFunc
}
func (b *builtinDateSig) Clone() builtinFunc {
newSig := &builtinDateSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals DATE(expr).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date
func (b *builtinDateSig) evalTime(row types.Row) (types.Time, bool, error) {
expr, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if expr.IsZero() {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(expr.String())))
}
expr.Time = types.FromDate(expr.Time.Year(), expr.Time.Month(), expr.Time.Day(), 0, 0, 0, 0)
expr.Type = mysql.TypeDate
return expr, false, nil
}
type dateLiteralFunctionClass struct {
baseFunctionClass
}
func (c *dateLiteralFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
con, ok := args[0].(*Constant)
if !ok {
panic("Unexpected parameter for date literal")
}
dt, err := con.Eval(nil)
if err != nil {
return nil, errors.Trace(err)
}
str := dt.GetString()
if !datePattern.MatchString(str) {
return nil, types.ErrIncorrectDatetimeValue.GenByArgs(str)
}
tm, err := types.ParseDate(ctx.GetSessionVars().StmtCtx, str)
if err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, []Expression{}, types.ETDatetime)
bf.tp.Tp, bf.tp.Flen, bf.tp.Decimal = mysql.TypeDate, 10, 0
sig := &builtinDateLiteralSig{bf, tm}
return sig, nil
}
type builtinDateLiteralSig struct {
baseBuiltinFunc
literal types.Time
}
func (b *builtinDateLiteralSig) Clone() builtinFunc {
newSig := &builtinDateLiteralSig{literal: b.literal}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals DATE 'stringLit'.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html
func (b *builtinDateLiteralSig) evalTime(row types.Row) (types.Time, bool, error) {
mode := b.ctx.GetSessionVars().SQLMode
if mode.HasNoZeroDateMode() && b.literal.IsZero() {
return b.literal, true, types.ErrIncorrectDatetimeValue.GenByArgs(b.literal.String())
}
if mode.HasNoZeroInDateMode() && (b.literal.InvalidZero() && !b.literal.IsZero()) {
return b.literal, true, types.ErrIncorrectDatetimeValue.GenByArgs(b.literal.String())
}
return b.literal, false, nil
}
type dateDiffFunctionClass struct {
baseFunctionClass
}
func (c *dateDiffFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDatetime, types.ETDatetime)
sig := &builtinDateDiffSig{bf}
return sig, nil
}
type builtinDateDiffSig struct {
baseBuiltinFunc
}
func (b *builtinDateDiffSig) Clone() builtinFunc {
newSig := &builtinDateDiffSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals a builtinDateDiffSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_datediff
func (b *builtinDateDiffSig) evalInt(row types.Row) (int64, bool, error) {
lhs, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
rhs, isNull, err := b.args[1].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if invalidLHS, invalidRHS := lhs.InvalidZero(), rhs.InvalidZero(); invalidLHS || invalidRHS {
if invalidLHS {
err = handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(lhs.String()))
}
if invalidRHS {
err = handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(rhs.String()))
}
return 0, true, errors.Trace(err)
}
return int64(types.DateDiff(lhs.Time, rhs.Time)), false, nil
}
type timeDiffFunctionClass struct {
baseFunctionClass
}
func (c *timeDiffFunctionClass) getArgEvalTp(fieldTp *types.FieldType) types.EvalType {
argTp := types.ETString
switch tp := fieldTp.EvalType(); tp {
case types.ETDuration, types.ETDatetime, types.ETTimestamp:
argTp = tp
}
return argTp
}
func (c *timeDiffFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
arg0FieldTp, arg1FieldTp := args[0].GetType(), args[1].GetType()
arg0Tp, arg1Tp := c.getArgEvalTp(arg0FieldTp), c.getArgEvalTp(arg1FieldTp)
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration, arg0Tp, arg1Tp)
bf.tp.Decimal = mathutil.Max(arg0FieldTp.Decimal, arg1FieldTp.Decimal)
var sig builtinFunc
// arg0 and arg1 must be the same time type(compatible), or timediff will return NULL.
// TODO: we don't really need Duration type, actually in MySQL, it use Time class to represent
// all the time type, and use filed type to distinguish datetime, date, timestamp or time(duration).
// With the duration type, we are hard to port all the MySQL behavior.
switch arg0Tp {
case types.ETDuration:
switch arg1Tp {
case types.ETDuration:
sig = &builtinDurationDurationTimeDiffSig{bf}
case types.ETDatetime, types.ETTimestamp:
sig = &builtinNullTimeDiffSig{bf}
default:
sig = &builtinDurationStringTimeDiffSig{bf}
}
case types.ETDatetime, types.ETTimestamp:
switch arg1Tp {
case types.ETDuration:
sig = &builtinNullTimeDiffSig{bf}
case types.ETDatetime, types.ETTimestamp:
sig = &builtinTimeTimeTimeDiffSig{bf}
default:
sig = &builtinTimeStringTimeDiffSig{bf}
}
default:
switch arg1Tp {
case types.ETDuration:
sig = &builtinStringDurationTimeDiffSig{bf}
case types.ETDatetime, types.ETTimestamp:
sig = &builtinStringTimeTimeDiffSig{bf}
default:
sig = &builtinStringStringTimeDiffSig{bf}
}
}
return sig, nil
}
type builtinDurationDurationTimeDiffSig struct {
baseBuiltinFunc
}
func (b *builtinDurationDurationTimeDiffSig) Clone() builtinFunc {
newSig := &builtinDurationDurationTimeDiffSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinDurationDurationTimeDiffSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timediff
func (b *builtinDurationDurationTimeDiffSig) evalDuration(row types.Row) (d types.Duration, isNull bool, err error) {
lhs, isNull, err := b.args[0].EvalDuration(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
rhs, isNull, err := b.args[1].EvalDuration(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
d, isNull, err = calculateDurationTimeDiff(b.ctx, lhs, rhs)
return d, isNull, errors.Trace(err)
}
type builtinTimeTimeTimeDiffSig struct {
baseBuiltinFunc
}
func (b *builtinTimeTimeTimeDiffSig) Clone() builtinFunc {
newSig := &builtinTimeTimeTimeDiffSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinTimeTimeTimeDiffSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timediff
func (b *builtinTimeTimeTimeDiffSig) evalDuration(row types.Row) (d types.Duration, isNull bool, err error) {
lhs, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
rhs, isNull, err := b.args[1].EvalTime(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
d, isNull, err = calculateTimeDiff(sc, lhs, rhs)
return d, isNull, errors.Trace(err)
}
type builtinDurationStringTimeDiffSig struct {
baseBuiltinFunc
}
func (b *builtinDurationStringTimeDiffSig) Clone() builtinFunc {
newSig := &builtinDurationStringTimeDiffSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinDurationStringTimeDiffSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timediff
func (b *builtinDurationStringTimeDiffSig) evalDuration(row types.Row) (d types.Duration, isNull bool, err error) {
lhs, isNull, err := b.args[0].EvalDuration(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
rhsStr, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
rhs, _, isDuration, err := convertStringToDuration(sc, rhsStr, b.tp.Decimal)
if err != nil || !isDuration {
return d, true, errors.Trace(err)
}
d, isNull, err = calculateDurationTimeDiff(b.ctx, lhs, rhs)
return d, isNull, errors.Trace(err)
}
type builtinStringDurationTimeDiffSig struct {
baseBuiltinFunc
}
func (b *builtinStringDurationTimeDiffSig) Clone() builtinFunc {
newSig := &builtinStringDurationTimeDiffSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinStringDurationTimeDiffSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timediff
func (b *builtinStringDurationTimeDiffSig) evalDuration(row types.Row) (d types.Duration, isNull bool, err error) {
lhsStr, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
rhs, isNull, err := b.args[1].EvalDuration(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
lhs, _, isDuration, err := convertStringToDuration(sc, lhsStr, b.tp.Decimal)
if err != nil || !isDuration {
return d, true, errors.Trace(err)
}
d, isNull, err = calculateDurationTimeDiff(b.ctx, lhs, rhs)
return d, isNull, errors.Trace(err)
}
// calculateTimeDiff calculates interval difference of two types.Time.
func calculateTimeDiff(sc *stmtctx.StatementContext, lhs, rhs types.Time) (d types.Duration, isNull bool, err error) {
d = lhs.Sub(sc, &rhs)
d.Duration, err = types.TruncateOverflowMySQLTime(d.Duration)
if types.ErrTruncatedWrongVal.Equal(err) {
err = sc.HandleTruncate(err)
}
return d, err != nil, errors.Trace(err)
}
// calculateTimeDiff calculates interval difference of two types.Duration.
func calculateDurationTimeDiff(ctx sessionctx.Context, lhs, rhs types.Duration) (d types.Duration, isNull bool, err error) {
d, err = lhs.Sub(rhs)
if err != nil {
return d, true, errors.Trace(err)
}
d.Duration, err = types.TruncateOverflowMySQLTime(d.Duration)
if types.ErrTruncatedWrongVal.Equal(err) {
sc := ctx.GetSessionVars().StmtCtx
err = sc.HandleTruncate(err)
}
return d, err != nil, errors.Trace(err)
}
type builtinTimeStringTimeDiffSig struct {
baseBuiltinFunc
}
func (b *builtinTimeStringTimeDiffSig) Clone() builtinFunc {
newSig := &builtinTimeStringTimeDiffSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinTimeStringTimeDiffSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timediff
func (b *builtinTimeStringTimeDiffSig) evalDuration(row types.Row) (d types.Duration, isNull bool, err error) {
lhs, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
rhsStr, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
_, rhs, isDuration, err := convertStringToDuration(sc, rhsStr, b.tp.Decimal)
if err != nil || isDuration {
return d, true, errors.Trace(err)
}
d, isNull, err = calculateTimeDiff(sc, lhs, rhs)
return d, isNull, errors.Trace(err)
}
type builtinStringTimeTimeDiffSig struct {
baseBuiltinFunc
}
func (b *builtinStringTimeTimeDiffSig) Clone() builtinFunc {
newSig := &builtinStringTimeTimeDiffSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinStringTimeTimeDiffSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timediff
func (b *builtinStringTimeTimeDiffSig) evalDuration(row types.Row) (d types.Duration, isNull bool, err error) {
lhsStr, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
rhs, isNull, err := b.args[1].EvalTime(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
_, lhs, isDuration, err := convertStringToDuration(sc, lhsStr, b.tp.Decimal)
if err != nil || isDuration {
return d, true, errors.Trace(err)
}
d, isNull, err = calculateTimeDiff(sc, lhs, rhs)
return d, isNull, errors.Trace(err)
}
type builtinStringStringTimeDiffSig struct {
baseBuiltinFunc
}
func (b *builtinStringStringTimeDiffSig) Clone() builtinFunc {
newSig := &builtinStringStringTimeDiffSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinStringStringTimeDiffSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timediff
func (b *builtinStringStringTimeDiffSig) evalDuration(row types.Row) (d types.Duration, isNull bool, err error) {
lhs, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
rhs, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return d, isNull, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
fsp := b.tp.Decimal
lhsDur, lhsTime, lhsIsDuration, err := convertStringToDuration(sc, lhs, fsp)
if err != nil {
return d, true, errors.Trace(err)
}
rhsDur, rhsTime, rhsIsDuration, err := convertStringToDuration(sc, rhs, fsp)
if err != nil {
return d, true, errors.Trace(err)
}
if lhsIsDuration != rhsIsDuration {
return d, true, nil
}
if lhsIsDuration {
d, isNull, err = calculateDurationTimeDiff(b.ctx, lhsDur, rhsDur)
} else {
d, isNull, err = calculateTimeDiff(sc, lhsTime, rhsTime)
}
return d, isNull, errors.Trace(err)
}
type builtinNullTimeDiffSig struct {
baseBuiltinFunc
}
func (b *builtinNullTimeDiffSig) Clone() builtinFunc {
newSig := &builtinNullTimeDiffSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinNullTimeDiffSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timediff
func (b *builtinNullTimeDiffSig) evalDuration(row types.Row) (d types.Duration, isNull bool, err error) {
return d, true, nil
}
// convertStringToDuration converts string to duration, it return types.Time because in some case
// it will converts string to datetime.
func convertStringToDuration(sc *stmtctx.StatementContext, str string, fsp int) (d types.Duration, t types.Time,
isDuration bool, err error) {
if n := strings.IndexByte(str, '.'); n >= 0 {
lenStrFsp := len(str[n+1:])
if lenStrFsp <= types.MaxFsp {
fsp = mathutil.Max(lenStrFsp, fsp)
}
}
return types.StrToDuration(sc, str, fsp)
}
type dateFormatFunctionClass struct {
baseFunctionClass
}
func (c *dateFormatFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETDatetime, types.ETString)
// worst case: formatMask=%r%r%r...%r, each %r takes 11 characters
bf.tp.Flen = (args[1].GetType().Flen + 1) / 2 * 11
sig := &builtinDateFormatSig{bf}
sig.setPbCode(tipb.ScalarFuncSig_DateFormatSig)
return sig, nil
}
type builtinDateFormatSig struct {
baseBuiltinFunc
}
func (b *builtinDateFormatSig) Clone() builtinFunc {
newSig := &builtinDateFormatSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinDateFormatSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_date-format
func (b *builtinDateFormatSig) evalString(row types.Row) (string, bool, error) {
t, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if t.InvalidZero() {
return "", true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(t.String())))
}
formatMask, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
res, err := t.DateFormat(formatMask)
return res, isNull, errors.Trace(err)
}
type fromDaysFunctionClass struct {
baseFunctionClass
}
func (c *fromDaysFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, types.ETInt)
bf.tp.Flen, bf.tp.Decimal = 10, 0
sig := &builtinFromDaysSig{bf}
return sig, nil
}
type builtinFromDaysSig struct {
baseBuiltinFunc
}
func (b *builtinFromDaysSig) Clone() builtinFunc {
newSig := &builtinFromDaysSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals FROM_DAYS(N).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_from-days
func (b *builtinFromDaysSig) evalTime(row types.Row) (types.Time, bool, error) {
n, isNull, err := b.args[0].EvalInt(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
return types.TimeFromDays(n), false, nil
}
type hourFunctionClass struct {
baseFunctionClass
}
func (c *hourFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDuration)
bf.tp.Flen, bf.tp.Decimal = 3, 0
sig := &builtinHourSig{bf}
return sig, nil
}
type builtinHourSig struct {
baseBuiltinFunc
}
func (b *builtinHourSig) Clone() builtinFunc {
newSig := &builtinHourSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals HOUR(time).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_hour
func (b *builtinHourSig) evalInt(row types.Row) (int64, bool, error) {
dur, isNull, err := b.args[0].EvalDuration(b.ctx, row)
// ignore error and return NULL
if isNull || err != nil {
return 0, true, nil
}
return int64(dur.Hour()), false, nil
}
type minuteFunctionClass struct {
baseFunctionClass
}
func (c *minuteFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDuration)
bf.tp.Flen, bf.tp.Decimal = 2, 0
sig := &builtinMinuteSig{bf}
return sig, nil
}
type builtinMinuteSig struct {
baseBuiltinFunc
}
func (b *builtinMinuteSig) Clone() builtinFunc {
newSig := &builtinMinuteSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals MINUTE(time).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_minute
func (b *builtinMinuteSig) evalInt(row types.Row) (int64, bool, error) {
dur, isNull, err := b.args[0].EvalDuration(b.ctx, row)
// ignore error and return NULL
if isNull || err != nil {
return 0, true, nil
}
return int64(dur.Minute()), false, nil
}
type secondFunctionClass struct {
baseFunctionClass
}
func (c *secondFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDuration)
bf.tp.Flen, bf.tp.Decimal = 2, 0
sig := &builtinSecondSig{bf}
return sig, nil
}
type builtinSecondSig struct {
baseBuiltinFunc
}
func (b *builtinSecondSig) Clone() builtinFunc {
newSig := &builtinSecondSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals SECOND(time).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_second
func (b *builtinSecondSig) evalInt(row types.Row) (int64, bool, error) {
dur, isNull, err := b.args[0].EvalDuration(b.ctx, row)
// ignore error and return NULL
if isNull || err != nil {
return 0, true, nil
}
return int64(dur.Second()), false, nil
}
type microSecondFunctionClass struct {
baseFunctionClass
}
func (c *microSecondFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDuration)
bf.tp.Flen, bf.tp.Decimal = 6, 0
sig := &builtinMicroSecondSig{bf}
return sig, nil
}
type builtinMicroSecondSig struct {
baseBuiltinFunc
}
func (b *builtinMicroSecondSig) Clone() builtinFunc {
newSig := &builtinMicroSecondSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals MICROSECOND(expr).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_microsecond
func (b *builtinMicroSecondSig) evalInt(row types.Row) (int64, bool, error) {
dur, isNull, err := b.args[0].EvalDuration(b.ctx, row)
// ignore error and return NULL
if isNull || err != nil {
return 0, true, nil
}
return int64(dur.MicroSecond()), false, nil
}
type monthFunctionClass struct {
baseFunctionClass
}
func (c *monthFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDatetime)
bf.tp.Flen, bf.tp.Decimal = 2, 0
sig := &builtinMonthSig{bf}
return sig, nil
}
type builtinMonthSig struct {
baseBuiltinFunc
}
func (b *builtinMonthSig) Clone() builtinFunc {
newSig := &builtinMonthSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals MONTH(date).
// see: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_month
func (b *builtinMonthSig) evalInt(row types.Row) (int64, bool, error) {
date, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if date.IsZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
}
return int64(date.Time.Month()), false, nil
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_monthname
type monthNameFunctionClass struct {
baseFunctionClass
}
func (c *monthNameFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETDatetime)
bf.tp.Flen = 10
sig := &builtinMonthNameSig{bf}
return sig, nil
}
type builtinMonthNameSig struct {
baseBuiltinFunc
}
func (b *builtinMonthNameSig) Clone() builtinFunc {
newSig := &builtinMonthNameSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
func (b *builtinMonthNameSig) evalString(row types.Row) (string, bool, error) {
arg, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return "", true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
mon := arg.Time.Month()
if arg.IsZero() || mon < 0 || mon > len(types.MonthNames) {
return "", true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(arg.String())))
} else if mon == 0 {
return "", true, nil
}
return types.MonthNames[mon-1], false, nil
}
type dayNameFunctionClass struct {
baseFunctionClass
}
func (c *dayNameFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETDatetime)
bf.tp.Flen = 10
sig := &builtinDayNameSig{bf}
return sig, nil
}
type builtinDayNameSig struct {
baseBuiltinFunc
}
func (b *builtinDayNameSig) Clone() builtinFunc {
newSig := &builtinDayNameSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinDayNameSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayname
func (b *builtinDayNameSig) evalString(row types.Row) (string, bool, error) {
arg, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
if arg.InvalidZero() {
return "", true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(arg.String())))
}
// Monday is 0, ... Sunday = 6 in MySQL
// but in go, Sunday is 0, ... Saturday is 6
// w will do a conversion.
res := (int64(arg.Time.Weekday()) + 6) % 7
return types.WeekdayNames[res], false, nil
}
type dayOfMonthFunctionClass struct {
baseFunctionClass
}
func (c *dayOfMonthFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDatetime)
bf.tp.Flen = 2
sig := &builtinDayOfMonthSig{bf}
return sig, nil
}
type builtinDayOfMonthSig struct {
baseBuiltinFunc
}
func (b *builtinDayOfMonthSig) Clone() builtinFunc {
newSig := &builtinDayOfMonthSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals a builtinDayOfMonthSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayofmonth
func (b *builtinDayOfMonthSig) evalInt(row types.Row) (int64, bool, error) {
arg, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if arg.IsZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(arg.String())))
}
return int64(arg.Time.Day()), false, nil
}
type dayOfWeekFunctionClass struct {
baseFunctionClass
}
func (c *dayOfWeekFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDatetime)
bf.tp.Flen = 1
sig := &builtinDayOfWeekSig{bf}
return sig, nil
}
type builtinDayOfWeekSig struct {
baseBuiltinFunc
}
func (b *builtinDayOfWeekSig) Clone() builtinFunc {
newSig := &builtinDayOfWeekSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals a builtinDayOfWeekSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayofweek
func (b *builtinDayOfWeekSig) evalInt(row types.Row) (int64, bool, error) {
arg, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if arg.InvalidZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(arg.String())))
}
// 1 is Sunday, 2 is Monday, .... 7 is Saturday
return int64(arg.Time.Weekday() + 1), false, nil
}
type dayOfYearFunctionClass struct {
baseFunctionClass
}
func (c *dayOfYearFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDatetime)
bf.tp.Flen = 3
sig := &builtinDayOfYearSig{bf}
return sig, nil
}
type builtinDayOfYearSig struct {
baseBuiltinFunc
}
func (b *builtinDayOfYearSig) Clone() builtinFunc {
newSig := &builtinDayOfYearSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals a builtinDayOfYearSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_dayofyear
func (b *builtinDayOfYearSig) evalInt(row types.Row) (int64, bool, error) {
arg, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if arg.InvalidZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(arg.String())))
}
return int64(arg.Time.YearDay()), false, nil
}
type weekFunctionClass struct {
baseFunctionClass
}
func (c *weekFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
argTps := []types.EvalType{types.ETDatetime}
if len(args) == 2 {
argTps = append(argTps, types.ETInt)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, argTps...)
bf.tp.Flen, bf.tp.Decimal = 2, 0
var sig builtinFunc
if len(args) == 2 {
sig = &builtinWeekWithModeSig{bf}
} else {
sig = &builtinWeekWithoutModeSig{bf}
}
return sig, nil
}
type builtinWeekWithModeSig struct {
baseBuiltinFunc
}
func (b *builtinWeekWithModeSig) Clone() builtinFunc {
newSig := &builtinWeekWithModeSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals WEEK(date, mode).
// see: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_week
func (b *builtinWeekWithModeSig) evalInt(row types.Row) (int64, bool, error) {
date, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if date.IsZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
}
mode, isNull, err := b.args[1].EvalInt(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(err)
}
week := date.Time.Week(int(mode))
return int64(week), false, nil
}
type builtinWeekWithoutModeSig struct {
baseBuiltinFunc
}
func (b *builtinWeekWithoutModeSig) Clone() builtinFunc {
newSig := &builtinWeekWithoutModeSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals WEEK(date).
// see: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_week
func (b *builtinWeekWithoutModeSig) evalInt(row types.Row) (int64, bool, error) {
date, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if date.IsZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
}
week := date.Time.Week(0)
return int64(week), false, nil
}
type weekDayFunctionClass struct {
baseFunctionClass
}
func (c *weekDayFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDatetime)
bf.tp.Flen = 1
sig := &builtinWeekDaySig{bf}
return sig, nil
}
type builtinWeekDaySig struct {
baseBuiltinFunc
}
func (b *builtinWeekDaySig) Clone() builtinFunc {
newSig := &builtinWeekDaySig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals WEEKDAY(date).
func (b *builtinWeekDaySig) evalInt(row types.Row) (int64, bool, error) {
date, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if date.IsZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
}
return int64(date.Time.Weekday()+6) % 7, false, nil
}
type weekOfYearFunctionClass struct {
baseFunctionClass
}
func (c *weekOfYearFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDatetime)
bf.tp.Flen, bf.tp.Decimal = 2, 0
sig := &builtinWeekOfYearSig{bf}
return sig, nil
}
type builtinWeekOfYearSig struct {
baseBuiltinFunc
}
func (b *builtinWeekOfYearSig) Clone() builtinFunc {
newSig := &builtinWeekOfYearSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals WEEKOFYEAR(date).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_weekofyear
func (b *builtinWeekOfYearSig) evalInt(row types.Row) (int64, bool, error) {
date, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if date.IsZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
}
week := date.Time.Week(3)
return int64(week), false, nil
}
type yearFunctionClass struct {
baseFunctionClass
}
func (c *yearFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDatetime)
bf.tp.Flen, bf.tp.Decimal = 4, 0
sig := &builtinYearSig{bf}
return sig, nil
}
type builtinYearSig struct {
baseBuiltinFunc
}
func (b *builtinYearSig) Clone() builtinFunc {
newSig := &builtinYearSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals YEAR(date).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_year
func (b *builtinYearSig) evalInt(row types.Row) (int64, bool, error) {
date, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if date.IsZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
}
return int64(date.Time.Year()), false, nil
}
type yearWeekFunctionClass struct {
baseFunctionClass
}
func (c *yearWeekFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
argTps := []types.EvalType{types.ETDatetime}
if len(args) == 2 {
argTps = append(argTps, types.ETInt)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, argTps...)
bf.tp.Flen, bf.tp.Decimal = 6, 0
var sig builtinFunc
if len(args) == 2 {
sig = &builtinYearWeekWithModeSig{bf}
} else {
sig = &builtinYearWeekWithoutModeSig{bf}
}
return sig, nil
}
type builtinYearWeekWithModeSig struct {
baseBuiltinFunc
}
func (b *builtinYearWeekWithModeSig) Clone() builtinFunc {
newSig := &builtinYearWeekWithModeSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals YEARWEEK(date,mode).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_yearweek
func (b *builtinYearWeekWithModeSig) evalInt(row types.Row) (int64, bool, error) {
date, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if date.IsZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
}
mode, isNull, err := b.args[1].EvalInt(b.ctx, row)
if err != nil {
return 0, true, errors.Trace(err)
}
if isNull {
mode = 0
}
year, week := date.Time.YearWeek(int(mode))
result := int64(week + year*100)
if result < 0 {
return int64(math.MaxUint32), false, nil
}
return result, false, nil
}
type builtinYearWeekWithoutModeSig struct {
baseBuiltinFunc
}
func (b *builtinYearWeekWithoutModeSig) Clone() builtinFunc {
newSig := &builtinYearWeekWithoutModeSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals YEARWEEK(date).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_yearweek
func (b *builtinYearWeekWithoutModeSig) evalInt(row types.Row) (int64, bool, error) {
date, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if date.InvalidZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
}
year, week := date.Time.YearWeek(0)
result := int64(week + year*100)
if result < 0 {
return int64(math.MaxUint32), false, nil
}
return result, false, nil
}
type fromUnixTimeFunctionClass struct {
baseFunctionClass
}
func (c *fromUnixTimeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err = c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
retTp, argTps := types.ETDatetime, make([]types.EvalType, 0, len(args))
argTps = append(argTps, types.ETDecimal)
if len(args) == 2 {
retTp = types.ETString
argTps = append(argTps, types.ETString)
}
_, isArg0Con := args[0].(*Constant)
isArg0Str := args[0].GetType().EvalType() == types.ETString
bf := newBaseBuiltinFuncWithTp(ctx, args, retTp, argTps...)
if len(args) == 1 {
if isArg0Str {
bf.tp.Decimal = types.MaxFsp
} else if isArg0Con {
arg0, _, err1 := args[0].EvalDecimal(ctx, nil)
if err1 != nil {
return sig, errors.Trace(err1)
}
fsp := int(arg0.GetDigitsFrac())
if fsp > types.MaxFsp {
fsp = types.MaxFsp
}
bf.tp.Decimal = fsp
}
sig = &builtinFromUnixTime1ArgSig{bf}
} else {
bf.tp.Flen = args[1].GetType().Flen
sig = &builtinFromUnixTime2ArgSig{bf}
}
return sig, nil
}
func evalFromUnixTime(ctx sessionctx.Context, fsp int, row types.Row, arg Expression) (res types.Time, isNull bool, err error) {
unixTimeStamp, isNull, err := arg.EvalDecimal(ctx, row)
if err != nil || isNull {
return res, isNull, errors.Trace(err)
}
// 0 <= unixTimeStamp <= INT32_MAX
if unixTimeStamp.IsNegative() {
return res, true, nil
}
integralPart, err := unixTimeStamp.ToInt()
if err != nil && !terror.ErrorEqual(err, types.ErrTruncated) {
return res, true, errors.Trace(err)
}
if integralPart > int64(math.MaxInt32) {
return res, true, nil
}
// Split the integral part and fractional part of a decimal timestamp.
// e.g. for timestamp 12345.678,
// first get the integral part 12345,
// then (12345.678 - 12345) * (10^9) to get the decimal part and convert it to nanosecond precision.
integerDecimalTp := new(types.MyDecimal).FromInt(integralPart)
fracDecimalTp := new(types.MyDecimal)
err = types.DecimalSub(unixTimeStamp, integerDecimalTp, fracDecimalTp)
if err != nil {
return res, true, errors.Trace(err)
}
nano := new(types.MyDecimal).FromInt(int64(time.Second))
x := new(types.MyDecimal)
err = types.DecimalMul(fracDecimalTp, nano, x)
if err != nil {
return res, true, errors.Trace(err)
}
fractionalPart, err := x.ToInt() // here fractionalPart is result multiplying the original fractional part by 10^9.
if err != nil && !terror.ErrorEqual(err, types.ErrTruncated) {
return res, true, errors.Trace(err)
}
fracDigitsNumber := int(unixTimeStamp.GetDigitsFrac())
if fsp < 0 {
fsp = types.MaxFsp
}
fsp = mathutil.Max(fracDigitsNumber, fsp)
if fsp > types.MaxFsp {
fsp = types.MaxFsp
}
sc := ctx.GetSessionVars().StmtCtx
tmp := time.Unix(integralPart, fractionalPart).In(sc.TimeZone)
t, err := convertTimeToMysqlTime(tmp, fsp)
if err != nil {
return res, true, errors.Trace(err)
}
return t, false, nil
}
type builtinFromUnixTime1ArgSig struct {
baseBuiltinFunc
}
func (b *builtinFromUnixTime1ArgSig) Clone() builtinFunc {
newSig := &builtinFromUnixTime1ArgSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals a builtinFromUnixTime1ArgSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_from-unixtime
func (b *builtinFromUnixTime1ArgSig) evalTime(row types.Row) (res types.Time, isNull bool, err error) {
return evalFromUnixTime(b.ctx, b.tp.Decimal, row, b.args[0])
}
type builtinFromUnixTime2ArgSig struct {
baseBuiltinFunc
}
func (b *builtinFromUnixTime2ArgSig) Clone() builtinFunc {
newSig := &builtinFromUnixTime2ArgSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinFromUnixTime2ArgSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_from-unixtime
func (b *builtinFromUnixTime2ArgSig) evalString(row types.Row) (res string, isNull bool, err error) {
format, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return "", true, errors.Trace(err)
}
t, isNull, err := evalFromUnixTime(b.ctx, b.tp.Decimal, row, b.args[0])
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
res, err = t.DateFormat(format)
return res, err != nil, errors.Trace(err)
}
type getFormatFunctionClass struct {
baseFunctionClass
}
func (c *getFormatFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETString, types.ETString)
bf.tp.Flen = 17
sig := &builtinGetFormatSig{bf}
return sig, nil
}
type builtinGetFormatSig struct {
baseBuiltinFunc
}
func (b *builtinGetFormatSig) Clone() builtinFunc {
newSig := &builtinGetFormatSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinGetFormatSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_get-format
func (b *builtinGetFormatSig) evalString(row types.Row) (string, bool, error) {
t, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
l, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
var res string
switch t {
case dateFormat:
switch l {
case usaLocation:
res = "%m.%d.%Y"
case jisLocation:
res = "%Y-%m-%d"
case isoLocation:
res = "%Y-%m-%d"
case eurLocation:
res = "%d.%m.%Y"
case internalLocation:
res = "%Y%m%d"
}
case datetimeFormat, timestampFormat:
switch l {
case usaLocation:
res = "%Y-%m-%d %H.%i.%s"
case jisLocation:
res = "%Y-%m-%d %H:%i:%s"
case isoLocation:
res = "%Y-%m-%d %H:%i:%s"
case eurLocation:
res = "%Y-%m-%d %H.%i.%s"
case internalLocation:
res = "%Y%m%d%H%i%s"
}
case timeFormat:
switch l {
case usaLocation:
res = "%h:%i:%s %p"
case jisLocation:
res = "%H:%i:%s"
case isoLocation:
res = "%H:%i:%s"
case eurLocation:
res = "%H.%i.%s"
case internalLocation:
res = "%H%i%s"
}
}
return res, false, nil
}
type strToDateFunctionClass struct {
baseFunctionClass
}
func (c *strToDateFunctionClass) getRetTp(ctx sessionctx.Context, arg Expression) (tp byte, fsp int) {
tp = mysql.TypeDatetime
if _, ok := arg.(*Constant); !ok {
return tp, types.MaxFsp
}
strArg := WrapWithCastAsString(ctx, arg)
format, isNull, err := strArg.EvalString(ctx, nil)
if err != nil || isNull {
return
}
isDuration, isDate := types.GetFormatType(format)
if isDuration && !isDate {
tp = mysql.TypeDuration
} else if !isDuration && isDate {
tp = mysql.TypeDate
}
if strings.Contains(format, "%f") {
fsp = types.MaxFsp
}
return
}
// See https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_str-to-date
func (c *strToDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
retTp, fsp := c.getRetTp(ctx, args[1])
switch retTp {
case mysql.TypeDate:
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, types.ETString, types.ETString)
bf.tp.Tp, bf.tp.Flen, bf.tp.Decimal = mysql.TypeDate, mysql.MaxDateWidth, types.MinFsp
sig = &builtinStrToDateDateSig{bf}
case mysql.TypeDatetime:
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, types.ETString, types.ETString)
if fsp == types.MinFsp {
bf.tp.Flen, bf.tp.Decimal = mysql.MaxDatetimeWidthNoFsp, types.MinFsp
} else {
bf.tp.Flen, bf.tp.Decimal = mysql.MaxDatetimeWidthWithFsp, types.MaxFsp
}
sig = &builtinStrToDateDatetimeSig{bf}
case mysql.TypeDuration:
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration, types.ETString, types.ETString)
if fsp == types.MinFsp {
bf.tp.Flen, bf.tp.Decimal = mysql.MaxDurationWidthNoFsp, types.MinFsp
} else {
bf.tp.Flen, bf.tp.Decimal = mysql.MaxDurationWidthWithFsp, types.MaxFsp
}
sig = &builtinStrToDateDurationSig{bf}
}
return sig, nil
}
type builtinStrToDateDateSig struct {
baseBuiltinFunc
}
func (b *builtinStrToDateDateSig) Clone() builtinFunc {
newSig := &builtinStrToDateDateSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
func (b *builtinStrToDateDateSig) evalTime(row types.Row) (types.Time, bool, error) {
date, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, isNull, errors.Trace(err)
}
format, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, isNull, errors.Trace(err)
}
var t types.Time
sc := b.ctx.GetSessionVars().StmtCtx
succ := t.StrToDate(sc, date, format)
if !succ {
return types.Time{}, true, handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(t.String()))
}
t.Type, t.Fsp = mysql.TypeDate, types.MinFsp
return t, false, nil
}
type builtinStrToDateDatetimeSig struct {
baseBuiltinFunc
}
func (b *builtinStrToDateDatetimeSig) Clone() builtinFunc {
newSig := &builtinStrToDateDatetimeSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
func (b *builtinStrToDateDatetimeSig) evalTime(row types.Row) (types.Time, bool, error) {
date, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, isNull, errors.Trace(err)
}
format, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, isNull, errors.Trace(err)
}
var t types.Time
sc := b.ctx.GetSessionVars().StmtCtx
succ := t.StrToDate(sc, date, format)
if !succ {
return types.Time{}, true, handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(t.String()))
}
t.Type, t.Fsp = mysql.TypeDatetime, b.tp.Decimal
return t, false, nil
}
type builtinStrToDateDurationSig struct {
baseBuiltinFunc
}
func (b *builtinStrToDateDurationSig) Clone() builtinFunc {
newSig := &builtinStrToDateDurationSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// TODO: If the NO_ZERO_DATE or NO_ZERO_IN_DATE SQL mode is enabled, zero dates or part of dates are disallowed.
// In that case, STR_TO_DATE() returns NULL and generates a warning.
func (b *builtinStrToDateDurationSig) evalDuration(row types.Row) (types.Duration, bool, error) {
date, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Duration{}, isNull, errors.Trace(err)
}
format, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Duration{}, isNull, errors.Trace(err)
}
var t types.Time
sc := b.ctx.GetSessionVars().StmtCtx
succ := t.StrToDate(sc, date, format)
if !succ {
return types.Duration{}, true, handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(t.String()))
}
t.Fsp = b.tp.Decimal
dur, err := t.ConvertToDuration()
return dur, err != nil, errors.Trace(err)
}
type sysDateFunctionClass struct {
baseFunctionClass
}
func (c *sysDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
var argTps = make([]types.EvalType, 0)
if len(args) == 1 {
argTps = append(argTps, types.ETInt)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, argTps...)
bf.tp.Flen, bf.tp.Decimal = 19, 0
var sig builtinFunc
if len(args) == 1 {
sig = &builtinSysDateWithFspSig{bf}
} else {
sig = &builtinSysDateWithoutFspSig{bf}
}
return sig, nil
}
type builtinSysDateWithFspSig struct {
baseBuiltinFunc
}
func (b *builtinSysDateWithFspSig) Clone() builtinFunc {
newSig := &builtinSysDateWithFspSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals SYSDATE(fsp).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_sysdate
func (b *builtinSysDateWithFspSig) evalTime(row types.Row) (d types.Time, isNull bool, err error) {
fsp, isNull, err := b.args[0].EvalInt(b.ctx, row)
if isNull || err != nil {
return types.Time{}, isNull, errors.Trace(err)
}
tz := b.ctx.GetSessionVars().GetTimeZone()
now := time.Now().In(tz)
result, err := convertTimeToMysqlTime(now, int(fsp))
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
return result, false, nil
}
type builtinSysDateWithoutFspSig struct {
baseBuiltinFunc
}
func (b *builtinSysDateWithoutFspSig) Clone() builtinFunc {
newSig := &builtinSysDateWithoutFspSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals SYSDATE().
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_sysdate
func (b *builtinSysDateWithoutFspSig) evalTime(row types.Row) (d types.Time, isNull bool, err error) {
tz := b.ctx.GetSessionVars().GetTimeZone()
now := time.Now().In(tz)
result, err := convertTimeToMysqlTime(now, 0)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
return result, false, nil
}
type currentDateFunctionClass struct {
baseFunctionClass
}
func (c *currentDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime)
bf.tp.Flen, bf.tp.Decimal = 10, 0
sig := &builtinCurrentDateSig{bf}
return sig, nil
}
type builtinCurrentDateSig struct {
baseBuiltinFunc
}
func (b *builtinCurrentDateSig) Clone() builtinFunc {
newSig := &builtinCurrentDateSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals CURDATE().
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_curdate
func (b *builtinCurrentDateSig) evalTime(row types.Row) (d types.Time, isNull bool, err error) {
tz := b.ctx.GetSessionVars().GetTimeZone()
year, month, day := time.Now().In(tz).Date()
result := types.Time{
Time: types.FromDate(year, int(month), day, 0, 0, 0, 0),
Type: mysql.TypeDate,
Fsp: 0}
return result, false, nil
}
type currentTimeFunctionClass struct {
baseFunctionClass
}
func (c *currentTimeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err = c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
if len(args) == 0 {
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration)
bf.tp.Flen, bf.tp.Decimal = mysql.MaxDurationWidthNoFsp, types.MinFsp
sig = &builtinCurrentTime0ArgSig{bf}
return sig, nil
}
// args[0] must be a constant which should not be null.
_, ok := args[0].(*Constant)
fsp := int64(types.MaxFsp)
if ok {
fsp, _, err = args[0].EvalInt(ctx, nil)
if err != nil {
return nil, errors.Trace(err)
}
if fsp > int64(types.MaxFsp) {
return nil, errors.Errorf("Too-big precision %v specified for 'curtime'. Maximum is %v.", fsp, types.MaxFsp)
} else if fsp < int64(types.MinFsp) {
return nil, errors.Errorf("Invalid negative %d specified, must in [0, 6].", fsp)
}
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration, types.ETInt)
bf.tp.Flen, bf.tp.Decimal = mysql.MaxDurationWidthWithFsp, int(fsp)
sig = &builtinCurrentTime1ArgSig{bf}
return sig, nil
}
type builtinCurrentTime0ArgSig struct {
baseBuiltinFunc
}
func (b *builtinCurrentTime0ArgSig) Clone() builtinFunc {
newSig := &builtinCurrentTime0ArgSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
func (b *builtinCurrentTime0ArgSig) evalDuration(row types.Row) (types.Duration, bool, error) {
tz := b.ctx.GetSessionVars().GetTimeZone()
dur := time.Now().In(tz).Format(types.TimeFormat)
res, err := types.ParseDuration(dur, types.MinFsp)
if err != nil {
return types.Duration{}, true, errors.Trace(err)
}
return res, false, nil
}
type builtinCurrentTime1ArgSig struct {
baseBuiltinFunc
}
func (b *builtinCurrentTime1ArgSig) Clone() builtinFunc {
newSig := &builtinCurrentTime1ArgSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
func (b *builtinCurrentTime1ArgSig) evalDuration(row types.Row) (types.Duration, bool, error) {
fsp, _, err := b.args[0].EvalInt(b.ctx, row)
if err != nil {
return types.Duration{}, true, errors.Trace(err)
}
tz := b.ctx.GetSessionVars().GetTimeZone()
dur := time.Now().In(tz).Format(types.TimeFSPFormat)
res, err := types.ParseDuration(dur, int(fsp))
if err != nil {
return types.Duration{}, true, errors.Trace(err)
}
return res, false, nil
}
type timeFunctionClass struct {
baseFunctionClass
}
func (c *timeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration, types.ETString)
sig := &builtinTimeSig{bf}
return sig, nil
}
type builtinTimeSig struct {
baseBuiltinFunc
}
func (b *builtinTimeSig) Clone() builtinFunc {
newSig := &builtinTimeSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinTimeSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_time.
func (b *builtinTimeSig) evalDuration(row types.Row) (res types.Duration, isNull bool, err error) {
expr, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return res, isNull, errors.Trace(err)
}
fsp := 0
if idx := strings.Index(expr, "."); idx != -1 {
fsp = len(expr) - idx - 1
}
if fsp, err = types.CheckFsp(fsp); err != nil {
return res, isNull, errors.Trace(err)
}
res, err = types.ParseDuration(expr, fsp)
if types.ErrTruncatedWrongVal.Equal(err) {
sc := b.ctx.GetSessionVars().StmtCtx
err = sc.HandleTruncate(err)
}
return res, isNull, errors.Trace(err)
}
type timeLiteralFunctionClass struct {
baseFunctionClass
}
func (c *timeLiteralFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
con, ok := args[0].(*Constant)
if !ok {
panic("Unexpected parameter for time literal")
}
dt, err := con.Eval(nil)
if err != nil {
return nil, errors.Trace(err)
}
str := dt.GetString()
if !isDuration(str) {
return nil, types.ErrIncorrectDatetimeValue.GenByArgs(str)
}
duration, err := types.ParseDuration(str, getFsp(str))
if err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, []Expression{}, types.ETDuration)
bf.tp.Flen, bf.tp.Decimal = 10, duration.Fsp
if duration.Fsp > 0 {
bf.tp.Flen += 1 + duration.Fsp
}
sig := &builtinTimeLiteralSig{bf, duration}
return sig, nil
}
type builtinTimeLiteralSig struct {
baseBuiltinFunc
duration types.Duration
}
func (b *builtinTimeLiteralSig) Clone() builtinFunc {
newSig := &builtinTimeLiteralSig{duration: b.duration}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals TIME 'stringLit'.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html
func (b *builtinTimeLiteralSig) evalDuration(row types.Row) (types.Duration, bool, error) {
return b.duration, false, nil
}
type utcDateFunctionClass struct {
baseFunctionClass
}
func (c *utcDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime)
bf.tp.Flen, bf.tp.Decimal = 10, 0
sig := &builtinUTCDateSig{bf}
return sig, nil
}
type builtinUTCDateSig struct {
baseBuiltinFunc
}
func (b *builtinUTCDateSig) Clone() builtinFunc {
newSig := &builtinUTCDateSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals UTC_DATE, UTC_DATE().
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-date
func (b *builtinUTCDateSig) evalTime(row types.Row) (types.Time, bool, error) {
year, month, day := time.Now().UTC().Date()
result := types.Time{
Time: types.FromGoTime(time.Date(year, month, day, 0, 0, 0, 0, time.UTC)),
Type: mysql.TypeDate,
Fsp: types.UnspecifiedFsp}
return result, false, nil
}
type utcTimestampFunctionClass struct {
baseFunctionClass
}
func getFlenAndDecimal4UTCTimestampAndNow(ctx sessionctx.Context, arg Expression) (flen, decimal int) {
if constant, ok := arg.(*Constant); ok {
fsp, isNull, err := constant.EvalInt(ctx, nil)
if isNull || err != nil || fsp > int64(types.MaxFsp) {
decimal = types.MaxFsp
} else if fsp < int64(types.MinFsp) {
decimal = types.MinFsp
} else {
decimal = int(fsp)
}
}
if decimal > 0 {
flen = 19 + 1 + decimal
} else {
flen = 19
}
return flen, decimal
}
func (c *utcTimestampFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
argTps := make([]types.EvalType, 0, 1)
if len(args) == 1 {
argTps = append(argTps, types.ETInt)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, argTps...)
if len(args) == 1 {
bf.tp.Flen, bf.tp.Decimal = getFlenAndDecimal4UTCTimestampAndNow(bf.ctx, args[0])
} else {
bf.tp.Flen, bf.tp.Decimal = 19, 0
}
var sig builtinFunc
if len(args) == 1 {
sig = &builtinUTCTimestampWithArgSig{bf}
} else {
sig = &builtinUTCTimestampWithoutArgSig{bf}
}
return sig, nil
}
func evalUTCTimestampWithFsp(fsp int) (types.Time, bool, error) {
result, err := convertTimeToMysqlTime(time.Now().UTC(), fsp)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
return result, false, nil
}
type builtinUTCTimestampWithArgSig struct {
baseBuiltinFunc
}
func (b *builtinUTCTimestampWithArgSig) Clone() builtinFunc {
newSig := &builtinUTCTimestampWithArgSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals UTC_TIMESTAMP(fsp).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-timestamp
func (b *builtinUTCTimestampWithArgSig) evalTime(row types.Row) (types.Time, bool, error) {
num, isNull, err := b.args[0].EvalInt(b.ctx, row)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
if !isNull && num > int64(types.MaxFsp) {
return types.Time{}, true, errors.Errorf("Too-big precision %v specified for 'utc_timestamp'. Maximum is %v.", num, types.MaxFsp)
}
if !isNull && num < int64(types.MinFsp) {
return types.Time{}, true, errors.Errorf("Invalid negative %d specified, must in [0, 6].", num)
}
result, isNull, err := evalUTCTimestampWithFsp(int(num))
return result, isNull, errors.Trace(err)
}
type builtinUTCTimestampWithoutArgSig struct {
baseBuiltinFunc
}
func (b *builtinUTCTimestampWithoutArgSig) Clone() builtinFunc {
newSig := &builtinUTCTimestampWithoutArgSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals UTC_TIMESTAMP().
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-timestamp
func (b *builtinUTCTimestampWithoutArgSig) evalTime(row types.Row) (types.Time, bool, error) {
result, isNull, err := evalUTCTimestampWithFsp(0)
return result, isNull, errors.Trace(err)
}
type nowFunctionClass struct {
baseFunctionClass
}
func (c *nowFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
argTps := make([]types.EvalType, 0, 1)
if len(args) == 1 {
argTps = append(argTps, types.ETInt)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, argTps...)
if len(args) == 1 {
bf.tp.Flen, bf.tp.Decimal = getFlenAndDecimal4UTCTimestampAndNow(bf.ctx, args[0])
} else {
bf.tp.Flen, bf.tp.Decimal = 19, 0
}
var sig builtinFunc
if len(args) == 1 {
sig = &builtinNowWithArgSig{bf}
} else {
sig = &builtinNowWithoutArgSig{bf}
}
return sig, nil
}
func evalNowWithFsp(ctx sessionctx.Context, fsp int) (types.Time, bool, error) {
sysTs, err := getSystemTimestamp(ctx)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, err := convertTimeToMysqlTime(sysTs, fsp)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
err = result.ConvertTimeZone(time.Local, ctx.GetSessionVars().GetTimeZone())
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
return result, false, nil
}
type builtinNowWithArgSig struct {
baseBuiltinFunc
}
func (b *builtinNowWithArgSig) Clone() builtinFunc {
newSig := &builtinNowWithArgSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals NOW(fsp)
// see: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_now
func (b *builtinNowWithArgSig) evalTime(row types.Row) (types.Time, bool, error) {
fsp, isNull, err := b.args[0].EvalInt(b.ctx, row)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
if isNull {
fsp = 0
} else if fsp > int64(types.MaxFsp) {
return types.Time{}, true, errors.Errorf("Too-big precision %v specified for 'now'. Maximum is %v.", fsp, types.MaxFsp)
} else if fsp < int64(types.MinFsp) {
return types.Time{}, true, errors.Errorf("Invalid negative %d specified, must in [0, 6].", fsp)
}
result, isNull, err := evalNowWithFsp(b.ctx, int(fsp))
return result, isNull, errors.Trace(err)
}
type builtinNowWithoutArgSig struct {
baseBuiltinFunc
}
func (b *builtinNowWithoutArgSig) Clone() builtinFunc {
newSig := &builtinNowWithoutArgSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals NOW()
// see: https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_now
func (b *builtinNowWithoutArgSig) evalTime(row types.Row) (types.Time, bool, error) {
result, isNull, err := evalNowWithFsp(b.ctx, 0)
return result, isNull, errors.Trace(err)
}
type extractFunctionClass struct {
baseFunctionClass
}
func (c *extractFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err = c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
datetimeUnits := map[string]struct{}{
"DAY": {},
"WEEK": {},
"MONTH": {},
"QUARTER": {},
"YEAR": {},
"DAY_MICROSECOND": {},
"DAY_SECOND": {},
"DAY_MINUTE": {},
"DAY_HOUR": {},
"YEAR_MONTH": {},
}
isDatetimeUnit := true
args[0] = WrapWithCastAsString(ctx, args[0])
if _, isCon := args[0].(*Constant); isCon {
unit, _, err1 := args[0].EvalString(ctx, nil)
if err1 != nil {
return nil, errors.Trace(err1)
}
_, isDatetimeUnit = datetimeUnits[unit]
}
var bf baseBuiltinFunc
if isDatetimeUnit {
bf = newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETString, types.ETDatetime)
sig = &builtinExtractDatetimeSig{bf}
} else {
bf = newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETString, types.ETDuration)
sig = &builtinExtractDurationSig{bf}
}
return sig, nil
}
type builtinExtractDatetimeSig struct {
baseBuiltinFunc
}
func (b *builtinExtractDatetimeSig) Clone() builtinFunc {
newSig := &builtinExtractDatetimeSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals a builtinExtractDatetimeSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_extract
func (b *builtinExtractDatetimeSig) evalInt(row types.Row) (int64, bool, error) {
unit, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(err)
}
dt, isNull, err := b.args[1].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(err)
}
res, err := types.ExtractDatetimeNum(&dt, unit)
return res, err != nil, errors.Trace(err)
}
type builtinExtractDurationSig struct {
baseBuiltinFunc
}
func (b *builtinExtractDurationSig) Clone() builtinFunc {
newSig := &builtinExtractDurationSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals a builtinExtractDurationSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_extract
func (b *builtinExtractDurationSig) evalInt(row types.Row) (int64, bool, error) {
unit, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(err)
}
dur, isNull, err := b.args[1].EvalDuration(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(err)
}
res, err := types.ExtractDurationNum(&dur, unit)
return res, err != nil, errors.Trace(err)
}
// baseDateArithmitical is the base class for all "builtinAddDateXXXSig" and "builtinSubDateXXXSig",
// which provides parameter getter and date arithmetical calculate functions.
type baseDateArithmitical struct {
// intervalRegexp is "*Regexp" used to extract string interval for "DAY" unit.
intervalRegexp *regexp.Regexp
}
func newDateArighmeticalUtil() baseDateArithmitical {
return baseDateArithmitical{
intervalRegexp: regexp.MustCompile(`[\d]+`),
}
}
func (du *baseDateArithmitical) getDateFromString(ctx sessionctx.Context, args []Expression, row types.Row, unit string) (types.Time, bool, error) {
dateStr, isNull, err := args[0].EvalString(ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
dateTp := mysql.TypeDate
if !types.IsDateFormat(dateStr) || types.IsClockUnit(unit) {
dateTp = mysql.TypeDatetime
}
sc := ctx.GetSessionVars().StmtCtx
date, err := types.ParseTime(sc, dateStr, dateTp, types.MaxFsp)
return date, err != nil, errors.Trace(handleInvalidTimeError(ctx, err))
}
func (du *baseDateArithmitical) getDateFromInt(ctx sessionctx.Context, args []Expression, row types.Row, unit string) (types.Time, bool, error) {
dateInt, isNull, err := args[0].EvalInt(ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
sc := ctx.GetSessionVars().StmtCtx
date, err := types.ParseTimeFromInt64(sc, dateInt)
if err != nil {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(ctx, err))
}
dateTp := mysql.TypeDate
if date.Type == mysql.TypeDatetime || date.Type == mysql.TypeTimestamp || types.IsClockUnit(unit) {
dateTp = mysql.TypeDatetime
}
date.Type = dateTp
return date, false, nil
}
func (du *baseDateArithmitical) getDateFromDatetime(ctx sessionctx.Context, args []Expression, row types.Row, unit string) (types.Time, bool, error) {
date, isNull, err := args[0].EvalTime(ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
dateTp := mysql.TypeDate
if date.Type == mysql.TypeDatetime || date.Type == mysql.TypeTimestamp || types.IsClockUnit(unit) {
dateTp = mysql.TypeDatetime
}
date.Type = dateTp
return date, false, nil
}
func (du *baseDateArithmitical) getIntervalFromString(ctx sessionctx.Context, args []Expression, row types.Row, unit string) (string, bool, error) {
interval, isNull, err := args[1].EvalString(ctx, row)
if isNull || err != nil {
return "", true, errors.Trace(err)
}
// unit "DAY" has to be specially handled.
if strings.ToLower(unit) == "day" {
if strings.ToLower(interval) == "true" {
interval = "1"
} else if strings.ToLower(interval) == "false" {
interval = "0"
} else {
interval = du.intervalRegexp.FindString(interval)
}
}
return interval, false, nil
}
func (du *baseDateArithmitical) getIntervalFromDecimal(ctx sessionctx.Context, args []Expression, row types.Row, unit string) (string, bool, error) {
interval, isNull, err := args[1].EvalString(ctx, row)
if isNull || err != nil {
return "", true, errors.Trace(err)
}
switch strings.ToUpper(unit) {
case "HOUR_MINUTE", "MINUTE_SECOND":
interval = strings.Replace(interval, ".", ":", -1)
case "YEAR_MONTH":
interval = strings.Replace(interval, ".", "-", -1)
case "DAY_HOUR":
interval = strings.Replace(interval, ".", " ", -1)
case "DAY_MINUTE":
interval = "0 " + strings.Replace(interval, ".", ":", -1)
case "DAY_SECOND":
interval = "0 00:" + strings.Replace(interval, ".", ":", -1)
case "DAY_MICROSECOND":
interval = "0 00:00:" + interval
case "HOUR_MICROSECOND":
interval = "00:00:" + interval
case "HOUR_SECOND":
interval = "00:" + strings.Replace(interval, ".", ":", -1)
case "MINUTE_MICROSECOND":
interval = "00:" + interval
case "SECOND_MICROSECOND":
/* keep interval as original decimal */
default:
// YEAR, QUARTER, MONTH, WEEK, DAY, HOUR, MINUTE, SECOND, MICROSECOND
args[1] = WrapWithCastAsInt(ctx, args[1])
interval, isNull, err = args[1].EvalString(ctx, row)
if isNull || err != nil {
return "", true, errors.Trace(err)
}
}
return interval, false, nil
}
func (du *baseDateArithmitical) getIntervalFromInt(ctx sessionctx.Context, args []Expression, row types.Row, unit string) (string, bool, error) {
interval, isNull, err := args[1].EvalInt(ctx, row)
if isNull || err != nil {
return "", true, errors.Trace(err)
}
return strconv.FormatInt(interval, 10), false, nil
}
func (du *baseDateArithmitical) add(ctx sessionctx.Context, date types.Time, interval string, unit string) (types.Time, bool, error) {
year, month, day, dur, err := types.ExtractTimeValue(unit, interval)
if err != nil {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(ctx, err))
}
goTime, err := date.Time.GoTime(time.Local)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
goTime = goTime.Add(dur)
goTime = goTime.AddDate(int(year), int(month), int(day))
if goTime.Nanosecond() == 0 {
date.Fsp = 0
}
date.Time = types.FromGoTime(goTime)
return date, false, nil
}
func (du *baseDateArithmitical) sub(ctx sessionctx.Context, date types.Time, interval string, unit string) (types.Time, bool, error) {
year, month, day, dur, err := types.ExtractTimeValue(unit, interval)
if err != nil {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(ctx, err))
}
year, month, day, dur = -year, -month, -day, -dur
goTime, err := date.Time.GoTime(time.Local)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
goTime = goTime.Add(dur)
goTime = goTime.AddDate(int(year), int(month), int(day))
if goTime.Nanosecond() == 0 {
date.Fsp = 0
}
date.Time = types.FromGoTime(goTime)
return date, false, nil
}
type addDateFunctionClass struct {
baseFunctionClass
}
func (c *addDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err = c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
dateEvalTp := args[0].GetType().EvalType()
if dateEvalTp != types.ETString && dateEvalTp != types.ETInt {
dateEvalTp = types.ETDatetime
}
intervalEvalTp := args[1].GetType().EvalType()
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal {
intervalEvalTp = types.ETInt
}
argTps := []types.EvalType{dateEvalTp, intervalEvalTp, types.ETString}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, argTps...)
bf.tp.Flen, bf.tp.Decimal = mysql.MaxDatetimeFullWidth, types.UnspecifiedLength
switch {
case dateEvalTp == types.ETString && intervalEvalTp == types.ETString:
sig = &builtinAddDateStringStringSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETString && intervalEvalTp == types.ETInt:
sig = &builtinAddDateStringIntSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETString && intervalEvalTp == types.ETDecimal:
sig = &builtinAddDateStringDecimalSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETString:
sig = &builtinAddDateIntStringSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETInt:
sig = &builtinAddDateIntIntSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETString:
sig = &builtinAddDateDatetimeStringSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETInt:
sig = &builtinAddDateDatetimeIntSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
}
return sig, nil
}
type builtinAddDateStringStringSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinAddDateStringStringSig) Clone() builtinFunc {
newSig := &builtinAddDateStringStringSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals ADDDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
func (b *builtinAddDateStringStringSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.add(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type builtinAddDateStringIntSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinAddDateStringIntSig) Clone() builtinFunc {
newSig := &builtinAddDateStringIntSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals ADDDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
func (b *builtinAddDateStringIntSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromInt(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.add(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type builtinAddDateStringDecimalSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinAddDateStringDecimalSig) Clone() builtinFunc {
newSig := &builtinAddDateStringDecimalSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals ADDDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
func (b *builtinAddDateStringDecimalSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromDecimal(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.add(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type builtinAddDateIntStringSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinAddDateIntStringSig) Clone() builtinFunc {
newSig := &builtinAddDateIntStringSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals ADDDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
func (b *builtinAddDateIntStringSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromInt(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.add(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type builtinAddDateIntIntSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinAddDateIntIntSig) Clone() builtinFunc {
newSig := &builtinAddDateIntIntSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals ADDDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
func (b *builtinAddDateIntIntSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromInt(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromInt(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.add(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type builtinAddDateDatetimeStringSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinAddDateDatetimeStringSig) Clone() builtinFunc {
newSig := &builtinAddDateDatetimeStringSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals ADDDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
func (b *builtinAddDateDatetimeStringSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromDatetime(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.add(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type builtinAddDateDatetimeIntSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinAddDateDatetimeIntSig) Clone() builtinFunc {
newSig := &builtinAddDateDatetimeIntSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals ADDDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_adddate
func (b *builtinAddDateDatetimeIntSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromDatetime(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromInt(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.add(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type subDateFunctionClass struct {
baseFunctionClass
}
func (c *subDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err = c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
dateEvalTp := args[0].GetType().EvalType()
if dateEvalTp != types.ETString && dateEvalTp != types.ETInt {
dateEvalTp = types.ETDatetime
}
intervalEvalTp := args[1].GetType().EvalType()
if intervalEvalTp != types.ETString && intervalEvalTp != types.ETDecimal {
intervalEvalTp = types.ETInt
}
argTps := []types.EvalType{dateEvalTp, intervalEvalTp, types.ETString}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, argTps...)
bf.tp.Flen, bf.tp.Decimal = mysql.MaxDatetimeFullWidth, types.UnspecifiedLength
switch {
case dateEvalTp == types.ETString && intervalEvalTp == types.ETString:
sig = &builtinSubDateStringStringSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETString && intervalEvalTp == types.ETInt:
sig = &builtinSubDateStringIntSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETString && intervalEvalTp == types.ETDecimal:
sig = &builtinSubDateStringDecimalSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETString:
sig = &builtinSubDateIntStringSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETInt && intervalEvalTp == types.ETInt:
sig = &builtinSubDateIntIntSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETString:
sig = &builtinSubDateDatetimeStringSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
case dateEvalTp == types.ETDatetime && intervalEvalTp == types.ETInt:
sig = &builtinSubDateDatetimeIntSig{
baseBuiltinFunc: bf,
baseDateArithmitical: newDateArighmeticalUtil(),
}
}
return sig, nil
}
type builtinSubDateStringStringSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinSubDateStringStringSig) Clone() builtinFunc {
newSig := &builtinSubDateStringStringSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals SUBDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate
func (b *builtinSubDateStringStringSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.sub(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type builtinSubDateStringIntSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinSubDateStringIntSig) Clone() builtinFunc {
newSig := &builtinSubDateStringIntSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals SUBDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate
func (b *builtinSubDateStringIntSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromInt(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.sub(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type builtinSubDateStringDecimalSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinSubDateStringDecimalSig) Clone() builtinFunc {
newSig := &builtinSubDateStringDecimalSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
func (b *builtinSubDateStringDecimalSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromDecimal(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.sub(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type builtinSubDateIntStringSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinSubDateIntStringSig) Clone() builtinFunc {
newSig := &builtinSubDateIntStringSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals SUBDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate
func (b *builtinSubDateIntStringSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromInt(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.sub(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type builtinSubDateIntIntSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinSubDateIntIntSig) Clone() builtinFunc {
newSig := &builtinSubDateIntIntSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals SUBDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate
func (b *builtinSubDateIntIntSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromInt(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromInt(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.sub(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type builtinSubDateDatetimeStringSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinSubDateDatetimeStringSig) Clone() builtinFunc {
newSig := &builtinSubDateDatetimeStringSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals SUBDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate
func (b *builtinSubDateDatetimeStringSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromDatetime(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromString(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.sub(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type builtinSubDateDatetimeIntSig struct {
baseBuiltinFunc
baseDateArithmitical
}
func (b *builtinSubDateDatetimeIntSig) Clone() builtinFunc {
newSig := &builtinSubDateDatetimeIntSig{baseDateArithmitical: b.baseDateArithmitical}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals SUBDATE(date,INTERVAL expr unit).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subdate
func (b *builtinSubDateDatetimeIntSig) evalTime(row types.Row) (types.Time, bool, error) {
unit, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
date, isNull, err := b.getDateFromDatetime(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
interval, isNull, err := b.getIntervalFromInt(b.ctx, b.args, row, unit)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
result, isNull, err := b.sub(b.ctx, date, interval, unit)
return result, isNull || err != nil, errors.Trace(err)
}
type timestampDiffFunctionClass struct {
baseFunctionClass
}
func (c *timestampDiffFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETString, types.ETDatetime, types.ETDatetime)
sig := &builtinTimestampDiffSig{bf}
return sig, nil
}
type builtinTimestampDiffSig struct {
baseBuiltinFunc
}
func (b *builtinTimestampDiffSig) Clone() builtinFunc {
newSig := &builtinTimestampDiffSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals a builtinTimestampDiffSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timestampdiff
func (b *builtinTimestampDiffSig) evalInt(row types.Row) (int64, bool, error) {
unit, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(err)
}
lhs, isNull, err := b.args[1].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
rhs, isNull, err := b.args[2].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if invalidLHS, invalidRHS := lhs.InvalidZero(), rhs.InvalidZero(); invalidLHS || invalidRHS {
if invalidLHS {
err = handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(lhs.String()))
}
if invalidRHS {
err = handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(rhs.String()))
}
return 0, true, errors.Trace(err)
}
return types.TimestampDiff(unit, lhs, rhs), false, nil
}
type unixTimestampFunctionClass struct {
baseFunctionClass
}
func (c *unixTimestampFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
var argTps []types.EvalType
var retTp types.EvalType
var retFLen, retDecimal int
if len(args) == 0 {
retTp, retDecimal = types.ETInt, 0
} else {
argTps = []types.EvalType{types.ETDatetime}
argType := args[0].GetType()
argEvaltp := argType.EvalType()
if argEvaltp == types.ETString {
// Treat types.ETString as unspecified decimal.
retDecimal = types.UnspecifiedLength
if cnst, ok := args[0].(*Constant); ok {
tmpStr, _, err := cnst.EvalString(ctx, nil)
if err != nil {
return nil, errors.Trace(err)
}
retDecimal = 0
if dotIdx := strings.LastIndex(tmpStr, "."); dotIdx >= 0 {
retDecimal = len(tmpStr) - dotIdx - 1
}
}
} else {
retDecimal = argType.Decimal
}
if retDecimal > 6 || retDecimal == types.UnspecifiedLength {
retDecimal = 6
}
if retDecimal == 0 {
retTp = types.ETInt
} else {
retTp = types.ETDecimal
}
}
if retTp == types.ETInt {
retFLen = 11
} else if retTp == types.ETDecimal {
retFLen = 12 + retDecimal
} else {
panic("Unexpected retTp")
}
bf := newBaseBuiltinFuncWithTp(ctx, args, retTp, argTps...)
bf.tp.Flen = retFLen
bf.tp.Decimal = retDecimal
var sig builtinFunc
if len(args) == 0 {
sig = &builtinUnixTimestampCurrentSig{bf}
} else if retTp == types.ETInt {
sig = &builtinUnixTimestampIntSig{bf}
} else if retTp == types.ETDecimal {
sig = &builtinUnixTimestampDecSig{bf}
}
return sig, nil
}
// goTimeToMysqlUnixTimestamp converts go time into MySQL's Unix timestamp.
// MySQL's Unix timestamp ranges in int32. Values out of range should be rewritten to 0.
func goTimeToMysqlUnixTimestamp(t time.Time, decimal int) (*types.MyDecimal, error) {
nanoSeconds := t.UnixNano()
if nanoSeconds < 0 || (nanoSeconds/1e3) >= (math.MaxInt32+1)*1e6 {
return new(types.MyDecimal), nil
}
dec := new(types.MyDecimal)
// Here we don't use float to prevent precision lose.
dec.FromInt(nanoSeconds)
err := dec.Shift(-9)
if err != nil {
return nil, errors.Trace(err)
}
err = dec.Round(dec, decimal, types.ModeHalfEven)
return dec, errors.Trace(err)
}
type builtinUnixTimestampCurrentSig struct {
baseBuiltinFunc
}
func (b *builtinUnixTimestampCurrentSig) Clone() builtinFunc {
newSig := &builtinUnixTimestampCurrentSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals a UNIX_TIMESTAMP().
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_unix-timestamp
func (b *builtinUnixTimestampCurrentSig) evalInt(row types.Row) (int64, bool, error) {
dec, err := goTimeToMysqlUnixTimestamp(time.Now(), 1)
if err != nil {
return 0, true, errors.Trace(err)
}
intVal, err := dec.ToInt()
terror.Log(errors.Trace(err))
return intVal, false, nil
}
type builtinUnixTimestampIntSig struct {
baseBuiltinFunc
}
func (b *builtinUnixTimestampIntSig) Clone() builtinFunc {
newSig := &builtinUnixTimestampIntSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals a UNIX_TIMESTAMP(time).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_unix-timestamp
func (b *builtinUnixTimestampIntSig) evalInt(row types.Row) (int64, bool, error) {
val, isNull, err := b.args[0].EvalTime(b.ctx, row)
if err != nil && terror.ErrorEqual(types.ErrInvalidTimeFormat.GenByArgs(val), err) {
// Return 0 for invalid date time.
return 0, false, nil
}
if isNull {
return 0, true, nil
}
t, err := val.Time.GoTime(getTimeZone(b.ctx))
if err != nil {
return 0, false, nil
}
dec, err := goTimeToMysqlUnixTimestamp(t, 1)
if err != nil {
return 0, true, errors.Trace(err)
}
intVal, err := dec.ToInt()
terror.Log(errors.Trace(err))
return intVal, false, nil
}
type builtinUnixTimestampDecSig struct {
baseBuiltinFunc
}
func (b *builtinUnixTimestampDecSig) Clone() builtinFunc {
newSig := &builtinUnixTimestampDecSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDecimal evals a UNIX_TIMESTAMP(time).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_unix-timestamp
func (b *builtinUnixTimestampDecSig) evalDecimal(row types.Row) (*types.MyDecimal, bool, error) {
val, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
// Return 0 for invalid date time.
return new(types.MyDecimal), isNull, nil
}
t, err := val.Time.GoTime(getTimeZone(b.ctx))
if err != nil {
return new(types.MyDecimal), false, nil
}
result, err := goTimeToMysqlUnixTimestamp(t, b.tp.Decimal)
return result, err != nil, errors.Trace(err)
}
type timestampFunctionClass struct {
baseFunctionClass
}
func (c *timestampFunctionClass) getDefaultFsp(tp *types.FieldType) int {
if tp.Tp == mysql.TypeDatetime || tp.Tp == mysql.TypeDate || tp.Tp == mysql.TypeDuration ||
tp.Tp == mysql.TypeTimestamp {
return tp.Decimal
}
switch cls := tp.EvalType(); cls {
case types.ETInt:
return types.MinFsp
case types.ETReal, types.ETDatetime, types.ETTimestamp, types.ETDuration, types.ETJson, types.ETString:
return types.MaxFsp
case types.ETDecimal:
if tp.Decimal < types.MaxFsp {
return tp.Decimal
}
return types.MaxFsp
}
return types.MaxFsp
}
func (c *timestampFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
evalTps, argLen := []types.EvalType{types.ETString}, len(args)
if argLen == 2 {
evalTps = append(evalTps, types.ETString)
}
fsp := c.getDefaultFsp(args[0].GetType())
if argLen == 2 {
fsp = mathutil.Max(fsp, c.getDefaultFsp(args[1].GetType()))
}
isFloat := false
switch args[0].GetType().Tp {
case mysql.TypeFloat, mysql.TypeDouble, mysql.TypeDecimal:
isFloat = true
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, evalTps...)
bf.tp.Decimal, bf.tp.Flen = fsp, 19
if fsp != 0 {
bf.tp.Flen += 1 + fsp
}
var sig builtinFunc
if argLen == 2 {
sig = &builtinTimestamp2ArgsSig{bf, isFloat}
} else {
sig = &builtinTimestamp1ArgSig{bf, isFloat}
}
return sig, nil
}
type builtinTimestamp1ArgSig struct {
baseBuiltinFunc
isFloat bool
}
func (b *builtinTimestamp1ArgSig) Clone() builtinFunc {
newSig := &builtinTimestamp1ArgSig{isFloat: b.isFloat}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals a builtinTimestamp1ArgSig.
// See https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_timestamp
func (b *builtinTimestamp1ArgSig) evalTime(row types.Row) (types.Time, bool, error) {
s, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, isNull, errors.Trace(err)
}
var tm types.Time
sc := b.ctx.GetSessionVars().StmtCtx
if b.isFloat {
tm, err = types.ParseTimeFromFloatString(sc, s, mysql.TypeDatetime, getFsp(s))
} else {
tm, err = types.ParseTime(sc, s, mysql.TypeDatetime, getFsp(s))
}
if err != nil {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
return tm, false, nil
}
type builtinTimestamp2ArgsSig struct {
baseBuiltinFunc
isFloat bool
}
func (b *builtinTimestamp2ArgsSig) Clone() builtinFunc {
newSig := &builtinTimestamp2ArgsSig{isFloat: b.isFloat}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals a builtinTimestamp2ArgsSig.
// See https://dev.mysql.com/doc/refman/5.5/en/date-and-time-functions.html#function_timestamp
func (b *builtinTimestamp2ArgsSig) evalTime(row types.Row) (types.Time, bool, error) {
arg0, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, isNull, errors.Trace(err)
}
var tm types.Time
sc := b.ctx.GetSessionVars().StmtCtx
if b.isFloat {
tm, err = types.ParseTimeFromFloatString(sc, arg0, mysql.TypeDatetime, getFsp(arg0))
} else {
tm, err = types.ParseTime(sc, arg0, mysql.TypeDatetime, getFsp(arg0))
}
if err != nil {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
arg1, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, isNull, errors.Trace(err)
}
if !isDuration(arg1) {
return types.Time{}, true, nil
}
duration, err := types.ParseDuration(arg1, getFsp(arg1))
if err != nil {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
tmp, err := tm.Add(duration)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
return tmp, false, nil
}
type timestampLiteralFunctionClass struct {
baseFunctionClass
}
func (c *timestampLiteralFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
con, ok := args[0].(*Constant)
if !ok {
panic("Unexpected parameter for timestamp literal")
}
dt, err := con.Eval(nil)
if err != nil {
return nil, errors.Trace(err)
}
str, err := dt.ToString()
if err != nil {
return nil, errors.Trace(err)
}
if !timestampPattern.MatchString(str) {
return nil, types.ErrIncorrectDatetimeValue.GenByArgs(str)
}
tm, err := types.ParseTime(ctx.GetSessionVars().StmtCtx, str, mysql.TypeTimestamp, getFsp(str))
if err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, []Expression{}, types.ETDatetime)
bf.tp.Flen, bf.tp.Decimal = mysql.MaxDatetimeWidthNoFsp, tm.Fsp
if tm.Fsp > 0 {
bf.tp.Flen += tm.Fsp + 1
}
sig := &builtinTimestampLiteralSig{bf, tm}
return sig, nil
}
type builtinTimestampLiteralSig struct {
baseBuiltinFunc
tm types.Time
}
func (b *builtinTimestampLiteralSig) Clone() builtinFunc {
newSig := &builtinTimestampLiteralSig{tm: b.tm}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals TIMESTAMP 'stringLit'.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-literals.html
func (b *builtinTimestampLiteralSig) evalTime(row types.Row) (types.Time, bool, error) {
return b.tm, false, nil
}
func getFsp(s string) (fsp int) {
fsp = len(s) - strings.Index(s, ".") - 1
if fsp == len(s) {
fsp = 0
} else if fsp > 6 {
fsp = 6
}
return
}
// getFsp4TimeAddSub is used to in function 'ADDTIME' and 'SUBTIME' to evaluate `fsp` for the
// second parameter. It's used only if the second parameter is of string type. It's different
// from getFsp in that the result of getFsp4TimeAddSub is either 6 or 0.
func getFsp4TimeAddSub(s string) int {
if len(s)-strings.Index(s, ".")-1 == len(s) {
return types.MinFsp
}
for _, c := range s[strings.Index(s, ".")+1:] {
if c != '0' {
return types.MaxFsp
}
}
return types.MinFsp
}
// getBf4TimeAddSub parses input types, generates baseBuiltinFunc and set related attributes for
// builtin function 'ADDTIME' and 'SUBTIME'
func getBf4TimeAddSub(ctx sessionctx.Context, args []Expression) (tp1, tp2 *types.FieldType, bf baseBuiltinFunc) {
tp1, tp2 = args[0].GetType(), args[1].GetType()
var argTp1, argTp2, retTp types.EvalType
switch tp1.Tp {
case mysql.TypeDatetime, mysql.TypeTimestamp:
argTp1, retTp = types.ETDatetime, types.ETDatetime
case mysql.TypeDuration:
argTp1, retTp = types.ETDuration, types.ETDuration
case mysql.TypeDate:
argTp1, retTp = types.ETDuration, types.ETString
default:
argTp1, retTp = types.ETString, types.ETString
}
switch tp2.Tp {
case mysql.TypeDatetime, mysql.TypeDuration:
argTp2 = types.ETDuration
default:
argTp2 = types.ETString
}
bf = newBaseBuiltinFuncWithTp(ctx, args, retTp, argTp1, argTp2)
bf.tp.Decimal = tp1.Decimal
if retTp == types.ETString {
bf.tp.Tp, bf.tp.Flen, bf.tp.Decimal = mysql.TypeString, mysql.MaxDatetimeWidthWithFsp, types.UnspecifiedLength
}
return
}
func getTimeZone(ctx sessionctx.Context) *time.Location {
ret := ctx.GetSessionVars().TimeZone
if ret == nil {
ret = time.Local
}
return ret
}
// isDuration returns a boolean indicating whether the str matches the format of duration.
// See https://dev.mysql.com/doc/refman/5.7/en/time.html
func isDuration(str string) bool {
return durationPattern.MatchString(str)
}
// strDatetimeAddDuration adds duration to datetime string, returns a string value.
func strDatetimeAddDuration(sc *stmtctx.StatementContext, d string, arg1 types.Duration) (string, error) {
arg0, err := types.ParseTime(sc, d, mysql.TypeDatetime, types.MaxFsp)
if err != nil {
return "", errors.Trace(err)
}
ret, err := arg0.Add(arg1)
if err != nil {
return "", errors.Trace(err)
}
fsp := types.MaxFsp
if ret.Time.Microsecond() == 0 {
fsp = types.MinFsp
}
ret.Fsp = fsp
return ret.String(), nil
}
// strDurationAddDuration adds duration to duration string, returns a string value.
func strDurationAddDuration(sc *stmtctx.StatementContext, d string, arg1 types.Duration) (string, error) {
arg0, err := types.ParseDuration(d, types.MaxFsp)
if err != nil {
return "", errors.Trace(err)
}
tmpDuration, err := arg0.Add(arg1)
if err != nil {
return "", errors.Trace(err)
}
tmpDuration.Fsp = types.MaxFsp
if tmpDuration.MicroSecond() == 0 {
tmpDuration.Fsp = types.MinFsp
}
return tmpDuration.String(), nil
}
// strDatetimeSubDuration subtracts duration from datetime string, returns a string value.
func strDatetimeSubDuration(sc *stmtctx.StatementContext, d string, arg1 types.Duration) (string, error) {
arg0, err := types.ParseTime(sc, d, mysql.TypeDatetime, types.MaxFsp)
if err != nil {
return "", errors.Trace(err)
}
arg1time, err := arg1.ConvertToTime(sc, uint8(getFsp(arg1.String())))
if err != nil {
return "", errors.Trace(err)
}
tmpDuration := arg0.Sub(sc, &arg1time)
fsp := types.MaxFsp
if tmpDuration.MicroSecond() == 0 {
fsp = types.MinFsp
}
resultDuration, err := tmpDuration.ConvertToTime(sc, mysql.TypeDatetime)
if err != nil {
return "", errors.Trace(err)
}
resultDuration.Fsp = fsp
return resultDuration.String(), nil
}
// strDurationSubDuration subtracts duration from duration string, returns a string value.
func strDurationSubDuration(sc *stmtctx.StatementContext, d string, arg1 types.Duration) (string, error) {
arg0, err := types.ParseDuration(d, types.MaxFsp)
if err != nil {
return "", errors.Trace(err)
}
tmpDuration, err := arg0.Sub(arg1)
if err != nil {
return "", errors.Trace(err)
}
tmpDuration.Fsp = types.MaxFsp
if tmpDuration.MicroSecond() == 0 {
tmpDuration.Fsp = types.MinFsp
}
return tmpDuration.String(), nil
}
type addTimeFunctionClass struct {
baseFunctionClass
}
func (c *addTimeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err = c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
tp1, tp2, bf := getBf4TimeAddSub(ctx, args)
switch tp1.Tp {
case mysql.TypeDatetime, mysql.TypeTimestamp:
switch tp2.Tp {
case mysql.TypeDuration:
sig = &builtinAddDatetimeAndDurationSig{bf}
case mysql.TypeDatetime, mysql.TypeTimestamp:
sig = &builtinAddTimeDateTimeNullSig{bf}
default:
sig = &builtinAddDatetimeAndStringSig{bf}
}
case mysql.TypeDate:
switch tp2.Tp {
case mysql.TypeDuration:
sig = &builtinAddDateAndDurationSig{bf}
case mysql.TypeDatetime, mysql.TypeTimestamp:
sig = &builtinAddTimeStringNullSig{bf}
default:
sig = &builtinAddDateAndStringSig{bf}
}
case mysql.TypeDuration:
switch tp2.Tp {
case mysql.TypeDuration:
sig = &builtinAddDurationAndDurationSig{bf}
case mysql.TypeDatetime, mysql.TypeTimestamp:
sig = &builtinAddTimeDurationNullSig{bf}
default:
sig = &builtinAddDurationAndStringSig{bf}
}
default:
switch tp2.Tp {
case mysql.TypeDuration:
sig = &builtinAddStringAndDurationSig{bf}
case mysql.TypeDatetime, mysql.TypeTimestamp:
sig = &builtinAddTimeStringNullSig{bf}
default:
sig = &builtinAddStringAndStringSig{bf}
}
}
return sig, nil
}
type builtinAddTimeDateTimeNullSig struct {
baseBuiltinFunc
}
func (b *builtinAddTimeDateTimeNullSig) Clone() builtinFunc {
newSig := &builtinAddTimeDateTimeNullSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals a builtinAddTimeDateTimeNullSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime
func (b *builtinAddTimeDateTimeNullSig) evalTime(row types.Row) (types.Time, bool, error) {
return types.ZeroDatetime, true, nil
}
type builtinAddDatetimeAndDurationSig struct {
baseBuiltinFunc
}
func (b *builtinAddDatetimeAndDurationSig) Clone() builtinFunc {
newSig := &builtinAddDatetimeAndDurationSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals a builtinAddDatetimeAndDurationSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime
func (b *builtinAddDatetimeAndDurationSig) evalTime(row types.Row) (types.Time, bool, error) {
arg0, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return types.ZeroDatetime, isNull, errors.Trace(err)
}
arg1, isNull, err := b.args[1].EvalDuration(b.ctx, row)
if isNull || err != nil {
return types.ZeroDatetime, isNull, errors.Trace(err)
}
result, err := arg0.Add(arg1)
return result, err != nil, errors.Trace(err)
}
type builtinAddDatetimeAndStringSig struct {
baseBuiltinFunc
}
func (b *builtinAddDatetimeAndStringSig) Clone() builtinFunc {
newSig := &builtinAddDatetimeAndStringSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals a builtinAddDatetimeAndStringSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime
func (b *builtinAddDatetimeAndStringSig) evalTime(row types.Row) (types.Time, bool, error) {
arg0, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return types.ZeroDatetime, isNull, errors.Trace(err)
}
s, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return types.ZeroDatetime, isNull, errors.Trace(err)
}
if !isDuration(s) {
return types.ZeroDatetime, true, nil
}
arg1, err := types.ParseDuration(s, getFsp(s))
if err != nil {
return types.ZeroDatetime, true, errors.Trace(err)
}
result, err := arg0.Add(arg1)
return result, err != nil, errors.Trace(err)
}
type builtinAddTimeDurationNullSig struct {
baseBuiltinFunc
}
func (b *builtinAddTimeDurationNullSig) Clone() builtinFunc {
newSig := &builtinAddTimeDurationNullSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinAddTimeDurationNullSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime
func (b *builtinAddTimeDurationNullSig) evalDuration(row types.Row) (types.Duration, bool, error) {
return types.ZeroDuration, true, nil
}
type builtinAddDurationAndDurationSig struct {
baseBuiltinFunc
}
func (b *builtinAddDurationAndDurationSig) Clone() builtinFunc {
newSig := &builtinAddDurationAndDurationSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinAddDurationAndDurationSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime
func (b *builtinAddDurationAndDurationSig) evalDuration(row types.Row) (types.Duration, bool, error) {
arg0, isNull, err := b.args[0].EvalDuration(b.ctx, row)
if isNull || err != nil {
return types.ZeroDuration, isNull, errors.Trace(err)
}
arg1, isNull, err := b.args[1].EvalDuration(b.ctx, row)
if isNull || err != nil {
return types.ZeroDuration, isNull, errors.Trace(err)
}
result, err := arg0.Add(arg1)
if err != nil {
return types.ZeroDuration, true, errors.Trace(err)
}
return result, false, nil
}
type builtinAddDurationAndStringSig struct {
baseBuiltinFunc
}
func (b *builtinAddDurationAndStringSig) Clone() builtinFunc {
newSig := &builtinAddDurationAndStringSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinAddDurationAndStringSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime
func (b *builtinAddDurationAndStringSig) evalDuration(row types.Row) (types.Duration, bool, error) {
arg0, isNull, err := b.args[0].EvalDuration(b.ctx, row)
if isNull || err != nil {
return types.ZeroDuration, isNull, errors.Trace(err)
}
s, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return types.ZeroDuration, isNull, errors.Trace(err)
}
if !isDuration(s) {
return types.ZeroDuration, true, nil
}
arg1, err := types.ParseDuration(s, getFsp(s))
if err != nil {
return types.ZeroDuration, true, errors.Trace(err)
}
result, err := arg0.Add(arg1)
if err != nil {
return types.ZeroDuration, true, errors.Trace(err)
}
return result, false, nil
}
type builtinAddTimeStringNullSig struct {
baseBuiltinFunc
}
func (b *builtinAddTimeStringNullSig) Clone() builtinFunc {
newSig := &builtinAddTimeStringNullSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinAddDurationAndDurationSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime
func (b *builtinAddTimeStringNullSig) evalString(row types.Row) (string, bool, error) {
return "", true, nil
}
type builtinAddStringAndDurationSig struct {
baseBuiltinFunc
}
func (b *builtinAddStringAndDurationSig) Clone() builtinFunc {
newSig := &builtinAddStringAndDurationSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinAddStringAndDurationSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime
func (b *builtinAddStringAndDurationSig) evalString(row types.Row) (result string, isNull bool, err error) {
var (
arg0 string
arg1 types.Duration
)
arg0, isNull, err = b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
arg1, isNull, err = b.args[1].EvalDuration(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
if isDuration(arg0) {
result, err = strDurationAddDuration(sc, arg0, arg1)
if err != nil {
return "", true, errors.Trace(err)
}
return result, false, nil
}
result, err = strDatetimeAddDuration(sc, arg0, arg1)
return result, err != nil, errors.Trace(err)
}
type builtinAddStringAndStringSig struct {
baseBuiltinFunc
}
func (b *builtinAddStringAndStringSig) Clone() builtinFunc {
newSig := &builtinAddStringAndStringSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinAddStringAndStringSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime
func (b *builtinAddStringAndStringSig) evalString(row types.Row) (result string, isNull bool, err error) {
var (
arg0, arg1Str string
arg1 types.Duration
)
arg0, isNull, err = b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
arg1Str, isNull, err = b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
arg1, err = types.ParseDuration(arg1Str, getFsp4TimeAddSub(arg1Str))
if err != nil {
return "", true, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
if isDuration(arg0) {
result, err = strDurationAddDuration(sc, arg0, arg1)
if err != nil {
return "", true, errors.Trace(err)
}
return result, false, nil
}
result, err = strDatetimeAddDuration(sc, arg0, arg1)
return result, err != nil, errors.Trace(err)
}
type builtinAddDateAndDurationSig struct {
baseBuiltinFunc
}
func (b *builtinAddDateAndDurationSig) Clone() builtinFunc {
newSig := &builtinAddDateAndDurationSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinAddDurationAndDurationSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime
func (b *builtinAddDateAndDurationSig) evalString(row types.Row) (string, bool, error) {
arg0, isNull, err := b.args[0].EvalDuration(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
arg1, isNull, err := b.args[1].EvalDuration(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
result, err := arg0.Add(arg1)
return result.String(), err != nil, errors.Trace(err)
}
type builtinAddDateAndStringSig struct {
baseBuiltinFunc
}
func (b *builtinAddDateAndStringSig) Clone() builtinFunc {
newSig := &builtinAddDateAndStringSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinAddDateAndStringSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_addtime
func (b *builtinAddDateAndStringSig) evalString(row types.Row) (string, bool, error) {
arg0, isNull, err := b.args[0].EvalDuration(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
s, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
if !isDuration(s) {
return "", true, nil
}
arg1, err := types.ParseDuration(s, getFsp4TimeAddSub(s))
if err != nil {
return "", true, errors.Trace(err)
}
result, err := arg0.Add(arg1)
return result.String(), err != nil, errors.Trace(err)
}
type convertTzFunctionClass struct {
baseFunctionClass
}
func (c *convertTzFunctionClass) getDecimal(ctx sessionctx.Context, arg Expression) int {
decimal := types.MaxFsp
if dt, isConstant := arg.(*Constant); isConstant {
switch arg.GetType().EvalType() {
case types.ETInt:
decimal = 0
case types.ETReal, types.ETDecimal:
decimal = arg.GetType().Decimal
case types.ETString:
str, isNull, err := dt.EvalString(ctx, nil)
if err == nil && !isNull {
decimal = types.DateFSP(str)
}
}
}
if decimal > types.MaxFsp {
return types.MaxFsp
}
if decimal < types.MinFsp {
return types.MinFsp
}
return decimal
}
func (c *convertTzFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
// tzRegex holds the regex to check whether a string is a time zone.
tzRegex, err := regexp.Compile(`(^(\+|-)(0?[0-9]|1[0-2]):[0-5]?\d$)|(^\+13:00$)`)
if err != nil {
return nil, errors.Trace(err)
}
decimal := c.getDecimal(ctx, args[0])
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, types.ETDatetime, types.ETString, types.ETString)
bf.tp.Decimal = decimal
sig := &builtinConvertTzSig{
baseBuiltinFunc: bf,
timezoneRegex: tzRegex,
}
return sig, nil
}
type builtinConvertTzSig struct {
baseBuiltinFunc
timezoneRegex *regexp.Regexp
}
func (b *builtinConvertTzSig) Clone() builtinFunc {
newSig := &builtinConvertTzSig{timezoneRegex: b.timezoneRegex}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals CONVERT_TZ(dt,from_tz,to_tz).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_convert-tz
func (b *builtinConvertTzSig) evalTime(row types.Row) (types.Time, bool, error) {
dt, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
fromTzStr, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
toTzStr, isNull, err := b.args[2].EvalString(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(err)
}
fromTzMatched := b.timezoneRegex.MatchString(fromTzStr)
toTzMatched := b.timezoneRegex.MatchString(toTzStr)
if !fromTzMatched && !toTzMatched {
fromTz, err := time.LoadLocation(fromTzStr)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
toTz, err := time.LoadLocation(toTzStr)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
t, err := dt.Time.GoTime(fromTz)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
return types.Time{
Time: types.FromGoTime(t.In(toTz)),
Type: mysql.TypeDatetime,
Fsp: b.tp.Decimal,
}, false, nil
}
if fromTzMatched && toTzMatched {
t, err := dt.Time.GoTime(time.Local)
if err != nil {
return types.Time{}, true, errors.Trace(err)
}
return types.Time{
Time: types.FromGoTime(t.Add(timeZone2Duration(toTzStr) - timeZone2Duration(fromTzStr))),
Type: mysql.TypeDatetime,
Fsp: b.tp.Decimal,
}, false, nil
}
return types.Time{}, true, nil
}
type makeDateFunctionClass struct {
baseFunctionClass
}
func (c *makeDateFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, types.ETInt, types.ETInt)
tp := bf.tp
tp.Tp, tp.Flen, tp.Decimal = mysql.TypeDate, mysql.MaxDateWidth, 0
sig := &builtinMakeDateSig{bf}
return sig, nil
}
type builtinMakeDateSig struct {
baseBuiltinFunc
}
func (b *builtinMakeDateSig) Clone() builtinFunc {
newSig := &builtinMakeDateSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evaluates a builtinMakeDateSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_makedate
func (b *builtinMakeDateSig) evalTime(row types.Row) (d types.Time, isNull bool, err error) {
args := b.getArgs()
var year, dayOfYear int64
year, isNull, err = args[0].EvalInt(b.ctx, row)
if isNull || err != nil {
return d, true, errors.Trace(err)
}
dayOfYear, isNull, err = args[1].EvalInt(b.ctx, row)
if isNull || err != nil {
return d, true, errors.Trace(err)
}
if dayOfYear <= 0 || year < 0 || year > 9999 {
return d, true, nil
}
if year < 70 {
year += 2000
} else if year < 100 {
year += 1900
}
startTime := types.Time{
Time: types.FromDate(int(year), 1, 1, 0, 0, 0, 0),
Type: mysql.TypeDate,
Fsp: 0,
}
retTimestamp := types.TimestampDiff("DAY", types.ZeroDate, startTime)
if retTimestamp == 0 {
return d, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(startTime.String())))
}
ret := types.TimeFromDays(retTimestamp + dayOfYear - 1)
if ret.IsZero() || ret.Time.Year() > 9999 {
return d, true, nil
}
return ret, false, nil
}
type makeTimeFunctionClass struct {
baseFunctionClass
}
func (c *makeTimeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
tp, flen, decimal := args[2].GetType().EvalType(), 10, 0
switch tp {
case types.ETInt:
case types.ETReal, types.ETDecimal:
decimal = args[2].GetType().Decimal
if decimal > 6 || decimal == types.UnspecifiedLength {
decimal = 6
}
if decimal > 0 {
flen += 1 + decimal
}
default:
flen, decimal = 17, 6
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration, types.ETInt, types.ETInt, types.ETReal)
bf.tp.Flen, bf.tp.Decimal = flen, decimal
sig := &builtinMakeTimeSig{bf}
return sig, nil
}
type builtinMakeTimeSig struct {
baseBuiltinFunc
}
func (b *builtinMakeTimeSig) Clone() builtinFunc {
newSig := &builtinMakeTimeSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinMakeTimeIntSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_maketime
func (b *builtinMakeTimeSig) evalDuration(row types.Row) (types.Duration, bool, error) {
dur := types.ZeroDuration
dur.Fsp = types.MaxFsp
hour, isNull, err := b.args[0].EvalInt(b.ctx, row)
if isNull || err != nil {
return dur, isNull, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
minute, isNull, err := b.args[1].EvalInt(b.ctx, row)
if isNull || err != nil {
return dur, isNull, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if minute < 0 || minute >= 60 {
return dur, true, nil
}
second, isNull, err := b.args[2].EvalReal(b.ctx, row)
if isNull || err != nil {
return dur, isNull, errors.Trace(err)
}
if second < 0 || second >= 60 {
return dur, true, nil
}
var overflow bool
// MySQL TIME datatype: https://dev.mysql.com/doc/refman/5.7/en/time.html
// ranges from '-838:59:59.000000' to '838:59:59.000000'
if hour < -838 {
hour = -838
overflow = true
} else if hour > 838 {
hour = 838
overflow = true
}
if hour == -838 || hour == 838 {
if second > 59 {
second = 59
}
}
if overflow {
minute = 59
second = 59
}
fsp := b.tp.Decimal
dur, err = types.ParseDuration(fmt.Sprintf("%02d:%02d:%v", hour, minute, second), fsp)
if err != nil {
return dur, true, errors.Trace(err)
}
return dur, false, nil
}
type periodAddFunctionClass struct {
baseFunctionClass
}
func (c *periodAddFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt, types.ETInt)
bf.tp.Flen = 6
sig := &builtinPeriodAddSig{bf}
return sig, nil
}
// period2Month converts a period to months, in which period is represented in the format of YYMM or YYYYMM.
// Note that the period argument is not a date value.
func period2Month(period uint64) uint64 {
if period == 0 {
return 0
}
year, month := period/100, period%100
if year < 70 {
year += 2000
} else if year < 100 {
year += 1900
}
return year*12 + month - 1
}
// month2Period converts a month to a period.
func month2Period(month uint64) uint64 {
if month == 0 {
return 0
}
year := month / 12
if year < 70 {
year += 2000
} else if year < 100 {
year += 1900
}
return year*100 + month%12 + 1
}
type builtinPeriodAddSig struct {
baseBuiltinFunc
}
func (b *builtinPeriodAddSig) Clone() builtinFunc {
newSig := &builtinPeriodAddSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals PERIOD_ADD(P,N).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_period-add
func (b *builtinPeriodAddSig) evalInt(row types.Row) (int64, bool, error) {
p, isNull, err := b.args[0].EvalInt(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(err)
}
if p == 0 {
return 0, false, nil
}
n, isNull, err := b.args[1].EvalInt(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(err)
}
sumMonth := int64(period2Month(uint64(p))) + n
return int64(month2Period(uint64(sumMonth))), false, nil
}
type periodDiffFunctionClass struct {
baseFunctionClass
}
func (c *periodDiffFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETInt, types.ETInt)
bf.tp.Flen = 6
sig := &builtinPeriodDiffSig{bf}
return sig, nil
}
type builtinPeriodDiffSig struct {
baseBuiltinFunc
}
func (b *builtinPeriodDiffSig) Clone() builtinFunc {
newSig := &builtinPeriodDiffSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals PERIOD_DIFF(P1,P2).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_period-diff
func (b *builtinPeriodDiffSig) evalInt(row types.Row) (int64, bool, error) {
p1, isNull, err := b.args[0].EvalInt(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(err)
}
p2, isNull, err := b.args[1].EvalInt(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(err)
}
return int64(period2Month(uint64(p1)) - period2Month(uint64(p2))), false, nil
}
type quarterFunctionClass struct {
baseFunctionClass
}
func (c *quarterFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDatetime)
bf.tp.Flen = 1
sig := &builtinQuarterSig{bf}
return sig, nil
}
type builtinQuarterSig struct {
baseBuiltinFunc
}
func (b *builtinQuarterSig) Clone() builtinFunc {
newSig := &builtinQuarterSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals QUARTER(date).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_quarter
func (b *builtinQuarterSig) evalInt(row types.Row) (int64, bool, error) {
date, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
if date.IsZero() {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(date.String())))
}
return int64((date.Time.Month() + 2) / 3), false, nil
}
type secToTimeFunctionClass struct {
baseFunctionClass
}
func (c *secToTimeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
var retFlen, retFsp int
argType := args[0].GetType()
argEvalTp := argType.EvalType()
if argEvalTp == types.ETString {
retFsp = types.UnspecifiedLength
} else {
retFsp = argType.Decimal
}
if retFsp > types.MaxFsp || retFsp == types.UnspecifiedLength {
retFsp = types.MaxFsp
} else if retFsp < types.MinFsp {
retFsp = types.MinFsp
}
retFlen = 10
if retFsp > 0 {
retFlen += 1 + retFsp
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration, types.ETReal)
bf.tp.Flen, bf.tp.Decimal = retFlen, retFsp
sig := &builtinSecToTimeSig{bf}
return sig, nil
}
type builtinSecToTimeSig struct {
baseBuiltinFunc
}
func (b *builtinSecToTimeSig) Clone() builtinFunc {
newSig := &builtinSecToTimeSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals SEC_TO_TIME(seconds).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_sec-to-time
func (b *builtinSecToTimeSig) evalDuration(row types.Row) (types.Duration, bool, error) {
secondsFloat, isNull, err := b.args[0].EvalReal(b.ctx, row)
if isNull || err != nil {
return types.Duration{}, isNull, errors.Trace(err)
}
var (
hour int64
minute int64
second int64
demical float64
secondDemical float64
negative string
)
if secondsFloat < 0 {
negative = "-"
secondsFloat = math.Abs(secondsFloat)
}
seconds := int64(secondsFloat)
demical = secondsFloat - float64(seconds)
hour = seconds / 3600
if hour > 838 {
hour = 838
minute = 59
second = 59
} else {
minute = seconds % 3600 / 60
second = seconds % 60
}
secondDemical = float64(second) + demical
var dur types.Duration
dur, err = types.ParseDuration(fmt.Sprintf("%s%02d:%02d:%v", negative, hour, minute, secondDemical), b.tp.Decimal)
if err != nil {
return types.Duration{}, err != nil, errors.Trace(err)
}
return dur, false, nil
}
type subTimeFunctionClass struct {
baseFunctionClass
}
func (c *subTimeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (sig builtinFunc, err error) {
if err = c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
tp1, tp2, bf := getBf4TimeAddSub(ctx, args)
switch tp1.Tp {
case mysql.TypeDatetime, mysql.TypeTimestamp:
switch tp2.Tp {
case mysql.TypeDuration:
sig = &builtinSubDatetimeAndDurationSig{bf}
case mysql.TypeDatetime, mysql.TypeTimestamp:
sig = &builtinSubTimeDateTimeNullSig{bf}
default:
sig = &builtinSubDatetimeAndStringSig{bf}
}
case mysql.TypeDate:
switch tp2.Tp {
case mysql.TypeDuration:
sig = &builtinSubDateAndDurationSig{bf}
case mysql.TypeDatetime, mysql.TypeTimestamp:
sig = &builtinSubTimeStringNullSig{bf}
default:
sig = &builtinSubDateAndStringSig{bf}
}
case mysql.TypeDuration:
switch tp2.Tp {
case mysql.TypeDuration:
sig = &builtinSubDurationAndDurationSig{bf}
case mysql.TypeDatetime, mysql.TypeTimestamp:
sig = &builtinSubTimeDurationNullSig{bf}
default:
sig = &builtinSubDurationAndStringSig{bf}
}
default:
switch tp2.Tp {
case mysql.TypeDuration:
sig = &builtinSubStringAndDurationSig{bf}
case mysql.TypeDatetime, mysql.TypeTimestamp:
sig = &builtinSubTimeStringNullSig{bf}
default:
sig = &builtinSubStringAndStringSig{bf}
}
}
return sig, nil
}
type builtinSubDatetimeAndDurationSig struct {
baseBuiltinFunc
}
func (b *builtinSubDatetimeAndDurationSig) Clone() builtinFunc {
newSig := &builtinSubDatetimeAndDurationSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals a builtinSubDatetimeAndDurationSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime
func (b *builtinSubDatetimeAndDurationSig) evalTime(row types.Row) (types.Time, bool, error) {
arg0, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return types.ZeroDatetime, isNull, errors.Trace(err)
}
arg1, isNull, err := b.args[1].EvalDuration(b.ctx, row)
if isNull || err != nil {
return types.ZeroDatetime, isNull, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
arg1time, err := arg1.ConvertToTime(sc, mysql.TypeDatetime)
if err != nil {
return arg1time, true, errors.Trace(err)
}
tmpDuration := arg0.Sub(sc, &arg1time)
result, err := tmpDuration.ConvertToTime(sc, arg0.Type)
return result, err != nil, errors.Trace(err)
}
type builtinSubDatetimeAndStringSig struct {
baseBuiltinFunc
}
func (b *builtinSubDatetimeAndStringSig) Clone() builtinFunc {
newSig := &builtinSubDatetimeAndStringSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals a builtinSubDatetimeAndStringSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime
func (b *builtinSubDatetimeAndStringSig) evalTime(row types.Row) (types.Time, bool, error) {
arg0, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return types.ZeroDatetime, isNull, errors.Trace(err)
}
s, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return types.ZeroDatetime, isNull, errors.Trace(err)
}
if err != nil {
return types.ZeroDatetime, true, errors.Trace(err)
}
if !isDuration(s) {
return types.ZeroDatetime, true, nil
}
arg1, err := types.ParseDuration(s, getFsp(s))
if err != nil {
return types.ZeroDatetime, true, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
arg1time, err := arg1.ConvertToTime(sc, mysql.TypeDatetime)
if err != nil {
return types.ZeroDatetime, true, errors.Trace(err)
}
tmpDuration := arg0.Sub(sc, &arg1time)
result, err := tmpDuration.ConvertToTime(sc, mysql.TypeDatetime)
return result, err != nil, errors.Trace(err)
}
type builtinSubTimeDateTimeNullSig struct {
baseBuiltinFunc
}
func (b *builtinSubTimeDateTimeNullSig) Clone() builtinFunc {
newSig := &builtinSubTimeDateTimeNullSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals a builtinSubTimeDateTimeNullSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime
func (b *builtinSubTimeDateTimeNullSig) evalTime(row types.Row) (types.Time, bool, error) {
return types.ZeroDatetime, true, nil
}
type builtinSubStringAndDurationSig struct {
baseBuiltinFunc
}
func (b *builtinSubStringAndDurationSig) Clone() builtinFunc {
newSig := &builtinSubStringAndDurationSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinSubStringAndDurationSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime
func (b *builtinSubStringAndDurationSig) evalString(row types.Row) (result string, isNull bool, err error) {
var (
arg0 string
arg1 types.Duration
)
arg0, isNull, err = b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
arg1, isNull, err = b.args[1].EvalDuration(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
if isDuration(arg0) {
result, err = strDurationSubDuration(sc, arg0, arg1)
if err != nil {
return "", true, errors.Trace(err)
}
return result, false, nil
}
result, err = strDatetimeSubDuration(sc, arg0, arg1)
return result, err != nil, errors.Trace(err)
}
type builtinSubStringAndStringSig struct {
baseBuiltinFunc
}
func (b *builtinSubStringAndStringSig) Clone() builtinFunc {
newSig := &builtinSubStringAndStringSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinAddStringAndStringSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime
func (b *builtinSubStringAndStringSig) evalString(row types.Row) (result string, isNull bool, err error) {
var (
s, arg0 string
arg1 types.Duration
)
arg0, isNull, err = b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
s, isNull, err = b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
arg1, err = types.ParseDuration(s, getFsp4TimeAddSub(s))
if err != nil {
return "", true, errors.Trace(err)
}
sc := b.ctx.GetSessionVars().StmtCtx
if isDuration(arg0) {
result, err = strDurationSubDuration(sc, arg0, arg1)
if err != nil {
return "", true, errors.Trace(err)
}
return result, false, nil
}
result, err = strDatetimeSubDuration(sc, arg0, arg1)
return result, err != nil, errors.Trace(err)
}
type builtinSubTimeStringNullSig struct {
baseBuiltinFunc
}
func (b *builtinSubTimeStringNullSig) Clone() builtinFunc {
newSig := &builtinSubTimeStringNullSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinSubTimeStringNullSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime
func (b *builtinSubTimeStringNullSig) evalString(row types.Row) (string, bool, error) {
return "", true, nil
}
type builtinSubDurationAndDurationSig struct {
baseBuiltinFunc
}
func (b *builtinSubDurationAndDurationSig) Clone() builtinFunc {
newSig := &builtinSubDurationAndDurationSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinAddDurationAndDurationSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime
func (b *builtinSubDurationAndDurationSig) evalDuration(row types.Row) (types.Duration, bool, error) {
arg0, isNull, err := b.args[0].EvalDuration(b.ctx, row)
if isNull || err != nil {
return types.ZeroDuration, isNull, errors.Trace(err)
}
arg1, isNull, err := b.args[1].EvalDuration(b.ctx, row)
if isNull || err != nil {
return types.ZeroDuration, isNull, errors.Trace(err)
}
result, err := arg0.Sub(arg1)
if err != nil {
return types.ZeroDuration, true, errors.Trace(err)
}
return result, false, nil
}
type builtinSubDurationAndStringSig struct {
baseBuiltinFunc
}
func (b *builtinSubDurationAndStringSig) Clone() builtinFunc {
newSig := &builtinSubDurationAndStringSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinAddDurationAndStringSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime
func (b *builtinSubDurationAndStringSig) evalDuration(row types.Row) (types.Duration, bool, error) {
arg0, isNull, err := b.args[0].EvalDuration(b.ctx, row)
if isNull || err != nil {
return types.ZeroDuration, isNull, errors.Trace(err)
}
s, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return types.ZeroDuration, isNull, errors.Trace(err)
}
if !isDuration(s) {
return types.ZeroDuration, true, nil
}
arg1, err := types.ParseDuration(s, getFsp(s))
if err != nil {
return types.ZeroDuration, true, errors.Trace(err)
}
result, err := arg0.Sub(arg1)
return result, err != nil, errors.Trace(err)
}
type builtinSubTimeDurationNullSig struct {
baseBuiltinFunc
}
func (b *builtinSubTimeDurationNullSig) Clone() builtinFunc {
newSig := &builtinSubTimeDurationNullSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals a builtinSubTimeDurationNullSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime
func (b *builtinSubTimeDurationNullSig) evalDuration(row types.Row) (types.Duration, bool, error) {
return types.ZeroDuration, true, nil
}
type builtinSubDateAndDurationSig struct {
baseBuiltinFunc
}
func (b *builtinSubDateAndDurationSig) Clone() builtinFunc {
newSig := &builtinSubDateAndDurationSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinAddDateAndDurationSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime
func (b *builtinSubDateAndDurationSig) evalString(row types.Row) (string, bool, error) {
arg0, isNull, err := b.args[0].EvalDuration(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
arg1, isNull, err := b.args[1].EvalDuration(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
result, err := arg0.Sub(arg1)
return result.String(), err != nil, errors.Trace(err)
}
type builtinSubDateAndStringSig struct {
baseBuiltinFunc
}
func (b *builtinSubDateAndStringSig) Clone() builtinFunc {
newSig := &builtinSubDateAndStringSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinAddDateAndStringSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_subtime
func (b *builtinSubDateAndStringSig) evalString(row types.Row) (string, bool, error) {
arg0, isNull, err := b.args[0].EvalDuration(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
s, isNull, err := b.args[1].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
if !isDuration(s) {
return "", true, nil
}
arg1, err := types.ParseDuration(s, getFsp4TimeAddSub(s))
if err != nil {
return "", true, errors.Trace(err)
}
result, err := arg0.Sub(arg1)
if err != nil {
return "", true, errors.Trace(err)
}
return result.String(), false, nil
}
type timeFormatFunctionClass struct {
baseFunctionClass
}
func (c *timeFormatFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETDuration, types.ETString)
// worst case: formatMask=%r%r%r...%r, each %r takes 11 characters
bf.tp.Flen = (args[1].GetType().Flen + 1) / 2 * 11
sig := &builtinTimeFormatSig{bf}
return sig, nil
}
type builtinTimeFormatSig struct {
baseBuiltinFunc
}
func (b *builtinTimeFormatSig) Clone() builtinFunc {
newSig := &builtinTimeFormatSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinTimeFormatSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_time-format
func (b *builtinTimeFormatSig) evalString(row types.Row) (string, bool, error) {
dur, isNull, err := b.args[0].EvalDuration(b.ctx, row)
// if err != nil, then dur is ZeroDuration, outputs 00:00:00 in this case which follows the behavior of mysql.
if err != nil {
log.Warnf("Expression.EvalDuration() in time_format() failed, due to %s", err.Error())
}
if isNull {
return "", isNull, errors.Trace(err)
}
formatMask, isNull, err := b.args[1].EvalString(b.ctx, row)
if err != nil || isNull {
return "", isNull, errors.Trace(err)
}
res, err := b.formatTime(b.ctx, dur, formatMask)
return res, isNull, errors.Trace(err)
}
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_time-format
func (b *builtinTimeFormatSig) formatTime(ctx sessionctx.Context, t types.Duration, formatMask string) (res string, err error) {
t2 := types.Time{
Time: types.FromDate(0, 0, 0, t.Hour(), t.Minute(), t.Second(), t.MicroSecond()),
Type: mysql.TypeDate, Fsp: 0}
str, err := t2.DateFormat(formatMask)
return str, errors.Trace(err)
}
type timeToSecFunctionClass struct {
baseFunctionClass
}
func (c *timeToSecFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDuration)
bf.tp.Flen = 10
sig := &builtinTimeToSecSig{bf}
return sig, nil
}
type builtinTimeToSecSig struct {
baseBuiltinFunc
}
func (b *builtinTimeToSecSig) Clone() builtinFunc {
newSig := &builtinTimeToSecSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals TIME_TO_SEC(time).
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_time-to-sec
func (b *builtinTimeToSecSig) evalInt(row types.Row) (int64, bool, error) {
duration, isNull, err := b.args[0].EvalDuration(b.ctx, row)
if isNull || err != nil {
return 0, isNull, errors.Trace(err)
}
var sign int
if duration.Duration >= 0 {
sign = 1
} else {
sign = -1
}
return int64(sign * (duration.Hour()*3600 + duration.Minute()*60 + duration.Second())), false, nil
}
type timestampAddFunctionClass struct {
baseFunctionClass
}
func (c *timestampAddFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETString, types.ETString, types.ETInt, types.ETDatetime)
bf.tp = &types.FieldType{Tp: mysql.TypeString, Flen: mysql.MaxDatetimeWidthNoFsp, Decimal: types.UnspecifiedLength}
sig := &builtinTimestampAddSig{bf}
return sig, nil
}
type builtinTimestampAddSig struct {
baseBuiltinFunc
}
func (b *builtinTimestampAddSig) Clone() builtinFunc {
newSig := &builtinTimestampAddSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalString evals a builtinTimestampAddSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_timestampadd
func (b *builtinTimestampAddSig) evalString(row types.Row) (string, bool, error) {
unit, isNull, err := b.args[0].EvalString(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
v, isNull, err := b.args[1].EvalInt(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
arg, isNull, err := b.args[2].EvalTime(b.ctx, row)
if isNull || err != nil {
return "", isNull, errors.Trace(err)
}
tm1, err := arg.Time.GoTime(time.Local)
if err != nil {
return "", isNull, errors.Trace(err)
}
var tb time.Time
fsp := types.DefaultFsp
switch unit {
case "MICROSECOND":
tb = tm1.Add(time.Duration(v) * time.Microsecond)
fsp = types.MaxFsp
case "SECOND":
tb = tm1.Add(time.Duration(v) * time.Second)
case "MINUTE":
tb = tm1.Add(time.Duration(v) * time.Minute)
case "HOUR":
tb = tm1.Add(time.Duration(v) * time.Hour)
case "DAY":
tb = tm1.AddDate(0, 0, int(v))
case "WEEK":
tb = tm1.AddDate(0, 0, 7*int(v))
case "MONTH":
tb = tm1.AddDate(0, int(v), 0)
case "QUARTER":
tb = tm1.AddDate(0, 3*int(v), 0)
case "YEAR":
tb = tm1.AddDate(int(v), 0, 0)
default:
return "", true, errors.Trace(types.ErrInvalidTimeFormat.GenByArgs(unit))
}
r := types.Time{Time: types.FromGoTime(tb), Type: mysql.TypeDatetime, Fsp: fsp}
if err = r.Check(); err != nil {
return "", true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
return r.String(), false, nil
}
type toDaysFunctionClass struct {
baseFunctionClass
}
func (c *toDaysFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDatetime)
sig := &builtinToDaysSig{bf}
return sig, nil
}
type builtinToDaysSig struct {
baseBuiltinFunc
}
func (b *builtinToDaysSig) Clone() builtinFunc {
newSig := &builtinToDaysSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals a builtinToDaysSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_to-days
func (b *builtinToDaysSig) evalInt(row types.Row) (int64, bool, error) {
arg, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
ret := types.TimestampDiff("DAY", types.ZeroDate, arg)
if ret == 0 {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(arg.String())))
}
return ret, false, nil
}
type toSecondsFunctionClass struct {
baseFunctionClass
}
func (c *toSecondsFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETInt, types.ETDatetime)
sig := &builtinToSecondsSig{bf}
return sig, nil
}
type builtinToSecondsSig struct {
baseBuiltinFunc
}
func (b *builtinToSecondsSig) Clone() builtinFunc {
newSig := &builtinToSecondsSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalInt evals a builtinToSecondsSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_to-seconds
func (b *builtinToSecondsSig) evalInt(row types.Row) (int64, bool, error) {
arg, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
ret := types.TimestampDiff("SECOND", types.ZeroDate, arg)
if ret == 0 {
return 0, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(arg.String())))
}
return ret, false, nil
}
type utcTimeFunctionClass struct {
baseFunctionClass
}
func (c *utcTimeFunctionClass) getFlenAndDecimal4UTCTime(ctx sessionctx.Context, args []Expression) (flen, decimal int) {
if len(args) == 0 {
flen, decimal = 8, 0
return
}
if constant, ok := args[0].(*Constant); ok {
fsp, isNull, err := constant.EvalInt(ctx, nil)
if isNull || err != nil || fsp > int64(types.MaxFsp) {
decimal = types.MaxFsp
} else if fsp < int64(types.MinFsp) {
decimal = types.MinFsp
} else {
decimal = int(fsp)
}
}
if decimal > 0 {
flen = 8 + 1 + decimal
} else {
flen = 8
}
return flen, decimal
}
func (c *utcTimeFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
argTps := make([]types.EvalType, 0, 1)
if len(args) == 1 {
argTps = append(argTps, types.ETInt)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDuration, argTps...)
bf.tp.Flen, bf.tp.Decimal = c.getFlenAndDecimal4UTCTime(bf.ctx, args)
var sig builtinFunc
if len(args) == 1 {
sig = &builtinUTCTimeWithArgSig{bf}
} else {
sig = &builtinUTCTimeWithoutArgSig{bf}
}
return sig, nil
}
type builtinUTCTimeWithoutArgSig struct {
baseBuiltinFunc
}
func (b *builtinUTCTimeWithoutArgSig) Clone() builtinFunc {
newSig := &builtinUTCTimeWithoutArgSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinUTCTimeWithoutArgSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-time
func (b *builtinUTCTimeWithoutArgSig) evalDuration(row types.Row) (types.Duration, bool, error) {
v, err := types.ParseDuration(time.Now().UTC().Format(types.TimeFormat), 0)
return v, false, err
}
type builtinUTCTimeWithArgSig struct {
baseBuiltinFunc
}
func (b *builtinUTCTimeWithArgSig) Clone() builtinFunc {
newSig := &builtinUTCTimeWithArgSig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalDuration evals a builtinUTCTimeWithArgSig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_utc-time
func (b *builtinUTCTimeWithArgSig) evalDuration(row types.Row) (types.Duration, bool, error) {
fsp, isNull, err := b.args[0].EvalInt(b.ctx, row)
if isNull || err != nil {
return types.Duration{}, isNull, errors.Trace(err)
}
if fsp > int64(types.MaxFsp) {
return types.Duration{}, true, errors.Errorf("Too-big precision %v specified for 'utc_time'. Maximum is %v.", fsp, types.MaxFsp)
}
if fsp < int64(types.MinFsp) {
return types.Duration{}, true, errors.Errorf("Invalid negative %d specified, must in [0, 6].", fsp)
}
v, err := types.ParseDuration(time.Now().UTC().Format(types.TimeFSPFormat), int(fsp))
return v, false, err
}
type lastDayFunctionClass struct {
baseFunctionClass
}
func (c *lastDayFunctionClass) getFunction(ctx sessionctx.Context, args []Expression) (builtinFunc, error) {
if err := c.verifyArgs(args); err != nil {
return nil, errors.Trace(err)
}
bf := newBaseBuiltinFuncWithTp(ctx, args, types.ETDatetime, types.ETDatetime)
bf.tp.Tp, bf.tp.Flen, bf.tp.Decimal = mysql.TypeDate, mysql.MaxDateWidth, types.DefaultFsp
sig := &builtinLastDaySig{bf}
return sig, nil
}
type builtinLastDaySig struct {
baseBuiltinFunc
}
func (b *builtinLastDaySig) Clone() builtinFunc {
newSig := &builtinLastDaySig{}
newSig.cloneFrom(&b.baseBuiltinFunc)
return newSig
}
// evalTime evals a builtinLastDaySig.
// See https://dev.mysql.com/doc/refman/5.7/en/date-and-time-functions.html#function_last-day
func (b *builtinLastDaySig) evalTime(row types.Row) (types.Time, bool, error) {
arg, isNull, err := b.args[0].EvalTime(b.ctx, row)
if isNull || err != nil {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(b.ctx, err))
}
tm := arg.Time
year, month, day := tm.Year(), tm.Month(), 30
if year == 0 && month == 0 && tm.Day() == 0 {
return types.Time{}, true, errors.Trace(handleInvalidTimeError(b.ctx, types.ErrIncorrectDatetimeValue.GenByArgs(arg.String())))
}
if month == 1 || month == 3 || month == 5 ||
month == 7 || month == 8 || month == 10 || month == 12 {
day = 31
} else if month == 2 {
day = 28
if tm.IsLeapYear() {
day = 29
}
}
ret := types.Time{
Time: types.FromDate(year, month, day, 0, 0, 0, 0),
Type: mysql.TypeDate,
Fsp: types.DefaultFsp,
}
return ret, false, nil
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/pingcap/tidb.git
git@gitee.com:pingcap/tidb.git
pingcap
tidb
tidb
v2.0.0

搜索帮助

0d507c66 1850385 C8b1a773 1850385