DBIO-MySQL

 view release on metacpan or  search on metacpan

lib/DBIO/MySQL/SQLMaker.pm  view on Meta::CPAN

  my ($target, $source, $attributes) = @_;

  my ($sql, @bind) = $self->next::method(@_);

  # Extract target table name for self-referencing detection
  my $target_name = $self->_extract_target_name($target);

  $sql = $self->_wrap_self_referencing_subquery($sql, $target_name) if $target_name;

  return ($sql, @bind);
}

sub delete {
  my $self = shift;
  my ($target, $source, $attributes) = @_;

  my ($sql, @bind) = $self->next::method(@_);

  # Extract target table name for self-referencing detection
  my $target_name = $self->_extract_target_name($target);

  $sql = $self->_wrap_self_referencing_subquery($sql, $target_name) if $target_name;

  return ($sql, @bind);
}

sub _extract_target_name {
  my ($self, $target) = @_;

  return unless defined $target;

  if (ref $target eq 'SCALAR') {
    if ($$target =~ /^ (?:
        \` ( [^`]+ ) \` #`
      | ( [\w\-]+ )
    ) $/x
    ) {
      return (defined $1) ? $1 : $2;
    }
    return; # complex scalar ref, can't deal
  }

  # For HASH refs (simple result source) or plain strings, return as-is
  return ref $target ? undef : $target;
}


#
# Support for MySQL lock clause syntax according to specification
# including updates introduced in MySQL 8.0.1)
# FOR UPDATE | FOR SHARE [OF tbl_name [, tbl_name] ...] [NOWAIT | SKIP LOCKED]
#

my $lock_types = {
  update => 'FOR UPDATE',
  share => 'FOR SHARE',
};

my $lock_modifiers = {
  nowait => 'NOWAIT',
  skip_locked => 'SKIP LOCKED'
};

sub _lock_select {
  my ($self, $type) = @_;

  # Handle hash-based configuration to support new featureset
  if (ref $type eq 'HASH') {
    my $lock_type = $type->{type};
    my $tables = $type->{of};
    my $modifier = $type->{modifier};

    my $lock_clause = $lock_types->{$lock_type}
      || $self->throw_exception("Unknown SELECT .. FOR type '$lock_type' requested");

    # Add OF clause if tables are specified
    if ($tables) {
      my @table_list = ref $tables eq 'ARRAY' ? @$tables : ($tables);
      if (@table_list) {
        my $quoted_tables = join(', ',
          map { $self->_quote($_) } @table_list
        );
        $lock_clause .= " OF $quoted_tables";
      }
    }

    # Add modifier if specified
    if ($modifier) {
      my $mod_sql = $lock_modifiers->{$modifier}
        || $self->throw_exception("Unknown lock modifier '$modifier' requested");
      $lock_clause .= " $mod_sql";
    }

    return " $lock_clause";
  }

  # Handle simple string types (for backward compatibility)
  my $sql = $lock_types->{$type}
    || $self->throw_exception("Unknown SELECT .. FOR type '$type' requested");

  return " $sql";
}


1;

__END__

=pod

=encoding UTF-8

=head1 NAME

DBIO::MySQL::SQLMaker - MySQL-specific SQL generation for DBIO

=head1 VERSION

version 0.900000

=head1 SYNOPSIS

lib/DBIO/MySQL/SQLMaker.pm  view on Meta::CPAN

MySQL-specific SQL generation layer for L<DBIO>. Extends L<DBIO::SQLMaker>
with the following MySQL adaptations:

=over 4

=item *

C<INSERT> with no columns emits C<INSERT INTO t () VALUES ()> instead of
the standard C<INSERT INTO t DEFAULT VALUES>, which MySQL does not support.

=item *

Supports C<STRAIGHT_JOIN> as a join type hint via the C<join_type> result
source attribute.

=item *

C<UPDATE> and C<DELETE> statements that reference the modification target
table in a subquery are automatically wrapped in a double subquery to work
around MySQL's restriction against self-referencing in DML.

=item *

Implements MySQL's C<SELECT ... FOR UPDATE / FOR SHARE> locking syntax,
including the C<OF tbl_name>, C<NOWAIT>, and C<SKIP LOCKED> clauses
introduced in MySQL 8.0.1.

=back

=head1 METHODS

=head2 apply_limit

Uses MySQL's C<LIMIT [offset,] rows> syntax instead of the standard
C<LIMIT rows OFFSET offset>.

=head2 insert

Overrides the standard C<INSERT> to emit C<INSERT INTO t () VALUES ()> for
rows with no column values, satisfying MySQL's syntax requirements.

=head2 update

=head2 delete

Overrides the base C<update> and C<delete> methods. When the modification
target table is referenced in a subquery within the same statement (a pattern
MySQL rejects), the affected subquery is automatically re-wrapped in an
additional C<SELECT * FROM (...) `_forced_double_subquery`> layer to satisfy
MySQL's parser.

=head2 _lock_select

Generates the locking clause appended to C<SELECT> statements. Accepts
either a plain string (C<'update'>, C<'share'>) or a hashref
for fine-grained control:

  $rs->search({}, { for => { type => 'update', of => ['tbl'], modifier => 'nowait' } });

Valid C<type> values: C<update>, C<share>.
Valid C<modifier> values: C<nowait>, C<skip_locked>.
The C<of> key takes a table name or arrayref of table names.

=seealso

=over 4

=item * L<DBIO::MySQL::Storage> - Storage class that uses this SQL maker

=item * L<DBIO::MySQL> - Schema component entry point

=back

=head1 AUTHOR

DBIO & DBIx::Class Authors

=head1 COPYRIGHT AND LICENSE

Copyright (C) 2026 DBIO Authors
Portions Copyright (C) 2005-2025 DBIx::Class Authors
Based on DBIx::Class, heavily modified.

This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut



( run in 1.002 second using v1.01-cache-2.11-cpan-bbe5e583499 )