Skip to content

IvorySQL:Optimize the VARIABLE and PRINT command codes#846

Merged
gaoxueyu merged 1 commit intoIvorySQL:masterfrom
jiaoshuntian:variable_refactor
Sep 17, 2025
Merged

IvorySQL:Optimize the VARIABLE and PRINT command codes#846
gaoxueyu merged 1 commit intoIvorySQL:masterfrom
jiaoshuntian:variable_refactor

Conversation

@jiaoshuntian
Copy link
Copy Markdown
Collaborator

@jiaoshuntian jiaoshuntian commented Aug 8, 2025

Summary by CodeRabbit

  • Refactor

    • Improved code clarity and maintainability for Oracle compatibility features in the interactive terminal, including enhanced comments, reorganization, and formatting updates.
    • Updated header files and internal documentation to clarify the distinction between PostgreSQL and Oracle-style variables and commands.
    • Replaced manual character checks with standard library functions for variable name validation.
    • No user-facing behavior or functionality has changed.
  • Style

    • Enhanced and standardized comments throughout code and headers for better readability and understanding.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Aug 8, 2025

Walkthrough

This change refactors and clarifies Oracle-compatible client command handling in the psql interactive terminal and related headers. It improves comments, reorganizes declarations, and enhances documentation for maintainability. Minor code changes include using isalpha for bind variable name validation and removing annotation comments. No functional logic or control flow is altered.

Changes

Cohort / File(s) Change Summary
Oracle Client Command Handling Refactor
src/bin/psql/mainloop.c
Refactored Oracle client command handling for clarity; improved comments, formatting, and code organization without changing logic.
Oracle-Compatible Scanner and Parser Header Improvements
src/bin/psql/psqlplus.h
Enhanced and reorganized comments, added macros and function declarations, clarified documentation, and removed redundant declarations.
Oracle-Compatible Parser Grammar Comment Update
src/bin/psql/psqlplusparse.y
Reworded a comment for clarity; no logic or structural changes.
Variable Handling and Validation Update
src/bin/psql/variables.c
Removed annotation comments and replaced manual character check with isalpha for bind variable name validation. No other logic changes.
Variable Struct and Enum Documentation
src/bin/psql/variables.h
Improved comments, introduced PsqlVarKind enum, and clarified struct field documentation. No functional changes.
Scanner Internal Structures Documentation
src/include/fe_utils/psqlscan_int.h
Added and clarified comments on enums and structs; fixed formatting and minor typos. No code logic changes.
Build File Cleanup
src/bin/psql/Makefile
Removed a single commented line; no build logic affected.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant PSQL Mainloop
    participant Oracle Scanner/Parser

    User->>PSQL Mainloop: Enter Oracle-compatible command
    PSQL Mainloop->>Oracle Scanner/Parser: Initialize scan state and scanner
    Oracle Scanner/Parser-->>PSQL Mainloop: Parse result (VARIABLE/PRINT/other)
    PSQL Mainloop->>PSQL Mainloop: Dispatch command based on parse result
    PSQL Mainloop->>Oracle Scanner/Parser: Cleanup scanner and state
    PSQL Mainloop-->>User: Output or error message
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~7 minutes

Possibly related PRs

  • IvorySQL/IvorySQL#805: Introduced the original Oracle-compatible "VARIABLE" and "PRINT" command support and parsing in the same files now being refactored and clarified.

Poem

In burrows deep where code does dwell,
A rabbit sharp refines the shell.
With comments clear and headers neat,
The Oracle paths are now complete.
No logic changed, just lines aligned—
A tidy warren, well-designed!
🐇✨

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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>, please review it.
    • Explain this complex logic.
    • 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 explain this code block.
  • 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 gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using 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 generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this 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.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

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: 2

🧹 Nitpick comments (7)
src/bin/psql/variables.c (1)

979-983: First-character check now locale-dependent – consider pg_isalpha for consistency

isalpha() is invoked on ASCII bytes to decide if the first char is a letter.
Although you guard with !IS_HIGHBIT_SET, behaviour of isalpha() still depends on the current locale, whereas the rest of the function uses an explicit ASCII whitelist for subsequent characters.
For complete locale-independence and consistency with the rest of the scan rules, prefer pg_isalpha() (or revert to the explicit ASCII table) instead of <ctype.h>’s isalpha().

src/bin/psql/mainloop.c (1)

485-514: Off-by-one risk when duplicating quotes

pg_malloc0(strlen(bind_var->init_value) * 2) can leave no room for
the terminating '\0' in the worst-case (input of length 1 produces
output length 1 plus NUL → need +1).
Allocate *2 + 1 to be safe:

- char *str_double_quote = pg_malloc0(strlen(bind_var->init_value) * 2);
+ char *str_double_quote = pg_malloc0(strlen(bind_var->init_value) * 2 + 1);
src/bin/psql/psqlplus.h (5)

23-27: Good rationale on keyword categories; consider preventing drift with grammar

These comments help future readers. To avoid divergence from psqlplusparse.y over time, consider generating the keyword tables from a single source (e.g., an X-macro .def file included by both the scanner and parser).


42-44: Prefer designated initializers for robustness

This avoids ordering mistakes if the struct changes later and improves readability.

Apply:

-/* Macro for defining keywords */
-#define PSQL_KEYWORD(name,value,category) {name,value,category},
+/* Macro for defining keywords (designated initializers for clarity) */
+#define PSQL_KEYWORD(name_, value_, category_) \
+	{ .name = (name_), .value = (value_), .category = (category_) },

49-53: OID docs — good; consider an explicit “FE-only” guard

Nice explanation. Optional: add a brief note that these defines must never be seen when including backend headers to avoid macro redefinition if someone accidentally includes pg_type_d.h in FE code.


63-66: Clarify units (bytes vs characters) for max lengths

Oracle’s limits depend on CHAR vs BYTE semantics. Consider noting whether these maxima are in characters, bytes, or dependent on NLS length semantics to prevent misinterpretation downstream.


83-86: Don’t define objects in headers; move callbacks to a .c/.l module

Defining a (file-scope) static in a header creates one copy per TU and can go stale. Prefer an extern declaration in the header and a single definition in the scanner module. Also consider zero-initialization instead of a “placeholder” element to avoid assumptions about struct shape.

Apply in header:

-/* Callback functions for the flex lexer */
-static const Ora_psqlScanCallbacks psqlplus_callbacks = {
-	NULL,	 /* placeholder for future callback functions */
-};
+/* Callback functions for the flex lexer (defined in psqlplus.l/.c) */
+extern const Ora_psqlScanCallbacks psqlplus_callbacks;

And define once (e.g., in psqlplus.l or a new psqlplus_callbacks.c):

const Ora_psqlScanCallbacks psqlplus_callbacks = { 0 };
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ffef63 and f53e62d.

📒 Files selected for processing (7)
  • src/bin/psql/Makefile (0 hunks)
  • src/bin/psql/mainloop.c (1 hunks)
  • src/bin/psql/psqlplus.h (3 hunks)
  • src/bin/psql/psqlplusparse.y (1 hunks)
  • src/bin/psql/variables.c (2 hunks)
  • src/bin/psql/variables.h (2 hunks)
  • src/include/fe_utils/psqlscan_int.h (3 hunks)
💤 Files with no reviewable changes (1)
  • src/bin/psql/Makefile
🔇 Additional comments (7)
src/bin/psql/psqlplusparse.y (1)

90-91: No functional change – comment wording looks good

Only wording updated; nothing to fix.

src/include/fe_utils/psqlscan_int.h (1)

88-95: Enum & struct comments improved – OK

Documentation-only edits; no action required.

src/bin/psql/variables.h (1)

85-95: Header refactor is comment-only – LGTM

Structural and naming comments add clarity without affecting ABI.

src/bin/psql/psqlplus.h (4)

6-6: Abstract clarification — LGTM

Clear and precise about Oracle compatibility. No issues.


32-40: Keyword struct docs — LGTM

Field docs are clear. Using int16 for token and category is fine given typical token ranges.


68-72: Scanner/parser interface grouping — LGTM

Forward-declaring YYSTYPE and grouping interfaces improves readability.


75-82: Confirm flex/bison entrypoint signatures

  • psqlplus_scanner_init, psqlplus_scanner_finish and psqlplus_yyerror in src/bin/psql/psqlplusscan.l match the declarations in src/bin/psql/psqlplus.h.
  • psqlplus_yyparse in mainloop.c lines 464–466 aligns with its header prototype.
  • The lexer function psqlplus_yylex is generated by flex—please ensure your %option prefix="psqlplus_yy" and bison-bridge (or equivalent) settings produce a definition matching
    extern int psqlplus_yylex(union YYSTYPE *lvalp, yyscan_t yyscanner);

Comment thread src/bin/psql/mainloop.c
Comment on lines +449 to +456
PsqlScanState pstate;
yyscan_t yyscanner;
char *psqlplus_line = pg_strdup(line); // Copy current input line for Oracle command processing

// Create and initialize Oracle compatibility mode scanning state
pstate = ora_psql_scan_create(&psqlplus_callbacks);
ora_psql_scan_setup(pstate, psqlplus_line,
strlen(psqlplus_line),
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.

⚠️ Potential issue

Undefined symbol psqlplus_callbacks – compilation will fail

pstate = ora_psql_scan_create(&psqlplus_callbacks);

psqlplus_callbacks is not declared anywhere in this TU (only Ora_psqlscan_callbacks exists above).
The build will break at link-time or compile-time depending on headers.

-    pstate = ora_psql_scan_create(&psqlplus_callbacks);
+    pstate = ora_psql_scan_create(&Ora_psqlscan_callbacks);
📝 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
PsqlScanState pstate;
yyscan_t yyscanner;
char *psqlplus_line = pg_strdup(line); // Copy current input line for Oracle command processing
// Create and initialize Oracle compatibility mode scanning state
pstate = ora_psql_scan_create(&psqlplus_callbacks);
ora_psql_scan_setup(pstate, psqlplus_line,
strlen(psqlplus_line),
PsqlScanState pstate;
yyscan_t yyscanner;
char *psqlplus_line = pg_strdup(line); // Copy current input line for Oracle command processing
// Create and initialize Oracle compatibility mode scanning state
- pstate = ora_psql_scan_create(&psqlplus_callbacks);
+ pstate = ora_psql_scan_create(&Ora_psqlscan_callbacks);
ora_psql_scan_setup(pstate, psqlplus_line,
strlen(psqlplus_line),
🤖 Prompt for AI Agents
In src/bin/psql/mainloop.c around lines 449 to 456, the symbol
psqlplus_callbacks is used but not declared, causing compilation errors. Replace
psqlplus_callbacks with the correctly declared symbol Ora_psqlscan_callbacks to
fix the undefined symbol issue and ensure successful compilation.

Comment thread src/bin/psql/psqlplus.h
Comment on lines +45 to 46
/* Macro to get extra data from yyscanner */
#define psql_yyget_extra(yyscanner) (*((PsqlScanStateData **) (yyscanner)))
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.

💡 Verification agent

🧩 Analysis chain

Verify yyscanner/extra layout; simplify macro to avoid aliasing surprises

This macro assumes yyscanner is actually a PsqlScanState* (i.e., a pointer to a PsqlScanState value), which is common in our psql scanner shim. If that assumption holds, the cast can be clearer and avoids referring to the concrete Data type.

Proposed change:

-/* Macro to get extra data from yyscanner */
-#define psql_yyget_extra(yyscanner) (*((PsqlScanStateData **) (yyscanner)))
+/* Macro to get extra data from yyscanner.
+ * Assumes yyscanner is a PsqlScanState* (see psqlplus_scanner_init). */
+#define psql_yyget_extra(yyscanner) (*(PsqlScanState *)(yyscanner))

If instead the scanner is a real Flex reentrant scanner, prefer using the generated accessor (e.g., psqlplus_yyget_extra(yyscanner)) rather than hard-coding layout.

To double-check current usage and definitions, you can run:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n -A2 -e 'typedef .* PsqlScanState;' fe_utils/psqlscan_int.h
rg -n -A3 -e 'psqlplus_scanner_init\\('
rg -n -A2 -e 'psqlplus_yyget_extra\\(|yyget_extra\\('

Length of output: 150


I couldn’t locate the typedef or initialization functions with the prior commands—let’s broaden the search across the repo:

This will confirm the actual types and usages so we can validate (or update) the macro safely.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the header defining PsqlScanState / PsqlScanStateData
fd -t f psqlscan_int.h

# Search for typedefs
rg -n -A2 'typedef.*PsqlScanState'
rg -n -A2 'typedef.*PsqlScanStateData'

# Find where the scanner is initialized
rg -n -A2 'psqlplus_scanner_init'

# Find any generated accessors
rg -n -A2 'psqlplus_yyget_extra'

Length of output: 2545


Let’s confirm what yyscan_t really is and how the scanner struct lays out its “extra” pointer:

This will tell us whether casting yyscan_t to a PsqlScanState * (vs. PsqlScanStateData **) is safe and compliant with strict-aliasing.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find how yyscan_t is defined
rg -n -A2 'typedef.*yyscan_t' -g '*.h'

# See any forward declarations of the guts struct
rg -n -A2 'struct.*yyguts_t' -g '*.h'

# Glimpse usage in psqlplus.h
rg -n -A2 'yyscan_t' src/bin/psql/psqlplus.h

Length of output: 1343


Simplify psql_yyget_extra macro to use the PsqlScanState alias

We’ve confirmed in src/include/fe_utils/psqlscan.h (and its Oracle mirror) that

typedef struct PsqlScanStateData *PsqlScanState;

and in src/include/fe_utils/psqlscan_int.h that

typedef void *yyscan_t;

No generated psqlplus_yyget_extra accessor exists, and the Flex reentrant scanner stores the user‐state pointer (PsqlScanStateData*) as its first field. We can therefore simplify the cast to avoid naming the Data type directly.

File: src/bin/psql/psqlplus.h
Lines: 45–46

-/* Macro to get extra data from yyscanner */
-#define psql_yyget_extra(yyscanner) (*((PsqlScanStateData **) (yyscanner)))
+/* Macro to get extra data from yyscanner.
+ * Assumes yyscanner is a PsqlScanState* (see psqlplus_scanner_init). */
+#define psql_yyget_extra(yyscanner) (*(PsqlScanState *)(yyscanner))

If in the future you switch to a “pure” Flex scanner, you can replace this with the generated psqlplus_yyget_extra(yyscanner) accessor instead.

🤖 Prompt for AI Agents
In src/bin/psql/psqlplus.h at lines 45-46, simplify the psql_yyget_extra macro
by casting yyscanner directly to the PsqlScanState type alias instead of
dereferencing to PsqlScanStateData*. Replace the current macro definition with
one that casts yyscanner to (PsqlScanState) to avoid referencing the Data struct
explicitly, aligning with the typedefs in psqlscan.h and psqlscan_int.h.

@gaoxueyu gaoxueyu merged commit b621866 into IvorySQL:master Sep 17, 2025
6 checks passed
@jiaoshuntian jiaoshuntian deleted the variable_refactor branch December 8, 2025 07:57
@coderabbitai coderabbitai bot mentioned this pull request Apr 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants