{"id":15566,"date":"2024-04-05T09:33:32","date_gmt":"2024-04-05T16:33:32","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=15566"},"modified":"2025-07-08T09:15:58","modified_gmt":"2025-07-08T16:15:58","slug":"improved-debuggability-for-sql-user-defined-functions","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/","title":{"rendered":"Improved Debuggability for SQL++ User-Defined Functions"},"content":{"rendered":"<p><span style=\"font-weight: 400;\"><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/userfun.html\">User-defined functions (UDFs)<\/a> are a very useful feature supported in SQL++.\u00a0<\/span><span style=\"font-weight: 400;\">Couchbase 7.6 introduces improvements that allow for more debuggability and visibility into UDF execution.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This blog will explore two new features in Couchbase 7.6 in the world of UDFs.<\/span><\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Profiling for SQL++ statements executed in JavaScript UDFs<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">EXPLAIN FUNCTION to access query plans of SQL++ statements within UDFs<\/span><\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p><span style=\"font-weight: 400;\">The examples in this post require the <a href=\"https:\/\/docs.couchbase.com\/server\/current\/manage\/manage-settings\/install-sample-buckets.html\">travel-sample dataset<\/a> to be installed.<\/span><\/p>\n<h2>Profiling SQL++ Executed in JavaScript UDFs<\/h2>\n<p><span style=\"font-weight: 400;\">Query profiling is a debuggability feature that SQL++ offers.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">When profiling is enabled for a statement\u2019s execution, the result of the request includes a detailed execution tree with timing and metrics of each step of the statement\u2019s execution. In addition to the profiling information being returned in the results of the statement, it can also be accessed for the request in the <em>system:active_requests<\/em> and <em>system:completed_requests<\/em> system keyspaces.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Here is a post that <a href=\"https:\/\/www.couchbase.com\/blog\/optimize-n1ql-performance-using-request-profiling\/\">delves deeper into request profiling<\/a>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In Couchbase 7.0, profiling was included for subqueries, including profiling subqueries from <em>Inline UDFs<\/em>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">However, with new features in Couchbase 7.6, profiling was extended to SQL++ statements within <em>JavaScript UDFs<\/em>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In earlier versions, to profile statements within a JavaScript UDF, the user would be required to open up the function\u2019s definition, individually run each statement within the UDF and collect their profiles. This additional step will no longer be needed in 7.6.0!<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now, when profiling is enabled, if the statement contains JavaScript UDF execution, profiles for all SQL++ statements executed in the UDF will also be collected. And this UDF related profiling information will be available in the request output, <em>system:active_requests<\/em> and <em>system:completed_requests<\/em> system keyspaces as well.<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">Example 1:<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Create a JavaScript UDF <em>js1<\/em> in a global library <em>lib1<\/em>\u00a0via the REST endpoint or via the UI.<\/span><\/p>\n<pre class=\"nums:false lang:js decode:true\">function js1() {\r\n\r\n\u00a0\u00a0\u00a0\u00a0var query = SELECT * FROM default:`travel-sample`.inventory.airline LIMIT 1;\r\n\r\n\u00a0\u00a0\u00a0\u00a0var res = [];\r\n\u00a0\u00a0\u00a0\u00a0for (const row of query) {\r\n\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0\u00a0res.push(row);\r\n\u00a0\u00a0\u00a0}\r\n\u00a0\u00a0\u00a0\u00a0query.close()\r\n\r\n\u00a0\u00a0\u00a0\u00a0return res;\r\n}<\/pre>\n<p><span style=\"font-weight: 400;\">Create the corresponding SQL++ function:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">CREATE FUNCTION js1() LANGUAGE JAVASCRIPT AS \"js1\" AT \"lib1\";<\/pre>\n<p><span style=\"font-weight: 400;\"> Execute the UDF with profiling enabled:<\/span><\/p>\n<pre class=\"nums:false lang:default decode:true\">EXECUTE FUNCTION js1();\r\n<\/pre>\n<p><span style=\"font-weight: 400;\">In the <\/span><b>profile<\/b><span style=\"font-weight: 400;\"> section of the returned response, the <\/span><b>executionTimings<\/b><span style=\"font-weight: 400;\"> subsection contains a field <\/span><b>~udfStatements<\/b><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><b>~udfStatements<\/b><span style=\"font-weight: 400;\">\u00a0is an array of profiling information that contains an entry for every SQL++ statement within the JavaScript UDF.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Every entry within the <\/span><b>~udfStatements<\/b><span style=\"font-weight: 400;\"> section contains:<\/span><\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\"><b>executionTimings <\/b>&#8211; <span style=\"font-weight: 400;\">The execution tree for the statement. It has metrics and timings information of every step of the statement\u2019s execution.<\/span><\/li>\n<li style=\"font-weight: 400;\"><b>statement<\/b> &#8211; <span style=\"font-weight: 400;\">The statement string.<\/span><\/li>\n<li style=\"font-weight: 400;\"><b>function<\/b> &#8211; <span style=\"font-weight: 400;\">The name of the function where the statement was executed. This is helpful to identify the UDF that executed the statement when there are nested UDF executions.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<pre class=\"lang:js decode:true \">{\r\n  \"requestID\": \"2c5576b5-f01d-445f-a35b-2213c606f394\",\r\n  \"signature\": null,\r\n  \"results\": [\r\n    [\r\n      {\r\n        \"airline\": {\r\n          \"callsign\": \"MILE-AIR\",\r\n          \"country\": \"United States\",\r\n          \"iata\": \"Q5\",\r\n          \"icao\": \"MLA\",\r\n          \"id\": 10,\r\n          \"name\": \"40-Mile Air\",\r\n          \"type\": \"airline\"\r\n        }\r\n      }\r\n    ]\r\n  ],\r\n  \"status\": \"success\",\r\n  \"metrics\": {\r\n    \"elapsedTime\": \"20.757583ms\",\r\n    \"executionTime\": \"20.636792ms\",\r\n    \"resultCount\": 1,\r\n    \"resultSize\": 310,\r\n    \"serviceLoad\": 2\r\n  },\r\n  \"profile\": {\r\n    \"phaseTimes\": {\r\n      \"authorize\": \"12.835\u00b5s\",\r\n      \"fetch\": \"374.667\u00b5s\",\r\n      \"instantiate\": \"27.75\u00b5s\",\r\n      \"parse\": \"251.708\u00b5s\",\r\n      \"plan\": \"9.125\u00b5s\",\r\n      \"primaryScan\": \"813.249\u00b5s\",\r\n      \"primaryScan.GSI\": \"813.249\u00b5s\",\r\n      \"project\": \"5.541\u00b5s\",\r\n      \"run\": \"27.925833ms\",\r\n      \"stream\": \"26.375\u00b5s\"\r\n    },\r\n    \"phaseCounts\": {\r\n      \"fetch\": 1,\r\n      \"primaryScan\": 1,\r\n      \"primaryScan.GSI\": 1\r\n    },\r\n    \"phaseOperators\": {\r\n      \"authorize\": 2,\r\n      \"fetch\": 1,\r\n      \"primaryScan\": 1,\r\n      \"primaryScan.GSI\": 1,\r\n      \"project\": 1,\r\n      \"stream\": 1\r\n    },\r\n    \"cpuTime\": \"468.626\u00b5s\",\r\n    \"requestTime\": \"2023-12-04T20:30:00.369+05:30\",\r\n    \"servicingHost\": \"127.0.0.1:8091\",\r\n    \"executionTimings\": {\r\n      \"#operator\": \"Authorize\",\r\n      \"#planPreparedTime\": \"2023-12-04T20:30:00.369+05:30\",\r\n      \"#stats\": {\r\n        \"#phaseSwitches\": 4,\r\n        \"execTime\": \"1.918\u00b5s\",\r\n        \"servTime\": \"1.125\u00b5s\"\r\n      },\r\n      \"privileges\": {\r\n        \"List\": []\r\n      },\r\n      \"~child\": {\r\n        \"#operator\": \"Sequence\",\r\n        \"#stats\": {\r\n          \"#phaseSwitches\": 2,\r\n          \"execTime\": \"2.208\u00b5s\"\r\n        },\r\n        \"~children\": [\r\n          {\r\n            \"#operator\": \"ExecuteFunction\",\r\n            \"#stats\": {\r\n              \"#itemsOut\": 1,\r\n              \"#phaseSwitches\": 4,\r\n              \"execTime\": \"22.375\u00b5s\",\r\n              \"kernTime\": \"20.271708ms\"\r\n            },\r\n            \"identity\": {\r\n              \"name\": \"js1\",\r\n              \"namespace\": \"default\",\r\n              \"type\": \"global\"\r\n            }\r\n          },\r\n          {\r\n            \"#operator\": \"Stream\",\r\n            \"#stats\": {\r\n              \"#itemsIn\": 1,\r\n              \"#itemsOut\": 1,\r\n              \"#phaseSwitches\": 2,\r\n              \"execTime\": \"26.375\u00b5s\"\r\n            },\r\n            \"serializable\": true\r\n          }\r\n        ]\r\n      },\r\n      \"~udfStatements\": [\r\n        {\r\n          \"executionTimings\": {\r\n            \"#operator\": \"Authorize\",\r\n            \"#stats\": {\r\n              \"#phaseSwitches\": 4,\r\n              \"execTime\": \"2.626\u00b5s\",\r\n              \"servTime\": \"7.166\u00b5s\"\r\n            },\r\n            \"privileges\": {\r\n              \"List\": [\r\n                {\r\n                  \"Priv\": 7,\r\n                  \"Props\": 0,\r\n                  \"Target\": \"default:travel-sample.inventory.airline\"\r\n                }\r\n              ]\r\n            },\r\n            \"~child\": {\r\n              \"#operator\": \"Sequence\",\r\n              \"#stats\": {\r\n                \"#phaseSwitches\": 2,\r\n                \"execTime\": \"4.375\u00b5s\"\r\n              },\r\n              \"~children\": [\r\n                {\r\n                  \"#operator\": \"PrimaryScan3\",\r\n                  \"#stats\": {\r\n                    \"#itemsIn\": 1,\r\n                    \"#itemsOut\": 1,\r\n                    \"#phaseSwitches\": 7,\r\n                    \"execTime\": \"22.082\u00b5s\",\r\n                    \"kernTime\": \"1.584\u00b5s\",\r\n                    \"servTime\": \"791.167\u00b5s\"\r\n                  },\r\n                  \"bucket\": \"travel-sample\",\r\n                  \"index\": \"def_inventory_airline_primary\",\r\n                  \"index_projection\": {\r\n                    \"primary_key\": true\r\n                  },\r\n                  \"keyspace\": \"airline\",\r\n                  \"limit\": \"1\",\r\n                  \"namespace\": \"default\",\r\n                  \"optimizer_estimates\": {\r\n                    \"cardinality\": 187,\r\n                    \"cost\": 45.28617059639748,\r\n                    \"fr_cost\": 12.1780009122802,\r\n                    \"size\": 12\r\n                  },\r\n                  \"scope\": \"inventory\",\r\n                  \"using\": \"gsi\"\r\n                },\r\n                {\r\n                  \"#operator\": \"Fetch\",\r\n                  \"#stats\": {\r\n                    \"#itemsIn\": 1,\r\n                    \"#itemsOut\": 1,\r\n                    \"#phaseSwitches\": 10,\r\n                    \"execTime\": \"18.376\u00b5s\",\r\n                    \"kernTime\": \"797.542\u00b5s\",\r\n                    \"servTime\": \"356.291\u00b5s\"\r\n                  },\r\n                  \"bucket\": \"travel-sample\",\r\n                  \"keyspace\": \"airline\",\r\n                  \"namespace\": \"default\",\r\n                  \"optimizer_estimates\": {\r\n                    \"cardinality\": 187,\r\n                    \"cost\": 192.01699202888378,\r\n                    \"fr_cost\": 24.89848658838975,\r\n                    \"size\": 204\r\n                  },\r\n                  \"scope\": \"inventory\"\r\n                },\r\n                {\r\n                  \"#operator\": \"InitialProject\",\r\n                  \"#stats\": {\r\n                    \"#itemsIn\": 1,\r\n                    \"#itemsOut\": 1,\r\n                    \"#phaseSwitches\": 7,\r\n                    \"execTime\": \"5.541\u00b5s\",\r\n                    \"kernTime\": \"1.1795ms\"\r\n                  },\r\n                  \"discard_original\": true,\r\n                  \"optimizer_estimates\": {\r\n                    \"cardinality\": 187,\r\n                    \"cost\": 194.6878862611588,\r\n                    \"fr_cost\": 24.912769445246838,\r\n                    \"size\": 204\r\n                  },\r\n                  \"preserve_order\": true,\r\n                  \"result_terms\": [\r\n                    {\r\n                      \"expr\": \"self\",\r\n                      \"star\": true\r\n                    }\r\n                  ]\r\n                },\r\n                {\r\n                  \"#operator\": \"Limit\",\r\n                  \"#stats\": {\r\n                    \"#itemsIn\": 1,\r\n                    \"#itemsOut\": 1,\r\n                    \"#phaseSwitches\": 4,\r\n                    \"execTime\": \"6.25\u00b5s\",\r\n                    \"kernTime\": \"333ns\"\r\n                  },\r\n                  \"expr\": \"1\",\r\n                  \"optimizer_estimates\": {\r\n                    \"cardinality\": 1,\r\n                    \"cost\": 24.927052302103924,\r\n                    \"fr_cost\": 24.927052302103924,\r\n                    \"size\": 204\r\n                  }\r\n                },\r\n                {\r\n                  \"#operator\": \"Receive\",\r\n                  \"#stats\": {\r\n                    \"#phaseSwitches\": 3,\r\n                    \"execTime\": \"10.324833ms\",\r\n                    \"kernTime\": \"792ns\",\r\n                    \"state\": \"running\"\r\n                  }\r\n                }\r\n              ]\r\n            }\r\n          },\r\n          \"statement\": \"SELECT * FROM default:`travel-sample`.inventory.airline LIMIT 1;\",\r\n          \"function\": \"default:js1\"\r\n        }\r\n      ],\r\n      \"~versions\": [\r\n        \"7.6.0-N1QL\",\r\n        \"7.6.0-1847-enterprise\"\r\n      ]\r\n    }\r\n  }\r\n}<\/pre>\n<h2>Query Plans with EXPLAIN FUNCTION<\/h2>\n<p><span style=\"font-weight: 400;\">SQL++ offers another wonderful capability to access the plan of a statement with the EXPLAIN statement. But the EXPLAIN statement does not extend to plans of statements within UDFs\u2014neither Inline or JavaScript UDFs.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In earlier versions, to analyze the query plans for SQL++ within a UDF it would require the user to open the function\u2019s definition, and individually run an EXPLAIN on all the statements within the UDF.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">These extra steps are minimized in Couchbase 7.6 with the introduction of a new statement\u2014<em>EXPLAIN FUNCTION<\/em>. This statement does exactly what EXPLAIN does, but for SQL++ statements within a UDF.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Let\u2019s explore how to use the EXPLAIN FUNCTION statement!<\/span><\/p>\n<h3>Syntax<\/h3>\n<pre class=\"lang:default decode:true \">explain_function ::= 'EXPLAIN' 'FUNCTION' function<\/pre>\n<p><span style=\"font-weight: 400;\">Here, <em>function<\/em>\u00a0refers to the name of the function.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">For more detailed information on syntax, please check out the documentation.<\/span><\/p>\n<h3>Prerequisites<\/h3>\n<p><span style=\"font-weight: 400;\">To run EXPLAIN FUNCTION on a UDF, the user must have sufficient <a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/userfun.html#rbac-privileges\">RBAC permissions<\/a> to <\/span><i><span style=\"font-weight: 400;\">execute<\/span><\/i><span style=\"font-weight: 400;\"> the function.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The user must also have the necessary RBAC permissions to execute the SQL++ statements within the UDF function body.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Here are the <a href=\"https:\/\/docs.couchbase.com\/server\/current\/learn\/security\/roles.html\">roles supported in Couchbase<\/a>.<\/span><\/p>\n<h3>Inline UDF<\/h3>\n<p><span style=\"font-weight: 400;\">EXPLAIN FUNCTION on an inline UDF will return the query plans of all the subqueries within its definition.<\/span><\/p>\n<h3><span style=\"font-weight: 400;\">Example 2 &#8211; EXPLAIN FUNCTION on an inline function<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Create an inline UDF and run EXPLAIN FUNCTION on it:<\/span><\/p>\n<pre class=\"lang:default decode:true\">CREATE FUNCTION inline1() { (\u00a0\u00a0\r\n\u00a0 SELECT * FROM default:`travel-sample`.inventory.airport WHERE city = \"Zachar Bay\"\r\n) };<\/pre>\n<pre class=\"lang:default decode:true\">EXPLAIN FUNCTION inline1();<\/pre>\n<p><span style=\"font-weight: 400;\">The results of the above statement will contain:<\/span><\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\"><b>function<\/b><span style=\"font-weight: 400;\">\u00a0&#8211; The name of the function EXPLAIN FUNCTION was run on.<\/span><\/li>\n<li style=\"font-weight: 400;\"><b>plans<\/b><span style=\"font-weight: 400;\">\u00a0&#8211; An array of plan information that contains an entry for every subquery within the Inline UDF.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<pre class=\"lang:js decode:true\">{\r\n        \"function\": \"default:inline1\",\r\n        \"plans\": [\r\n            {\r\n                \"cardinality\": 1.1176470588235294,\r\n                \"cost\": 25.117642854609013,\r\n                \"plan\": {\r\n                    \"#operator\": \"Sequence\",\r\n                    \"~children\": [\r\n                        {\r\n                            \"#operator\": \"IndexScan3\",\r\n                            \"bucket\": \"travel-sample\",\r\n                            \"index\": \"def_inventory_airport_city\",\r\n                            \"index_id\": \"2605c88c115dd3a2\",\r\n                            \"index_projection\": {\r\n                                \"primary_key\": true\r\n                            },\r\n                            \"keyspace\": \"airport\",\r\n                            \"namespace\": \"default\",\r\n                            \"optimizer_estimates\": {\r\n                                \"cardinality\": 1.1176470588235294,\r\n                                \"cost\": 12.200561852726496,\r\n                                \"fr_cost\": 12.179450078755286,\r\n                                \"size\": 12\r\n                            },\r\n                            \"scope\": \"inventory\",\r\n                            \"spans\": [\r\n                                {\r\n                                    \"exact\": true,\r\n                                    \"range\": [\r\n                                        {\r\n                                            \"high\": \"\\\\\"Zachar Bay\\\\\"\",\r\n                                            \"inclusion\": 3,\r\n                                            \"index_key\": \"`city`\",\r\n                                            \"low\": \"\\\\\"Zachar Bay\\\\\"\"\r\n                                        }\r\n                                    ]\r\n                                }\r\n                            ],\r\n                            \"using\": \"gsi\"\r\n                        },\r\n                        {\r\n                            \"#operator\": \"Fetch\",\r\n                            \"bucket\": \"travel-sample\",\r\n                            \"keyspace\": \"airport\",\r\n                            \"namespace\": \"default\",\r\n                            \"optimizer_estimates\": {\r\n                                \"cardinality\": 1.1176470588235294,\r\n                                \"cost\": 25.082370508382763,\r\n                                \"fr_cost\": 24.96843677065826,\r\n                                \"size\": 249\r\n                            },\r\n                            \"scope\": \"inventory\"\r\n                        },\r\n                        {\r\n                            \"#operator\": \"Parallel\",\r\n                            \"~child\": {\r\n                                \"#operator\": \"Sequence\",\r\n                                \"~children\": [\r\n                                    {\r\n                                        \"#operator\": \"Filter\",\r\n                                        \"condition\": \"((`airport`.`city`) = \\\\\"Zachar Bay\\\\\")\",\r\n                                        \"optimizer_estimates\": {\r\n                                            \"cardinality\": 1.1176470588235294,\r\n                                            \"cost\": 25.100006681495888,\r\n                                            \"fr_cost\": 24.98421650449632,\r\n                                            \"size\": 249\r\n                                        }\r\n                                    },\r\n                                    {\r\n                                        \"#operator\": \"InitialProject\",\r\n                                        \"discard_original\": true,\r\n                                        \"optimizer_estimates\": {\r\n                                            \"cardinality\": 1.1176470588235294,\r\n                                            \"cost\": 25.117642854609013,\r\n                                            \"fr_cost\": 24.99999623833438,\r\n                                            \"size\": 249\r\n                                        },\r\n                                        \"result_terms\": [\r\n                                            {\r\n                                                \"expr\": \"self\",\r\n                                                \"star\": true\r\n                                            }\r\n                                        ]\r\n                                    }\r\n                                ]\r\n                            }\r\n                        }\r\n                    ]\r\n                },\r\n                \"statement\": \"select self.* from `default`:`travel-sample`.`inventory`.`airport` where ((`airport`.`city`) = \\\\\"Zachar Bay\\\\\")\"\r\n            }\r\n        ]\r\n    }<\/pre>\n<h3>JavaScript UDF<\/h3>\n<p><span style=\"font-weight: 400;\">SQL++ statements within JavaScript UDFs can be of two types and EXPLAIN FUNCTION works differently based on the way the SQL++ statement is called.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Here is the documentation reference to <a href=\"https:\/\/docs.couchbase.com\/server\/current\/javascript-udfs\/calling-n1ql-from-javascript.html\">calling SQL++ in JavaScript functions<\/a>.<\/span><\/p>\n<h4>Embedded SQL++<\/h4>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">Embedded SQL++ is \u201cembedded\u201d in the function body and its detection is handled by the JavaScript transpiler.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">EXPLAIN FUNCTION can return query plans for embedded SQL++ statements.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h4><\/h4>\n<h4>\u00a0SQL++ executed by the N1QL() function call<\/h4>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">SQL++ can also be executed by passing a statement in the form of a string as an argument to the N1QL() function.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">When parsing the function for potential SQL++ statements to run the EXPLAIN on, it is difficult to get the dynamic string in the function argument. This can only be reliably resolved at runtime.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">With this reasoning, EXPLAIN FUNCTION does not return the query plans for SQL++ statements executed via N1QL() calls. But instead returns the line numbers where the N1QL() function calls have been made. This line number is calculated from the beginning of the function definition.<\/span><\/li>\n<li style=\"font-weight: 400;\"><span style=\"font-weight: 400;\">The user can then map the line numbers in the actual function definition and investigate further.<\/span><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<h3><span style=\"font-weight: 400;\">Example 3 &#8211; EXPLAIN FUNCTION on an external JavaScript function<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">Create a JavaScript UDF <em>js2<\/em> in a global library <em>lib1<\/em> via the REST endpoint or via the UI:<\/span><\/p>\n<pre class=\"lang:js decode:true \">function js2() { \r\n    \/\/ SQL++ executed by a N1QL() function call\r\n    var query1 = N1QL(\"UPDATE default:`travel-sample` SET test = 1 LIMIT 1\");\r\n    \r\n    \/\/ Embedded SQL++\r\n    var query2 = SELECT * FROM default:`travel-sample` LIMIT 1;\r\n    \r\n    var res = [];\r\n    for (const row of query2) {\r\n        res.push(row);\r\n    }\r\n    query2.close()\r\n\r\n    return res;\r\n}\r\n<\/pre>\n<p><span style=\"font-weight: 400;\"> Create the corresponding SQL++ function:<\/span><\/p>\n<pre class=\"lang:default decode:true \">CREATE FUNCTION js2() LANGUAGE JAVASCRIPT AS \"js2\" AT \"lib1\";<\/pre>\n<p><span style=\"font-weight: 400;\"> Run EXPLAIN FUNCTION on the SQL++ function:<\/span><\/p>\n<pre class=\"lang:default decode:true \">EXPLAIN FUNCTION js2;<\/pre>\n<p><span style=\"font-weight: 400;\">The results of the above statement will contain:<\/span><\/p>\n<ol>\n<li style=\"list-style-type: none;\">\n<ol>\n<li style=\"font-weight: 400;\"><b>function<\/b><span style=\"font-weight: 400;\">\u00a0&#8211; The name of the function EXPLAIN FUNCTION was run on.<\/span><\/li>\n<li style=\"font-weight: 400;\"><b>line_numbers<\/b><span style=\"font-weight: 400;\">\u00a0&#8211; An array of line numbers calculated from the beginning of the JavaScript function definition where there are N1QL() function calls.<\/span><\/li>\n<li style=\"font-weight: 400;\"><b>plans<\/b><span style=\"font-weight: 400;\">\u00a0&#8211; An array of plan information that contains an entry for every <\/span><i><span style=\"font-weight: 400;\">embedded<\/span><\/i><span style=\"font-weight: 400;\"> SQL++ statement within the JavaScript UDF.<\/span><\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<pre class=\"lang:js decode:true\">{\r\n  \"function\": \"default:js2\",\r\n  \"line_numbers\": [\r\n    4\r\n  ],\r\n  \"plans\": [\r\n    {\r\n      \"cardinality\": 1,\r\n      \"cost\": 25.51560885530435,\r\n      \"plan\": {\r\n        \"#operator\": \"Authorize\",\r\n        \"privileges\": {\r\n          \"List\": [\r\n            {\r\n              \"Target\": \"default:travel-sample\",\r\n              \"Priv\": 7,\r\n              \"Props\": 0\r\n            }\r\n          ]\r\n        },\r\n        \"~child\": {\r\n          \"#operator\": \"Sequence\",\r\n          \"~children\": [\r\n            {\r\n              \"#operator\": \"Sequence\",\r\n              \"~children\": [\r\n                {\r\n                  \"#operator\": \"Sequence\",\r\n                  \"~children\": [\r\n                    {\r\n                      \"#operator\": \"PrimaryScan3\",\r\n                      \"index\": \"def_primary\",\r\n                      \"index_projection\": {\r\n                        \"primary_key\": true\r\n                      },\r\n                      \"keyspace\": \"travel-sample\",\r\n                      \"limit\": \"1\",\r\n                      \"namespace\": \"default\",\r\n                      \"optimizer_estimates\": {\r\n                        \"cardinality\": 31591,\r\n                        \"cost\": 5402.279801258844,\r\n                        \"fr_cost\": 12.170627071041082,\r\n                        \"size\": 11\r\n                      },\r\n                      \"using\": \"gsi\"\r\n                    },\r\n                    {\r\n                      \"#operator\": \"Fetch\",\r\n                      \"keyspace\": \"travel-sample\",\r\n                      \"namespace\": \"default\",\r\n                      \"optimizer_estimates\": {\r\n                        \"cardinality\": 31591,\r\n                        \"cost\": 46269.39474997121,\r\n                        \"fr_cost\": 25.46387878667884,\r\n                        \"size\": 669\r\n                      }\r\n                    },\r\n                    {\r\n                      \"#operator\": \"Parallel\",\r\n                      \"~child\": {\r\n                        \"#operator\": \"Sequence\",\r\n                        \"~children\": [\r\n                          {\r\n                            \"#operator\": \"InitialProject\",\r\n                            \"discard_original\": true,\r\n                            \"optimizer_estimates\": {\r\n                              \"cardinality\": 31591,\r\n                              \"cost\": 47086.49704894546,\r\n                              \"fr_cost\": 25.489743820991595,\r\n                              \"size\": 669\r\n                            },\r\n                            \"preserve_order\": true,\r\n                            \"result_terms\": [\r\n                              {\r\n                                \"expr\": \"self\",\r\n                                \"star\": true\r\n                              }\r\n                            ]\r\n                          }\r\n                        ]\r\n                      }\r\n                    }\r\n                  ]\r\n                },\r\n                {\r\n                  \"#operator\": \"Limit\",\r\n                  \"expr\": \"1\",\r\n                  \"optimizer_estimates\": {\r\n                    \"cardinality\": 1,\r\n                    \"cost\": 25.51560885530435,\r\n                    \"fr_cost\": 25.51560885530435,\r\n                    \"size\": 669\r\n                  }\r\n                }\r\n              ]\r\n            },\r\n            {\r\n              \"#operator\": \"Stream\",\r\n              \"optimizer_estimates\": {\r\n                \"cardinality\": 1,\r\n                \"cost\": 25.51560885530435,\r\n                \"fr_cost\": 25.51560885530435,\r\n                \"size\": 669\r\n              },\r\n              \"serializable\": true\r\n            }\r\n          ]\r\n        }\r\n      },\r\n      \"statement\": \"SELECT * FROM default:`travel-sample` LIMIT 1 ;\"\r\n    }\r\n  ]\r\n}<\/pre>\n<h3>Constraints<\/h3>\n<p><span style=\"font-weight: 400;\">If the N1QL() function has been aliased in a JavaScript function definition, EXPLAIN FUNCTION will not be able to return the line numbers where this aliased function was called. For example:<\/span><\/p>\n<pre class=\"lang:js decode:true\">function js3() {\r\n  var alias = N1QL;\r\n  var q = alias(\"SELECT 1\");\r\n}<\/pre>\n<p><span style=\"font-weight: 400;\">If the UDF contains nested UDF executions, EXPLAIN FUNCTION does not support generating the query plans of SQL++ statements within these nested UDFs.<\/span><\/p>\n<h2>Summary<\/h2>\n<p>Couchbase 7.6 introduces new features for UDF debuggability which will help users peek into UDF execution easily.<\/p>\n<p>Reference the following documentation links to learn more, or check out the other Couchbase 7.6 innovations:<\/p>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/couchbase-server-7-6-top-developer-features\/\">Couchbase Server 7.6 Features That Developers Will Love<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/userfun.html\">User Defined Functions<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/createfunction.html#create-function-inline\"> Inline UDFs<\/a><\/li>\n<li><span style=\"font-weight: 400;\"><a href=\"https:\/\/docs.couchbase.com\/server\/current\/javascript-udfs\/javascript-functions-with-couchbase.html\">A guide to JavaScript UDFs<\/a><\/span><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/createfunction.html#create-function-external\">Creating an external UDF<\/a><\/li>\n<li><a href=\"https:\/\/www.couchbase.com\/blog\/from-n1ql-to-javascript-and-back-part-1-introduction\/\">Blog series on JavaScript UDFs<\/a><\/li>\n<li><a href=\"https:\/\/docs.couchbase.com\/server\/current\/n1ql\/n1ql-language-reference\/explain.html\">Couchbase SQL++ EXPLAIN statement<\/a><\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>User-defined functions (UDFs) are a very useful feature supported in SQL++.\u00a0Couchbase 7.6 introduces improvements that allow for more debuggability and visibility into UDF execution. This blog will explore two new features in Couchbase 7.6 in the world of UDFs. Profiling [&hellip;]<\/p>\n","protected":false},"author":85183,"featured_media":15569,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1815,1816,10133,9327,1812],"tags":[9945,9949,1854,8911],"ppma_author":[9950],"class_list":["post-15566","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-best-practices-and-tutorials","category-couchbase-server","category-engineering","category-javascript","category-n1ql-query","tag-couchbase-7-6","tag-debug","tag-profiling","tag-udf"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v26.0 (Yoast SEO v26.0) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Debuggability for SQL++ UDFs Improved in Couchbase 7.6<\/title>\n<meta name=\"description\" content=\"Couchbase 7.6 introduces new features to debug user-defined functions (UDFs) which will help users peek into execution easily. Learn about them 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.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Improved Debuggability for SQL++ User-Defined Functions\" \/>\n<meta property=\"og:description\" content=\"Couchbase 7.6 introduces new features to debug user-defined functions (UDFs) which will help users peek into execution easily. Learn about them here.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2024-04-05T16:33:32+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-07-08T16:15:58+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/Screenshot-2024-04-05-at-10.36.07\u202fAM.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2868\" \/>\n\t<meta property=\"og:image:height\" content=\"1574\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Dhanya Gowrish, Software Engineer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dhanya Gowrish, Software Engineer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/\"},\"author\":{\"name\":\"Dhanya Gowrish, Software Engineer\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/1515ea2da3d43fe576990a63041fbd73\"},\"headline\":\"Improved Debuggability for SQL++ User-Defined Functions\",\"datePublished\":\"2024-04-05T16:33:32+00:00\",\"dateModified\":\"2025-07-08T16:15:58+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/\"},\"wordCount\":1081,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/Screenshot-2024-04-05-at-10.36.07\u202fAM.png\",\"keywords\":[\"Couchbase 7.6\",\"debug\",\"profiling\",\"User Defined Function (UDF)\"],\"articleSection\":[\"Best Practices and Tutorials\",\"Couchbase Server\",\"Engineering\",\"JavaScript\",\"SQL++ \/ N1QL Query\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/\",\"name\":\"Debuggability for SQL++ UDFs Improved in Couchbase 7.6\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/Screenshot-2024-04-05-at-10.36.07\u202fAM.png\",\"datePublished\":\"2024-04-05T16:33:32+00:00\",\"dateModified\":\"2025-07-08T16:15:58+00:00\",\"description\":\"Couchbase 7.6 introduces new features to debug user-defined functions (UDFs) which will help users peek into execution easily. Learn about them here.\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/Screenshot-2024-04-05-at-10.36.07\u202fAM.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/Screenshot-2024-04-05-at-10.36.07\u202fAM.png\",\"width\":2868,\"height\":1574},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Improved Debuggability for SQL++ User-Defined Functions\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/1515ea2da3d43fe576990a63041fbd73\",\"name\":\"Dhanya Gowrish, Software Engineer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/e3bcefcd291385aabb0a1a9135722c59\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/dhanyagowrish-couchbase.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/dhanyagowrish-couchbase.png\",\"caption\":\"Dhanya Gowrish, Software Engineer\"},\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/dhanyagowrish\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Debuggability for SQL++ UDFs Improved in Couchbase 7.6","description":"Couchbase 7.6 introduces new features to debug user-defined functions (UDFs) which will help users peek into execution easily. Learn about them 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.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/","og_locale":"en_US","og_type":"article","og_title":"Improved Debuggability for SQL++ User-Defined Functions","og_description":"Couchbase 7.6 introduces new features to debug user-defined functions (UDFs) which will help users peek into execution easily. Learn about them here.","og_url":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/","og_site_name":"The Couchbase Blog","article_published_time":"2024-04-05T16:33:32+00:00","article_modified_time":"2025-07-08T16:15:58+00:00","og_image":[{"width":2868,"height":1574,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/Screenshot-2024-04-05-at-10.36.07\u202fAM.png","type":"image\/png"}],"author":"Dhanya Gowrish, Software Engineer","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Dhanya Gowrish, Software Engineer","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/"},"author":{"name":"Dhanya Gowrish, Software Engineer","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/1515ea2da3d43fe576990a63041fbd73"},"headline":"Improved Debuggability for SQL++ User-Defined Functions","datePublished":"2024-04-05T16:33:32+00:00","dateModified":"2025-07-08T16:15:58+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/"},"wordCount":1081,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/Screenshot-2024-04-05-at-10.36.07\u202fAM.png","keywords":["Couchbase 7.6","debug","profiling","User Defined Function (UDF)"],"articleSection":["Best Practices and Tutorials","Couchbase Server","Engineering","JavaScript","SQL++ \/ N1QL Query"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/","url":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/","name":"Debuggability for SQL++ UDFs Improved in Couchbase 7.6","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/Screenshot-2024-04-05-at-10.36.07\u202fAM.png","datePublished":"2024-04-05T16:33:32+00:00","dateModified":"2025-07-08T16:15:58+00:00","description":"Couchbase 7.6 introduces new features to debug user-defined functions (UDFs) which will help users peek into execution easily. Learn about them here.","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/Screenshot-2024-04-05-at-10.36.07\u202fAM.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/Screenshot-2024-04-05-at-10.36.07\u202fAM.png","width":2868,"height":1574},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/improved-debuggability-for-sql-user-defined-functions\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Improved Debuggability for SQL++ User-Defined Functions"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/1515ea2da3d43fe576990a63041fbd73","name":"Dhanya Gowrish, Software Engineer","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/e3bcefcd291385aabb0a1a9135722c59","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/dhanyagowrish-couchbase.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/dhanyagowrish-couchbase.png","caption":"Dhanya Gowrish, Software Engineer"},"url":"https:\/\/www.couchbase.com\/blog\/author\/dhanyagowrish\/"}]}},"authors":[{"term_id":9950,"user_id":85183,"is_guest":0,"slug":"dhanyagowrish","display_name":"Dhanya Gowrish, Software Engineer","avatar_url":{"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/dhanyagowrish-couchbase.png","url2x":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2024\/04\/dhanyagowrish-couchbase.png"},"author_category":"","last_name":"Gowrish, Software Engineer","first_name":"Dhanya","job_title":"","user_url":"","description":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/15566","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/85183"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=15566"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/15566\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/15569"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=15566"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=15566"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=15566"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=15566"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}