{"id":950,"date":"2017-06-27T00:00:00","date_gmt":"2017-06-27T00:00:00","guid":{"rendered":"https:\/\/en.pingcap.com\/blog\/refactor-builtin\/"},"modified":"2024-03-18T06:53:22","modified_gmt":"2024-03-18T13:53:22","slug":"refactor-builtin","status":"publish","type":"post","link":"https:\/\/www.pingcap.com\/ko\/blog\/refactor-builtin\/","title":{"rendered":"Refactoring the Built-in Functions in TiDB"},"content":{"rendered":"<p>In order to accelerate expression evaluation, we recently refactored its framework. This tutorial will show you how to use the new computational framework to rewrite or add a built-in function in TiDB.<\/p>\n<h2>Table of Content<\/h2>\n<ul>\n<li><a href=\"#the-overall-process\">The overall process<\/a><\/li>\n<li><a href=\"#example\">Example<\/a>\n<ul>\n<li><a href=\"#take-a-look-at-expressionbuiltin_stringgo\">Take a look at <code>builtin_string.go<\/code><\/a><\/li>\n<li><a href=\"#refine-the-existing-testlength-method\">Refine the existing <code>TestLength()<\/code> method<\/a><\/li>\n<li><a href=\"#test-the-implementation-of-length-at-the-sql-level\">Test the implementation of LENGTH at the SQL level<\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#before-refactoring\">Before refactoring&#8230;<\/a><\/li>\n<li><a href=\"#after-refactoring\">After refactoring&#8230;<\/a><\/li>\n<li><a href=\"#appendix\">Appendix<\/a><\/li>\n<\/ul>\n<h3>The overall process<\/h3>\n<ol>\n<li>Select any function to your interest from the expression directory, assuming the function is named XX.<\/li>\n<li>Override the <code>XXFunctionClass.getFunction()<\/code> method:\n<p>This method refers to MySQL rules, inferring the return value type according to the parameter of the built-in function.<\/p>\n<p>Different function signatures will be generated based on the number &amp; type of the parameters, and the return value type of the function.<\/p>\n<p>See detailed description of the function signature in the appendix at the end of this article.<\/li>\n<li>Implement the <code>evalYY()<\/code> method on all the function signatures corresponding to the built-in function. YY represents the return value type of the function signature.<\/li>\n<li>Add tests\n<p>In the expression directory, refine tests about the implementation of the given function in the <code>TestXX()<\/code> method.<\/p>\n<p>In the executor directory, add tests at the SQL level.<\/li>\n<li>Run <code>make dev<\/code> and ensure that all the test cases pass.<\/li>\n<\/ol>\n<h3>Example:<\/h3>\n<p>Let&#8217;s look at the <a href=\"https:\/\/github.com\/pingcap\/tidb\/pull\/3519\">PR<\/a> of overriding the <code>LENGTH ()<\/code> function for detailed explanation:<\/p>\n<h4>Take a look at <code>expression\/builtin_string.go<\/code>:<\/h4>\n<p>First, let&#8217;s take a look at the <code>expression\/builtin_string.go<\/code> file:<\/p>\n<ol>\n<li>Implement the <code>lengthFunctionClass.getFunction()<\/code> method. This method mainly accomplishes two tasks:\n<ol>\n<li>Infer the return value type of the <code>LEGNTH<\/code> function according to MySQL rules.<\/li>\n<li>Generate function signature based on the number &amp; type of parameters, and return value type of the <code>LENGTH<\/code> function. Because the <code>LENGTH<\/code> function only has one number &amp; type of parameters, and return value type, we don&#8217;t need to define a type for the new function signature. Instead, we modified the existing <code>builtinLengthSig<\/code>, so that it could be <strong>composite with <code>baseIntBuiltinFunc<\/code>, which means that the return value type in the given function signature is int.<\/strong><\/li>\n<\/ol>\n<pre><code class=\"language-go\">type builtinLengthSig struct {\n    baseIntBuiltinFunc\n}\nfunc (c *lengthFunctionClass) getFunction(args []Expression, ctx context.Context) (builtinFunc, error) {\n\n\/\/Infer the return value type of `LEGNTH` function according to MySQL rules\ntp := types.NewFieldType(mysql.TypeLonglong)\ntp.Flen = 10\ntypes.SetBinChsClnFlag(tp)\n\n\/\/Generate function signature based on the number &amp; type of parameters, and return value type. Note that after refactoring, instead of the `newBaseBuiltinFunc` method, the `newBaseBuiltinFuncWithTp` method is used here.\n\/\/In the `newBaseBuiltinFuncWithTp` function declaration, `args` represents the function's parameters, `tp` represents the return value type of the function, and `argsTp` represents the correct types of all parameters in the function signature.\n\/\/ The number of parameters for `LENGTH` is 1, the parameter type is string, and the return value type is int. Therefore, `tp` here stands for the return value type of the function and `tpString` is used to identify the correct type of parameter. For a function with multiple parameters, when calling `newBaseBuiltinFuncWithTp`, we need to input the correct types of all parameters.\nbf, err := newBaseBuiltinFuncWithTp(args, tp, ctx, tpString)\n    if err != nil {\n            return nil, errors.Trace(err)\n    }\n    sig := &amp;builtinLengthSig{baseIntBuiltinFunc{bf}}\n    return sig.setSelf(sig), errors.Trace(c.verifyArgs(args))\n}\n<\/code><\/pre>\n<\/li>\n<li>Implement the <code>builtinLengthSig.evalInt()<\/code> method:\n<pre><code class=\"language-go\">func (b *builtinLengthSig) evalInt(row []types.Datum) (int64, bool, error) {\n\/\/ For the `builtinLengthSig` function signature, the parameter type is decided as string, so we can directly call the `b.args[0].EvalString()` method to calculate the parameter:\n    val, isNull, err := b.args[0].EvalString(row, b.ctx.GetSessionVars().StmtCtx)\n    if isNull || err != nil {\n            return 0, isNull, errors.Trace(err)\n    }\n    return int64(len([]byte(val))), false, nil\n}\n<\/code><\/pre>\n<\/li>\n<\/ol>\n<div class=\"trackable-btns\"><a href=\"\/download\"><button>Download TiDB<\/button><\/a><br \/>\n<a href=\"https:\/\/share.hsforms.com\/1e2W03wLJQQKPd1d9rCbj_Q2npzm\"><button>Subscribe to Blog<\/button><\/a><\/div>\n<h4>Refine the existing <code>TestLength()<\/code> method:<\/h4>\n<p>Moving on to <code>expression\/builtin_string_test.go<\/code>, let&#8217;s refine the existing <code>TestLength()<\/code> method:<\/p>\n<pre><code class=\"language-go\">func (s *testEvaluatorSuite) TestLength(c *C) {\n    defer testleak.AfterTest(c)() \/\/ This line is used to monitor goroutine leak.\n    \/\/ You can use the following cases to test the `LENGTH` function\n    \/\/ Note: in addition to normal cases, it is best to add some abnormal cases, such as the input args is nil, or the function has different types of parameters.\n    cases := []struct {\n           args     interface{}\n           expected int64\n           isNil    bool\n           getErr   bool\n    }{\n           {\"abc\", 3, false, false},\n           {\"\u4f60\u597d\", 6, false, false},\n           {1, 1, false, false},\n           ...\n    }\n    for _, t := range cases {\n           f, err := newFunctionForTest(s.ctx, ast.Length, primitiveValsToConstants([]interface{}{t.args})...)\n           c.Assert(err, IsNil)\n           \/\/ The following lines test the return value type of the `LENGTH` function:\n           tp := f.GetType()\n           c.Assert(tp.Tp, Equals, mysql.TypeLonglong)\n           c.Assert(tp.Charset, Equals, charset.CharsetBin)\n           c.Assert(tp.Collate, Equals, charset.CollationBin)\n           c.Assert(tp.Flag, Equals, uint(mysql.BinaryFlag))\n           c.Assert(tp.Flen, Equals, 10)\n           \/\/ The following lines test the evaluation result of LENGTH function:\n           d, err := f.Eval(nil)\n           if t.getErr {\n                  c.Assert(err, NotNil)\n           } else {\n                  c.Assert(err, IsNil)\n                  if t.isNil {\n                         c.Assert(d.Kind(), Equals, types.KindNull)\n                  } else {\n                         c.Assert(d.GetInt64(), Equals, t.expected)\n                  }\n           }\n    }\n    \/\/ The following lines test whether the function has determinacy:\n    f, err := funcs[ast.Length].getFunction([]Expression{Zero}, s.ctx)\n    c.Assert(err, IsNil)\n    c.Assert(f.isDeterministic(), IsTrue)\n}\n<\/code><\/pre>\n<h4>Test the implementation of <code>LENGTH<\/code> at the SQL level<\/h4>\n<p>Finally let&#8217;s look at <code>executor\/executor_test.go<\/code> and test the implementation of <code>LENGTH<\/code> at the SQL level:<\/p>\n<pre><code class=\"language-go\">\/\/ Tests for string built-in functions can be added in the following method:\nfunc (s *testSuite) TestStringBuiltin(c *C) {\n    defer func() {\n           s.cleanEnv(c)\n           testleak.AfterTest(c)()\n    }()\n    tk := testkit.NewTestKit(c, s.store)\n    tk.MustExec(\"use test\")\n    \/\/ for length\n    \/\/ It's best that these tests can also cover different scenarios:\n    tk.MustExec(\"drop table if exists t\")\n    tk.MustExec(\"create table t(a int, b double, c datetime, d time, e char(20), f bit(10))\")\n    tk.MustExec(`insert into t values(1, 1.1, \"2017-01-01 12:01:01\", \"12:01:01\", \"abcdef\", 0b10101)`)\n    result := tk.MustQuery(\"select length(a), length(b), length(c), length(d), length(e), length(f), length(null) from t\")\n    result.Check(testkit.Rows(\"1 3 19 8 6 2 &lt;nil&gt;\"))\n}\n<\/code><\/pre>\n<h3>Before refactoring&#8230;<\/h3>\n<p>TiDB abstracts the expression through the Expression interface (defined in the expression\/expression.go file) and defines the <code>eval<\/code> method to evaluate the expression:<\/p>\n<pre><code class=\"language-go\">type Expression interface{\n    ...\n    eval(row []types.Datum) (types.Datum, error)\n    ...\n}\n<\/code><\/pre>\n<p>Expressions that implement the Expression interface include:<\/p>\n<ul>\n<li>Scalar Function<\/li>\n<li>Column<\/li>\n<li>Constant<\/li>\n<\/ul>\n<p>The case below shows the framework of expression evaluation before refactoring:<\/p>\n<pre><code class=\"language-sql\">create table t (\n    c1 int,\n    c2 varchar(20),\n    c3 double\n)\nselect * from t where c1 + CONCAT( c2, c3 &lt; \"1.1\" )\n<\/code><\/pre>\n<p>About the <code>where<\/code> condition in the <code>select<\/code> statement shown above:<\/p>\n<p>In the <strong>compiling phase<\/strong>. TiDB will build an expression tree as shown in the graph below:<\/p>\n<p>In the <strong>executing phase<\/strong>, the <code>eval<\/code> method of the root node is called, and the expression is evaluated by the following traversal expression tree.<\/p>\n<p>The evaluate the <code>&lt;<\/code> expression, take the types of the two parameters into account, and convert the values of the two parameters into required data types according to certain rules. In the expression tree above, the parameter types are double and varchar. According to the evaluation rules of MySQL, these two parameters need to be compared using the float type. Therefore, &#8220;1.1&#8221; should be converted to double type, and then be evaluated.<\/p>\n<p>Similarly, for the <code>CONCAT<\/code> expression in the expression tree above, the parameters should be converted to string type before evaluation. For the expression &#8216;+&#8217;, the parameters should be converted to double before evaluation.<\/p>\n<p>Therefore, before refactoring, the framework of expression evaluation needs to <strong>determine the data type of the parameter on each branch repeatedly<\/strong> for every group of data involved. If the parameter type does not meet the evaluation rules of the expression, you need to convert it to the corresponding data type.<\/p>\n<p>Moreover, from the definition of the <code>Expression.eval ()<\/code> method, we can see that when evaluating, we must <strong>continually wrap and unwrap intermediate results through the Datum structure<\/strong>, which also increases time and capacity cost.<\/p>\n<p>In order to solve these two problems, we refactored the expression evaluation framework.<\/p>\n<h3>After refactoring&#8230;<\/h3>\n<p>The refactored framework has two advantages:<\/p>\n<ol>\n<li>In the compiling phase, we use the existing information on expression types to generate the expression with parameter types that match the evaluation rules. This way, no extra branch judgment about the parameter types are needed in the executing phase.<\/li>\n<li>Only the original data types are involved in the evaluation, thus avoiding the time and capacity cost by Datum.<\/li>\n<\/ol>\n<p>Let&#8217;s go back to the previous example, in the <strong>compiling phase<\/strong>, the generated expression tree is shown in the following graph. For expressions that do not match the function parameters types, we add the <code>cast<\/code> function for type conversion:<\/p>\n<img loading=\"lazy\" decoding=\"async\" width=\"789\" height=\"721\" class=\"wp-image-952\" src=\"https:\/\/en.pingcap.com\/wp-content\/uploads\/2017\/06\/after_reconstruction.png\" alt=\"Add the cast function for type conversion\" srcset=\"https:\/\/static.pingcap.com\/files\/2017\/06\/after_reconstruction.png 789w, https:\/\/static.pingcap.com\/files\/2017\/06\/after_reconstruction-300x274.png 300w, https:\/\/static.pingcap.com\/files\/2017\/06\/after_reconstruction-768x702.png 768w\" sizes=\"auto, (max-width: 789px) 100vw, 789px\" \/>\n<p>In this way, in the <strong>executing phase<\/strong>, for every <code>ScalarFunction<\/code>, it is guaranteed that all of its parameter types match the data types in the given expression evaluation, and we don&#8217;t need to check and convert parameter types repeatedly.<\/p>\n<h3>Appendix<\/h3>\n<ul>\n<li>For a built-in function, multiple function signatures may be created to handle different scenarios, depending on the number &amp; type of parameters, and the type of return value. For most built-in functions, each parameter type and return value type are determined, so only a function signature is needed.<\/li>\n<li>For referring rules of more complicated return value type, you can refer to the implementation and test of the <code>CONCAT<\/code> function. You can use the <code>MySQLWorkbench<\/code> tool to run the query <code>select funcName (arg0, arg1, ...)<\/code> to observe the field type of the return value in MySQL&#8217;s built-in functions when inputting different parameters.<\/li>\n<li>In the evaluation process of TiDB expression, only the following six evaluation types (currently we are implementing the JSON type) are supported:\n<ol>\n<li>int (int64)<\/li>\n<li>real (float64)<\/li>\n<li>decimal<\/li>\n<li>string<\/li>\n<li>Time<\/li>\n<li>Duration<\/li>\n<\/ol>\n<p>The <code>WrapWithCastAsXX ()<\/code> method can convert an expression to the corresponding type.<\/li>\n<li>For a function signature, its return value type has been determined, so when defining, you need to combine it with the corresponding <code>baseXXBuiltinFunc<\/code> and implement the <code>evalXX ()<\/code> method. Note that XX should only be one of the six types listed above.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In order to accelerate expression evaluation, we recently refactored its framework. This tutorial will show you how to use the new computational framework to rewrite or add a built-in function in TiDB.<\/p>","protected":false},"author":104,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"ub_ctt_via":"","footnotes":""},"categories":[18],"tags":[7,29],"class_list":["post-950","post","type-post","status-publish","format-standard","hentry","category-community","tag-query-execution","tag-tutorial"],"acf":[],"featured_image_src":null,"author_info":{"display_name":"Huaiyu Xu","author_link":"https:\/\/www.pingcap.com\/ko\/blog\/author\/huaiyu-xu\/"},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.9 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Refactoring the Built-in Functions in TiDB | TiDB<\/title>\n<meta name=\"description\" content=\"Learn about the benefits of TiDB and the TiDB Cloud solutions from PingCAP. Read our latest post &quot;Refactoring the Built-in Functions in TiDB&quot; here.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.pingcap.com\/ko\/blog\/refactor-builtin\/\" \/>\n<meta property=\"og:locale\" content=\"ko_KR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Refactoring the Built-in Functions in TiDB | TiDB\" \/>\n<meta property=\"og:description\" content=\"Learn about the benefits of TiDB and the TiDB Cloud solutions from PingCAP. Read our latest post &quot;Refactoring the Built-in Functions in TiDB&quot; here.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.pingcap.com\/ko\/blog\/refactor-builtin\/\" \/>\n<meta property=\"og:site_name\" content=\"TiDB\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/facebook.com\/pingcap2015\" \/>\n<meta property=\"article:published_time\" content=\"2017-06-27T00:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2024-03-18T13:53:22+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/en.pingcap.com\/wp-content\/uploads\/2017\/06\/after_reconstruction.png\" \/>\n<meta name=\"author\" content=\"Huaiyu Xu\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@PingCAP\" \/>\n<meta name=\"twitter:site\" content=\"@PingCAP\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Huaiyu Xu\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8\ubd84\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/\"},\"author\":{\"name\":\"Huaiyu Xu\",\"@id\":\"https:\/\/www.pingcap.com\/#\/schema\/person\/7857f9f7426d9f90e11e6fbd0da7c3ea\"},\"headline\":\"Refactoring the Built-in Functions in TiDB\",\"datePublished\":\"2017-06-27T00:00:00+00:00\",\"dateModified\":\"2024-03-18T13:53:22+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/\"},\"wordCount\":980,\"publisher\":{\"@id\":\"https:\/\/www.pingcap.com\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/en.pingcap.com\/wp-content\/uploads\/2017\/06\/after_reconstruction.png\",\"keywords\":[\"Query execution\",\"Tutorial\"],\"articleSection\":[\"Community\"],\"inLanguage\":\"ko-KR\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/\",\"url\":\"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/\",\"name\":\"Refactoring the Built-in Functions in TiDB | TiDB\",\"isPartOf\":{\"@id\":\"https:\/\/www.pingcap.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/en.pingcap.com\/wp-content\/uploads\/2017\/06\/after_reconstruction.png\",\"datePublished\":\"2017-06-27T00:00:00+00:00\",\"dateModified\":\"2024-03-18T13:53:22+00:00\",\"description\":\"Learn about the benefits of TiDB and the TiDB Cloud solutions from PingCAP. Read our latest post \\\"Refactoring the Built-in Functions in TiDB\\\" here.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#breadcrumb\"},\"inLanguage\":\"ko-KR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#primaryimage\",\"url\":\"https:\/\/en.pingcap.com\/wp-content\/uploads\/2017\/06\/after_reconstruction.png\",\"contentUrl\":\"https:\/\/en.pingcap.com\/wp-content\/uploads\/2017\/06\/after_reconstruction.png\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.pingcap.com\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Refactoring the Built-in Functions in TiDB\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.pingcap.com\/#website\",\"url\":\"https:\/\/www.pingcap.com\/\",\"name\":\"TiDB\",\"description\":\"TiDB | SQL at Scale\",\"publisher\":{\"@id\":\"https:\/\/www.pingcap.com\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.pingcap.com\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ko-KR\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.pingcap.com\/#organization\",\"name\":\"PingCAP\",\"url\":\"https:\/\/www.pingcap.com\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\/\/www.pingcap.com\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/static.pingcap.com\/files\/2021\/11\/pingcap-logo.png\",\"contentUrl\":\"https:\/\/static.pingcap.com\/files\/2021\/11\/pingcap-logo.png\",\"width\":811,\"height\":232,\"caption\":\"PingCAP\"},\"image\":{\"@id\":\"https:\/\/www.pingcap.com\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/facebook.com\/pingcap2015\",\"https:\/\/x.com\/PingCAP\",\"https:\/\/linkedin.com\/company\/pingcap\",\"https:\/\/youtube.com\/channel\/UCuq4puT32DzHKT5rU1IZpIA\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.pingcap.com\/#\/schema\/person\/7857f9f7426d9f90e11e6fbd0da7c3ea\",\"name\":\"Huaiyu Xu\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ko-KR\",\"@id\":\"https:\/\/www.pingcap.com\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/static.pingcap.com\/files\/2022\/10\/17234942\/avatar.jpg\",\"contentUrl\":\"https:\/\/static.pingcap.com\/files\/2022\/10\/17234942\/avatar.jpg\",\"caption\":\"Huaiyu Xu\"},\"description\":\"Software Engineer\",\"url\":\"https:\/\/www.pingcap.com\/ko\/blog\/author\/huaiyu-xu\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Refactoring the Built-in Functions in TiDB | TiDB","description":"Learn about the benefits of TiDB and the TiDB Cloud solutions from PingCAP. Read our latest post \"Refactoring the Built-in Functions in TiDB\" here.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.pingcap.com\/ko\/blog\/refactor-builtin\/","og_locale":"ko_KR","og_type":"article","og_title":"Refactoring the Built-in Functions in TiDB | TiDB","og_description":"Learn about the benefits of TiDB and the TiDB Cloud solutions from PingCAP. Read our latest post \"Refactoring the Built-in Functions in TiDB\" here.","og_url":"https:\/\/www.pingcap.com\/ko\/blog\/refactor-builtin\/","og_site_name":"TiDB","article_publisher":"https:\/\/facebook.com\/pingcap2015","article_published_time":"2017-06-27T00:00:00+00:00","article_modified_time":"2024-03-18T13:53:22+00:00","og_image":[{"url":"https:\/\/en.pingcap.com\/wp-content\/uploads\/2017\/06\/after_reconstruction.png","type":"","width":"","height":""}],"author":"Huaiyu Xu","twitter_card":"summary_large_image","twitter_creator":"@PingCAP","twitter_site":"@PingCAP","twitter_misc":{"Written by":"Huaiyu Xu","Est. reading time":"8\ubd84"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#article","isPartOf":{"@id":"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/"},"author":{"name":"Huaiyu Xu","@id":"https:\/\/www.pingcap.com\/#\/schema\/person\/7857f9f7426d9f90e11e6fbd0da7c3ea"},"headline":"Refactoring the Built-in Functions in TiDB","datePublished":"2017-06-27T00:00:00+00:00","dateModified":"2024-03-18T13:53:22+00:00","mainEntityOfPage":{"@id":"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/"},"wordCount":980,"publisher":{"@id":"https:\/\/www.pingcap.com\/#organization"},"image":{"@id":"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#primaryimage"},"thumbnailUrl":"https:\/\/en.pingcap.com\/wp-content\/uploads\/2017\/06\/after_reconstruction.png","keywords":["Query execution","Tutorial"],"articleSection":["Community"],"inLanguage":"ko-KR"},{"@type":"WebPage","@id":"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/","url":"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/","name":"Refactoring the Built-in Functions in TiDB | TiDB","isPartOf":{"@id":"https:\/\/www.pingcap.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#primaryimage"},"image":{"@id":"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#primaryimage"},"thumbnailUrl":"https:\/\/en.pingcap.com\/wp-content\/uploads\/2017\/06\/after_reconstruction.png","datePublished":"2017-06-27T00:00:00+00:00","dateModified":"2024-03-18T13:53:22+00:00","description":"Learn about the benefits of TiDB and the TiDB Cloud solutions from PingCAP. Read our latest post \"Refactoring the Built-in Functions in TiDB\" here.","breadcrumb":{"@id":"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#breadcrumb"},"inLanguage":"ko-KR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.pingcap.com\/blog\/refactor-builtin\/"]}]},{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#primaryimage","url":"https:\/\/en.pingcap.com\/wp-content\/uploads\/2017\/06\/after_reconstruction.png","contentUrl":"https:\/\/en.pingcap.com\/wp-content\/uploads\/2017\/06\/after_reconstruction.png"},{"@type":"BreadcrumbList","@id":"https:\/\/www.pingcap.com\/blog\/refactor-builtin\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.pingcap.com\/"},{"@type":"ListItem","position":2,"name":"Refactoring the Built-in Functions in TiDB"}]},{"@type":"WebSite","@id":"https:\/\/www.pingcap.com\/#website","url":"https:\/\/www.pingcap.com\/","name":"\ud2f0DB","description":"TiDB | SQL at Scale","publisher":{"@id":"https:\/\/www.pingcap.com\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.pingcap.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ko-KR"},{"@type":"Organization","@id":"https:\/\/www.pingcap.com\/#organization","name":"PingCAP","url":"https:\/\/www.pingcap.com\/","logo":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.pingcap.com\/#\/schema\/logo\/image\/","url":"https:\/\/static.pingcap.com\/files\/2021\/11\/pingcap-logo.png","contentUrl":"https:\/\/static.pingcap.com\/files\/2021\/11\/pingcap-logo.png","width":811,"height":232,"caption":"PingCAP"},"image":{"@id":"https:\/\/www.pingcap.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/facebook.com\/pingcap2015","https:\/\/x.com\/PingCAP","https:\/\/linkedin.com\/company\/pingcap","https:\/\/youtube.com\/channel\/UCuq4puT32DzHKT5rU1IZpIA"]},{"@type":"Person","@id":"https:\/\/www.pingcap.com\/#\/schema\/person\/7857f9f7426d9f90e11e6fbd0da7c3ea","name":"Huaiyu Xu","image":{"@type":"ImageObject","inLanguage":"ko-KR","@id":"https:\/\/www.pingcap.com\/#\/schema\/person\/image\/","url":"https:\/\/static.pingcap.com\/files\/2022\/10\/17234942\/avatar.jpg","contentUrl":"https:\/\/static.pingcap.com\/files\/2022\/10\/17234942\/avatar.jpg","caption":"Huaiyu Xu"},"description":"Software Engineer","url":"https:\/\/www.pingcap.com\/ko\/blog\/author\/huaiyu-xu\/"}]}},"grav_blocks":false,"card_markup":"<a class=\"card-resource bg-white\" href=\"https:\/\/www.pingcap.com\/ko\/blog\/refactor-builtin\/\"><div class=\"card-resource__content-container\"><div class=\"card-resource__content-head\"><div class=\"card-resource__category\">Community<\/div><\/div><h5 class=\"card-resource__title\">Refactoring the Built-in Functions in TiDB<\/h5><\/div><\/a>","_links":{"self":[{"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/posts\/950","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/users\/104"}],"replies":[{"embeddable":true,"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/comments?post=950"}],"version-history":[{"count":2,"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/posts\/950\/revisions"}],"predecessor-version":[{"id":16051,"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/posts\/950\/revisions\/16051"}],"wp:attachment":[{"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/media?parent=950"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/categories?post=950"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.pingcap.com\/ko\/wp-json\/wp\/v2\/tags?post=950"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}