Skip to content

OSPP 2024: Improve pg_get_functiondef#684

Merged
gaoxueyu merged 12 commits intoIvorySQL:masterfrom
Iam-WenYi:master
Aug 26, 2024
Merged

OSPP 2024: Improve pg_get_functiondef#684
gaoxueyu merged 12 commits intoIvorySQL:masterfrom
Iam-WenYi:master

Conversation

@Iam-WenYi
Copy link
Copy Markdown
Contributor

@Iam-WenYi Iam-WenYi commented Aug 16, 2024

在既有 pg_get_functiondef 函数的基础上,增强了其功能:

  • 允许输入多个 oid 以导出不同的函数定义
  • 允许根据函数名称导出函数定义,且支持多个不同的函数名称,同一个函数名称对应不同实现的导出

image
image
image
image

Summary by CodeRabbit

  • New Features

    • Introduced the pg_get_functiondef extension for retrieving PostgreSQL function definitions.
    • Added three functions: pg_get_functiondef(), pg_get_functiondef(OID, VARIADIC OID[]), and pg_get_functiondef(VARIADIC TEXT[]) for enhanced function introspection.
    • Introduced the pg_get_functiondef_extend function, allowing users to retrieve function definitions based on an array of function names.
    • Added the pg_get_functiondef_mul function for retrieving definitions of multiple functions based on their OIDs.
    • Included regression testing capabilities for the new extension.
  • Bug Fixes

    • Implemented error handling for cases with insufficient input parameters in the pg_get_functiondef_no_input function.
  • Documentation

    • Added SQL usage examples to demonstrate the functionality of the pg_get_functiondef extension.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Aug 16, 2024

Walkthrough

The recent changes introduce the pg_get_functiondef extension to PostgreSQL, enhancing its capabilities for retrieving function definitions. This extension includes new SQL functions, control files, and Makefiles for seamless building and installation, allowing developers to introspect PostgreSQL functions more effectively and flexibly.

Changes

File(s) Change Summary
contrib/Makefile Added pg_get_functiondef to the SUBDIRS variable to include the new module in the build process.
contrib/pg_get_functiondef/Makefile, contrib/pg_get_functiondef/control, contrib/pg_get_functiondef/*.c, contrib/pg_get_functiondef/*.sql Introduced a new Makefile, control file, and source files to implement the pg_get_functiondef extension, defining multiple functions for retrieving function definitions.
contrib/pg_get_functiondef/pg_get_functiondef--1.0.sql Created SQL file to define and demonstrate usage of new functions, including creating and dropping the pg_get_functiondef extension with example queries.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant PostgreSQL
    participant pg_get_functiondef

    User->>PostgreSQL: Call pg_get_functiondef()
    PostgreSQL->>pg_get_functiondef: Retrieve function definition
    pg_get_functiondef-->>PostgreSQL: Return function definition
    PostgreSQL-->>User: Display function definition
Loading

🐇 In a database so vast and bright,
New functions spring with pure delight.
With pg_get_functiondef, we find our way,
Fetching definitions without delay!
A hop, a jump, through code we weave,
PostgreSQL’s magic, we gladly believe! 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Outside diff range, codebase verification and nitpick comments (3)
contrib/pg_get_functiondef/pg_get_functiondef_extend.c (1)

34-63: Correct Typo in Function Name and Comments.

The function name DescibleFunctionByName should be corrected to DescribeFunctionByName. Similarly, update comments to reflect the correct spelling.

- char *DescibleFunctionByName(char *function_name);
- char *DescibleFunctionByName(char *function_name)
+ char *DescribeFunctionByName(char *function_name);
+ char *DescribeFunctionByName(char *function_name)
contrib/pg_get_functiondef/pg_get_functiondef_mul.c (2)

1-4: Improve header comments for clarity.

The header comments could be more descriptive to better explain the purpose and functionality of the file.

/*
    pg_get_functiondef_mul.c
-   The achieve of pg_get_functiondef(oid, oid, ...)
+   Implementation of pg_get_functiondef_mul to retrieve function definitions for multiple OIDs.
*/

61-68: Potential Memory Leak in OID Handling

The code in pg_get_functiondef_mul.c does not appear to handle memory deallocation for info->oids in all error cases. While pfree(info->oids) is called when the cursor exceeds the count, it is not clear if this is handled in case of errors elsewhere in the function. Consider adding explicit memory cleanup for info->oids in all error paths to prevent memory leaks.

  • Ensure info->oids is freed in all error scenarios, especially before any ereport(ERROR, ...) calls.
Analysis chain

Check for potential memory leaks in OID handling.

Ensure that the memory allocated for oids is properly freed in case of an error before the function exits.

Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for memory leaks related to OID handling in the function.

# Test: Ensure that memory allocated for OIDs is freed in case of errors.
rg --type c -A 5 'pfree(info->oids)' 

Length of output: 38


Script:

#!/bin/bash
# Find the function containing the specified code snippet to check for memory management practices.
ast-grep --lang c --pattern $'{
  /* Get user input, store to oids[] */
  deconstruct_array_builtin((ArrayType *)oids_array, OIDOID, &oids, NULL, &count);
  info->oids = palloc((count + 1) * sizeof(Oid));
  info->oids[0] = PG_GETARG_OID(0);
  for (int i = 1; i <= count; i++)
  {
    info->oids[i] = DatumGetObjectId(oids[i - 1]);
  }
}' -A 20

Length of output: 344


Script:

#!/bin/bash
# Search for the function using deconstruct_array_builtin to identify the function handling OIDs.
rg --type c -A 20 'deconstruct_array_builtin'

Length of output: 78445


Script:

#!/bin/bash
# Search for memory context management functions in pg_get_functiondef_mul.c to check for cleanup mechanisms.
rg --type c 'MemoryContext|pfree|reset' contrib/pg_get_functiondef/pg_get_functiondef_mul.c -A 10 -B 10

Length of output: 1320

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between fa4c4cf and c5f4c83.

Files ignored due to path filters (1)
  • contrib/pg_get_functiondef/expected/pg_get_functiondef.out is excluded by !**/*.out
Files selected for processing (8)
  • contrib/Makefile (1 hunks)
  • contrib/pg_get_functiondef/Makefile (1 hunks)
  • contrib/pg_get_functiondef/pg_get_functiondef--1.0.sql (1 hunks)
  • contrib/pg_get_functiondef/pg_get_functiondef.control (1 hunks)
  • contrib/pg_get_functiondef/pg_get_functiondef_extend.c (1 hunks)
  • contrib/pg_get_functiondef/pg_get_functiondef_mul.c (1 hunks)
  • contrib/pg_get_functiondef/pg_get_functiondef_no_input.c (1 hunks)
  • contrib/pg_get_functiondef/sql/pg_get_functiondef.sql (1 hunks)
Files skipped from review due to trivial changes (1)
  • contrib/pg_get_functiondef/pg_get_functiondef.control
Additional comments not posted (8)
contrib/pg_get_functiondef/sql/pg_get_functiondef.sql (1)

1-12: SQL commands are well-structured.

The SQL commands effectively test the new functionality of handling multiple OIDs and function names. They cover various scenarios, ensuring robustness.

contrib/pg_get_functiondef/pg_get_functiondef--1.0.sql (1)

3-13: SQL function definitions are correctly implemented.

The SQL functions are well-defined to interface with their respective C implementations, allowing for flexible input handling.

contrib/pg_get_functiondef/pg_get_functiondef_no_input.c (1)

13-24: C function implementation is correct.

The function correctly handles the case where no arguments are provided, using ereport to generate a detailed error message.

contrib/pg_get_functiondef/Makefile (1)

1-26: Makefile Setup Looks Good.

The Makefile is well-structured and follows standard practices for PostgreSQL extensions. It includes necessary variables and conditional PGXS logic for building the pg_get_functiondef module.

contrib/pg_get_functiondef/pg_get_functiondef_mul.c (3)

17-28: Struct and function declaration are well-defined.

The FunctionInfoData struct and the PG_FUNCTION_INFO_V1 macro are correctly used for storing function information and declaring the PostgreSQL function.


93-97: Cleanup logic is well-implemented.

The function correctly frees allocated resources and handles the end of the result set.


101-123: Verify memory management during tuple construction.

Ensure that all allocated memory for tuple_values and its elements is properly freed to prevent memory leaks.

contrib/Makefile (1)

36-36: Addition of pg_get_functiondef to build process.

The pg_get_functiondef directory has been successfully added to the SUBDIRS list, indicating its inclusion in the build process. Ensure that the directory contains the necessary files for successful compilation and integration.

Comment on lines +43 to +47
if (SPI_OK_CONNECT != SPI_connect())
{
ereport(ERROR, errmsg("SPI connect failed!"));
PG_RETURN_NULL();
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper error handling for SPI connection.

The error handling for SPI_connect is minimal. Consider adding more context to the error message or handling specific error codes.

ereport(ERROR, (errmsg("SPI connect failed: %s", SPI_result_code_string(SPI_result))));

Comment on lines +72 to +78
appendStringInfo(&query, "SELECT ");
appendStringInfo(&query, "pg_get_functiondef(%d)", info->oids[0]);
for (int i = 1; i < count; i++)
{
appendStringInfo(&query, ", pg_get_functiondef(%d)", info->oids[i]);
}
appendStringInfo(&query, ", pg_get_functiondef(%d);", info->oids[info->count - 1]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimize query construction for readability.

The query construction could be simplified for better readability and maintainability.

appendStringInfo(&query, "SELECT pg_get_functiondef(%d)", info->oids[0]);
for (int i = 1; i < info->count; i++)
{
    appendStringInfo(&query, ", pg_get_functiondef(%d)", info->oids[i]);
}
appendStringInfoChar(&query, ';');

Comment on lines +67 to +125
Datum pg_get_functiondef_extend(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx = NULL;
FunctionInfo info = NULL;

if (SRF_IS_FIRSTCALL())
{
ArrayType *arguments_raw;
int count_of_arguments;
Datum *arguments;
MemoryContext old_context;

funcctx = SRF_FIRSTCALL_INIT();
old_context = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);

arguments_raw = PG_GETARG_ARRAYTYPE_P(0);
deconstruct_array_builtin((ArrayType *)arguments_raw, TEXTOID, &arguments, NULL, &count_of_arguments);

info = (FunctionInfo)palloc0(sizeof(struct FunctionInfoData));
funcctx->user_fctx = info;

info->function_name = palloc0(count_of_arguments * sizeof(char *));
for (int i = 0; i < count_of_arguments; i++)
{
info->function_name[i] = text_to_cstring((text *)arguments[i]);
}

info->cursor = 0;
info->count_of_arguments = count_of_arguments;

if (get_call_result_type(fcinfo, NULL, &info->result_desc) != TYPEFUNC_COMPOSITE)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context that cannot accept type record")));
}
info->result_tuple_meta = TupleDescGetAttInMetadata(info->result_desc);
MemoryContextSwitchTo(old_context);
}

funcctx = SRF_PERCALL_SETUP();
info = (FunctionInfo)(funcctx->user_fctx);

if (info->cursor == info->count_of_arguments)
{
SRF_RETURN_DONE(funcctx);
}
else
{
HeapTuple tuple;
Datum tuple_return;
char **values;
values = palloc0(sizeof(char *) * 2);
values[0] = pstrdup(info->function_name[info->cursor]);
values[1] = DescibleFunctionByName(info->function_name[info->cursor]);
info->cursor++;
tuple = BuildTupleFromCStrings(info->result_tuple_meta, values);
tuple_return = HeapTupleGetDatum(tuple);
SRF_RETURN_NEXT(funcctx, tuple_return);
}
PG_RETURN_NULL();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct Function Call to DescribeFunctionByName.

Update the call to the function within pg_get_functiondef_extend to use the corrected function name DescribeFunctionByName.

- values[1] = DescibleFunctionByName(info->function_name[info->cursor]);
+ values[1] = DescribeFunctionByName(info->function_name[info->cursor]);
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Datum pg_get_functiondef_extend(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx = NULL;
FunctionInfo info = NULL;
if (SRF_IS_FIRSTCALL())
{
ArrayType *arguments_raw;
int count_of_arguments;
Datum *arguments;
MemoryContext old_context;
funcctx = SRF_FIRSTCALL_INIT();
old_context = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
arguments_raw = PG_GETARG_ARRAYTYPE_P(0);
deconstruct_array_builtin((ArrayType *)arguments_raw, TEXTOID, &arguments, NULL, &count_of_arguments);
info = (FunctionInfo)palloc0(sizeof(struct FunctionInfoData));
funcctx->user_fctx = info;
info->function_name = palloc0(count_of_arguments * sizeof(char *));
for (int i = 0; i < count_of_arguments; i++)
{
info->function_name[i] = text_to_cstring((text *)arguments[i]);
}
info->cursor = 0;
info->count_of_arguments = count_of_arguments;
if (get_call_result_type(fcinfo, NULL, &info->result_desc) != TYPEFUNC_COMPOSITE)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context that cannot accept type record")));
}
info->result_tuple_meta = TupleDescGetAttInMetadata(info->result_desc);
MemoryContextSwitchTo(old_context);
}
funcctx = SRF_PERCALL_SETUP();
info = (FunctionInfo)(funcctx->user_fctx);
if (info->cursor == info->count_of_arguments)
{
SRF_RETURN_DONE(funcctx);
}
else
{
HeapTuple tuple;
Datum tuple_return;
char **values;
values = palloc0(sizeof(char *) * 2);
values[0] = pstrdup(info->function_name[info->cursor]);
values[1] = DescibleFunctionByName(info->function_name[info->cursor]);
info->cursor++;
tuple = BuildTupleFromCStrings(info->result_tuple_meta, values);
tuple_return = HeapTupleGetDatum(tuple);
SRF_RETURN_NEXT(funcctx, tuple_return);
}
PG_RETURN_NULL();
Datum pg_get_functiondef_extend(PG_FUNCTION_ARGS)
{
FuncCallContext *funcctx = NULL;
FunctionInfo info = NULL;
if (SRF_IS_FIRSTCALL())
{
ArrayType *arguments_raw;
int count_of_arguments;
Datum *arguments;
MemoryContext old_context;
funcctx = SRF_FIRSTCALL_INIT();
old_context = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
arguments_raw = PG_GETARG_ARRAYTYPE_P(0);
deconstruct_array_builtin((ArrayType *)arguments_raw, TEXTOID, &arguments, NULL, &count_of_arguments);
info = (FunctionInfo)palloc0(sizeof(struct FunctionInfoData));
funcctx->user_fctx = info;
info->function_name = palloc0(count_of_arguments * sizeof(char *));
for (int i = 0; i < count_of_arguments; i++)
{
info->function_name[i] = text_to_cstring((text *)arguments[i]);
}
info->cursor = 0;
info->count_of_arguments = count_of_arguments;
if (get_call_result_type(fcinfo, NULL, &info->result_desc) != TYPEFUNC_COMPOSITE)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context that cannot accept type record")));
}
info->result_tuple_meta = TupleDescGetAttInMetadata(info->result_desc);
MemoryContextSwitchTo(old_context);
}
funcctx = SRF_PERCALL_SETUP();
info = (FunctionInfo)(funcctx->user_fctx);
if (info->cursor == info->count_of_arguments)
{
SRF_RETURN_DONE(funcctx);
}
else
{
HeapTuple tuple;
Datum tuple_return;
char **values;
values = palloc0(sizeof(char *) * 2);
values[0] = pstrdup(info->function_name[info->cursor]);
values[1] = DescribeFunctionByName(info->function_name[info->cursor]);
info->cursor++;
tuple = BuildTupleFromCStrings(info->result_tuple_meta, values);
tuple_return = HeapTupleGetDatum(tuple);
SRF_RETURN_NEXT(funcctx, tuple_return);
}
PG_RETURN_NULL();

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between c5f4c83 and 6751b4c.

Files ignored due to path filters (1)
  • contrib/pg_get_functiondef/expected/pg_get_functiondef.out is excluded by !**/*.out
Files selected for processing (3)
  • contrib/pg_get_functiondef/pg_get_functiondef_extend.c (1 hunks)
  • contrib/pg_get_functiondef/pg_get_functiondef_mul.c (1 hunks)
  • contrib/pg_get_functiondef/sql/pg_get_functiondef.sql (1 hunks)
Files skipped from review due to trivial changes (1)
  • contrib/pg_get_functiondef/sql/pg_get_functiondef.sql
Files skipped from review as they are similar to previous changes (2)
  • contrib/pg_get_functiondef/pg_get_functiondef_extend.c
  • contrib/pg_get_functiondef/pg_get_functiondef_mul.c

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 6751b4c and 1a1b146.

Files selected for processing (1)
  • contrib/pg_get_functiondef/pg_get_functiondef_extend.c (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • contrib/pg_get_functiondef/pg_get_functiondef_extend.c

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Outside diff range, codebase verification and nitpick comments (1)
contrib/pg_get_functiondef/pg_get_functiondef_mul.c (1)

1-4: Enhance the file header for clarity.

Consider adding more details about the purpose and usage of the pg_get_functiondef_mul function in the file header.

/*
    pg_get_functiondef_mul.c
    Implementation of pg_get_functiondef_mul, which retrieves function definitions
    for multiple OIDs or function names simultaneously in PostgreSQL.
*/
Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 1a1b146 and f70b795.

Files selected for processing (1)
  • contrib/pg_get_functiondef/pg_get_functiondef_mul.c (1 hunks)
Additional comments not posted (6)
contrib/pg_get_functiondef/pg_get_functiondef_mul.c (6)

17-26: Struct definition is well-organized.

The FunctionInfoData struct is clear and encapsulates the necessary data for function execution.


28-28: Function declaration is correct.

The use of PG_FUNCTION_INFO_V1 for pg_get_functiondef_mul is appropriate and follows PostgreSQL conventions.


43-47: Ensure proper error handling for SPI connection.

The error handling for SPI_connect is minimal. Consider adding more context to the error message or handling specific error codes.


74-79: Optimize query construction for readability.

The query construction could be simplified for better readability and maintainability.


92-99: Ensure proper cleanup on function completion.

While the function correctly cleans up resources, ensure that all allocated memory and resources are freed, especially if additional allocations are added in the future.


63-70: Check for NULL in deconstruct_array_builtin.

Ensure that the deconstruct_array_builtin function handles NULL values appropriately for oids and other parameters.

Verification successful

NULL Handling in deconstruct_array_builtin is Appropriate

The deconstruct_array_builtin function relies on deconstruct_array for NULL handling, which appropriately manages NULL pointers for its parameters. Therefore, the current implementation is correct.

  • deconstruct_array checks for NULL array elements and handles the nullsp parameter correctly.
Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that deconstruct_array_builtin handles NULL values correctly.

# Test: Search for the function usage. Expect: Proper NULL handling in the code.
rg --type c -A 5 $'deconstruct_array_builtin'

Length of output: 24828


Script:

#!/bin/bash
# Extract the implementation of deconstruct_array_builtin from arrayfuncs.c to verify NULL handling.
ast-grep --lang c --pattern $'void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp) {
  $$$
}' --json

Length of output: 3289


Script:

#!/bin/bash
# Extract the implementation of deconstruct_array to verify NULL handling.
ast-grep --lang c --pattern $'void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp) {
  $$$
}' --json

Length of output: 3447

Comment on lines +53 to +59
/* If can't return composite type, end the work */
if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("function returning record called in context that cannot accept type record")));
SPI_finish();
SRF_RETURN_DONE(funcctx);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improve error handling for composite type check.

The error message when the function cannot return a composite type is generic. Consider providing more context or suggestions for resolving the issue.

ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
    errmsg("Function returning record called in a context that cannot accept type record. Ensure the function is called in a suitable context.")));

Comment on lines +81 to +85
{
ereport(ERROR, errmsg("SPI select failed!"));
SPI_finish();
PG_RETURN_NULL();
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enhance error handling for SPI_execute.

The error handling for SPI_execute is minimal. Consider adding more context to the error message or handling specific error codes.

ereport(ERROR, (errmsg("SPI select failed: %s", SPI_result_code_string(SPI_result))));

Comment on lines +102 to +125
char **tuple_values;
HeapTuple tuple;
Datum tuple_return;
char *record = SPI_getvalue(info->spi_table->vals[0], info->spi_table->tupdesc, info->cursor);
tuple_values = palloc(2 * sizeof(char *));
tuple_values[0] = palloc(sizeof(char) * 16);
sprintf(tuple_values[0], "%d", info->oids[info->cursor - 1]);
if (record)
{
tuple_values[1] = palloc(sizeof(char) * (strlen(record) + 1));
sprintf(tuple_values[1], "%s", record);
}
else
{
tuple_values[1] = palloc(sizeof(char) * 1);
memset(tuple_values[1], 0, sizeof(char));
}
tuple = BuildTupleFromCStrings(info->result_tuple_meta, tuple_values);
info->cursor += 1;
tuple_return = HeapTupleGetDatum(tuple);
pfree(tuple_values[0]);
pfree(tuple_values[1]);
pfree(tuple_values);
SRF_RETURN_NEXT(funcctx, tuple_return);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optimize memory allocation for tuple values.

Consider using palloc0 for initializing tuple_values to zero, which can prevent potential issues with uninitialized memory.

-  tuple_values = palloc(2 * sizeof(char *));
+  tuple_values = palloc0(2 * sizeof(char *));
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
char **tuple_values;
HeapTuple tuple;
Datum tuple_return;
char *record = SPI_getvalue(info->spi_table->vals[0], info->spi_table->tupdesc, info->cursor);
tuple_values = palloc(2 * sizeof(char *));
tuple_values[0] = palloc(sizeof(char) * 16);
sprintf(tuple_values[0], "%d", info->oids[info->cursor - 1]);
if (record)
{
tuple_values[1] = palloc(sizeof(char) * (strlen(record) + 1));
sprintf(tuple_values[1], "%s", record);
}
else
{
tuple_values[1] = palloc(sizeof(char) * 1);
memset(tuple_values[1], 0, sizeof(char));
}
tuple = BuildTupleFromCStrings(info->result_tuple_meta, tuple_values);
info->cursor += 1;
tuple_return = HeapTupleGetDatum(tuple);
pfree(tuple_values[0]);
pfree(tuple_values[1]);
pfree(tuple_values);
SRF_RETURN_NEXT(funcctx, tuple_return);
char **tuple_values;
HeapTuple tuple;
Datum tuple_return;
char *record = SPI_getvalue(info->spi_table->vals[0], info->spi_table->tupdesc, info->cursor);
tuple_values = palloc0(2 * sizeof(char *));
tuple_values[0] = palloc(sizeof(char) * 16);
sprintf(tuple_values[0], "%d", info->oids[info->cursor - 1]);
if (record)
{
tuple_values[1] = palloc(sizeof(char) * (strlen(record) + 1));
sprintf(tuple_values[1], "%s", record);
}
else
{
tuple_values[1] = palloc(sizeof(char) * 1);
memset(tuple_values[1], 0, sizeof(char));
}
tuple = BuildTupleFromCStrings(info->result_tuple_meta, tuple_values);
info->cursor += 1;
tuple_return = HeapTupleGetDatum(tuple);
pfree(tuple_values[0]);
pfree(tuple_values[1]);
pfree(tuple_values);
SRF_RETURN_NEXT(funcctx, tuple_return);

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between f70b795 and 7f46d44.

Files ignored due to path filters (1)
  • contrib/pg_get_functiondef/expected/pg_get_functiondef_1.out is excluded by !**/*.out
Files selected for processing (1)
  • contrib/pg_get_functiondef/pg_get_functiondef_mul.c (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • contrib/pg_get_functiondef/pg_get_functiondef_mul.c

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 7f46d44 and 354927c.

Files ignored due to path filters (2)
  • contrib/pg_get_functiondef/expected/pg_get_functiondef.out is excluded by !**/*.out
  • contrib/pg_get_functiondef/expected/pg_get_functiondef_1.out is excluded by !**/*.out
Files selected for processing (2)
  • contrib/pg_get_functiondef/pg_get_functiondef_no_input.c (1 hunks)
  • contrib/pg_get_functiondef/sql/pg_get_functiondef.sql (1 hunks)
Files skipped from review due to trivial changes (2)
  • contrib/pg_get_functiondef/pg_get_functiondef_no_input.c
  • contrib/pg_get_functiondef/sql/pg_get_functiondef.sql

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between 354927c and 3672923.

Files selected for processing (1)
  • contrib/pg_get_functiondef/pg_get_functiondef_extend.c (1 hunks)
Files skipped from review as they are similar to previous changes (1)
  • contrib/pg_get_functiondef/pg_get_functiondef_extend.c

@gaoxueyu gaoxueyu added the Community Community Supported Feature label Aug 26, 2024
@gaoxueyu gaoxueyu merged commit b329d7c into IvorySQL:master Aug 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Community Community Supported Feature

Projects

No open projects
Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants